Ruby元编程,RSpec如何"应该"工作?

Dan*_*iel 13 ruby rspec metaprogramming

我正在阅读RSpec,我正在试图弄清楚RSpec的"应该"是如何实现的.

有人可以介绍一下这个函数的元性质是如何工作的吗?

代码位于:

http://github.com/dchelimsky/rspec/blob/master/lib/spec/expectations/extensions/kernel.rb

TIA,

-daniel

澄清:

target.should == 5
Run Code Online (Sandbox Code Playgroud)

目标的价值是如何传递给"应该"的,而这又是"=="与5的对比?

Bry*_*Ash 27

看看类OperatorMatcher.

这一切都归结为Ruby允许你省略句号和括号.你真正写的是:

target.should.send(:==, 5)
Run Code Online (Sandbox Code Playgroud)

也就是说,将消息发送should到对象target,然后将消息发送==到任何should返回.

这个方法should是猴子修补的Kernel,所以它可以被任何对象接收.在Matcher通过返回should保持actual在这种情况下target.

Matcher工具的方法==,其确实与比较的expected,在这种情况下,是数字5.减少例子,你可以尝试自己:

module Kernel
  def should
    Matcher.new(self)
  end
end

class Matcher
  def initialize(actual)
    @actual = actual
  end

  def == expected
    if @actual == expected
      puts "Hurrah!"
    else
      puts "Booo!"
    end
  end
end

target = 4
target.should == 5
=> Booo!

target = 5
target.should == 5
=> Hurrah!
Run Code Online (Sandbox Code Playgroud)

  • 感谢一个很好的解释,不仅回答了问题,而且是对Ruby中某些机制的一个很好的总结.对于刚接触Ruby的人,请注意函数中的最后一个表达式是隐式返回值,因此在C++中应该是Matcher*Kernel :: should(){返回新的Matcher(this); } (3认同)
  • 第一:非常好的答案,非常感谢!两个快速观察:您可以在类Object上执行此操作,而不是在内核模块上定义"should".我发现它更安全,因为它不那么通用.第二件事是你不需要元编程来定义方法==.您可以将其定义为任何其他常规方法,以便更容易阅读:def ==(预期) (2认同)