カテゴリ: Ruby 更新日: 2026/03/14

RubyのEnumerator自作ガイド!to_enumとenum_forで柔軟な繰り返し処理を実現

Enumerator を自作する:to_enum・enum_for で柔軟なAPI設計
Enumerator を自作する:to_enum・enum_for で柔軟なAPI設計

先生と生徒の会話形式で理解しよう

生徒

「Rubyで自分だけの特別な繰り返し処理を作りたいのですが、どうすればいいですか?」

先生

「そんな時はEnumeratorを自作するのが一番です。to_enumやenum_forという魔法を使えば、どんなメソッドも便利な繰り返し機能に変身させることができますよ。」

生徒

「Enumeratorって、配列のeachみたいに使えるあの機能のことですよね?難しくないですか?」

先生

「仕組みさえ分かれば意外と簡単です。プログラミング未経験の方でも理解できるように、基礎から丁寧に解説していきますね!」

1. Enumeratorとは何だろう?

1. Enumeratorとは何だろう?
1. Enumeratorとは何だろう?

プログラミングの世界では、たくさんのデータを一つずつ順番に取り出して処理することを繰り返し処理(ループ)と呼びます。Rubyにおいて、この繰り返しを専門に担当してくれる道具がEnumerator(エニュメレータ)です。

例えば、本棚から本を一つずつ取り出す「動作そのもの」をオブジェクトとして取り出したようなイメージです。これを使うことで、一度に全てのデータを読み込むのではなく、必要な時に必要な分だけデータを取り出すことができるようになります。これはコンピュータのメモリを節約したり、プログラムを柔軟に設計したりする上で非常に重要な考え方です。

Rubyの配列(Array)やハッシュ(Hash)などのデータの集まりには、最初からこのEnumeratorを生成する機能が備わっていますが、自分で定義したクラスやメソッドにこの機能を持たせることが、今回のテーマである「自作」の目的です。

2. to_enumメソッドの役割と基本的な使い方

2. to_enumメソッドの役割と基本的な使い方
2. to_enumメソッドの役割と基本的な使い方

to_enumは、あるメソッドを「繰り返しの道具(Enumerator)」に変換するためのメソッドです。例えば、自分で作った挨拶をするだけのメソッドがあったとしましょう。そのままではただ実行して終わりですが、to_enumを通すことで、そのメソッドを何度も呼び出したり、途中で止めたりすることができるようになります。

初心者の方向けに、最もシンプルな例で考えてみましょう。特定の処理を繰り返す準備を整えるのがto_enumの仕事です。これを使うと、Rubyの便利な機能(mapやselectなど)が自作の処理でも使えるようになります。


class Robot
  def hello
    yield "こんにちは"
    yield "おはよう"
    yield "こんばんは"
  end

  def hello_enum
    # helloメソッドをベースにEnumeratorを作る
    to_enum(:hello)
  end
end

robot = Robot.new
enum = robot.hello_enum

# 順番に中身を取り出す
puts enum.next
puts enum.next

こんにちは
おはよう

3. enum_forはto_enumの別名?

3. enum_forはto_enumの別名?
3. enum_forはto_enumの別名?

Rubyを学んでいると、to_enumの他にもenum_forという名前のメソッドを見かけることがあります。実は、これら二つは全く同じ動きをします。プログラミング言語の中には、このように同じ機能に複数の名前がついていることがあります。

なぜ二つあるのかというと、文脈によって読みやすい方を選べるようにするためです。「このメソッドをEnumeratorに変換(to)する」という意味で使いたい時はto_enum、「このメソッドのための(for)Enumeratorを作る」という意味で使いたい時はenum_forを使うのが一般的です。どちらを使っても間違いではないので、自分がしっくりくる方を選んでください。

4. 柔軟なAPI設計に欠かせないブロックの省略対応

4. 柔軟なAPI設計に欠かせないブロックの省略対応
4. 柔軟なAPI設計に欠かせないブロックの省略対応

Rubyのメソッドでは、eachのように「ブロック(命令の塊)」を渡して使うことが多いです。しかし、使い手がブロックを渡すのを忘れてしまった場合、プログラムがエラーで止まってしまうことがあります。これを防ぎ、より使いやすい設計(API設計)にするために、Enumeratorの自作が活躍します。

具体的には、「もしブロックが渡されなかったら、Enumeratorを返す」という処理を加えます。これにより、メソッドの利用者はeach単体で使って後から色々な加工をしたり、直接ループを回したりと、自由に使い方を選べるようになります。これが「柔軟な設計」の第一歩です。


def repeat_message(message, count)
  # ブロックがない場合はEnumeratorを返す
  return to_enum(:repeat_message, message, count) unless block_given?

  count.times do
    yield message
  end
end

# ブロックを渡さないと、Enumeratorオブジェクトが手に入る
my_enum = repeat_message("ハロー", 3)

# あとからmapなどで加工ができる!
result = my_enum.map { |m| m + "!" }
p result

["ハロー!", "ハロー!", "ハロー!"]

5. パソコン未経験者でもわかるyield(イールド)の仕組み

5. パソコン未経験者でもわかるyield(イールド)の仕組み
5. パソコン未経験者でもわかるyield(イールド)の仕組み

ここで、先ほどのコードにも出てきたyieldという言葉について解説します。これは、メソッドを実行している途中で「一時停止して、外から渡された命令を実行してきて!」とバトンを渡す仕組みのことです。

料理のレシピに例えると分かりやすいでしょう。「野菜を切る」という手順があった時、切り方をあらかじめ決めておくのではなく、その時々で「みじん切りにして」や「乱切りにして」という具体的な指示を受け取れるようにしておくのがyieldの役割です。to_enumは、このバトンを渡すタイミングを管理し、一つずつ順番に実行できるようにしてくれる司令塔なのです。

6. 引数があるメソッドをEnumeratorにする時のコツ

6. 引数があるメソッドをEnumeratorにする時のコツ
6. 引数があるメソッドをEnumeratorにする時のコツ

メソッドに引数(ひきすう:命令に付け加える詳細な情報)がある場合、to_enumにそれらの引数も教えてあげる必要があります。これを忘れると、後から繰り返し処理を動かそうとした時に、「どのデータを使えばいいかわからない」とコンピュータが困ってしまいます。

to_enum(:メソッド名, 引数1, 引数2...)という書き方をすることで、その情報を保存したままEnumeratorを作ることができます。これにより、特定の範囲の数字だけを扱う処理や、特定の文字を加工する処理などを、いつでも好きな時に再開できる状態で保持しておけるのです。


class Counter
  def up_to(max)
    # 引数maxをto_enumに渡すのがポイント
    return enum_for(:up_to, max) unless block_given?

    current = 1
    while current <= max
      yield current
      current += 1
    end
  end
end

counter = Counter.new
# 5まで数える列を作る
five_steps = counter.up_to(5)

# 最初の3つだけ取り出す
p five_steps.first(3)

[1, 2, 3]

7. 無限に続くデータ列を作ってみよう

7. 無限に続くデータ列を作ってみよう
7. 無限に続くデータ列を作ってみよう

Enumeratorの自作が最も輝く場面の一つに、「無限の繰り返し」があります。例えば、1, 2, 4, 8...と永遠に倍になっていく数列や、同じパターンをずっと繰り返す処理などです。配列でこれを作ろうとすると、パソコンのメモリがいっぱいになってフリーズしてしまいますが、Enumeratorなら大丈夫です。

必要な時に次の値を一つだけ計算して取り出す「遅延評価(ちえんひょうか)」という仕組みのおかげで、無限に続くデータであっても安全に扱うことができます。これは現代のプログラミングにおいて非常に強力な武器になります。


# 永遠に2倍になっていく数列の種
powers_of_two = Enumerator.new do |yielder|
  n = 1
  loop do
    yielder << n
    n *= 2
  end
end

# 最初の10個だけ表示する(無限でも止まらない!)
p powers_of_two.take(10)

[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]

8. 良いプログラムを書くためのカプセル化とAPI

8. 良いプログラムを書くためのカプセル化とAPI
8. 良いプログラムを書くためのカプセル化とAPI

自分でEnumeratorを作れるようになると、あなたの書くプログラムの品質が格段に上がります。その理由はカプセル化という考え方にあります。これは、内部の複雑な処理を隠して、使い手には「これを使えばデータが取れるよ」という簡単な窓口だけを見せる技術です。

to_enumを適切に使うことで、他のプログラマー(あるいは未来の自分)がそのメソッドを使う際に、中身がどうなっているかを気にせずにwith_indexselectといったRuby標準の強力な機能と組み合わせて使えるようになります。これが、美しいコードを書くためのプロの技なのです。

9. 実践!複雑な条件での繰り返し処理

9. 実践!複雑な条件での繰り返し処理
9. 実践!複雑な条件での繰り返し処理

最後に、少し複雑な例として、特定の文字が含まれる行だけを取り出す検索機のような機能をEnumeratorで作ってみましょう。ファイルを一行ずつ読み込んで処理するような実務に近い形をシミュレーションします。

このように、大きなデータの中から必要なものを探す処理も、一度Enumeratorにしてしまえば、後のフィルタリング(絞り込み)がとても楽になります。Rubyの表現力の高さを実感できるはずです。


class TextFilter
  def initialize(text)
    @lines = text.split("\n")
  end

  def find_word(keyword)
    return to_enum(:find_word, keyword) unless block_given?

    @lines.each do |line|
      yield line if line.include?(keyword)
    end
  end
end

doc = "Rubyは楽しい\nPythonも人気\nRubyの仕事を探す"
filter = TextFilter.new(doc)

# Rubyが含まれる行だけを抽出して、さらに番号を振る
filter.find_word("Ruby").with_index(1) do |line, i|
  puts "#{i}: #{line}"
end

1: Rubyは楽しい
2: Rubyの仕事を探す

10. 学習を深めるためのステップ

10. 学習を深めるためのステップ
10. 学習を深めるためのステップ

今回学んだto_enumenum_forは、最初は少し難しく感じたかもしれません。しかし、実際に自分でコードを書いて動かしてみると、その便利さが身に染みてわかるようになります。プログラミングの学習において、一番の先生は「実際に動くコード」です。

まずは、今回紹介したサンプルコードをコピーして、少しずつ数字や文字を変えて実行してみてください。エラーが出たら、それは成長のチャンスです。なぜ動かないのかを考える過程で、Rubyの仕組みがより深く理解できるようになります。少しずつ慣れていけば、あなたも必ず思い通りのプログラムが書けるようになりますよ!

カテゴリの一覧へ
新着記事
New1
Ruby
Rubyの文法超入門:式と文・endの役割をやさしく解説
New2
Rails
Nodeは本当に不要?Railsのimportmap最小構成とjsbundling構成の違いと選び方
New3
Rails
Rails開発で使うデータベースの選び方とSQLite・MySQL・PostgreSQLの初期設定
New4
Ruby
Ruby環境構築の最終チェック!セットアップ失敗あるあると確認リスト
人気記事
No.1
Java&Spring記事人気No1
Rails
Railsメール確認(confirmable)の実装手順を完全ガイド!初心者でもわかる有効化リンクと期限設定
No.2
Java&Spring記事人気No2
Ruby
OpenSSL関連エラーの直し方を完全解説!証明書・ビルドオプション・brew対策まとめ
No.3
Java&Spring記事人気No3
Ruby
WindowsでRubyをインストールする方法!RubyInstallerとMSYS2を使った完全ガイド
No.4
Java&Spring記事人気No4
Ruby
RubyのEnumerable完全解説!cycle・zipで繰り返しの達人になろう
No.5
Java&Spring記事人気No5
Ruby
プロキシ環境でも安心!社内ネットワーク下でのRuby gemインストール完全ガイド【SSL対応も解説】
No.6
Java&Spring記事人気No6
Ruby
PATHと環境変数の正しい設定!Windows・Mac・Linux別チェックリスト付き
No.7
Java&Spring記事人気No7
Ruby
Rubyのany? all? none? one? を完全攻略!条件判定を劇的に短く書く方法
No.8
Java&Spring記事人気No8
Rails
asdfで複数言語を一元管理:Ruby/Node/psql をまとめてセットアップ