gpt4 book ai didi

ruby - RSpec 认为 block 没有收到 "call"消息?

转载 作者:数据小太阳 更新时间:2023-10-29 07:56:14 26 4
gpt4 key购买 nike

我想使用 RSpec 来确保我的可枚举类与 Ruby 的访问者模式兼容:

# foo.rb
class Foo
def initialize(enum)
@enum = enum
end
include Enumerable
def each(&block)
@enum.each(&block)
end
end

这是我的 rspec 文件:

# spec/foo_spec.rb
require 'rspec'
require './foo.rb'

describe Foo do
let(:items) { [1, 2, 3] }
describe '#each' do
it 'calls the given block each time' do
block = proc { |x| x }
block.should_receive(:call).exactly(items.size).times
Foo.new(items).each(&block)
end
end
end

但令人惊讶的是,我的示例在运行时失败了(使用 rspec v2.14.5):

# $ bundle exec rspec

Failures:

1) Foo#each calls the given block each time
Failure/Error: block.should_receive(:call).exactly(items.size).times
(#<Proc:0x007fbabbdf3f90@/private/tmp/rspec-mystery/spec/foo_spec.rb:8>).call(any args)
expected: 3 times with any arguments
received: 0 times with any arguments
# ./spec/foo_spec.rb:12:in `block (3 levels) in <top (required)>'

Finished in 0.00082 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/foo_spec.rb:11 # Foo#each calls the given block each time

更令人惊讶的是,当通过 ruby​​/irb 使用时,类本身的行为完全符合我的预期:

# $ irb -r ./foo.rb

1.9.3-p125 :002 > f = Foo.new [1, 2, 3]
=> #<Foo:0x007ffda4059f70 @enum=[1, 2, 3]>
1.9.3-p125 :003 > f.each
=> #<Enumerator: [1, 2, 3]:each>
1.9.3-p125 :004 > block = proc { |x| puts "OK: #{x}" }
=> #<Proc:0x007ffda483fcd0@(irb):4>
1.9.3-p125 :005 > f.each &block
OK: 1
OK: 2
OK: 3
=> [1, 2, 3]

为什么 RSpec 没有注意到“ block ”实际上收到了三次“调用”消息?

最佳答案

Why doesn't RSpec notice that the "block" does in fact receive the "call" message three times?

因为 AFAICT,在 MRI 上,它没有。

#each 不是由 Enumerable 提供的,仅由实现它的类提供,并且在您的测试中,您使用的是数组。

这是来自 Array#each 的源代码(C) :

VALUE rb_ary_each(VALUE array)
{
long i;
volatile VALUE ary = array;

RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(RARRAY_PTR(ary)[i]);
}
return ary;
}

由此看来,Array#each yields block 而不是显式调用它。

更新:

您的代码和测试在 Rubinius 和 JRuby 上也失败了,所以看起来他们的标准库在这里也没有使用 call。正如@mechanicalfish 指出的那样,您实际上只需要测试迭代器遍历集合的次数是否正确。

关于ruby - RSpec 认为 block 没有收到 "call"消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20061521/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com