Skip to content

Enumerator::Product と Enumerator.product を追加 (Ruby 3.2)#3312

Open
Watson1978 wants to merge 2 commits into
rurema:masterfrom
Watson1978:enumerator-product-and-producer
Open

Enumerator::Product と Enumerator.product を追加 (Ruby 3.2)#3312
Watson1978 wants to merge 2 commits into
rurema:masterfrom
Watson1978:enumerator-product-and-producer

Conversation

@Watson1978

@Watson1978 Watson1978 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

概要

Ruby 4.0 に存在するのにリファレンスに項目が無かった [c:Enumerator::Product] と
[m:Enumerator.product] を追加しました。どちらも Ruby 3.2 で追加された公開 API です。

  • Enumerator::Product (新規ファイル) — neweach / inspect / rewind / size
  • Enumerator.product (Enumerator.md に追加) — Enumerator::Product.new と同じもの

Enumerator.product も同じ PR で追加しました (レビュー対応)

当初は Enumerator::Product だけを追加していましたが、クラスの説明と new
- **SEE** から参照している [m:Enumerator.product] が doctree に未定義で
リンク切れになるとのご指摘をいただき、この PR で Enumerator.md にも追加しました。
Ruby 3.2 で追加されたメソッドなので #@since 3.2 で囲んでいます。

説明は [m:Enumerator::Product.new] と同じです として、参照先の内容を複製しない
形にしました。

ブロックを渡した場合の返り値を rdoc と変えています

enumerator.c の call-seq は次のようになっています。

 *   Enumerator.product(*enums) -> enumerator
 *   Enumerator.product(*enums) { |elts| ... } -> enumerator

しかし実装はブロックがあるとき nil を返します。

    if (!NIL_P(block)) {
        enum_product_run(obj, block);
        return Qnil;
    }

rdoc の本文も「ブロックを渡した場合は nil を返す」と説明しており、実機でも nil が返ります。
call-seq 側の誤りと考えられるため、るりまは実機に合わせて -> nil としました。

$ ruby -e 'p(Enumerator.product(1..2, ["a", "b"]) { })'
nil

Enumerator::Producer は非対応にしました

対になる Enumerator::Producer も未収録でしたが、Ruby 本体の enumerator.c

/* :nodoc: Producer */
rb_cEnumProducer = rb_define_class_under(rb_cEnumerator, "Producer", rb_cObject);

:nodoc: 指定された内部実装クラスで、ri にもドキュメントがありません
(Enumerator.produce が返すのは通常の [c:Enumerator] で、Producer は表に出ません)。
:nodoc: のものは収録しない方針に従い、こちらは収録せずトラッカーで非対応としました。

登場バージョン

2.7.8 〜 3.1.6: なし
3.2.11 以降:    Enumerator::Product / Enumerator.product

3.1.6 では Enumerator.productNoMethodError (Did you mean? produce) になります。

記述の根拠(実機で確認)

  • 各オブジェクトには each ではなく each_entry が呼ばれ、N 個のオブジェクトの
    直積は各繰り返しでちょうど N 要素の配列になります。
  • 引数なしで作った場合は空の引数リストでブロックを1回呼びます。
  • size は各オブジェクトのサイズの積を返し、無限を含む場合は [m:Float::INFINITY]、
    分からない場合は nil を返します。
$ ruby -e 'p Enumerator::Product.new(1.., [4, 5]).size'
Infinity
  • Enumerator.product の返り値は Enumerator::Product です。
$ ruby -e 'p Enumerator.product(1..2, ["a", "b"]).class'
Enumerator::Product

検証

  • サンプルコードは 3.2 / 3.3 / 3.4 / 4.0 で実行して出力を確認しました。
  • rake check_format / check_blank_lines / check_indent_in_samplecode /
    check_single_space_indent
  • bitclust update --markdowntree=manual/api を 3.1 / 3.2 / 3.3 / 4.0 で実行し、
    エラーが出ないこと、3.1 では未登録・3.2 以降でクラスと 5 項目が登録されることを
    確認しました。
  • Enumerator.product も同様に、4.0 の DB では bitclust lookup --method='Enumerator.product'
    で引けること、3.1 の DB では no such method になることを確認しました。

🤖 Generated with Claude Code

Enumerator を継承する公開クラスで、Enumerator.product から作られる。
実機で確認し、独立ファイルとして収録した。since は front matter で 3.2 とした。

each / inspect / rewind / size と Enumerator::Product.new を記載した。
各オブジェクトには each ではなく each_entry が呼ばれ N 要素の配列になること、
引数なしのときは空の引数リストでブロックを1回呼ぶこと、size は積・不明なら nil・
無限を含むなら Float::INFINITY を返すことを実機で確認した。

対になる Enumerator::Producer は enumerator.c で /* :nodoc: Producer */ と
指定された内部実装クラスで、ri にもドキュメントが無いため収録しない
(トラッカーで非対応とする)。

bitclust のデータベース生成を 3.1 / 3.2 / 3.3 / 4.0 で実行し、3.1 では未登録、
3.2 以降でクラスと 5 項目が登録されることを確認済み。例は 3.2 / 3.3 / 3.4 / 4.0 で
実行して出力を確認した。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@znz

znz commented Jul 25, 2026

Copy link
Copy Markdown
Member

レビューありがとうございます。実機(all-ruby, Ruby 3.0.7〜4.0.6)で確認しました。クラスのドキュメントの内容はとても正確で、記載の例はすべて実機の出力と一致しました。

  • Enumerator::Product3.2 以降(3.0/3.1 では未定義)で、front matter since: "3.2" は正しいです。3.0/3.1 のレンダリングでも出力されないことを確認しました。
  • Enumerator::Product.new(1..3, [4, 5]).to_a # => [[1, 4], [1, 5], ...] / size # => 6 を確認。
  • inspect # => "#<Enumerator::Product: [1..3, [4, 5]]>" は実機の出力と完全一致。
  • rewindself を返すこと、無限列挙で sizeInfinity になることも確認しました。
  • レンダリングは compileerror 0 でした。

1 点だけ、リンク切れになる箇所があります。

[m:Enumerator.product] が未定義

冒頭の「このクラスのオブジェクトは [m:Enumerator.product] から作られます。」と、new- **SEE** [m:Enumerator.product] の 2 箇所で [m:Enumerator.product] を参照していますが、Enumerator.product は doctree のどこにも定義されていませんmanual/api/_builtin/Enumerator.md のクラスメソッドは現状 newproduce のみ)。このままだと 2 箇所ともリンク切れになります。

Enumerator::ProductEnumerator.product から作られる対のものなので、この PR で Enumerator.mdEnumerator.product も一緒に追加していただくのが良いと思います。参考までに実機で確認した挙動です(3.2+):

Enumerator.product(1..2, ["a", "b"]).class  # => Enumerator::Product
Enumerator.product(1..2, ["a", "b"]).to_a
# => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
# ブロックを渡すと各要素を yield し、返り値は nil

🤖 Generated with Claude Code

Enumerator::Product から参照している [m:Enumerator.product] が未定義で
リンク切れになる指摘への対応。Ruby 3.2 で追加されたメソッドなので
#@SInCE 3.2 で囲む。

ブロックを渡した場合の返り値は、rdoc の call-seq が
`Enumerator.product(*enums) { |elts| ... } -> enumerator` としているが、
enumerator.c の実装は nil を返しており(rdoc 本文も returns nil)、
実機の確認結果に合わせて -> nil とした。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Watson1978 Watson1978 changed the title Enumerator::Product を追加 (Ruby 3.2) Enumerator::Product と Enumerator.product を追加 (Ruby 3.2) Jul 25, 2026
@Watson1978

Copy link
Copy Markdown
Contributor Author

確認ありがとうございます。ご指摘のとおり [m:Enumerator.product] がリンク切れになっていたので、
この PR で Enumerator.mdEnumerator.product を追加しました (ca60fe5)。

  • Ruby 3.2 で追加されたメソッドなので #@since 3.2 で囲んでいます。
    3.1.6 では NoMethodError (Did you mean? produce) になることを確認しました。
  • 説明は [m:Enumerator::Product.new] と同じです として、参照先の内容を複製しない形にしました。
  • 例は 2 つで、ブロックなし (to_a / size) とブロックあり (各要素を yield して nil を返す) です。

1 点、rdoc とあえて変えたところがあります。ブロックを渡した場合の返り値です。

enumerator.c の call-seq は Enumerator.product(*enums) { |elts| ... } -> enumerator
となっていますが、実装は

    if (!NIL_P(block)) {
        enum_product_run(obj, block);
        return Qnil;
    }

nil を返します。rdoc の本文にも「ブロックを渡した場合は nil を返す」と書かれており、
実機でも nil でした。

$ ruby -e 'p(Enumerator.product(1..2, ["a", "b"]) { })'
nil

そのため、るりまは実機に合わせて -> nil としています。
call-seq 側の誤りだと思われるので、ruby/ruby への修正も別途検討します。

検証:

  • 実機 3.1.6 / 3.2.11 / 3.3.12 / 3.4.10 / 4.0.6 で、記載した例の出力を確認しました。
  • rake check_format / check_blank_lines / check_indent_in_samplecode /
    check_single_space_indent はすべて通っています。
  • 4.0 の DB で bitclust lookup --method='Enumerator.product' が引けること、
    3.1 の DB では no such method になることを確認しました。

PR のタイトルと本文も、Enumerator.product を含む内容に更新しました。

🤖 Generated with Claude Code

@znz

znz commented Jul 25, 2026

Copy link
Copy Markdown
Member

対応ありがとうございます。ca60fe554 で Enumerator.product を追加いただいたのを確認しました。マージ可と考えます。

  • Enumerator.product は Ruby 3.2 で追加なので #@since 3.2 の閾は正しく、レンダリングでも 3.1 で不在・3.2/4.0 で出力されることを確認しました。これで Enumerator::Product 側の [m:Enumerator.product] 参照も解決します。
  • ブロックなしの例(to_a / size # => 6)、ブロックありの例(各要素を yield)とも実機の出力と一致しました。
  • ブロック形の返り値 -> nil も実機どおりです(rdoc の call-seq は -> enumerator ですが、実装・rdoc 本文とも nil で、コミットメッセージのご判断に同意です)。
  • [m:Enumerator::Product.new] / [c:Enumerator::Product] / [c:Enumerable] のリンクもすべて有効で、Enumerator.md / Enumerator__Product.md とも compileerror 0 でした。

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants