2010-07-30 99 views
3

有两个很好的理由,红宝石1.8不支持重载像某些种类||/or&&/and!/not?:为什么Ruby 1.9允许覆盖! !=!〜?

  • 短路语义不能在没有与Ruby的方法来实现语言的非常广泛的变化。
  • Ruby被硬编码为仅在布尔上下文中将nilfalse视为false。

第一个原因不适用于!/not但第二个原因仍然存在。这不像是你可以使用!来引入你自己的布尔类对象,而&&/||仍然是硬编码的。对于其他用途,已有互补运算符~&/|

我能想象有很多的代码期待!obj是同义与obj ? false : true,并!!objobj ? true : false - 我甚至不确定代码应该如何应对计算结果为布尔值的背景下真正的对象,但!到非虚假的东西。

它看起来不像Ruby计划引入对其他错误值的支持。 Ruby stdlib中没有任何内容似乎覆盖了!,所以我没有找到任何示例。

它有一些真的很好用,我错过了吗?

回答

1

自我回复。到目前为止,我找到了一个合理的用途。我可以破解这个在1.9.2工作在短短的几行字:

describe "Mathematics" do 
    it "2 + 2 != 5" do 
    (2+2).should != 5 
    end 
end 

1.9.2之前的Ruby这样的语句:

describe "Mathematics" do 
    it "2 + 2 != 5" do 
    ((2+2).should == 5) ? false : true 
    end 
end 

但作为返回值被扔掉了,我们没有办法区别== 5!= 5缺少要求Ruby的块的分析树。 PositiveOperatorMatcher#==(5)只会引发ExpectationNotMetError异常,就是这样。看来should !~ /pattern/should !be_something等也可以做成工作。

这是对(2+2).should_not == 5的一些改进,但并不是一个很大的改进。而且无法进一步破解它以获得诸如(2+2).should be_even or be_odd之类的内容。

当然这里要做的正确的事情是asking Ruby for parse tree and macro-expanding that。或者在Ruby解释器中使用调试钩子。有比这更好的用例吗?

顺便说一句,它不足以允许覆盖!,同时翻译!=/!~旧的方式。要求!((2+2).should == 5)工作#==在调用!之前不能引发异常。但是如果#==失败并且!不能运行,执行将会继续。我们将能够在块退出后报告断言失败,但是会在第一次失败后执行测试的代价。(除非我们在断言失败之后打开ruby调试钩子来查看下一个方法调用是否是!self,或类似的东西)