From df42a6b0fa47f3428f968aa0c8e47621ff3cc883 Mon Sep 17 00:00:00 2001 From: tompng Date: Thu, 23 Nov 2023 23:04:23 +0900 Subject: [PATCH] Fix exception(backtrace=nil) prints nothing --- lib/irb.rb | 67 +++++++++++++++----------------- test/irb/test_raise_exception.rb | 7 +--- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/lib/irb.rb b/lib/irb.rb index 754765425..8c3039482 100644 --- a/lib/irb.rb +++ b/lib/irb.rb @@ -697,7 +697,7 @@ def encode_with_invalid_byte_sequence(str, enc) end def handle_exception(exc) - if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && + if exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && !(SyntaxError === exc) && !(EncodingError === exc) # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno. irb_bug = true @@ -705,44 +705,41 @@ def handle_exception(exc) irb_bug = false end - if exc.backtrace - order = nil - if RUBY_VERSION < '3.0.0' - if STDOUT.tty? - message = exc.full_message(order: :bottom) - order = :bottom - else - message = exc.full_message(order: :top) - order = :top - end - else # '3.0.0' <= RUBY_VERSION + if RUBY_VERSION < '3.0.0' + if STDOUT.tty? + message = exc.full_message(order: :bottom) + order = :bottom + else message = exc.full_message(order: :top) order = :top end - message = convert_invalid_byte_sequence(message, exc.message.encoding) - message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s) - message = message.gsub(/((?:^\t.+$\n)+)/) { |m| - case order - when :top - lines = m.split("\n") - when :bottom - lines = m.split("\n").reverse - end - unless irb_bug - lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact - if lines.size > @context.back_trace_limit - omit = lines.size - @context.back_trace_limit - lines = lines[0..(@context.back_trace_limit - 1)] - lines << "\t... %d levels..." % omit - end - end - lines = lines.reverse if order == :bottom - lines.map{ |l| l + "\n" }.join - } - # The "" in "(irb)" may be the top level of IRB so imitate the main object. - message = message.gsub(/\(irb\):(?\d+):in `<(?top \(required\))>'/) { "(irb):#{$~[:num]}:in `
'" } - puts message + else # '3.0.0' <= RUBY_VERSION + message = exc.full_message(order: :top) + order = :top end + message = convert_invalid_byte_sequence(message, exc.message.encoding) + message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s) + message = message.gsub(/((?:^\t.+$\n)+)/) { |m| + case order + when :top + lines = m.split("\n") + when :bottom + lines = m.split("\n").reverse + end + unless irb_bug + lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact + if lines.size > @context.back_trace_limit + omit = lines.size - @context.back_trace_limit + lines = lines[0..(@context.back_trace_limit - 1)] + lines << "\t... %d levels..." % omit + end + end + lines = lines.reverse if order == :bottom + lines.map{ |l| l + "\n" }.join + } + # The "" in "(irb)" may be the top level of IRB so imitate the main object. + message = message.gsub(/\(irb\):(?\d+):in `<(?top \(required\))>'/) { "(irb):#{$~[:num]}:in `
'" } + puts message puts 'Maybe IRB bug!' if irb_bug rescue Exception => handler_exc begin diff --git a/test/irb/test_raise_exception.rb b/test/irb/test_raise_exception.rb index 9ca534dba..c373dd733 100644 --- a/test/irb/test_raise_exception.rb +++ b/test/irb/test_raise_exception.rb @@ -7,11 +7,8 @@ module TestIRB class RaiseExceptionTest < TestCase def test_raise_exception_with_nil_backtrace bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : [] - assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, /Exception: foo/, []) - e = Exception.new("foo") - puts e.inspect - def e.backtrace; nil; end - raise e + assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<-IRB, /#/, []) + raise Exception.new("foo").tap {|e| def e.backtrace; nil; end } IRB end