ブロックなしの場合は配列を返す
あるメソッドがブロックを受け付けるかどうかはあらかじめ決まっている。受け付けるものは「ブロック付きメソッド」と呼び、それはそういうもんだと思った。で、すべてのメソッドはブロックを受け付けるか、あるいは受け付けないかのどちらかなのかな、と思ってしまった。
これはそんなことはなくて、yield文が使われているライブラリを眺めていて、こんなのがいっぱいあるのに気づいた。
def new_xml_stylesheet xss = XMLStyleSheet.new(@maker) @xml_stylesheets << xss if block_given? yield xss else xss end end
要するにブロックを受け取ったかどうかはメソッド定義の中で判定して、それに応じた処理をしてやればいいのだ。配列っぽいやつはeachで1つずつyieldしてブロックで処理してもいいし、ブロックなしで呼び出されたら配列を返すまで、ということでいいみたいだ。
というわけでArryaの要素をランダムに並べ替えるrand_eachメソッドで、ブロックあり/なしの両方に対応させてみた。
class Array def rand_each @ary = [] while(self.size > 0) r = rand(self.size) @ary << self[r] self.delete_at(r) end if block_given? @ary.each{|e| yield(e) } else @ary end end end
irb(main):001:0> require 'y.rb' => true irb(main):002:0> (0..9).to_a.rand_each{|i| puts i} 8 1 5 6 0 9 3 7 4 2 => [8, 1, 5, 6, 0, 9, 3, 7, 4, 2] irb(main):003:0> (0..9).to_a.rand_each => [3, 9, 6, 0, 4, 1, 7, 8, 5, 2]
しかし、どうもメソッド名にeachが入ってるのって何か変だな。ふつうに考えたら、ブロックなしのほうはArray#randにするんだろうなぁ。