Class: Generator
- Inherits:
-
Object
- Object
- Generator
- Includes:
- Enumerable
- Defined in:
- lib/rubysl/generator/generator.rb
Overview
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
Instance Method Summary collapse
-
#current ⇒ Object
Returns the element at the current position.
-
#each ⇒ Object
Rewinds the generator and enumerates the elements.
-
#end? ⇒ Boolean
Returns true if the generator has reached the end.
-
#index ⇒ Object
Returns the current index (position) counting from zero.
-
#initialize(enum = nil, &block) ⇒ Generator
constructor
Creates a new generator either from an Enumerable object or from a block.
-
#next ⇒ Object
Returns the element at the current position and moves forward.
-
#next? ⇒ Boolean
Returns true if the generator has not reached the end yet.
-
#pos ⇒ Object
Returns the current index (position) counting from zero.
-
#rewind ⇒ Object
Rewinds the generator.
-
#yield(value) ⇒ Object
Yields an element to the generator.
Constructor Details
#initialize(enum = nil, &block) ⇒ Generator
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.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# 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 |
Instance Method Details
#current ⇒ Object
Returns the element at the current position.
145 146 147 148 149 150 151 |
# File 'lib/rubysl/generator/generator.rb', line 145 def current if @queue.empty? raise EOFError, "no more elements available" end @queue.first end |
#each ⇒ Object
Rewinds the generator and enumerates the elements.
161 162 163 164 165 166 167 168 169 |
# File 'lib/rubysl/generator/generator.rb', line 161 def each rewind until end? yield self.next end self end |
#end? ⇒ Boolean
Returns true if the generator has reached the end.
102 103 104 105 106 107 108 109 110 |
# 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 |
#index ⇒ Object
Returns the current index (position) counting from zero.
118 119 120 |
# File 'lib/rubysl/generator/generator.rb', line 118 def index @index end |
#next ⇒ Object
Returns the element at the current position and moves forward.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# 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 |
#next? ⇒ Boolean
Returns true if the generator has not reached the end yet.
113 114 115 |
# File 'lib/rubysl/generator/generator.rb', line 113 def next? !end? end |
#pos ⇒ Object
Returns the current index (position) counting from zero.
123 124 125 |
# File 'lib/rubysl/generator/generator.rb', line 123 def pos @index end |
#rewind ⇒ Object
Rewinds the generator.
154 155 156 157 158 |
# File 'lib/rubysl/generator/generator.rb', line 154 def rewind initialize(nil, &@block) if @index.nonzero? self end |
#yield(value) ⇒ Object
Yields an element to the generator.
93 94 95 96 97 98 99 |
# File 'lib/rubysl/generator/generator.rb', line 93 def yield(value) # Running inside @fiber @queue << value Rubinius::Fiber.yield self end |