ruby-changes:40137
From: knu <ko1@a...>
Date: Thu, 22 Oct 2015 18:58:14 +0900 (JST)
Subject: [ruby-changes:40137] knu:r52218 (trunk): Kernel#loop returns the result value of a finished iterator
knu 2015-10-22 18:58:01 +0900 (Thu, 22 Oct 2015) New Revision: 52218 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52218 Log: 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] Modified files: trunk/ChangeLog trunk/NEWS trunk/test/ruby/test_enumerator.rb trunk/vm_eval.c Index: ChangeLog =================================================================== --- ChangeLog (revision 52217) +++ ChangeLog (revision 52218) @@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Thu Oct 22 18:52:53 2015 Akinori MUSHA <knu@i...> + + * 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@r...> * lib/net/imap (idle): add a new argument timeout for keep-alive. Index: vm_eval.c =================================================================== --- vm_eval.c (revision 52217) +++ vm_eval.c (revision 52218) @@ -24,7 +24,7 @@ static void vm_set_eval_stack(rb_thread_ https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L24 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) https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1079 } 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, V https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1106 * # ... * 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) https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L2200 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"); } Index: NEWS =================================================================== --- NEWS (revision 52217) +++ NEWS (revision 52218) @@ -64,6 +64,11 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L64 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] Index: test/ruby/test_enumerator.rb =================================================================== --- test/ruby/test_enumerator.rb (revision 52217) +++ test/ruby/test_enumerator.rb (revision 52218) @@ -46,6 +46,14 @@ class TestEnumerator < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enumerator.rb#L46 } 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/