зеркало из https://github.com/github/ruby.git
[ruby/irb] Provide more useful message when
`IRB::Inspector#inspect_value` errors (https://github.com/ruby/irb/pull/511) **Before** ``` irb(main):001:0> c = Cat.new "foo" (Object doesn't support #inspect) => ``` **After** ``` irb(main):001:0> c = Cat.new "foo" An error occurred when inspecting the object: #<NoMethodError: undefined method `is_a?' for foo:Cat if obj.is_a?(String) ^^^^^^> Result of Kernel#inspect: #<Cat:0x0000000109090d80 @name="foo"> => ```
This commit is contained in:
Родитель
4f611df3f7
Коммит
0aa50a03b1
|
@ -35,6 +35,7 @@ module IRB # :nodoc:
|
|||
# irb(main):001:0> "what?" #=> omg! what?
|
||||
#
|
||||
class Inspector
|
||||
KERNEL_INSPECT = Object.instance_method(:inspect)
|
||||
# Default inspectors available to irb, this includes:
|
||||
#
|
||||
# +:pp+:: Using Kernel#pretty_inspect
|
||||
|
@ -93,9 +94,18 @@ module IRB # :nodoc:
|
|||
# Proc to call when the input is evaluated and output in irb.
|
||||
def inspect_value(v)
|
||||
@inspect.call(v)
|
||||
rescue
|
||||
puts "(Object doesn't support #inspect)"
|
||||
''
|
||||
rescue => e
|
||||
puts "An error occurred when inspecting the object: #{e.inspect}"
|
||||
|
||||
begin
|
||||
# TODO: change this to bind_call when we drop support for Ruby 2.6
|
||||
puts "Result of Kernel#inspect: #{KERNEL_INSPECT.bind(v).call}"
|
||||
''
|
||||
rescue => e
|
||||
puts "An error occurred when running Kernel#inspect: #{e.inspect}"
|
||||
puts e.backtrace.join("\n")
|
||||
''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -125,11 +125,11 @@ module TestIRB
|
|||
[:marshal, "123", Marshal.dump(123)],
|
||||
],
|
||||
failed: [
|
||||
[false, "BasicObject.new", /\(Object doesn't support #inspect\)\n(=> )?\n/],
|
||||
[:p, "class Foo; undef inspect ;end; Foo.new", /\(Object doesn't support #inspect\)\n(=> )?\n/],
|
||||
[true, "BasicObject.new", /\(Object doesn't support #inspect\)\n(=> )?\n/],
|
||||
[:yaml, "BasicObject.new", /\(Object doesn't support #inspect\)\n(=> )?\n/],
|
||||
[:marshal, "[Object.new, Class.new]", /\(Object doesn't support #inspect\)\n(=> )?\n/]
|
||||
[false, "BasicObject.new", /#<NoMethodError: undefined method `to_s' for/],
|
||||
[:p, "class Foo; undef inspect ;end; Foo.new", /#<NoMethodError: undefined method `inspect' for/],
|
||||
[true, "BasicObject.new", /#<NoMethodError: undefined method `is_a\?' for/],
|
||||
[:yaml, "BasicObject.new", /#<NoMethodError: undefined method `inspect' for/],
|
||||
[:marshal, "[Object.new, Class.new]", /#<TypeError: can't dump anonymous class #<Class:/]
|
||||
]
|
||||
}.each do |scenario, cases|
|
||||
cases.each do |inspect_mode, input, expected|
|
||||
|
@ -149,6 +149,58 @@ module TestIRB
|
|||
end
|
||||
end
|
||||
|
||||
def test_object_inspection_falls_back_to_kernel_inspect_when_errored
|
||||
omit if RUBY_ENGINE == "truffleruby"
|
||||
verbose, $VERBOSE = $VERBOSE, nil
|
||||
main = Object.new
|
||||
main.singleton_class.module_eval <<~RUBY
|
||||
class Foo
|
||||
def inspect
|
||||
raise "foo"
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new(["Foo.new"]))
|
||||
out, err = capture_output do
|
||||
irb.eval_input
|
||||
end
|
||||
assert_empty err
|
||||
assert_match(/An error occurred when inspecting the object: #<RuntimeError: foo>/, out)
|
||||
assert_match(/Result of Kernel#inspect: #<#<Class:.*>::Foo:/, out)
|
||||
ensure
|
||||
$VERBOSE = verbose
|
||||
end
|
||||
|
||||
def test_object_inspection_prints_useful_info_when_kernel_inspect_also_errored
|
||||
omit if RUBY_VERSION < '2.7' || RUBY_ENGINE == "truffleruby"
|
||||
verbose, $VERBOSE = $VERBOSE, nil
|
||||
main = Object.new
|
||||
main.singleton_class.module_eval <<~RUBY
|
||||
class Foo
|
||||
def initialize
|
||||
# Kernel#inspect goes through instance variables with #inspect
|
||||
# So this will cause Kernel#inspect to fail
|
||||
@foo = BasicObject.new
|
||||
end
|
||||
|
||||
def inspect
|
||||
raise "foo"
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
irb = IRB::Irb.new(IRB::WorkSpace.new(main), TestInputMethod.new(["Foo.new"]))
|
||||
out, err = capture_output do
|
||||
irb.eval_input
|
||||
end
|
||||
assert_empty err
|
||||
assert_match(/An error occurred when inspecting the object: #<RuntimeError: foo>/, out)
|
||||
assert_match(/An error occurred when running Kernel#inspect: #<NoMethodError: undefined method `inspect' for/, out)
|
||||
ensure
|
||||
$VERBOSE = verbose
|
||||
end
|
||||
|
||||
def test_default_config
|
||||
assert_equal(true, @context.use_autocomplete?)
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче