在 rspec 上下文中解释 procs 的用法

Explain the usage of procs in an rspec context

这是一个使用自定义 RSpec 匹配器的期望,yield_variables:

specify { expect{ |p| [3,4,5].my_each(&p) }.to yield_variables [3,4,5] }

我的 yield_variables 匹配器的匹配项?方法使用一个名为 Probe 的自定义 class(Probe 是 RSpec 的 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

现在我的 ap inside matches? 报告:[3,4,5] 这就是我所期望的。但是,我不知道探测器 class 是如何工作的!!

问题 1) 火柴?区块

通常情况下,我们传递给匹配的参数?是我们期望的主题return。即,我希望 [3,4,5] 被传递到块中。 相反,|p| [3,4,5].my_each(&p) 作为 proc 传递到块中。这是为什么?

问题2)block.call(探查)

我对 proc 有点不太了解所以请慢慢解释。但基本上,这里我们采用我的 Probe class 和 'send' 块的新实例作为参数。这就是我尽力解释的方式,但我可能完全错了,所以请慢慢解释。

问题3)to_proc是怎么调用的?

.to_proc 到底是怎么自动调用的?我相信它是由 block.call(probe) 自动调用的。 to_proc是和initialize一样自动调用的方法吗?每当将 class 发送到 proc 时,它会自动调用吗? (顺便说一句, class 被发送到 proc 的短语对我来说甚至没有 100% 的意义 - 请解释。该块不再作为参数传递到 class 中。或者如果该块作为参数传递 block.call 语法感觉真的很奇怪和倒退)

问题4)to_proc

to_proc 如何访问期望的主题,即 |p| [3,4,5].my_each(&p)? Proc.new 的 *args 如何自动填充每个可能的 yield 参数,即使我只传入了 |p| ? Proc.new 如何与我的 my_each 一起循环,将我所有的参数递增地放入数组中? Proc.new 如何了解主题 |p| [3,4,5].my_each(&p)?如何??请解释,谢谢。

基于块的行进器与其他匹配器的工作方式略有不同。通常,如果对您感兴趣的表达式进行求值并将结果传递给您,您想做一些不可能的事情。

例如,raises_error 匹配器想要执行块本身以查看是否引发了正确的异常,而 change 匹配器想要在前后评估其他表达式以查看它是否更改以指定的方式。这就是为什么向您传递的是块而不是值。

您传递给 expect 的块采用 1 个参数并将其用作对 my_each 的调用中的块,因此当您的 Probe.probe 方法调用该块时,它必须传递一些东西作为价值。您已经表述为 "sending the block to the probe instance" 但它是另一种方式:使用 probe 作为参数调用该块。

块执行并调用my_each。这里 pProbe 的实例。在参数前加上 & 告诉 ruby 这个参数应该用作方法的块(方法是 my_each)。如果参数还不是 proc ruby 调用 to_proc 。这就是 Probe#to_proc 的调用方式

假设 my_each 的行为与正常的 each 相似,它将调用它的块(即 to_proc 的 return 值)一次数组中的值。

通常情况下,您的匹配器会将 Probe.probe 中的 return 值与实际值进行比较。