[前][次][番号順一覧][スレッド一覧]

ruby-changes:64786

From: aycabta <ko1@a...>
Date: Fri, 8 Jan 2021 13:38:36 +0900 (JST)
Subject: [ruby-changes:64786] 917050220a (master): [ruby/irb] Use Exception#full_message to show backtrace in the correct order

https://git.ruby-lang.org/ruby.git/commit/?id=917050220a

From 917050220a1fd41bdb3e50ea54a200b0c285bcd4 Mon Sep 17 00:00:00 2001
From: aycabta <aycabta@g...>
Date: Fri, 8 Jan 2021 04:17:21 +0900
Subject: [ruby/irb] Use Exception#full_message to show backtrace in the
 correct order

[Bug #17466]

https://github.com/ruby/irb/commit/1c76845cca

diff --git a/lib/irb.rb b/lib/irb.rb
index 2926825..c7563d1 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -610,50 +610,44 @@ module IRB https://github.com/ruby/ruby/blob/trunk/lib/irb.rb#L610
         irb_bug = false
       end
 
-      if STDOUT.tty?
-        attr = ATTR_TTY
-        print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n"
-      else
-        attr = ATTR_PLAIN
-      end
-      messages = []
-      lasts = []
-      levels = 0
       if exc.backtrace
-        count = 0
-        exc.backtrace.each do |m|
-          m = @context.workspace.filter_backtrace(m) or next unless irb_bug
-          count += 1
-          if attr == ATTR_TTY
-            m = sprintf("%9d: from %s", count, m)
+        order = nil
+        if '2.5.0' == RUBY_VERSION
+          # Exception#full_message doesn't have keyword arguments.
+          message = exc.full_message # the same of (highlight: true, order: bottom)
+          order = :bottom
+        elsif '2.5.1' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
+          if STDOUT.tty?
+            message = exc.full_message(order: :bottom)
+            order = :bottom
           else
-            m = "\tfrom #{m}"
-          end
-          if messages.size < @context.back_trace_limit
-            messages.push(m)
-          elsif lasts.size < @context.back_trace_limit
-            lasts.push(m).shift
-            levels += 1
+            message = exc.full_message(order: :top)
+            order = :top
           end
+        else # RUBY_VERSION < '2.5.0' || '3.0.0' <= RUBY_VERSION
+          message = exc.full_message(order: :top)
+          order = :top
         end
-      end
-      if attr == ATTR_TTY
-        unless lasts.empty?
-          puts lasts.reverse
-          printf "... %d levels...\n", levels if levels > 0
-        end
-        puts messages.reverse
-      end
-      converted_exc_s = convert_invalid_byte_sequence(exc.to_s.dup)
-      m = converted_exc_s.split(/\n/)
-      print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n"
-      puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"}
-      if attr == ATTR_PLAIN
-        puts messages
-        unless lasts.empty?
-          puts lasts
-          printf "... %d levels...\n", levels if levels > 0
-        end
+        message = convert_invalid_byte_sequence(message)
+        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[0..(@context.back_trace_limit - 1)]
+              lines << '... %d levels...' % omit
+            end
+          end
+          lines = lines.reverse if order == :bottom
+          lines.map{ |l| l + "\n" }.join
+        }
+        puts message
       end
       print "Maybe IRB bug!\n" if irb_bug
     end
diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb
index d1c3ec6..b3d1884 100644
--- a/test/irb/test_context.rb
+++ b/test/irb/test_context.rb
@@ -83,6 +83,7 @@ module TestIRB https://github.com/ruby/ruby/blob/trunk/test/irb/test_context.rb#L83
     end
 
     def test_eval_input
+      skip if RUBY_ENGINE == 'truffleruby'
       verbose, $VERBOSE = $VERBOSE, nil
       input = TestInputMethod.new([
         "raise 'Foo'\n",
@@ -95,7 +96,7 @@ module TestIRB https://github.com/ruby/ruby/blob/trunk/test/irb/test_context.rb#L96
         irb.eval_input
       end
       assert_empty err
-      assert_pattern_list([:*, /RuntimeError \(.*Foo.*\).*\n/,
+      assert_pattern_list([:*, /\(irb\):1:in `<main>': Foo \(RuntimeError\)\n/,
                            :*, /#<RuntimeError: Foo>\n/,
                            :*, /0$/,
                            :*, /0$/,
@@ -415,5 +416,65 @@ module TestIRB https://github.com/ruby/ruby/blob/trunk/test/irb/test_context.rb#L416
       assert_equal("=> abc\ndef\n",
                    out)
     end
+
+    def test_eval_input_with_exception
+      skip if RUBY_ENGINE == 'truffleruby'
+      verbose, $VERBOSE = $VERBOSE, nil
+      input = TestInputMethod.new([
+        "def hoge() fuga; end; def fuga() raise; end; hoge\n",
+      ])
+      irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
+      out, err = capture_output do
+        irb.eval_input
+      end
+      assert_empty err
+      if '2.5.0' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
+        expected = [
+          :*, /Traceback \(most recent call last\):\n/,
+          :*, /\t 2: from \(irb\):1:in `<main>'\n/,
+          :*, /\t 1: from \(irb\):1:in `hoge'\n/,
+          :*, /\(irb\):1:in `fuga': unhandled exception\n/,
+        ]
+      else
+        expected = [
+          :*, /\(irb\):1:in `fuga': unhandled exception\n/,
+          :*, /\tfrom \(irb\):1:in `hoge'\n/,
+          :*, /\tfrom \(irb\):1:in `<main>'\n/,
+        ]
+      end
+      assert_pattern_list(expected, out)
+    ensure
+      $VERBOSE = verbose
+    end
+
+    def test_eval_input_with_invalid_byte_sequence_exception
+      skip if RUBY_ENGINE == 'truffleruby'
+      verbose, $VERBOSE = $VERBOSE, nil
+      input = TestInputMethod.new([
+        %Q{def hoge() fuga; end; def fuga() raise "A\\xF3B"; end; hoge\n},
+      ])
+      irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
+      out, err = capture_output do
+        irb.eval_input
+      end
+      assert_empty err
+      if '2.5.0' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
+        expected = [
+          :*, /Traceback \(most recent call last\):\n/,
+          :*, /\t 2: from \(irb\):1:in `<main>'\n/,
+          :*, /\t 1: from \(irb\):1:in `hoge'\n/,
+          :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/,
+        ]
+      else
+        expected = [
+          :*, /\(irb\):1:in `fuga': A\\xF3B \(RuntimeError\)\n/,
+          :*, /\tfrom \(irb\):1:in `hoge'\n/,
+          :*, /\tfrom \(irb\):1:in `<main>'\n/,
+        ]
+      end
+      assert_pattern_list(expected, out)
+    ensure
+      $VERBOSE = verbose
+    end
   end
 end
diff --git a/test/irb/test_raise_no_backtrace_exception.rb b/test/irb/test_raise_no_backtrace_exception.rb
index 9babc29..40ee0c5 100644
--- a/test/irb/test_raise_no_backtrace_exception.rb
+++ b/test/irb/test_raise_no_backtrace_exception.rb
@@ -17,7 +17,7 @@ IRB https://github.com/ruby/ruby/blob/trunk/test/irb/test_raise_no_backtrace_exception.rb#L17
     def test_raise_exception_with_invalid_byte_sequence
       skip if RUBY_ENGINE == 'truffleruby'
       bundle_exec = ENV.key?('BUNDLE_GEMFILE') ? ['-rbundler/setup'] : []
-      assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<~IRB, /StandardError \(A\\xF3B\)/, [])
+      assert_in_out_err(bundle_exec + %w[-rirb -W0 -e IRB.start(__FILE__) -- -f --], <<~IRB, /A\\xF3B \(StandardError\)/, [])
         raise StandardError, "A\\xf3B"
       IRB
     end
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]