意識して使ってないけど、配列のeachメソッドやループのtimesなどがこれに該当する。
Enumerableオブジェクト
組み込みオブジェクトのArrayやHashがincludeしているモジュール。Enumerableをincludeして、eachメソッドを定義してあげれば独自モジュールでもEnumerableが提供する様々なメソッドを利用出来る。
Arrayを使った場合のコード
array = [1, 2, 3] # eachでループ array.each {|x| puts x } # 添字付きでループ array.each_with_index {|x, i| puts "#{i} = #{x}" }出力結果はこんな感じ
1 2 3 0 = 1 1 = 2 2 = 3
独自クラスの場合
class Hoge include Enumerable def initialize(num) @num = num end def each @num.each {|num| # prefixにhoge_を付加する。 yield "hoge_#{num}" } end end出力結果はこんな感じ
Enumerableで定義されてるgrepもちゃんと使えてるのが分かる。
each start... hoge_1 hoge_2 hoge_3 hoge_4 grep start... hoge_2 hoge_3
ruby始めた頃は、each_with_indexなんて知らなくて、こんなループをかいてた・・・。
まぁ、動くから間違ってはないけど直感的ではないよね。一瞬なにがしたいんだ?って思ってしまう。
array.count.times {|i| puts "array[#{i}] = [#{array[i]}]" }
Enumeratorオブエクト
each以外のメソッドでもEnumerableを使うためのラッパークラスEnumeratorはイミュータブルなので、生成したあとの状態変更はできない。
なので、配列でパラメータ渡しをするのではなくEnumeratorを指定したほうが良い。
# eachメソッドを定義しているクラスのto_enumを呼び出すと、Enumeratorを生成できる。 enum = array.to_enum enum.each {|x| puts x } # enumメソッドを定義していないクラスの場合 class Hoge def initialize(num) @num = num end def hoge @num.each {|num| yield "hoge_#{num}" } end end hoge = Hoge.new([1, 2, 3, 4]) # enum_forメソッドに、eachと同義のhogeメソッドを指定して Enumeratorを生成する。 enum = hoge.enum_for(:hoge) puts "each start..." enum.each {|x| puts x } puts "grep start..." enum.grep(/^.*[23]$/) {|x| puts x }実行結果はこんな感じ
hogeメソッドしか持っていなくても、Enumerableのメソッドを利用できている。
each start... hoge_1 hoge_2 hoge_3 hoge_4 grep start... hoge_2 hoge_3