Class: Enumerator
- Includes:
- Enumerable
- Defined in:
- ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb,
ext/enterprise_script_service/mruby/mrbgems/mruby-enum-lazy/mrblib/lazy.rb
Overview
A class which allows both internal and external iteration.
An Enumerator can be created by the following methods.
Most methods have two forms: a block form where the contents are evaluated for each item in the enumeration, and a non-block form which returns a new Enumerator wrapping the iteration.
enumerator = %w(one two three).each
puts enumerator.class # => Enumerator
enumerator.each_with_object("foo") do |item, obj|
puts "#{obj}: #{item}"
end
# foo: one
# foo: two
# foo: three
enum_with_obj = enumerator.each_with_object("foo")
puts enum_with_obj.class # => Enumerator
enum_with_obj.each do |item, obj|
puts "#{obj}: #{item}"
end
# foo: one
# foo: two
# foo: three
This allows you to chain Enumerators together. For example, you can map a list’s elements to strings containing the index and the element as a string via:
puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
# => ["0:foo", "1:bar", "2:baz"]
An Enumerator can also be used as an external iterator. For example, Enumerator#next returns the next value of the iterator or raises StopIteration if the Enumerator is at the end.
e = [1,2,3].each # returns an enumerator object.
puts e.next # => 1
puts e.next # => 2
puts e.next # => 3
puts e.next # raises StopIteration
You can use this to implement an internal iterator as follows:
def ext_each(e)
while true
begin
vs = e.next_values
rescue StopIteration
return $!.result
end
y = yield(*vs)
e.feed y
end
end
o = Object.new
def o.each
puts yield
puts yield(1)
puts yield(1, 2)
3
end
# use o.each as an internal iterator directly.
puts o.each {|*x| puts x; [:b, *x] }
# => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
# convert o.each to an external iterator for
# implementing an internal iterator.
puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
# => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
Direct Known Subclasses
Defined Under Namespace
Classes: Generator, Lazy, Yielder
Constant Summary
Constants included from Enumerable
Instance Attribute Summary collapse
-
#args ⇒ Object
writeonly
Sets the attribute args.
-
#fib ⇒ Object
writeonly
Sets the attribute fib.
-
#meth ⇒ Object
writeonly
Sets the attribute meth.
-
#obj ⇒ Object
writeonly
Sets the attribute obj.
Instance Method Summary collapse
-
#each(*argv, &block) ⇒ Object
call-seq: enum.each { |elm| block } -> obj enum.each -> enum enum.each(*appending_args) { |elm| block } -> obj enum.each(*appending_args) -> an_enumerator.
-
#each_with_index(&block) ⇒ Object
call-seq: e.each_with_index {|(*args), idx| … } e.each_with_index.
-
#feed(value) ⇒ Object
call-seq: e.feed obj -> nil.
-
#initialize(obj = nil, meth = :each, *args, &block) ⇒ Enumerator
constructor
Creates a new Enumerator object, which can be used as an Enumerable.
- #initialize_copy(obj) ⇒ Object
- #inspect ⇒ Object
-
#next ⇒ Object
call-seq: e.next -> object.
-
#next_values ⇒ Object
call-seq: e.next_values -> array.
-
#peek ⇒ Object
call-seq: e.peek -> object.
-
#peek_values ⇒ Object
call-seq: e.peek_values -> array.
-
#rewind ⇒ Object
call-seq: e.rewind -> e.
-
#with_index(offset = 0, &block) ⇒ Object
call-seq: e.with_index(offset = 0) {|(*args), idx| … } e.with_index(offset = 0).
-
#with_object(object, &block) ⇒ Object
call-seq: e.each_with_object(obj) {|(*args), obj| … } e.each_with_object(obj) e.with_object(obj) {|(*args), obj| … } e.with_object(obj).
Methods included from Enumerable
#all?, #any?, #collect, #count, #cycle, #detect, #drop, #drop_while, #each_cons, #each_slice, #each_with_object, #entries, #find_all, #find_index, #first, #flat_map, #grep, #group_by, #hash, #include?, #inject, #lazy, #max, #max_by, #min, #min_by, #minmax, #minmax_by, #none?, #one?, #partition, #reject, #reverse_each, #sort, #sort_by, #take, #take_while, #to_h, to_h, #uniq, #zip
Constructor Details
#initialize(size = nil, &block) ⇒ Enumerator #initialize(obj, method = :each, *args) ⇒ Enumerator
Creates a new Enumerator object, which can be used as an Enumerable.
In the first form, iteration is defined by the given block, in which a “yielder” object, given as block parameter, can be used to yield a value by calling the yield method (aliased as <<):
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 112 def initialize(obj=nil, meth=:each, *args, &block) if block obj = Generator.new(&block) else raise ArgumentError unless obj end if @obj and !self.respond_to?(meth) raise NoMethodError, "undefined method #{meth}" end @obj = obj @meth = meth @args = args.dup @fib = nil @dst = nil @lookahead = nil @feedvalue = nil @stop_exc = false end |
Instance Attribute Details
#args=(value) ⇒ Object
Sets the attribute args
131 132 133 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 131 def args=(value) @args = value end |
#fib=(value) ⇒ Object
Sets the attribute fib
131 132 133 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 131 def fib=(value) @fib = value end |
#meth=(value) ⇒ Object
Sets the attribute meth
131 132 133 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 131 def meth=(value) @meth = value end |
#obj=(value) ⇒ Object
Sets the attribute obj
131 132 133 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 131 def obj=(value) @obj = value end |
Instance Method Details
#each(*argv, &block) ⇒ Object
call-seq:
enum.each { |elm| block } -> obj
enum.each -> enum
enum.each(*appending_args) { |elm| block } -> obj
enum.each(*appending_args) -> an_enumerator
Iterates over the block according to how this Enumerator was constructed. If no block and no arguments are given, returns self.
Examples
"Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
obj = Object.new
def obj.each_arg(a, b=:b, *rest)
yield a
yield b
yield rest
:method_returned
end
enum = obj.to_enum :each_arg, :a, :x
enum.each.to_a #=> [:a, :x, []]
enum.each.equal?(enum) #=> true
enum.each { |elm| elm } #=> :method_returned
enum.each(:y, :z).to_a #=> [:a, :x, [:y, :z]]
enum.each(:y, :z).equal?(enum) #=> false
enum.each(:y, :z) { |elm| elm } #=> :method_returned
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 271 def each(*argv, &block) obj = self if 0 < argv.length obj = self.dup args = obj.args if !args.empty? args = args.dup args.concat argv else args = argv.dup end obj.args = args end return obj unless block enumerator_block_call(&block) end |
#each_with_index(&block) ⇒ Object
call-seq:
e.each_with_index {|(*args), idx| ... }
e.each_with_index
Same as Enumerator#with_index(0), i.e. there is no starting offset.
If no block is given, a new Enumerator is returned that includes the index.
184 185 186 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 184 def each_with_index(&block) with_index(0, &block) end |
#feed(value) ⇒ Object
call-seq:
e.feed obj -> nil
Sets the value to be returned by the next yield inside e.
If the value is not set, the yield returns nil.
This value is cleared after being yielded.
# Array#map passes the array's elements to "yield" and collects the
# results of "yield" as an array.
# Following example shows that "next" returns the passed elements and
# values passed to "feed" are collected as an array which can be
# obtained by StopIteration#result.
e = [1,2,3].map
p e.next #=> 1
e.feed "a"
p e.next #=> 2
e.feed "b"
p e.next #=> 3
e.feed "c"
begin
e.next
rescue StopIteration
p $!.result #=> ["a", "b", "c"]
end
o = Object.new
def o.each
x = yield # (2) blocks
p x # (5) => "foo"
x = yield # (6) blocks
p x # (8) => nil
x = yield # (9) blocks
p x # not reached w/o another e.next
end
e = o.to_enum
e.next # (1)
e.feed "foo" # (3)
e.next # (4)
e.next # (7)
# (10)
521 522 523 524 525 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 521 def feed(value) raise TypeError, "feed value already set" if @feedvalue @feedvalue = value nil end |
#initialize_copy(obj) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 134 def initialize_copy(obj) raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator raise TypeError, "can't copy execution context" if obj.fib @obj = obj.obj @meth = obj.meth @args = obj.args @fib = nil @lookahead = nil @feedvalue = nil self end |
#inspect ⇒ Object
225 226 227 228 229 230 231 232 233 234 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 225 def inspect return "#<#{self.class}: uninitialized>" unless @obj if @args && @args.size > 0 args = @args.join(", ") "#<#{self.class}: #{@obj}:#{@meth}(#{args})>" else "#<#{self.class}: #{@obj}:#{@meth}>" end end |
#next ⇒ Object
call-seq:
e.next -> object
Returns the next object in the enumerator, and move the internal position forward. When the position reached at the end, StopIteration is raised.
Example
a = [1,2,3]
e = a.to_enum
p e.next #=> 1
p e.next #=> 2
p e.next #=> 3
p e.next #raises StopIteration
Note that enumeration sequence by next does not affect other non-external enumeration methods, unless the underlying iteration methods itself has side-effect
313 314 315 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 313 def next next_values.__svalue end |
#next_values ⇒ Object
call-seq:
e.next_values -> array
Returns the next object as an array in the enumerator, and move the internal position forward. When the position reached at the end, StopIteration is raised.
This method can be used to distinguish yield and yield nil.
Example
o = Object.new
def o.each
yield
yield 1
yield 1, 2
yield nil
yield [1, 2]
end
e = o.to_enum
p e.next_values
p e.next_values
p e.next_values
p e.next_values
p e.next_values
e = o.to_enum
p e.next
p e.next
p e.next
p e.next
p e.next
## yield args next_values next
# yield [] nil
# yield 1 [1] 1
# yield 1, 2 [1, 2] [1, 2]
# yield nil [nil] nil
# yield [1, 2] [[1, 2]] [1, 2]
Note that next_values does not affect other non-external enumeration methods unless underlying iteration method itself has side-effect
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 361 def next_values if @lookahead vs = @lookahead @lookahead = nil return vs end raise @stop_exc if @stop_exc curr = Fiber.current if !@fib || !@fib.alive? @dst = curr @fib = Fiber.new do result = each do |*args| feedvalue = nil Fiber.yield args if @feedvalue feedvalue = @feedvalue @feedvalue = nil end feedvalue end @stop_exc = StopIteration.new "iteration reached an end" @stop_exc.result = result Fiber.yield nil end @lookahead = nil end vs = @fib.resume curr if @stop_exc @fib = nil @dst = nil @lookahead = nil @feedvalue = nil raise @stop_exc end vs end |
#peek ⇒ Object
call-seq:
e.peek -> object
Returns the next object in the enumerator, but doesn’t move the internal position forward. If the position is already at the end, StopIteration is raised.
Example
a = [1,2,3]
e = a.to_enum
p e.next #=> 1
p e.peek #=> 2
p e.peek #=> 2
p e.peek #=> 2
p e.next #=> 2
p e.next #=> 3
p e.next #raises StopIteration
421 422 423 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 421 def peek peek_values.__svalue end |
#peek_values ⇒ Object
call-seq:
e.peek_values -> array
Returns the next object as an array, similar to Enumerator#next_values, but doesn’t move the internal position forward. If the position is already at the end, StopIteration is raised.
Example
o = Object.new
def o.each
yield
yield 1
yield 1, 2
end
e = o.to_enum
p e.peek_values #=> []
e.next
p e.peek_values #=> [1]
p e.peek_values #=> [1]
e.next
p e.peek_values #=> [1, 2]
e.next
p e.peek_values # raises StopIteration
451 452 453 454 455 456 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 451 def peek_values if @lookahead.nil? @lookahead = next_values end @lookahead.dup end |
#rewind ⇒ Object
call-seq:
e.rewind -> e
Rewinds the enumeration sequence to the beginning.
If the enclosed object responds to a “rewind” method, it is called.
466 467 468 469 470 471 472 473 474 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 466 def rewind @obj.rewind if @obj.respond_to? :rewind @fib = nil @dst = nil @lookahead = nil @feedvalue = nil @stop_exc = false self end |
#with_index(offset = 0, &block) ⇒ Object
call-seq:
e.with_index(offset = 0) {|(*args), idx| ... }
e.with_index(offset = 0)
Iterates the given block for each element with an index, which starts from offset. If no block is given, returns a new Enumerator that includes the index, starting from offset
offset-
the starting index to use
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 157 def with_index(offset=0, &block) return to_enum :with_index, offset unless block offset = if offset.nil? 0 elsif offset.respond_to?(:to_int) offset.to_int else raise TypeError, "no implicit conversion of #{offset.class} into Integer" end n = offset - 1 enumerator_block_call do |*i| n += 1 block.call i.__svalue, n end end |
#with_object(object, &block) ⇒ Object
call-seq:
e.each_with_object(obj) {|(*args), obj| ... }
e.each_with_object(obj)
e.with_object(obj) {|(*args), obj| ... }
e.with_object(obj)
Iterates the given block for each element with an arbitrary object, obj, and returns obj
If no block is given, returns a new Enumerator.
216 217 218 219 220 221 222 223 |
# File 'ext/enterprise_script_service/mruby/mrbgems/mruby-enumerator/mrblib/enumerator.rb', line 216 def with_object(object, &block) return to_enum(:with_object, object) unless block enumerator_block_call do |i| block.call [i,object] end object end |