ブロックを付けておくといろいろ出来ます。
new {|y| ... } -> EnumeratorEnumerator オブジェクトを生成して返します。与えられたブロックは Enumerator::Yielder オブジェクトを引数として実行されます。
生成された Enumerator オブジェクトに対して each を呼ぶと、この生成時に指定されたブロックを実行し、Yielder オブジェクトに対して << メソッドが呼ばれるたびに、 each に渡されたブロックが繰り返されます。
new に渡されたブロックが終了した時点で each の繰り返しが終わります。 このときのブロックの返り値が each の返り値となります。enum = Enumerator.new{ |y| (1..10).each{ |i| y << i if i % 5 == 0 } } enum.each{ |i| p i } #=> 5 10 fib = Enumerator.new { |y| a = b = 1 loop { y << a a, b = b, a + b } } p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
ということで、ポイントは「<<」メソッドでローカルブロック変数に配列(というかenumerableな)要素を入れ込むということですね。
無限リストを作る例
# ブロックなしだと succ で進める
# ブロックありだと、ブロックの評価結果を次の要素にするdef builis(start) Enumerator.new { |y| i = start loop { y << i i = block_given? ? yield(i) : i.succ } } end
利用例としては、やはりフィボナッチ数列。
#みんな大好きフィボナッチ builis([0,1]){ |x| [x[1], x[0]+x[1]] }.take(15).map(&:first) #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377] #みんな大好きフィボナッチもう一つ builis([]){ |x| [x,x[0]] }.take(15).map{ |x|x.flatten.size } #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
ここの内容には関係ないですが、後者は思いつきませんよw