From: "knu (Akinori MUSHA)" Date: 2012-12-02T22:00:58+09:00 Subject: [ruby-dev:46685] [Ruby 1.8 - Bug #7493] ブロックを渡された場合最初の1要素のみを返すEnumeratorに対してnextを送り続けると、2度目にStopIteration例外が発生する Issue #7493 has been updated by knu (Akinori MUSHA). 1.8では、nextは lib/generator.rb で実装されています。 ブロック(の返り値)を欲するメソッドのEnumeratorをnextで回すというのは、つまり必要なブロックを渡していないわけで、そういう使い方は1.8では想定していませんでした。 つまり、事務的な答えとしては、挙動は不定ですということになります。 ただ、空のブロック({})の評価値がnilになることを考えると、1.9以降のようにnilを返してやるのが自然と言えるでしょうね。 Enumerable#to_a も、内部ではnilを返すブロックで繰り返しています。 直すとしたらこうですが、1.8.7はこの類の修正が入ることはもうないでしょうね。 気になるようであれば、ローカルで当てたりモンキーパッチしてみてください。 一応 ruby_1_8 には入れておきます。 Index: lib/generator.rb =================================================================== --- lib/generator.rb (revision 38134) +++ lib/generator.rb (working copy) @@ -69,7 +69,7 @@ class Generator def initialize(enum = nil, &block) if enum @block = proc { |g| - enum.each { |x| g.yield x } + enum.each { |x| g.yield x; nil } } else @block = block ---------------------------------------- Bug #7493: ブロックを渡された場合最初の1要素のみを返すEnumeratorに対してnextを送り続けると、2度目にStopIteration例外が発生する https://bugs.ruby-lang.org/issues/7493#change-34315 Author: kachick (Kenichi Kamiya) Status: Open Priority: Normal Assignee: Category: Target version: Ruby 1.8.7 ruby -v: ruby 1.8.7 (2012-10-12 patchlevel 371) [x86_64-linux] 「ブロック付きで動かした場合、最初に見つかった1要素のみを返すメソッド」からEnumeratorを作ると、 2度目のnextでStopIteration例外を返すようです。 思い至った限りで確認したメソッドは、以下の物です。 * Array#index * Array#find_index * Array#rindex * Enumerable#detect * Enumerable#find これは、1.8.7と1.9間の仕様に於ける差異と考えた方が良いのでしょうか? 生成されたEnumeratorに対してto_aを送ると全要素を含むArrayが返る事から、 1.8.7に於いても全要素走査出来る方が自然では無いかと感じました。 # to_aとの差異は、dbussinkの指摘で気づくことが出来ました。 # https://github.com/rubinius/rubinius/pull/2063#issuecomment-10881875 array = [:a, :b, :c] index_enum = array.index index_enum.to_a #=> [:a, :b, :c] index_enum.next #=> :a index_enum.next #=> StopIteration: iteration reached at end -- http://bugs.ruby-lang.org/