2 # enumerator.rb Enumerator class
3 # See Copyright Notice in mruby.h
6 # A class which allows both internal and external iteration.
8 # An Enumerator can be created by the following methods.
11 # - {Enumerator#initialize Enumerator.new}
13 # Most methods have two forms: a block form where the contents
14 # are evaluated for each item in the enumeration, and a non-block form
15 # which returns a new Enumerator wrapping the iteration.
17 # enumerator = %w(one two three).each
18 # puts enumerator.class # => Enumerator
20 # enumerator.each_with_object("foo") do |item, obj|
21 # puts "#{obj}: #{item}"
28 # enum_with_obj = enumerator.each_with_object("foo")
29 # puts enum_with_obj.class # => Enumerator
31 # enum_with_obj.each do |item, obj|
32 # puts "#{obj}: #{item}"
39 # This allows you to chain Enumerators together. For example, you
40 # can map a list's elements to strings containing the index
41 # and the element as a string via:
43 # puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
44 # # => ["0:foo", "1:bar", "2:baz"]
46 # An Enumerator can also be used as an external iterator.
47 # For example, Enumerator#next returns the next value of the iterator
48 # or raises StopIteration if the Enumerator is at the end.
50 # e = [1,2,3].each # returns an enumerator object.
54 # puts e.next # raises StopIteration
56 # You can use this to implement an internal iterator as follows:
62 # rescue StopIteration
79 # # use o.each as an internal iterator directly.
80 # puts o.each {|*x| puts x; [:b, *x] }
81 # # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
83 # # convert o.each to an external iterator for
84 # # implementing an internal iterator.
85 # puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
86 # # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
92 # @overload initialize(size = nil, &block)
93 # @overload initialize(obj, method = :each, *args)
95 # Creates a new Enumerator object, which can be used as an
98 # In the first form, iteration is defined by the given block, in
99 # which a "yielder" object, given as block parameter, can be used to
100 # yield a value by calling the +yield+ method (aliased as +<<+):
102 # fib = Enumerator.new do |y|
110 # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
112 # In the second, deprecated, form, a generated Enumerator iterates over the
113 # given object using the given method with the given arguments passed. This
114 # form is left only for internal use.
116 # Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum
118 def initialize(obj=NONE, meth=:each, *args, &block)
120 obj = Generator.new(&block)
122 raise ArgumentError, "wrong number of arguments (given 0, expected 1+)"
134 attr_accessor :obj, :meth, :args
137 def initialize_copy(obj)
138 raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator
139 raise TypeError, "can't copy execution context" if obj.fib
151 # e.with_index(offset = 0) {|(*args), idx| ... }
152 # e.with_index(offset = 0)
154 # Iterates the given block for each element with an index, which
155 # starts from +offset+. If no block is given, returns a new Enumerator
156 # that includes the index, starting from +offset+
158 # +offset+:: the starting index to use
160 def with_index(offset=0, &block)
161 return to_enum :with_index, offset unless block
166 offset = offset.__to_int
170 enumerator_block_call do |*i|
172 block.call i.__svalue, n
178 # e.each_with_index {|(*args), idx| ... }
181 # Same as Enumerator#with_index(0), i.e. there is no starting offset.
183 # If no block is given, a new Enumerator is returned that includes the index.
185 def each_with_index(&block)
186 with_index(0, &block)
191 # e.each_with_object(obj) {|(*args), obj| ... }
192 # e.each_with_object(obj)
193 # e.with_object(obj) {|(*args), obj| ... }
196 # Iterates the given block for each element with an arbitrary object, +obj+,
199 # If no block is given, returns a new Enumerator.
202 # to_three = Enumerator.new do |y|
208 # to_three_with_string = to_three.with_object("foo")
209 # to_three_with_string.each do |x,string|
210 # puts "#{string}: #{x}"
217 def with_object(object, &block)
218 return to_enum(:with_object, object) unless block
220 enumerator_block_call do |i|
221 block.call [i,object]
227 if @args && @args.size > 0
228 args = @args.join(", ")
229 "#<#{self.class}: #{@obj.inspect}:#{@meth}(#{args})>"
231 "#<#{self.class}: #{@obj.inspect}:#{@meth}>"
237 # enum.each { |elm| block } -> obj
239 # enum.each(*appending_args) { |elm| block } -> obj
240 # enum.each(*appending_args) -> an_enumerator
242 # Iterates over the block according to how this Enumerator was constructed.
243 # If no block and no arguments are given, returns self.
247 # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
248 # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
249 # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
253 # def obj.each_arg(a, b=:b, *rest)
260 # enum = obj.to_enum :each_arg, :a, :x
262 # enum.each.to_a #=> [:a, :x, []]
263 # enum.each.equal?(enum) #=> true
264 # enum.each { |elm| elm } #=> :method_returned
266 # enum.each(:y, :z).to_a #=> [:a, :x, [:y, :z]]
267 # enum.each(:y, :z).equal?(enum) #=> false
268 # enum.each(:y, :z) { |elm| elm } #=> :method_returned
270 def each(*argv, &block)
283 return obj unless block
284 enumerator_block_call(&block)
287 def enumerator_block_call(&block)
288 @obj.__send__ @meth, *@args, &block
290 private :enumerator_block_call
296 # Returns the next object in the enumerator, and move the internal position
297 # forward. When the position reached at the end, StopIteration is raised.
306 # p e.next #raises StopIteration
308 # Note that enumeration sequence by +next+ does not affect other non-external
309 # enumeration methods, unless the underlying iteration methods itself has
318 # e.next_values -> array
320 # Returns the next object as an array in the enumerator, and move the
321 # internal position forward. When the position reached at the end,
322 # StopIteration is raised.
324 # This method can be used to distinguish <code>yield</code> and <code>yield
350 # ## yield args next_values next
353 # # yield 1, 2 [1, 2] [1, 2]
354 # # yield nil [nil] nil
355 # # yield [1, 2] [[1, 2]] [1, 2]
357 # Note that +next_values+ does not affect other non-external enumeration
358 # methods unless underlying iteration method itself has side-effect
366 raise @stop_exc if @stop_exc
370 if !@fib || !@fib.alive?
373 result = each do |*args|
377 feedvalue = @feedvalue
382 @stop_exc = StopIteration.new "iteration reached an end"
383 @stop_exc.result = result
389 vs = @fib.resume curr
404 # Returns the next object in the enumerator, but doesn't move the internal
405 # position forward. If the position is already at the end, StopIteration
418 # p e.next #raises StopIteration
426 # e.peek_values -> array
428 # Returns the next object as an array, similar to Enumerator#next_values, but
429 # doesn't move the internal position forward. If the position is already at
430 # the end, StopIteration is raised.
441 # p e.peek_values #=> []
443 # p e.peek_values #=> [1]
444 # p e.peek_values #=> [1]
446 # p e.peek_values #=> [1, 2]
448 # p e.peek_values # raises StopIteration
452 @lookahead = next_values
461 # Rewinds the enumeration sequence to the beginning.
463 # If the enclosed object responds to a "rewind" method, it is called.
466 @obj.rewind if @obj.respond_to? :rewind
479 # Sets the value to be returned by the next yield inside +e+.
481 # If the value is not set, the yield returns nil.
483 # This value is cleared after being yielded.
485 # # Array#map passes the array's elements to "yield" and collects the
486 # # results of "yield" as an array.
487 # # Following example shows that "next" returns the passed elements and
488 # # values passed to "feed" are collected as an array which can be
489 # # obtained by StopIteration#result.
499 # rescue StopIteration
500 # p $!.result #=> ["a", "b", "c"]
505 # x = yield # (2) blocks
507 # x = yield # (6) blocks
509 # x = yield # (9) blocks
510 # p x # not reached w/o another e.next
521 raise TypeError, "feed value already set" if @feedvalue
529 def initialize(&block)
530 raise TypeError, "wrong argument type #{self.class} (expected Proc)" unless block.kind_of? Proc
535 def each(*args, &block)
536 args.unshift Yielder.new(&block)
543 def initialize(&block)
544 raise LocalJumpError, "no block given" unless block
563 # obj.to_enum(method = :each, *args) -> enum
564 # obj.enum_for(method = :each, *args) -> enum
565 # obj.to_enum(method = :each, *args) {|*args| block} -> enum
566 # obj.enum_for(method = :each, *args){|*args| block} -> enum
568 # Creates a new Enumerator which will enumerate by calling +method+ on
569 # +obj+, passing +args+ if any.
571 # If a block is given, it will be used to calculate the size of
572 # the enumerator without the need to iterate it (see Enumerator#size).
578 # enum = str.enum_for(:each_byte)
579 # enum.each { |b| puts b }
584 # # protect an array from being modified by some_method
586 # some_method(a.to_enum)
588 # It is typical to call to_enum when defining methods for
589 # a generic Enumerable, in case no block is passed.
591 # Here is such an example, with parameter passing and a sizing block:
594 # # a generic method to repeat the values of any enumerable
596 # raise ArgumentError, "#{n} is negative!" if n < 0
597 # unless block_given?
598 # return to_enum(__method__, n) do # __method__ is :repeat here
599 # sz = size # Call size and multiply by n...
600 # sz * n if sz # but return nil if size itself is nil
604 # n.times { yield *val }
609 # %i[hello world].repeat(2) { |w| puts w }
610 # # => Prints 'hello', 'hello', 'world', 'world'
611 # enum = (1..14).repeat(3)
612 # # => returns an Enumerator when called without a block
613 # enum.first(4) # => [1, 1, 1, 2]
615 def to_enum(meth=:each, *args)
616 Enumerator.new self, meth, *args
618 alias enum_for to_enum
622 # use Enumerator to use infinite sequence
623 def zip(*args, &block)
624 args = args.map do |a|
625 if a.respond_to?(:each)
628 raise TypeError, "wrong argument type #{a.class} (must respond to :each)"
632 result = block ? nil : []