summaryrefslogtreecommitdiff
path: root/enumerator.c
diff options
context:
space:
mode:
authorknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-12-11 12:14:10 +0000
committerknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-12-11 12:14:10 +0000
commit5d8659a195065794642cd7cc0872c724812b67bd (patch)
treec79fa57ed7d0c62ae235ec903683e1e2e9e9b0f7 /enumerator.c
parentdd5a95a14c2c4bc223c4abbc3d1b64e144693d99 (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.c50
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");