class Generator
Generator
converts an internal iterator (i.e. an Enumerable object) to an external iterator.
Note that it is not very fast since it is implemented using continuations, which are currently slow.
Example¶ ↑
require 'generator' # Generator from an Enumerable object g = Generator.new(['A', 'B', 'C', 'Z']) while g.next? puts g.next end # Generator from a block g = Generator.new { |g| for i in 'A'..'C' g.yield i end g.yield 'Z' } # The same result as above while g.next? puts g.next end
Public Class Methods
Creates a new generator either from an Enumerable object or from a block.
In the former, block is ignored even if given.
In the latter, the given block is called with the generator itself, and expected to call the yield
method for each element.
# File lib/rubysl/generator/generator.rb, line 69 def initialize(enum=nil, &block) if enum @block = proc do |g| enum.each { |x| g.yield x } end else @block = block end @index = 0 @queue = [] @done = false @fiber = Rubinius::Fiber.new do @block.call(self) @done = true @fiber = nil end self end
Public Instance Methods
Returns the element at the current position.
# File lib/rubysl/generator/generator.rb, line 145 def current if @queue.empty? raise EOFError, "no more elements available" end @queue.first end
Rewinds the generator and enumerates the elements.
# File lib/rubysl/generator/generator.rb, line 161 def each rewind until end? yield self.next end self end
Returns true if the generator has reached the end.
# File lib/rubysl/generator/generator.rb, line 102 def end? return true if @done return false unless @queue.empty? # Turn the loop over and see if we hit the end @fiber.resume return @done end
Returns the current index (position) counting from zero.
# File lib/rubysl/generator/generator.rb, line 118 def index @index end
Returns the element at the current position and moves forward.
# File lib/rubysl/generator/generator.rb, line 128 def next raise EOFError, "end of iteration hit" if end? @fiber.resume if @queue.empty? # We've driven the fiber ahead and least once now, so we should # have values if there are values to be had unless @queue.empty? @index += 1 return @queue.shift end raise EOFError, "end of iteration hit" end
Returns true if the generator has not reached the end yet.
# File lib/rubysl/generator/generator.rb, line 113 def next? !end? end
Returns the current index (position) counting from zero.
# File lib/rubysl/generator/generator.rb, line 123 def pos @index end
Rewinds the generator.
# File lib/rubysl/generator/generator.rb, line 154 def rewind initialize(nil, &@block) if @index.nonzero? self end
Yields an element to the generator.
# File lib/rubysl/generator/generator.rb, line 93 def yield(value) # Running inside @fiber @queue << value Rubinius::Fiber.yield self end