diff options
author | knu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-12-11 12:14:10 +0000 |
---|---|---|
committer | knu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-12-11 12:14:10 +0000 |
commit | 5d8659a195065794642cd7cc0872c724812b67bd (patch) | |
tree | c79fa57ed7d0c62ae235ec903683e1e2e9e9b0f7 | |
parent | dd5a95a14c2c4bc223c4abbc3d1b64e144693d99 (diff) |
* enumerator.c (enumerator_next, enumerator_rewind),
lib/generator.rb (Enumerator#rewind): If the enclosed object
responds to a "rewind" method, call it.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@20645 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | NEWS | 10 | ||||
-rw-r--r-- | enumerator.c | 50 | ||||
-rw-r--r-- | lib/generator.rb | 6 |
4 files changed, 67 insertions, 5 deletions
@@ -1,3 +1,9 @@ +Thu Dec 11 21:09:47 2008 Akinori MUSHA <[email protected]> + + * enumerator.c (enumerator_next, enumerator_rewind), + lib/generator.rb (Enumerator#rewind): If the enclosed object + responds to a "rewind" method, call it. + Thu Dec 11 21:07:56 2008 Kouhei Sutou <[email protected]> * lib/rss/maker.rb, lib/rss/maker/0.9.rb, lib/rss/maker/base.rb: @@ -36,6 +36,10 @@ with all sufficient information, see the ChangeLog file. Now can generate an enumerator from a block that defines enumeration instead of an enumerable object. + * Enumerator#rewind + + Now calls the "rewind" method of the enclosed object if defined. + * Hash#default_proc= New method. @@ -117,6 +121,12 @@ with all sufficient information, see the ChangeLog file. * do not raise ShiftingError if an aged file already exists. (no ShiftingError will be raised from 1.2.7, just warn() instead) +=== Compatibility issues (excluding feature bug fixes) + + * Enumerator#rewind + + See above. + == Changes since the 1.8.6 release === Configuration changes diff --git a/enumerator.c b/enumerator.c index 541083890f..3dc2ab9bbc 100644 --- a/enumerator.c +++ b/enumerator.c @@ -22,6 +22,7 @@ */ VALUE rb_cEnumerator; static VALUE sym_each; +static ID id_rewind; VALUE rb_eStopIteration; @@ -497,6 +498,18 @@ enumerator_with_object(obj, memo) return memo; } +static int +require_generator() +{ + static int done = 0; + + if (done) + return 0; /* not the first time */ + rb_require("generator"); + done = 1; + return 1; /* the first time */ +} + /* * call-seq: * e.next => object @@ -517,8 +530,15 @@ static VALUE enumerator_next(obj) VALUE obj; { - rb_require("generator"); - return rb_funcall(obj, rb_intern("next"), 0, 0); + if (require_generator()) { + /* + * Call the new rewind method that the generator library + * redefines. + */ + return rb_funcall(obj, rb_intern("next"), 0, 0); + } else { + rb_raise(rb_eRuntimeError, "unexpected call; the generator library must have failed in redefining this method"); + } } /* @@ -526,14 +546,33 @@ enumerator_next(obj) * e.rewind => e * * Rewinds the enumeration sequence by the next method. + * + * If the enclosed object responds to a "rewind" method, it is called. */ static VALUE enumerator_rewind(obj) VALUE obj; { - rb_require("generator"); - return rb_funcall(obj, rb_intern("rewind"), 0, 0); + if (require_generator()) { + /* + * Call the new rewind method that the generator library + * redefines. + */ + return rb_funcall(obj, rb_intern("rewind"), 0, 0); + } else { + /* + * Once the generator library is loaded and the rewind method + * is overridden, this method changes itself to a secret knob + * to rewind the internal object. (black magic!) + */ + struct enumerator *e; + + e = enumerator_ptr(obj); + if (rb_respond_to(e->obj, id_rewind)) + rb_funcall(e->obj, id_rewind, 0); + return obj; + } } /* @@ -815,7 +854,8 @@ Init_Enumerator() rb_define_method(rb_cYielder, "yield", yielder_yield, -2); rb_define_method(rb_cYielder, "<<", yielder_yield, -2); - sym_each = ID2SYM(rb_intern("each")); + sym_each = ID2SYM(rb_intern("each")); + id_rewind = rb_intern("rewind"); /* backward compatibility */ rb_provide("enumerator.so"); diff --git a/lib/generator.rb b/lib/generator.rb index 03527af331..e6034a9f9a 100644 --- a/lib/generator.rb +++ b/lib/generator.rb @@ -193,12 +193,18 @@ class Enumerator raise StopIteration, 'iteration reached at end' end + # :nodoc: + alias __orig_rewind rewind + # call-seq: # e.rewind => e # # Rewinds the enumeration sequence by the next method. + # + # If the enclosed object responds to a "rewind" method, it is called. def rewind __generator.rewind + __orig_rewind self end end |