* enumerator.c: Improve documentation. Patch by Dave Copeland.

[Ruby 1.9 - Bug #4757]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31704 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2011-05-22 23:33:21 +00:00
parent b7576c3d7a
commit 6cfb4b614a
2 changed files with 197 additions and 142 deletions

View File

@ -1,3 +1,8 @@
Mon May 23 08:32:59 2011 Eric Hodel <drbrain@segment7.net>
* enumerator.c: Improve documentation. Patch by Dave Copeland.
[Ruby 1.9 - Bug #4757]
Mon May 23 07:19:45 2011 Martin Bosslet <Martin.Bosslet@googlemail.com> Mon May 23 07:19:45 2011 Martin Bosslet <Martin.Bosslet@googlemail.com>
* NEWS (openssl): Infinite length support. Different behavior of * NEWS (openssl): Infinite length support. Different behavior of

View File

@ -17,33 +17,52 @@
/* /*
* Document-class: Enumerator * Document-class: Enumerator
* *
* A class which provides a method `each' to be used as an Enumerable * A class which allows both internal and external iteration.
* object.
* *
* An enumerator can be created by following methods. * An Enumerator can be created by the following methods.
* - Kernel#to_enum * - Kernel#to_enum
* - Kernel#enum_for * - Kernel#enum_for
* - Enumerator.new * - Enumerator.new
* *
* Also, most iteration methods without a block returns an enumerator. * Most methods have two forms: a block form where the contents
* For example, Array#map returns an enumerator if a block is not given. * are evaluated for each item in the enumeration, and a non-block form
* The enumerator has the with_index method. * which returns a new Enumerator wrapping the iteration.
* So ary.map.with_index works as follows.
* *
* p %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" } * enumerator = %w(one two three).each
* #=> ["0:foo", "1:bar", "2:baz"] * 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
* *
* An enumerator object can be used as an external iterator. * This allows you to chain Enumerators together. For example, you
* I.e. Enumerator#next returns the next value of the iterator. * can map a list's elements to strings containing the index
* Enumerator#next raises StopIteration at end. * 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. * e = [1,2,3].each # returns an enumerator object.
* p e.next #=> 1 * puts e.next # => 1
* p e.next #=> 2 * puts e.next # => 2
* p e.next #=> 3 * puts e.next # => 3
* p e.next #raises StopIteration * 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) * def ext_each(e)
* while true * while true
@ -58,21 +77,22 @@
* end * end
* *
* o = Object.new * o = Object.new
*
* def o.each * def o.each
* p yield * puts yield
* p yield(1) * puts yield(1)
* p yield(1, 2) * puts yield(1, 2)
* 3 * 3
* end * end
* *
* # use o.each as an internal iterator directly. * # 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 * # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
* *
* # convert o.each to an external iterator for * # convert o.each to an external iterator for
* # implementing an internal iterator. * # 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 * # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
* *
*/ */
VALUE rb_cEnumerator; VALUE rb_cEnumerator;
@ -151,22 +171,31 @@ enumerator_ptr(VALUE obj)
} }
/* /*
* call-seq: * call-seq:
* obj.to_enum(method = :each, *args) * obj.to_enum(method = :each, *args)
* obj.enum_for(method = :each, *args) * obj.enum_for(method = :each, *args)
* *
* Returns Enumerator.new(self, method, *args). * Creates a new Enumerator which will enumerate by on calling +method+ on
* +obj+.
* *
* e.g.: * +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+
* *
* str = "xyz" * === Example
* *
* enum = str.enum_for(:each_byte) * str = "xyz"
* a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
* *
* # protects an array from being modified * enum = str.enum_for(:each_byte)
* a = [1, 2, 3] * enum.each { |b| puts b }
* some_method(a.to_enum) * # => 120
* # => 121
* # => 122
*
* # protect an array from being modified by some_method
* a = [1, 2, 3]
* some_method(a.to_enum)
* *
*/ */
static VALUE static VALUE
@ -217,36 +246,38 @@ enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv)
} }
/* /*
* call-seq: * call-seq:
* Enumerator.new(obj, method = :each, *args) * Enumerator.new { |yielder| ... }
* Enumerator.new { |y| ... } * Enumerator.new(obj, method = :each, *args)
* *
* Creates a new Enumerator object, which is to be used as an * Creates a new Enumerator object, which can be used as an
* Enumerable object iterating in a given way. * Enumerable.
* *
* In the first form, a generated Enumerator iterates over the given * In the first form, iteration is defined by the given block, in
* object using the given method with the given arguments passed. * which a "yielder" object, given as block parameter, can be used to
* Use of this form is discouraged. Use Kernel#enum_for(), alias * yield a value by calling the +yield+ method (aliased as +<<+):
* to_enum, instead.
* *
* e = Enumerator.new(ObjectSpace, :each_object) * fib = Enumerator.new do |y|
* #-> ObjectSpace.enum_for(:each_object) * a = b = 1
* loop do
* y << a
* a, b = b, a + b
* end
* end
* *
* e.select { |obj| obj.is_a?(Class) } #=> array of all classes * p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
* *
* In the second form, iteration is defined by the given block, in * In the second, deprecated, form, a generated Enumerator iterates over the
* which a "yielder" object given as block parameter can be used to * given object using the given method with the given arguments passed.
* yield a value by calling the +yield+ method, alias +<<+.
* *
* fib = Enumerator.new { |y| * Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum
* a = b = 1 * instead.
* loop { *
* y << a * e = Enumerator.new(ObjectSpace, :each_object)
* a, b = b, a + b * #-> ObjectSpace.enum_for(:each_object)
* } *
* } * e.select { |obj| obj.is_a?(Class) } #=> array of all classes
* *
* p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
*/ */
static VALUE static VALUE
enumerator_initialize(int argc, VALUE *argv, VALUE obj) enumerator_initialize(int argc, VALUE *argv, VALUE obj)
@ -320,11 +351,11 @@ enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
} }
/* /*
* call-seq: * call-seq:
* enum.each {...} * enum.each {...}
* *
* Iterates the given block using the object and the method specified * Iterates over the block according to how this Enumerable was constructed.
* in the first place. If no block is given, returns self. * If no block is given, returns self.
* *
*/ */
static VALUE static VALUE
@ -350,12 +381,15 @@ enumerator_with_index_i(VALUE val, VALUE m, int argc, VALUE *argv)
} }
/* /*
* call-seq: * call-seq:
* e.with_index(offset = 0) {|(*args), idx| ... } * e.with_index(offset = 0) {|(*args), idx| ... }
* e.with_index(offset = 0) * e.with_index(offset = 0)
* *
* Iterates the given block for each element with an index, which * 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 static VALUE
@ -370,12 +404,13 @@ enumerator_with_index(int argc, VALUE *argv, VALUE obj)
} }
/* /*
* call-seq: * call-seq:
* e.each_with_index {|(*args), idx| ... } * e.each_with_index {|(*args), idx| ... }
* e.each_with_index * e.each_with_index
* *
* Same as Enumerator#with_index, except each_with_index does not * Same as Enumerator#with_index(0), i.e. there is no starting offset.
* receive an offset argument. *
* If no block is given, a new Enumerator is returned that includes the index.
* *
*/ */
static VALUE static VALUE
@ -394,15 +429,31 @@ enumerator_with_object_i(VALUE val, VALUE memo, int argc, VALUE *argv)
} }
/* /*
* call-seq: * call-seq:
* e.with_object(obj) {|(*args), memo_obj| ... } * e.with_object(obj) {|(*args), obj| ... }
* e.with_object(obj) * e.with_object(obj)
* *
* Iterates the given block for each element with an arbitrary * Iterates the given block for each element with an arbitrary object, +obj+,
* object given, and returns the initially given object. * and returns +obj+
* *
* If no block is given, returns an enumerator. * If no block is given, returns a new 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 static VALUE
enumerator_with_object(VALUE obj, VALUE memo) enumerator_with_object(VALUE obj, VALUE memo)
@ -478,11 +529,14 @@ get_next_values(VALUE obj, struct enumerator *e)
* call-seq: * call-seq:
* e.next_values -> array * e.next_values -> array
* *
* Returns the next object as an array in the enumerator, * Returns the next object as an array in the enumerator, and move the
* and move the internal position forward. * internal position forward. When the position reached at the end,
* When the position reached at the end, StopIteration is raised. * StopIteration is raised.
* *
* This method can be used to distinguish <code>yield</code> and <code>yield nil</code>. * This method can be used to distinguish <code>yield</code> and <code>yield
* nil</code>.
*
* === Example
* *
* o = Object.new * o = Object.new
* def o.each * def o.each
@ -512,9 +566,9 @@ get_next_values(VALUE obj, struct enumerator *e)
* # yield nil [nil] nil * # yield nil [nil] nil
* # yield [1, 2] [[1, 2]] [1, 2] * # 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 * non-external enumeration methods, unless underlying iteration methods
* methods itself has side-effect, e.g. IO#each_line. * itself has side-effect, e.g. IO#each_line.
* *
*/ */
@ -557,9 +611,10 @@ ary2sv(VALUE args, int dup)
* call-seq: * call-seq:
* e.next -> object * e.next -> object
* *
* Returns the next object in the enumerator, and move the internal * Returns the next object in the enumerator, and move the internal position
* position forward. When the position reached at the end, StopIteration * forward. When the position reached at the end, StopIteration is raised.
* is raised. *
* === Example
* *
* a = [1,2,3] * a = [1,2,3]
* e = a.to_enum * e = a.to_enum
@ -568,9 +623,9 @@ ary2sv(VALUE args, int dup)
* p e.next #=> 3 * p e.next #=> 3
* p e.next #raises StopIteration * p e.next #raises StopIteration
* *
* Note that enumeration sequence by next method does not affect other * Note that enumeration sequence by +next+ does not affect other non-external
* non-external enumeration methods, unless underlying iteration * enumeration methods, unless the underlying iteration methods itself has
* methods itself has side-effect, e.g. IO#each_line. * side-effect, e.g. IO#each_line.
* *
*/ */
@ -596,9 +651,11 @@ enumerator_peek_values(VALUE obj)
* call-seq: * call-seq:
* e.peek_values -> array * e.peek_values -> array
* *
* Returns the next object as an array in the enumerator, * Returns the next object as an array, similar to Enumerator#next_values, but
* but don't move the internal position forward. * doesn't move the internal position forward. If the position is already at
* When the position reached at the end, StopIteration is raised. * the end, StopIteration is raised.
*
* === Example
* *
* o = Object.new * o = Object.new
* def o.each * def o.each
@ -628,10 +685,12 @@ enumerator_peek_values_m(VALUE obj)
* call-seq: * call-seq:
* e.peek -> object * e.peek -> object
* *
* Returns the next object in the enumerator, but don't move the internal * Returns the next object in the enumerator, but doesn't move the internal
* position forward. When the position reached at the end, StopIteration * position forward. If the position is already at the end, StopIteration
* is raised. * is raised.
* *
* === Example
*
* a = [1,2,3] * a = [1,2,3]
* e = a.to_enum * e = a.to_enum
* p e.next #=> 1 * p e.next #=> 1
@ -655,38 +714,26 @@ enumerator_peek(VALUE obj)
* call-seq: * call-seq:
* e.feed obj -> nil * 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 is 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 * three_times = Enumerator.new do |yielder|
* def o.each * 3.times do |x|
* # (2) * result = yielder.yield(x)
* x = yield * puts result
* p x #=> "foo" * end
* # (5)
* x = yield
* p x #=> nil
* # (7)
* x = yield
* # not reached
* p x
* end * end
* e = o.to_enum
* # (1)
* e.next
* # (3)
* e.feed "foo"
* # (4)
* e.next
* # (6)
* e.next
* # (8)
* *
* three_times.next # => 0
* three_times.feed("foo")
* three_times.next # => 1, prints "foo"
* three_times.next # => 2, prints nothing
*/ */
static VALUE static VALUE
enumerator_feed(VALUE obj, VALUE v) enumerator_feed(VALUE obj, VALUE v)
{ {
@ -704,7 +751,7 @@ enumerator_feed(VALUE obj, VALUE v)
* call-seq: * call-seq:
* e.rewind -> e * 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. * If the enclosed object responds to a "rewind" method, it is called.
*/ */
@ -785,7 +832,7 @@ inspect_enumerator(VALUE obj, VALUE dummy, int recur)
* call-seq: * call-seq:
* e.inspect -> string * e.inspect -> string
* *
* Create a printable version of <i>e</i>. * Creates a printable version of <i>e</i>.
*/ */
static VALUE static VALUE
@ -1027,27 +1074,27 @@ generator_each(VALUE obj)
} }
/* /*
* Document-class: StopIteration * Document-class: StopIteration
* *
* Raised to stop the iteration, in particular by Enumerator#next. It is * Raised to stop the iteration, in particular by Enumerator#next. It is
* rescued by Kernel#loop. * rescued by Kernel#loop.
* *
* loop do * loop do
* puts "Hello" * puts "Hello"
* raise StopIteration * raise StopIteration
* puts "World" * puts "World"
* end * end
* puts "Done!" * puts "Done!"
* *
* <em>produces:</em> * <em>produces:</em>
* *
* Hello * Hello
* Done! * Done!
*/ */
/* /*
* call-seq: * call-seq:
* stopiteration.result -> value * result -> value
* *
* Returns the return value of the iterator. * Returns the return value of the iterator.
* *
@ -1058,14 +1105,17 @@ generator_each(VALUE obj)
* yield 3 * yield 3
* 100 * 100
* end * end
*
* e = o.to_enum * e = o.to_enum
* p e.next #=> 1 *
* p e.next #=> 2 * puts e.next #=> 1
* p e.next #=> 3 * puts e.next #=> 2
* puts e.next #=> 3
*
* begin * begin
* e.next * e.next
* rescue StopIteration * rescue StopIteration => ex
* p $!.result #=> 100 * puts ex.result #=> 100
* end * end
* *
*/ */