这是一个利用自定义RSpec匹配器yield_variables:
的期望specify { expect{ |p| [3,4,5].my_each(&p) }.to yield_variables [3,4,5] }
我的yield_variables匹配器的匹配?方法使用一个名为Probe的自定义类(Probe是RSpec' s yield probe的精简版):
...
def matches? block
ap Probe.probe block
# note i am inspecting what is returned by Probe.probe with ap
end
...
# Probe class is what all my questions are about!
class Probe
attr_accessor :yielded_args
def initialize
self.yielded_args = []
end
def self.probe(block)
probe = new
block.call(probe)
probe.yielded_args
end
def to_proc
Proc.new { |*args| yielded_args << args }
end
end
现在我在matches?
内的ap报告了这个:[3,4,5]
这就是我的期望。但是,我不知道Probe类是如何工作的!
问题1)比赛?块
通常,我们传递的参数匹配?是我们期望主题回归的。即,我希望将[3,4,5]
传递给阻止。
相反,|p| [3,4,5].my_each(&p)
作为proc传递到块中。这是为什么?
问题2) block.call(探测)
我对触发器有点不确定所以请慢慢解释。但基本上,我们在这里采用我的Probe类的一个新实例并且发送&#39;它的块,作为一个论点。这就是我如何尽我所能解释它,但我可能完全错了,所以请慢慢解释。
问题3)如何调用to_proc?
如何自动调用.to_proc?我相信它会被block.call(探测器)自动调用。 to_proc是一个自动调用的方法,比如initialize?每当将类发送到proc时它会自动调用吗? (顺便说一句,这个类被发送到一个proc的短语对我来说甚至没有任何意义 - 请解释一下。该块不再作为参数传递给该类。或者如果该块被传递作为一个参数,block.call语法感觉非常奇怪和倒退)
问题4) to_proc
to_proc如何访问期望主题,即|p| [3,4,5].my_each(&p)
? Proc.new&#39; s * args如何自动填充每一个可能的yield参数,即使我只传入了| p | ? Proc.new如何与my_each一起循环,逐步将我的所有args放在一个数组中? Proc.new如何知道主题|p| [3,4,5].my_each(&p)
?怎么样??请解释一下,谢谢。
答案 0 :(得分:2)
基于块的游行者与其他游戏玩家的工作方式略有不同。通常,如果评估了您感兴趣的表达式并将结果传递给您,您通常会做一些无法实现的事情。
例如,raises_error
匹配器想要执行块本身以查看是否引发了正确的异常,并且change
匹配器想要在之前和之后评估其他表达式,以查看它是否在指定的方式。这就是你传递一个块而不是值的原因。
您传递给expect
的块接受1个参数,并将其用作my_each
调用中的块,因此当您的Probe.probe方法调用块时,它必须传递一些内容作为值。你的措辞是“将块发送到探测器实例”,但它是另一种方式:使用probe作为参数调用块。
该块执行并调用my_each
。在此处p
是Probe
的实例。使用&amp;前缀参数告诉ruby这个参数应该用作方法的块(方法是my_each)。如果参数不是proc ruby,则调用to_proc
。这就是Probe#to_proc的调用方式
假设my_each
的行为与普通each
类似,它将为数组中的每个值调用其块(即to_proc
的返回值)。< / p>
通常,您的匹配器会将Probe.probe
的返回值与实际值进行比较。