File.foreachのスタブ

先日 モックとスタブ - 日々此妄想 の悩み

File.foreachみたいなブロック付きメソッドのスタブってどうやって書くのかなぁ。。。。

Young risk taker.: [RSpec] Mock API を見ていて、たぶん and_yield だというところまでは目をつけていた。

yield

わかってるつもりだったけど、ちょっと甘かったっぽい。

def foo
  yield(1,2)
end

foo {|a,b|
  p [a, b]
}  # => [1, 2] (要するに p [1, 2] を実行した)

これは理解できてたんですよ。はい。


じゃー Array#each みたいなのはどうするのか理解できてなかったっぽい。*1


で、and_yieldを知るには、まずyieldだと思ってRubyのリファレンスを見ました。すると目から

def bar
  yield 10
  yield 20
  yield 30
end

# barに「1引数手続き、その働きは引数に3を足してpで印字する」というものを渡して実行させる
bar {|v|
  p v + 3
} #  13
  #  23
  #  33 (同じブロックが3つのyieldで3回起動された。
  #      具体的には p 10 + 3; p 20 + 3; p 30 + 3 を実行した)

鱗!!!!!!!!


へー、そうなんだ。そうだったんだ。しらなんだ。yieldってそうやって使うのね(恥)

と、いう事で and_yield

さて、では File.foreach のスタブはどう書くか。。。
こうしてみた。

File.stub!(:foreach).and_yield('1| one')

File.foreach('text_file') do |line|
  line.split[1] # => 'one'
end

まぁ、これは悩む前もできてた、問題は複数行の時

こうしてみた。

File.stub!(:foreach).and_yield('1| one').and_yield('2| two').and_yield('3| tree')

File.foreach('text_file') do |line|
  line.split[1] # => 'one', 'two', 'tree'
end

やったー。できたー。


yieldってそうやってつかうのねー。なるほどなるほど。

という事で、もうちょっとスマートに

text_file = %w(1| one
               2| two
               3| tree)
foreach_stub = File.stub!(:foreach)
text_file.each do |line|
  foreach_stub.and_yield(line)
end

とか、しとくんですかね?

*1:正解はRubyリファレンスのyieldのところに書いてあります