From: "marcandre (Marc-Andre Lafortune)" Date: 2013-01-17T02:01:11+09:00 Subject: [ruby-core:51469] [ruby-trunk - Bug #7696] Lazy enumerators with state can't be rewound Issue #7696 has been updated by marcandre (Marc-Andre Lafortune). I had not see #6142. Yes, it's the same. 1) Add attr_accessor to Yielder and document the fact that the yielder is unique to a single enumeration run. def drop(n) n = Backports::coerce_to_int(n) Lazy.new(self) do |yielder, *values| yielder.memo ||= n if yielder.memo > 0 yielder.memo -= 1 else yielder.yield(*values) end end end 2) Optional named argument `prepare` for Lazy.new to be called before `each`: def drop(n) remain = nil Lazy.new(self, prepare: ->{remain = n}) do |yielder, *values| if remain > 0 remain -= 1 else yielder.yield(*values) end end end 3) Add a method 'prepare' method to Enumerator::Lazy and encourage subclassing. `prepare` would be called before `each` class LazyDropper < Enumerator::Lazy def initialize(obj, n) @n = n super do |yielder, *values| if @remain > 0 @remain -= 1 else yielder.yield(*values) end end def prepare @remain = @n end end MRI should use the same kind of mechanism for the enums requiring state ---------------------------------------- Bug #7696: Lazy enumerators with state can't be rewound https://bugs.ruby-lang.org/issues/7696#change-35449 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: High Assignee: Category: core Target version: 2.0.0 ruby -v: r38800 The 4 lazy enumerators requiring internal state, i.e. {take|drop}{_while}, don't work as expected after a couple `next` and a call to `rewind`. For example: e=(1..42).lazy.take(2) e.next # => 1 e.next # => 2 e.rewind e.next # => 1 e.next # => StopIteration: iteration reached an end, expected 2 This is related to #7691; the current API does not give an easy way to handle state. Either there's a dedicated callback to rewind, or data must be attached to the yielder. -- http://bugs.ruby-lang.org/