mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* enumerator.c (next_i): fix to return with Fiber#yield at
the end of each block. [ruby-dev:31470] * enumerator.c (enumerator_next_p): call init_next if not initialized. [ruby-dev:31514] * test/ruby/test_enumerator.rb: add tests for Enumerator. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13120 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
009debfd02
commit
ad56f8c611
4 changed files with 73 additions and 10 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
Tue Aug 21 03:55:20 2007 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
|
* enumerator.c (next_i): fix to return with Fiber#yield at
|
||||||
|
the end of each block. [ruby-dev:31470]
|
||||||
|
|
||||||
|
* enumerator.c (enumerator_next_p): call init_next if not
|
||||||
|
initialized. [ruby-dev:31514]
|
||||||
|
|
||||||
|
* test/ruby/test_enumerator.rb: add tests for Enumerator.
|
||||||
|
|
||||||
Mon Aug 20 23:28:39 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
|
Mon Aug 20 23:28:39 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||||
|
|
||||||
* string.c (Init_String): remove Symbol.intern and Symbol#dump.
|
* string.c (Init_String): remove Symbol.intern and Symbol#dump.
|
||||||
|
|
19
enumerator.c
19
enumerator.c
|
@ -13,6 +13,7 @@
|
||||||
************************************************/
|
************************************************/
|
||||||
|
|
||||||
#include "ruby/ruby.h"
|
#include "ruby/ruby.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Document-class: Enumerable::Enumerator
|
* Document-class: Enumerable::Enumerator
|
||||||
|
@ -42,6 +43,7 @@ struct enumerator {
|
||||||
VALUE fib;
|
VALUE fib;
|
||||||
VALUE next;
|
VALUE next;
|
||||||
VALUE dst;
|
VALUE dst;
|
||||||
|
VALUE has_next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -237,6 +239,7 @@ enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, VALUE *argv)
|
||||||
if (argc) ptr->args = rb_ary_new4(argc, argv);
|
if (argc) ptr->args = rb_ary_new4(argc, argv);
|
||||||
ptr->fib = 0;
|
ptr->fib = 0;
|
||||||
ptr->next = ptr->dst = Qnil;
|
ptr->next = ptr->dst = Qnil;
|
||||||
|
ptr->has_next = Qnil;
|
||||||
|
|
||||||
return enum_obj;
|
return enum_obj;
|
||||||
}
|
}
|
||||||
|
@ -381,19 +384,20 @@ static VALUE
|
||||||
next_i(VALUE curr, VALUE obj)
|
next_i(VALUE curr, VALUE obj)
|
||||||
{
|
{
|
||||||
struct enumerator *e = enumerator_ptr(obj);
|
struct enumerator *e = enumerator_ptr(obj);
|
||||||
|
|
||||||
e->dst = curr;
|
e->dst = curr;
|
||||||
|
|
||||||
rb_block_call(obj, rb_intern("each"), 0, 0, next_ii, obj);
|
rb_block_call(obj, rb_intern("each"), 0, 0, next_ii, obj);
|
||||||
return e->next;
|
e->has_next = Qfalse;
|
||||||
|
rb_fiber_yield(e->dst, 1, &e->next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
next_init(VALUE obj, struct enumerator *e)
|
next_init(VALUE obj, struct enumerator *e)
|
||||||
{
|
{
|
||||||
VALUE curr = rb_fiber_current();
|
VALUE curr = rb_fiber_current();
|
||||||
|
|
||||||
e->dst = curr;
|
e->dst = curr;
|
||||||
e->fib = rb_block_call(rb_cFiber, rb_intern("new"), 0, 0, next_i, obj);
|
e->fib = rb_block_call(rb_cFiber, rb_intern("new"), 0, 0, next_i, obj);
|
||||||
|
e->has_next = Qtrue;
|
||||||
rb_fiber_yield(e->fib, 1, &curr);
|
rb_fiber_yield(e->fib, 1, &curr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,16 +420,18 @@ enumerator_next(VALUE obj)
|
||||||
{
|
{
|
||||||
struct enumerator *e = enumerator_ptr(obj);
|
struct enumerator *e = enumerator_ptr(obj);
|
||||||
VALUE curr, v;
|
VALUE curr, v;
|
||||||
|
|
||||||
curr = rb_fiber_current();
|
curr = rb_fiber_current();
|
||||||
|
|
||||||
if (!e->fib) {
|
if (!e->fib) {
|
||||||
next_init(obj, e);
|
next_init(obj, e);
|
||||||
}
|
}
|
||||||
if (!rb_fiber_alive_p(e->fib)) {
|
|
||||||
|
if (!e->has_next) {
|
||||||
e->fib = 0;
|
e->fib = 0;
|
||||||
e->next = e->dst = Qnil;
|
e->next = e->dst = Qnil;
|
||||||
rb_raise(rb_eStopIteration, "Enumerator#each reached at end");
|
rb_raise(rb_eStopIteration, "Enumerator#each reached at end");
|
||||||
}
|
}
|
||||||
|
|
||||||
v = rb_fiber_yield(e->fib, 1, &curr);
|
v = rb_fiber_yield(e->fib, 1, &curr);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -441,11 +447,10 @@ static VALUE
|
||||||
enumerator_next_p(VALUE obj)
|
enumerator_next_p(VALUE obj)
|
||||||
{
|
{
|
||||||
struct enumerator *e = enumerator_ptr(obj);
|
struct enumerator *e = enumerator_ptr(obj);
|
||||||
|
|
||||||
if (!e->fib) {
|
if (!e->fib) {
|
||||||
next_init(obj, e);
|
next_init(obj, e);
|
||||||
}
|
}
|
||||||
return rb_fiber_alive_p(e->fib);
|
return e->has_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
48
test/ruby/test_enumerator.rb
Normal file
48
test/ruby/test_enumerator.rb
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
require 'test/unit'
|
||||||
|
|
||||||
|
class TestEnumerator < Test::Unit::TestCase
|
||||||
|
def enum_test obj
|
||||||
|
i = 0
|
||||||
|
obj.map{|e|
|
||||||
|
[i+=1, e]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_iterators
|
||||||
|
assert_equal [[1, 0], [2, 1], [3, 2]], enum_test(3.times)
|
||||||
|
assert_equal [[1, :x], [2, :y], [3, :z]], enum_test([:x, :y, :z].each)
|
||||||
|
assert_equal [[1, [:x, 1]], [2, [:y, 2]]], enum_test({:x=>1, :y=>2})
|
||||||
|
end
|
||||||
|
|
||||||
|
## Enumerator as Iterator
|
||||||
|
|
||||||
|
def test_next
|
||||||
|
e = 3.times
|
||||||
|
3.times{|i|
|
||||||
|
assert_equal i, e.next
|
||||||
|
}
|
||||||
|
assert_raise(StopIteration){e.next}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_next?
|
||||||
|
e = 3.times
|
||||||
|
assert_equal true, e.next?
|
||||||
|
3.times{|i|
|
||||||
|
assert_equal true, e.next?
|
||||||
|
assert_equal i, e.next
|
||||||
|
}
|
||||||
|
assert_equal false, e.next?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_nested_itaration
|
||||||
|
def (o = Object.new).each
|
||||||
|
yield :ok1
|
||||||
|
yield [:ok2, :x].each.next
|
||||||
|
end
|
||||||
|
e = o.to_enum
|
||||||
|
assert_equal :ok1, e.next
|
||||||
|
assert_equal :ok2, e.next
|
||||||
|
assert_raise(StopIteration){e.next}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#define RUBY_VERSION "1.9.0"
|
#define RUBY_VERSION "1.9.0"
|
||||||
#define RUBY_RELEASE_DATE "2007-08-20"
|
#define RUBY_RELEASE_DATE "2007-08-21"
|
||||||
#define RUBY_VERSION_CODE 190
|
#define RUBY_VERSION_CODE 190
|
||||||
#define RUBY_RELEASE_CODE 20070820
|
#define RUBY_RELEASE_CODE 20070821
|
||||||
#define RUBY_PATCHLEVEL 0
|
#define RUBY_PATCHLEVEL 0
|
||||||
|
|
||||||
#define RUBY_VERSION_MAJOR 1
|
#define RUBY_VERSION_MAJOR 1
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
#define RUBY_VERSION_TEENY 0
|
#define RUBY_VERSION_TEENY 0
|
||||||
#define RUBY_RELEASE_YEAR 2007
|
#define RUBY_RELEASE_YEAR 2007
|
||||||
#define RUBY_RELEASE_MONTH 8
|
#define RUBY_RELEASE_MONTH 8
|
||||||
#define RUBY_RELEASE_DAY 20
|
#define RUBY_RELEASE_DAY 21
|
||||||
|
|
||||||
#ifdef RUBY_EXTERN
|
#ifdef RUBY_EXTERN
|
||||||
RUBY_EXTERN const char ruby_version[];
|
RUBY_EXTERN const char ruby_version[];
|
||||||
|
|
Loading…
Add table
Reference in a new issue