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 /enumerator.c | |
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
Diffstat (limited to 'enumerator.c')
-rw-r--r-- | enumerator.c | 50 |
1 files changed, 45 insertions, 5 deletions
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"); |