英文:
#inspect on BasicObject oddity
问题
从BasicObject继承时会出现以下情况:
class Test < BasicObject
def inspect
"foobar"
end
end
test = Test.new
test.inspect
# => "foobar"
test
(Object doesn't support #inspect)
=>
是否可以以一种方式实现inspect,以便在IRB中正常运行?
英文:
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?
答案1
得分: 2
这是IRB::ColorPrinter#pp
中的一个bug:
def pp(obj)
if obj.is_a?(String)
# 避免调用 Ruby 2.4+ 的 String#pretty_print 函数,它会将字符串按 "\n" 进行分割
text(obj.inspect)
else
super
end
end
BasicObject
没有is_a?
方法,因此会引发NoMethodError
异常。由 IRb Inspector 引发的任何异常都会在代码中以相同方式处理,不论原因和来源:
# 在 irb 中评估输入并输出时调用的 Proc 函数。
def inspect_value(v)
@inspect.call(v)
rescue
puts "(Object doesn't support #inspect)"
''
end
这是两种反模式的结合:显式继承检查和 Pokemon 异常处理。嘿,没有人曾声称 Ruby 标准库是良好代码的示例。(也没有人声称 IRb 是一个好的 REPL。)
这种错误吞噬行为具有误导性,并且一个月前就已经被报告为错误了:
> 似乎IRB::Inspector#inspect_value
会吞噬错误,然后只提供一个具有误导性和无帮助的消息(Object doesn't support #inspect)。
实际上,已经有一个Pull Request解决了这个bug报告,并改进了这个错误消息,可以立即告诉您出了什么问题。实际上,Bug报告和Pull请求使用来激发这个更改的示例就是您的问题:一个不响应is_a?
的对象:
> # 之前
> lang-ruby > irb(main):001:0> c = Cat.new "foo" > (Object doesn't support #inspect) >
> # 之后
> lang-none > irb(main):001:0> c = Cat.new "foo" > 在检查对象时发生了错误:#<NoMethodError: > undefined method `is_a?' for foo:Cat > > if obj.is_a?(String) > ^^^^^^> > Kernel#inspect 的结果:#<Cat:0x0000000109090d80 @name="foo"> >
然而,Bug报告和Pull请求只关于错误消息,它们没有解决错误本身,可以通过使用Module#===
来解决,而不是使用Object#is_a?
。
英文:
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
> lang-ruby
> irb(main):001:0> c = Cat.new "foo"
> (Object doesn't support #inspect)
>
> # After
> lang-none
> 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?
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论