The following happens when inheriting from BasicObject:
class Test < BasicObject
def inspect
"foobar"
end
end
test = Test.new
test.inspect
# => "foobar"
test
(Object doesn't support #inspect)
=>
Is it possible to implement inspect in a way for it to behave normally in IRB?
It's a bug in IRb, or more precisely, in IRB::ColorPrinter#pp
:
def pp(obj)
if obj.is_a?(String)
# Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
text(obj.inspect)
else
super
end
end
BasicObject
does not have is_a?
, so this will raise
a NoMethodError
exception. Any exception raise
d by an IRb Inspector, in turn, is treated the same, regardless of cause and origin:
# 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)"
''
end
This is a combination of two anti-patterns: explicit inheritance checking and Pokemon exception handling. Hey, nobody ever claimed the Ruby standard library is an example of good code. (And nobody ever claimed IRb is a good REPL either.)
The fact that this error-swallowing behavior is misleading was already filed as a bug a month ago:
It seems like
IRB::Inspector#inspect_value
can swallow errors and then only provides a misleading and unhelpful message (Object doesn't support #inspect).
There is actually a Pull Request which addresses this bug report and improves this very error message and would have immediately told you what is going wrong. In fact, the example the Bug Report and the Pull Request uses to motivate the change is literally your problem: an object that doesn't respond to is_a?
:
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">
However, the Bug Report and the Pull Request are only about the error message, they do not address the error itself, which could be addressed by using Module#===
instead of Object#is_a?
.