From: "Mauricio Fernández" Date: 2003-03-26T01:14:46+09:00 Subject: Re: External iterators all nice and neat (was: Re: Iterate over two lists in parallel) 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") Here's the class I propose as nicer (cause not (less?) buggy): 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 @outer = nil end def get callcc do |@outer| @cont.call if @cont @collection.each { |elem| callcc { |@cont| @outer.call elem } } @cont = nil # reset the continuation @outer.call nil unless @deathThroes throw :iter_done # does this still work? TEST ME!!! end 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 *** -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Sic transit discus mundi -- From the System Administrator's Guide, by Lars Wirzenius