if RUBY_VERSION < "1.9" require 'enumerator' Enumerator = Enumerable::Enumerator end # Iteration encapsulates a step in an each loop. # class Iteration attr_reader :enum, :index, :value, :prior def initialize(enum) @enum = enum @index = 0 @value = nil @prior = [] end def first? index == 0 end def last? index+1 == enum.size end def after enum.slice(index+1..-1) end #private # TODO: For Ruby 1.9 make private and use fcall. # def __step__(value, &block) @value = value block.call @index += 1 @prior << value end #def next_iteration # @index += 1 # @prior << value # @after.shift if enum.respond_to?(:shift) #end end class Enumerator # TODO: How to access the underlying object of enumeration? # We need it to provide #size and #slice if possible. # # def iteration #:yield: it = Iteration.new(self) each do |e| it.__step__(e){ yield(it) } end end def with_iteration(&block) it = Iteration.new(self) each do |e| it.__step__(e){ yield(e,it) } end end end class Array # Iterate over each element of array using an iteration object. # # [1,2,3].each_iteration do |it| # p it.index # p it.value # p it.first? # p it.last? # p it.prior # p it.after # end # # on each successive iteration produces: # # 0 1 2 # 1 2 3 # true false false # false false true # [] [1] [1,2] # [2,3] [3] [] # # CREDIT: Trans def each_iteration(&block) if block_given? it = Iteration.new(self) each do |e| it.__step__(e){ yield(it) } end else Enumerator.new(self, :each_iteration) end end # Same as #each_iteration, but provides both the iterated # element and the iteration. # def each_with_iteration(&block) if block_given? it = Iteration.new(self) each do |e| it.__step__(e){ yield(e, it) } end else Enumerator.new(self, :each_iteration) end end end