LoginSignup
29
27

More than 5 years have passed since last update.

ブロックを与えない場合にEnumeratorを返すメソッドを作る

Posted at

Rubyのイテレータなメソッドの中には「ブロックを指定しないとEnumeratorを返す」メソッドがいっぱいありますが、そういうメソッドの作り方がRuby歴数ヶ月の自分にはわからなかったので調べました。

  1. ブロックが指定されたかどうかはblock_given?でわかる
  2. Enumeratorを返すんだからEnumerator.newとかするのかな?
  3. Enumeratorの説明を見てみる
  4. Enumeratorを生成するにはEnumerator.new、Object#to_enum、Object#enum_forの3つの方法があるらしい
  5. おもむろに~/lib/ruby/の下でgrepしてみたらそれっぽいコードが引っかかる

というわけで、本体同梱クラスをお手本にして、こうすればよいということがわかりました。

class Foo
  def initialize(str)
    @str = str
  end

  def each_word(minlength = 1)
    # ↓これ
    return enum_for(__method__, minlength) unless block_given?

    @str.split(/\W+/).each do |word|
      yield(word) if word.length >= minlength
    end
  end
end

ブロックが指定されなかったときは、自身のメソッド名を引数にしてenum_forでEnumeratorを返してやればよいわけですね。
※Kernel#__method__は現在のメソッド名を返します。

こんな感じに使えるようになりました。

foo = Foo.new('Lorem ipsum dolor sit amet, consectetur adipisicing elit')
foo.each_word(5) do |v|
  puts v
end
puts

words = foo.each_word(7)
p words
words.with_index do |v, i|
  puts "#{i}: #{v}"
end
Lorem
ipsum
dolor
consectetur
adipisicing

#<Enumerator: #<Foo:0xc42618 @str="Lorem ipsum dolor sit amet, consectetur adipisicing elit">:each_word(7)>
0: consectetur
1: adipisicing
29
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
27