Class: Generator
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 |
# File 'lib/generator.rb', line 69 def initialize(enum = nil, &block) if enum @block = proc { |g| enum.each { |x| g.yield x } } else @block = block end @index = 0 @queue = [] @cont_next = @cont_yield = @cont_endp = nil if @cont_next = callcc { |c| c } @block.call(self) @cont_endp.call(nil) if @cont_endp end self end |
Instance Method Details
#current ⇒ Object
Returns the element at the current position.
141 142 143 144 145 146 147 |
# File 'lib/generator.rb', line 141 def current() if @queue.empty? raise EOFError, "no more elements available" end @queue.first end |
#each ⇒ Object
Rewinds the generator and enumerates the elements.
157 158 159 160 161 162 163 164 165 |
# File 'lib/generator.rb', line 157 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 |
# File 'lib/generator.rb', line 102 def end?() if @cont_endp = callcc { |c| c } @cont_yield.nil? && @queue.empty? else @queue.empty? end end |
#index ⇒ Object
Returns the current index (position) counting from zero.
116 117 118 |
# File 'lib/generator.rb', line 116 def index() @index end |
#next ⇒ Object
Returns the element at the current position and moves forward.
126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/generator.rb', line 126 def next() if end? raise EOFError, "no more elements available" end if @cont_next = callcc { |c| c } @cont_yield.call(nil) if @cont_yield end @index += 1 @queue.shift end |
#next? ⇒ Boolean
Returns true if the generator has not reached the end yet.
111 112 113 |
# File 'lib/generator.rb', line 111 def next?() !end? end |
#pos ⇒ Object
Returns the current index (position) counting from zero.
121 122 123 |
# File 'lib/generator.rb', line 121 def pos() @index end |
#rewind ⇒ Object
Rewinds the generator.
150 151 152 153 154 |
# File 'lib/generator.rb', line 150 def rewind() initialize(nil, &@block) if @index.nonzero? self end |
#yield(value) ⇒ Object
Yields an element to the generator.
92 93 94 95 96 97 98 99 |
# File 'lib/generator.rb', line 92 def yield(value) if @cont_yield = callcc { |c| c } @queue << value @cont_next.call(nil) end self end |