mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* enumerator.c (enumerator_next_p): should check correctly even when
e.next has not been called before. * enumerator.c (enumerator_next): raise StopIteration (name taken from Python) instead of IndexError. * enum.c (enum_zip): catch StopIteration exception. * enumerator.c (enumerator_with_index): return Enumerator if no block is given. * test/ruby/test_iterator.rb (TestIterator::test_enumerator): add test for enumerators. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12905 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
cc317d9208
commit
c186fdb90b
5 changed files with 68 additions and 14 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
Wed Aug 8 15:52:01 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* enumerator.c (enumerator_next_p): should check correctly even when
|
||||
e.next has not been called before.
|
||||
|
||||
* enumerator.c (enumerator_next): raise StopIteration (name taken
|
||||
from Python) instead of IndexError.
|
||||
|
||||
* enum.c (enum_zip): catch StopIteration exception.
|
||||
|
||||
* enumerator.c (enumerator_with_index): return Enumerator if no
|
||||
block is given.
|
||||
|
||||
* test/ruby/test_iterator.rb (TestIterator::test_enumerator): add
|
||||
test for enumerators.
|
||||
|
||||
Wed Aug 8 11:48:37 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* bignum.c (rb_big2str0): should not use RTEST for non-VALUE.
|
||||
|
|
2
enum.c
2
enum.c
|
@ -1411,7 +1411,7 @@ enum_zip(int argc, VALUE *argv, VALUE obj)
|
|||
RETURN_ENUMERATOR(obj, argc, argv);
|
||||
result = rb_block_given_p() ? Qnil : rb_ary_new();
|
||||
memo = rb_node_newnode(NODE_MEMO, result, rb_ary_new4(argc, argv), obj);
|
||||
rb_rescue2(zip_b, (VALUE)memo, 0, 0, rb_eIndexError, (VALUE)0);
|
||||
rb_rescue2(zip_b, (VALUE)memo, 0, 0, rb_eStopIteration, (VALUE)0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
44
enumerator.c
44
enumerator.c
|
@ -23,6 +23,8 @@
|
|||
static VALUE rb_cEnumerator;
|
||||
static VALUE sym_each, sym_each_with_index, sym_each_slice, sym_each_cons;
|
||||
|
||||
VALUE rb_eStopIteration;
|
||||
|
||||
static VALUE
|
||||
proc_call(VALUE proc, VALUE args)
|
||||
{
|
||||
|
@ -234,7 +236,7 @@ enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv)
|
|||
}
|
||||
if (argc) ptr->args = rb_ary_new4(argc, argv);
|
||||
ptr->fib = 0;
|
||||
ptr->next = ptr->dst = Qundef;
|
||||
ptr->next = ptr->dst = Qnil;
|
||||
|
||||
return enum_obj;
|
||||
}
|
||||
|
@ -339,7 +341,7 @@ enumerator_with_index(VALUE obj)
|
|||
int argc = 0;
|
||||
VALUE *argv = 0;
|
||||
|
||||
/* RETURN_ENUMERATOR(obj, 0, 0); ?? */
|
||||
RETURN_ENUMERATOR(obj, 0, 0);
|
||||
if (e->args) {
|
||||
argc = RARRAY_LEN(e->args);
|
||||
argv = RARRAY_PTR(e->args);
|
||||
|
@ -368,9 +370,9 @@ next_ii(VALUE i, VALUE obj)
|
|||
VALUE tmp = e->next;
|
||||
|
||||
e->next = i;
|
||||
if (tmp != Qundef) {
|
||||
e->next = i;
|
||||
e->dst = rb_fiber_yield(e->dst, 1, &tmp);
|
||||
tmp = rb_fiber_yield(e->dst, 1, &tmp);
|
||||
if (tmp != Qnil) {
|
||||
e->dst = tmp;
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
@ -385,13 +387,23 @@ next_i(VALUE curr, VALUE obj)
|
|||
return e->next;
|
||||
}
|
||||
|
||||
static void
|
||||
next_init(VALUE obj, struct enumerator *e)
|
||||
{
|
||||
VALUE curr = rb_fiber_current();
|
||||
|
||||
e->dst = curr;
|
||||
e->fib = rb_block_call(rb_cFiber, rb_intern("new"), 0, 0, next_i, obj);
|
||||
rb_fiber_yield(e->fib, 1, &curr);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* e.next => object
|
||||
*
|
||||
* Returns the next object in the enumerator, and move the internal
|
||||
* position forward. When the position reached at the end, internal
|
||||
* position is rewinded then IndexError is raised.
|
||||
* position is rewinded then StopIteration is raised.
|
||||
*
|
||||
* Note that enumeration sequence by next method does not affect other
|
||||
* non-external enumeration methods, unless underlying iteration
|
||||
|
@ -407,13 +419,12 @@ enumerator_next(VALUE obj)
|
|||
|
||||
curr = rb_fiber_current();
|
||||
if (!e->fib) {
|
||||
e->dst = curr;
|
||||
e->fib = rb_block_call(rb_cFiber, rb_intern("new"), 0, 0, next_i, obj);
|
||||
next_init(obj, e);
|
||||
}
|
||||
else if (!rb_fiber_alive_p(e->fib)) {
|
||||
if (!rb_fiber_alive_p(e->fib)) {
|
||||
e->fib = 0;
|
||||
e->next = e->dst = Qundef;
|
||||
rb_raise(rb_eIndexError, "Enumerator#each reached at end");
|
||||
e->next = e->dst = Qnil;
|
||||
rb_raise(rb_eStopIteration, "Enumerator#each reached at end");
|
||||
}
|
||||
v = rb_fiber_yield(e->fib, 1, &curr);
|
||||
return v;
|
||||
|
@ -429,7 +440,12 @@ enumerator_next(VALUE obj)
|
|||
static VALUE
|
||||
enumerator_next_p(VALUE obj)
|
||||
{
|
||||
return rb_fiber_alive_p(enumerator_ptr(obj)->fib);
|
||||
struct enumerator *e = enumerator_ptr(obj);
|
||||
|
||||
if (!e->fib) {
|
||||
next_init(obj, e);
|
||||
}
|
||||
return rb_fiber_alive_p(e->fib);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -445,7 +461,7 @@ enumerator_rewind(VALUE obj)
|
|||
struct enumerator *e = enumerator_ptr(obj);
|
||||
|
||||
e->fib = 0;
|
||||
e->next = e->dst = Qundef;
|
||||
e->next = e->dst = Qnil;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -471,6 +487,8 @@ Init_Enumerator(void)
|
|||
rb_define_method(rb_cEnumerator, "next?", enumerator_next_p, 0);
|
||||
rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
|
||||
|
||||
rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
|
||||
|
||||
sym_each = ID2SYM(rb_intern("each"));
|
||||
sym_each_with_index = ID2SYM(rb_intern("each_with_index"));
|
||||
sym_each_slice = ID2SYM(rb_intern("each_slice"));
|
||||
|
|
|
@ -798,6 +798,7 @@ RUBY_EXTERN VALUE rb_eFatal;
|
|||
RUBY_EXTERN VALUE rb_eArgError;
|
||||
RUBY_EXTERN VALUE rb_eEOFError;
|
||||
RUBY_EXTERN VALUE rb_eIndexError;
|
||||
RUBY_EXTERN VALUE rb_eStopIteration;
|
||||
RUBY_EXTERN VALUE rb_eKeyError;
|
||||
RUBY_EXTERN VALUE rb_eRangeError;
|
||||
RUBY_EXTERN VALUE rb_eIOError;
|
||||
|
|
|
@ -488,4 +488,23 @@ class TestIterator < Test::Unit::TestCase
|
|||
def test_block_given_within_iterator
|
||||
assert_equal(["b"], ["a", "b", "c"].grep(IterString.new("b")) {|s| s})
|
||||
end
|
||||
|
||||
def test_enumerator
|
||||
[1,2,3].each.with_index {|x,i|
|
||||
assert_equal(x, i+1)
|
||||
}
|
||||
|
||||
e = [1,2,3].each
|
||||
assert_equal(1, e.next)
|
||||
assert_equal(true, e.next?)
|
||||
assert_equal(2, e.next)
|
||||
assert_equal(3, e.next)
|
||||
assert_raises(StopIteration){e.next}
|
||||
e.rewind
|
||||
assert_equal(true, e.next?)
|
||||
assert_equal(1, e.next)
|
||||
|
||||
assert_equal([[1, 8, 10], [2, 6, 11], [3, 4, 12]],
|
||||
(1..10).zip([8,6,4],(10..100)).to_a)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue