反省した。RubyのblockやProcを分かったつもりになっていて、しょうもないところでハマった。自戒を込めてブログに残しておくことにした。
$ ruby -v
ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin15]
例1
def method_1
if block_given?
puts 'Yes'
yield
else
puts 'No'
end
end
method_1 { puts 'I am a block' }
つまりmethod_1に I am a block
の出力というブロックを渡して、ブロックが有ればYesと共にそれを出せと。
method_1にはブロック引数が無いが、この例のようにそれが問題になることもなく、yieldすればちゃんと実行される。
実行結果
$ ruby block_sample_1.rb
Yes!
I am a block
例2
def method_1
if block_given?
puts 'Yes :method_1'
else
puts 'No :method_1'
end
method_2
end
def method_2
if block_given?
puts 'Yes :method_2'
yield
else
puts 'No :method_2'
end
end
method_1 { puts 'I am a block' }
blockが渡されたmethod_1からmethod_2を呼び出す例。
実行結果
$ ruby block_sample_2.rb
Yes :method_1
No :method_2
渡されたblockはmethod_1まで。method_2には到達していない。
例3
つまり&引数名にしてブロックをProcオブジェクト化して渡す必要がある。その対策後のコード例がこれ。
def method_1 &block
if block_given?
puts 'Yes :method_1'
else
puts 'No :method_1'
end
method_2 &block
end
def method_2
if block_given?
puts 'Yes :method_2'
yield
else
puts 'No :method_2'
end
end
method_1 { puts 'I am a block' }
実行結果
これでしっかりblockがProc化されてmethod_2にまで到達していることが分かる。
$ ruby block_sample_3.rb
Yes :method_1
Yes :method_2
I am a block
例4
def method_1 &block
if block_given?
puts 'Yes :method_1'
else
puts 'No :method_1'
end
method_2 plus_one 1, &block
end
def plus_one number
number + 1
end
def method_2 number, &block
if block_given?
puts 'Yes :method_2'
puts number
yield
else
puts 'No :method_2'
end
end
method_1 { puts 'I am a block' }
実行結果
$ ruby block_sample_4.rb
Yes :method_1
No :method_2
method_2にまでブロックが到達していない。これでハマった。とくに例3と変わったことをしているようにも思えない。ただdef plus_one numberを加えただけで、そこにblockはまったく関係無さそう。なぜmethod_2にまでブロックが到達しないのか、しばらく分からなかった。
見つけた答えがこれ。
例5
def method_1 &block
if block_given?
puts 'Yes :method_1'
else
puts 'No :method_1'
end
method_2 plus_one(1), &block
end
def plus_one number
number + 1
end
def method_2 number, &block
if block_given?
puts 'Yes :method_2'
puts number
yield
else
puts 'No :method_2'
end
end
method_1 { puts 'I am a block' }
実行結果
$ ruby block_sample_5.rb
Yes :method_1
Yes :method_2
2
I am a block
例4との違いはここの()だけ。
method_2 plus_one(1), &block
つかれた。。。
エンジニアの皆様へ
「ほとんどのエンジニアには解けるが、下位10%のダメなエンジニアにだけ解けないパズル?」なるものをシリーズ化してパズル1から8まで作成した。もしご興味あれば解いてみてください。
http://tango-ruby.hatenablog.com/entry/2015/11/30/122814