Project

General

Profile

Bug #4757 ยป 0003-clean-up-can-clarify-Enumerator.patch

davetron5000 (David Copeland), 05/22/2011 04:28 AM

View differences:

enumerator.c
/*
* Document-class: Enumerator
*
* A class which provides a method `each' to be used as an Enumerable
* object.
* A class which allows iteration, typically via an #each method.
*
* An enumerator can be created by following methods.
* An Enumerator can be created by the following methods.
* - Kernel#to_enum
* - Kernel#enum_for
* - Enumerator.new
*
* Also, most iteration methods without a block returns an enumerator.
* For example, Array#map returns an enumerator if a block is not given.
* The enumerator has the with_index method.
* So ary.map.with_index works as follows.
* 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.
*
* p %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" }
* 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 object can be used as an external iterator.
* I.e. Enumerator#next returns the next value of the iterator.
* Enumerator#next raises StopIteration at end.
* An Enumerator can 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.
* p e.next #=> 1
* p e.next #=> 2
* p e.next #=> 3
* p e.next #raises StopIteration
* puts e.next #=> 1
* puts e.next #=> 2
* puts e.next #=> 3
* puts e.next #raises StopIteration
*
* An external iterator can be used to implement an internal iterator as follows.
* You can use this to implement an internal iterator as follows:
*
* def ext_each(e)
* while true
......
*
* o = Object.new
* def o.each
* p yield
* p yield(1)
* p yield(1, 2)
* puts yield
* puts yield(1)
* puts yield(1, 2)
* 3
* end
*
* # use o.each as an internal iterator directly.
* p o.each {|*x| p x; [:b, *x] }
* 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.
* p ext_each(o.to_enum) {|*x| p x; [:b, *x] }
* puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
* #=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
*
*/
......
* obj.to_enum(method = :each, *args)
* obj.enum_for(method = :each, *args)
*
* Returns Enumerator.new(self, method, *args).
* Returns a new Enumerator based on calling
* +method+ on +obj+
*
* +method+:: the method to call on +obj+ to generate the enumeration
* +args+:: arguments that will be passed in +method+ <i>in addition</i>
* to the item itself. Note that the number of args
* must not exceed the number expected by +method+
*
* e.g.:
* === Example
*
* str = "xyz"
*
* enum = str.enum_for(:each_byte)
* a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
* enum.each { |b| puts b }
* # 120
* # 121
* # 122
*
* # protects an array from being modified
* # protects an array from being modified by some_method
* a = [1, 2, 3]
* some_method(a.to_enum)
*
......
/*
* call-seq:
* Enumerator.new { |yielder| ... }
* Enumerator.new(obj, method = :each, *args)
* Enumerator.new { |y| ... }
*
* Creates a new Enumerator object, which is to be used as an
* Enumerable object iterating in a given way.
* 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
*
* In the first form, a generated Enumerator iterates over the given
* p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
*
* In the second, deprecated, form, a generated Enumerator iterates over the given
* object using the given method with the given arguments passed.
* Use of this form is discouraged. Use Kernel#enum_for(), alias
* to_enum, instead.
* Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum
* instead.
*
* e = Enumerator.new(ObjectSpace, :each_object)
* #-> ObjectSpace.enum_for(:each_object)
*
* e.select { |obj| obj.is_a?(Class) } #=> array of all classes
*
* In the second 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, alias +<<+.
*
* fib = Enumerator.new { |y|
* a = b = 1
* loop {
* y << a
* a, b = b, a + b
* }
* }
*
* p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
*/
static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj)
......
* call-seq:
* enum.each {...}
*
* Iterates the given block using the object and the method specified
* in the first place. If no block is given, returns self.
* Iterates over the block according to how this Enumerable was constructed.
* If no block is given, returns self.
*
*/
static VALUE
......
* 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 an enumerator.
* 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
*
*/
static VALUE
......
* e.each_with_index {|(*args), idx| ... }
* e.each_with_index
*
* Same as Enumerator#with_index, except each_with_index does not
* receive an offset argument.
* 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.
*
*/
static VALUE
......
/*
* call-seq:
* e.with_object(obj) {|(*args), memo_obj| ... }
* e.with_object(obj) {|(*args), obj| ... }
* e.with_object(obj)
*
* Iterates the given block for each element with an arbitrary
* object given, and returns the initially given object.
* object, +obj+, and returns +obj+
*
* If no block is given, returns a new Enumerator.
*
* If no block is given, returns an enumerator.
* === Example
*
* to_three = Enumerator.new do |y|
* 3.times do |x|
* y << x
* end
* end
*
* to_three_with_string = to_three.with_object("foo")
* to_three_with_string.each do |x,string|
* puts "#{string}: #{x}"
* end
* # foo:0
* # foo:1
* # foo:2
*/
static VALUE
enumerator_with_object(VALUE obj, VALUE memo)
......
*
* This method can be used to distinguish <code>yield</code> and <code>yield nil</code>.
*
* === Example
*
* o = Object.new
* def o.each
* yield
......
* # yield nil [nil] nil
* # yield [1, 2] [[1, 2]] [1, 2]
*
* Note that enumeration sequence by next_values method does not affect other
* Note that enumeration sequenced by +next_values+ does not affect other
* non-external enumeration methods, unless underlying iteration
* methods itself has side-effect, e.g. IO#each_line.
*
......
* 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 #=> 3
* p e.next #raises StopIteration
*
* Note that enumeration sequence by next method does not affect other
* non-external enumeration methods, unless underlying iteration
* Note that enumeration sequence by +next+ does not affect other
* non-external enumeration methods, unless the underlying iteration
* methods itself has side-effect, e.g. IO#each_line.
*
*/
......
* call-seq:
* e.peek_values -> array
*
* Returns the next object as an array in the enumerator,
* but don't move the internal position forward.
* When the position reached at the end, StopIteration is raised.
* 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
......
* call-seq:
* e.peek -> object
*
* Returns the next object in the enumerator, but don't move the internal
* position forward. When the position reached at the end, StopIteration
* 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
......
* call-seq:
* e.feed obj -> nil
*
* Set the value for the next yield in the enumerator returns.
* Set the value to be returned by the next call
* to +yield+ by the enumerator. If the
* value is not set, the +yield+ returns +nil+
* and the value is cleared after it's used
* the first time.
*
* If the value is not set, the yield returns nil.
* +obj+:: the object to return from the next call
* to the Enumerator's +yield+
*
* This value is cleared after used.
* === Example
*
* o = Object.new
* def o.each
* # (2)
* x = yield
* p x #=> "foo"
* # (5)
* x = yield
* p x #=> nil
* # (7)
* x = yield
* # not reached
* p x
* end
* e = o.to_enum
* # (1)
* e.next
* # (3)
* e.feed "foo"
* # (4)
* e.next
* # (6)
* e.next
* # (8)
* three_times = Enumerator.new do |yielder|
* 3.times do |x|
* result = yielder.yield(x)
* puts result
* end
* end
*
* three_times.next # => 0
* three_times.feed("foo")
* three_times.next # => 1, prints "foo"
* three_times.next # => 2, prints nothing
*/
static VALUE
enumerator_feed(VALUE obj, VALUE v)
{
......
* call-seq:
* e.rewind -> e
*
* Rewinds the enumeration sequence by the next method.
* Rewinds the enumeration sequence by one step.
*
* If the enclosed object responds to a "rewind" method, it is called.
*/
......
/*
* call-seq:
* stopiteration.result -> value
* result -> value
*
* Returns the return value of the iterator.
*
......
* 100
* end
* e = o.to_enum
* p e.next #=> 1
* p e.next #=> 2
* p e.next #=> 3
* puts e.next #=> 1
* puts e.next #=> 2
* puts e.next #=> 3
* begin
* e.next
* rescue StopIteration
* p $!.result #=> 100
* rescue StopIteration => ex
* puts ex.result #=> 100
* end
*
*/
    (1-1/1)