Bug #8982
closedNoMethodError#message produces surprising output when #inspect is defined on an anonymous class
Description
=begin
Given the following script:
def raise_no_method_error_for_anonymous_class_with_inspect(&block)
klass = Class.new do
define_method(:inspect, &block)
end
begin
instance = klass.new
puts "#inspect output: #{instance.inspect} (#{instance.inspect.length} chars)"
instance.undefined_method
rescue NoMethodError => e
puts e.message
end
puts
end
raise_no_method_error_for_anonymous_class_with_inspect do
"#"
end
raise_no_method_error_for_anonymous_class_with_inspect do
""
end
raise_no_method_error_for_anonymous_class_with_inspect do
"#<MyAnonymousClass #{'a' * 45}>"
end
raise_no_method_error_for_anonymous_class_with_inspect do
"#<MyAnonymousClass #{'a' * 46}>"
end
It produces the following output:
#inspect output: # (19 chars)
undefined method `undefined_method' for #
#inspect output: (18 chars)
undefined method `undefined_method' for :#Class:0x1017270e8
#inspect output: # (65 chars)
undefined method `undefined_method' for #
#inspect output: # (66 chars)
undefined method `undefined_method' for #<#Class:0x1017266e8:0x101726698>
There are two surprising things here:
- It matters whether or not the first character in my
inspect
is a#
. If it's not, ruby appends the class's#inspect
output to it. - It matters how long my
inspect
string is. If it's less than 66 characters, it's used; if it's more than 65, it's discarded, and the default anonymous#inspect
is used instead.
Both of these things are extremely surprising and seem very arbitrary and inconsistent.
I brought this up on ruby parley and @charliesome was kind enough to point me to the code that's the source of this issue:
((<error.c#L1091-1104|URL:https://github.com/ruby/ruby/blob/870dc20922d1ab0b628d24e64e971e8eb77ecd61/error.c#L1091-1104>))
So it looks intentional, but I think this is a bug.
=end