From f406e904567459113c27e4248d49032178f0d5f9 Mon Sep 17 00:00:00 2001 From: nick evans Date: Tue, 10 Feb 2026 18:24:24 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20parser=20backtrace=20detai?= =?UTF-8?q?ls=20for=20ruby=20<=3D=203.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the backtrace_locations don't _explicitly_ include the class name, this still feelds inherently brittle. But it's very useful! It's a worthwhile tradeoff, IMO. --- lib/net/imap/errors.rb | 11 ++++++++--- test/net/imap/test_errors.rb | 9 +++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/net/imap/errors.rb b/lib/net/imap/errors.rb index cfa21fbe..a64cab41 100644 --- a/lib/net/imap/errors.rb +++ b/lib/net/imap/errors.rb @@ -101,8 +101,9 @@ def initialize(message = "unspecified parse error", # included. Defaults to the value of Net::IMAP.debug. # # When +parser_backtrace+ is true, a simplified backtrace is included, - # containing only frames which belong to methods in parser_class. Most - # parser method names are based on rules in the IMAP grammar. + # containing only frames for methods in parser_class (since ruby 3.4) or + # which have "net/imap/response_parser" in the path (before ruby 3.4). + # Most parser method names are based on rules in the IMAP grammar. def detailed_message(parser_state: Net::IMAP.debug, parser_backtrace: false, **) @@ -124,7 +125,11 @@ def detailed_message(parser_state: Net::IMAP.debug, backtrace_locations&.each_with_index do |loc, idx| next if loc.base_label.include? "parse_error" break if loc.base_label == "parse" - next unless loc.label.include?(parser_class.name) + if loc.label.include?("#") # => Class#method, since ruby 3.4 + next unless loc.label&.include?(parser_class.name) + else + next unless loc.path&.include?("net/imap/response_parser") + end msg << "\n caller[%2d]: %-30s (%s:%d)" % [ idx, loc.base_label, diff --git a/test/net/imap/test_errors.rb b/test/net/imap/test_errors.rb index 61370af5..3c0b70e7 100644 --- a/test/net/imap/test_errors.rb +++ b/test/net/imap/test_errors.rb @@ -88,6 +88,15 @@ def self.SGR(*attr) = CSI attr.join(?;), ?m "#{BOLD}#{msg} (#{BOLD_UNDERLINE}#{name}#{RESET}#{BOLD})#{RESET}", err.detailed_message(highlight: true) ) + + # with parser_backtrace + Net::IMAP.debug = false + parser = Net::IMAP::ResponseParser.new + error = parser.parse("* 123 FETCH (UNKNOWN ...)\r\n") rescue $! + no_hl = error.detailed_message(parser_backtrace: true) + no_color = error.detailed_message(parser_backtrace: true, highlight: true) + assert_include no_hl, "caller[ 1]: %-30s (" % "msg_att" + assert_include no_color, "caller[ 1]: %-30s (" % "msg_att" end test "ResponseTooLargeError" do