diff options
author | knu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-10-22 09:58:01 +0000 |
---|---|---|
committer | knu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-10-22 09:58:01 +0000 |
commit | f4c487173cd0c09993a51f684d8ae7e031b3f302 (patch) | |
tree | 73dfc17a8e2401dfece8c763b9dc9a401ebe0287 | |
parent | 53d6e605b0d4d61405d4cce36699fca904573b2c (diff) |
Kernel#loop returns the result value of a finished iterator
* vm_eval.c (rb_f_loop): When a loop is stopped by a StopIteration
exception, return what the enumerator has returned instead of
nil. [ruby-core:71133] [Feature #11498]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52218 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | test/ruby/test_enumerator.rb | 8 | ||||
-rw-r--r-- | vm_eval.c | 25 |
4 files changed, 40 insertions, 4 deletions
@@ -1,3 +1,9 @@ +Thu Oct 22 18:52:53 2015 Akinori MUSHA <knu@iDaemons.org> + + * vm_eval.c (rb_f_loop): When a loop is stopped by a StopIteration + exception, return what the enumerator has returned instead of + nil. [ruby-core:71133] [Feature #11498] + Thu Oct 22 18:25:10 2015 Shugo Maeda <shugo@ruby-lang.org> * lib/net/imap (idle): add a new argument timeout for keep-alive. @@ -64,6 +64,11 @@ with all sufficient information, see the ChangeLog file. this parameter is bitwise-ORed to oflags generated by normal mode argument. [Feature #11253] +* Kernel + + * Kernel#loop, when stopped by a StopIteration exception, returns + what the enumerator has returned instead of nil. + * Module * Module#deprecate_constant [Feature #11398] diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index 91c91a4bbd..e81d2e4e72 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -46,6 +46,14 @@ class TestEnumerator < Test::Unit::TestCase } end + def test_loop_return_value + assert_equal nil, loop { break } + assert_equal 42, loop { break 42 } + + e = Enumerator.new { |y| y << 1; y << 2; :stopped } + assert_equal :stopped, loop { e.next while true } + end + def test_nested_iteration def (o = Object.new).each yield :ok1 @@ -24,7 +24,7 @@ static void vm_set_eval_stack(rb_thread_t * th, const rb_iseq_t *iseq, const rb_ static int vm_collect_local_variables_in_heap(rb_thread_t *th, const VALUE *dfp, const struct local_var_list *vars); static VALUE rb_eUncaughtThrow; -static ID id_tag, id_value; +static ID id_result, id_tag, id_value; #define id_mesg idMesg /* vm_backtrace.c */ @@ -1079,6 +1079,12 @@ loop_i(void) } static VALUE +loop_stop(VALUE dummy, VALUE exc) +{ + return rb_attr_get(exc, id_result); +} + +static VALUE rb_f_loop_size(VALUE self, VALUE args, VALUE eobj) { return DBL2NUM(INFINITY); @@ -1100,15 +1106,25 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj) * # ... * end * - * StopIteration raised in the block breaks the loop. + * StopIteration raised in the block breaks the loop. In this case, + * loop returns the "result" value stored in the exception. + * + * enum = Enumerator.new { |y| + * y << "one" + * y << "two" + * :ok + * } + * + * result = loop { + * puts enum.next + * } #=> :ok */ static VALUE rb_f_loop(VALUE self) { RETURN_SIZED_ENUMERATOR(self, 0, 0, rb_f_loop_size); - rb_rescue2(loop_i, (VALUE)0, 0, 0, rb_eStopIteration, (VALUE)0); - return Qnil; /* dummy */ + return rb_rescue2(loop_i, (VALUE)0, loop_stop, (VALUE)0, rb_eStopIteration, (VALUE)0); } #if VMDEBUG @@ -2184,6 +2200,7 @@ Init_vm_eval(void) rb_define_method(rb_eUncaughtThrow, "value", uncaught_throw_value, 0); rb_define_method(rb_eUncaughtThrow, "to_s", uncaught_throw_to_s, 0); + id_result = rb_intern_const("result"); id_tag = rb_intern_const("tag"); id_value = rb_intern_const("value"); } |