#检查BasicObject的奇怪之处

huangapple go评论60阅读模式
英文:

#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 raised 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?.

huangapple
  • 本文由 发表于 2023年2月18日 23:51:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75494505.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定