[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]