ブロックなしの場合は配列を返す

あるメソッドがブロックを受け付けるかどうかはあらかじめ決まっている。受け付けるものは「ブロック付きメソッド」と呼び、それはそういうもんだと思った。で、すべてのメソッドはブロックを受け付けるか、あるいは受け付けないかのどちらかなのかな、と思ってしまった。

これはそんなことはなくて、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にするんだろうなぁ。