From: Julian Snitow Date: 2003-03-26T05:44:19+09:00 Subject: Re: External iterators all nice and neat (was: Re: Iterate over two lists in parallel) Mauricio Fern�ndez wrote: > On Tue, Mar 25, 2003 at 05:02:19PM +0900, Julian Snitow wrote: > >>I don't know about generators, but for traversing a collection, my >>iterator externalizer class (which I posted not 15 minutes ago ;-) can >>handle this with trivial changes. Here it is, ready to eat, just add >>water, etc. You will not find a nicer iterator class, or I will >>self.eat(@hat) :-) >> >>######## put this in 'iteration.rb' or something like that ### >>module Iteration >> class ExternalIterator >> def initialize(collection, deathThroes=false) >> @collection = collection >> @cont = nil >> @deathThroes = deathThroes >> end >> def get >> @cont.call if @cont >> @collection.each { |elem| >> callcc { |@cont| >> return elem >> } >> } >> @cont = nil # reset the continuation >> return nil unless @deathThroes >> throw :iter_done >> end >> end >> def iter(deathThroes=false) >> ExternalIterator.new(self, deathThroes) >> end >>end > > > Credits go to Han Holl [67861] for finding this: > > batsman@tux-chan:/tmp$ expand -t 2 u.rb > ######## put this in 'iteration.rb' or something like that ### > module Iteration > class ExternalIterator > def initialize(collection, deathThroes=false) > @collection = collection > @cont = nil > @deathThroes = deathThroes > end > def get > @cont.call if @cont > @collection.each { |elem| > callcc { |@cont| > return elem > } > } > @cont = nil # reset the continuation > return nil unless @deathThroes > throw :iter_done > end > end > def iter(deathThroes=false) > ExternalIterator.new(self, deathThroes) > end > end > > class Array; include Iteration; end > > arr = ["foo", "bar", "baz", "qux", "florp", "bzaa", "worble"] > ex = arr.iter > > puts ex.get > puts "---" > puts ex.get > puts "***" > batsman@tux-chan:/tmp$ ruby u.rb > foo > --- > bar > --- > baz > --- > qux > --- > florp > --- > bzaa > --- > worble > --- > nil > --- > foo > *** > > I guess this means that... > > Object.const_get("Julian Snitow").send("eat!".intern, "hat") Not quite. ;) Array#shift returns nil when the collection is empty, so I used that behavior, too. So once you've got nil, the iteration is over, and any further calls to ex.get will be those of a new iteration.