class Generator

Public Class Methods

new(enum = nil, &block) click to toggle source

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/sequence/generator.rb, line 76
def initialize(enum = nil, &block)
  if enum
    @block = proc{|g| enum.each{|value| g.yield value}}
  else
    @block = block
  end
  @index = 0
  @queue = []
  @main_thread = nil
  @loop_thread.kill if defined?(@loop_thread)
  @loop_thread = Thread.new do
    Thread.stop
    begin
      @block.call(self)
    rescue
      @main_thread.raise $!
    ensure
      @main_thread.wakeup
    end
  end
  Thread.pass until @loop_thread.stop?
  self
end

Public Instance Methods

current() click to toggle source

Returns the element at the current position.

# File lib/sequence/generator.rb, line 160
def current
  raise EOFError.new("no more elements available") if end?
  @queue.first
end
each() { |next| ... } click to toggle source

Rewinds the generator and enumerates the elements.

# File lib/sequence/generator.rb, line 172
def each
  rewind
  until end?
    yield self.next
  end
  self
end
end?() click to toggle source

Returns true if the generator has reached the end.

# File lib/sequence/generator.rb, line 117
def end?
  if @queue.empty?
    if @main_thread
      raise "should not be called in Generator.new{|g| ... }"
    end
    Thread.critical = true
    begin
      @main_thread = Thread.current
      @loop_thread.wakeup
      Thread.stop
    rescue ThreadError
      # ignore
    ensure
      @main_thread = nil
      Thread.critical = false
    end
  end
  @queue.empty?
end
index() click to toggle source

Returns the current index (position) counting from zero.

# File lib/sequence/generator.rb, line 143
def index
  @index
end
next() click to toggle source

Returns the element at the current position and moves forward.

# File lib/sequence/generator.rb, line 153
def next
  raise EOFError.new("no more elements available") if end?
  @index += 1
  @queue.shift
end
next?() click to toggle source

Returns true if the generator has not reached the end yet.

# File lib/sequence/generator.rb, line 138
def next?
  !end?
end
pos() click to toggle source

Returns the current index (position) counting from zero.

# File lib/sequence/generator.rb, line 148
def pos
  @index
end
rewind() click to toggle source

Rewinds the generator.

# File lib/sequence/generator.rb, line 166
def rewind
  initialize(nil, &@block) if @index.nonzero?
  self
end
yield(value) click to toggle source

Yields an element to the generator.

# File lib/sequence/generator.rb, line 101
def yield(value)
  if Thread.current != @loop_thread
    raise "should be called in Generator.new{|g| ... }"
  end
  Thread.critical = true
  begin
    @queue << value
    @main_thread.wakeup
    Thread.stop
  ensure
    Thread.critical = false
  end
  self
end