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

ruby-changes:54396

From: samuel <ko1@a...>
Date: Fri, 28 Dec 2018 22:03:16 +0900 (JST)
Subject: [ruby-changes:54396] samuel:r66610 (trunk): Implement Fiber#raise. Fixes #10344.

samuel	2018-12-28 22:03:09 +0900 (Fri, 28 Dec 2018)

  New Revision: 66610

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66610

  Log:
    Implement Fiber#raise. Fixes #10344.
    
    This allows raising exceptions in another fiber, similarly to
    Thread#raise.

  Modified files:
    trunk/cont.c
    trunk/test/ruby/test_fiber.rb
Index: cont.c
===================================================================
--- cont.c	(revision 66609)
+++ cont.c	(revision 66610)
@@ -1228,6 +1228,8 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/cont.c#L1228
 make_passing_arg(int argc, const VALUE *argv)
 {
     switch (argc) {
+      case -1:
+	return argv[0];
       case 0:
 	return Qnil;
       case 1:
@@ -1956,6 +1958,32 @@ rb_fiber_m_resume(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/cont.c#L1958
 
 /*
  *  call-seq:
+ *     fiber.raise                                 -> obj
+ *     fiber.raise(string)                         -> obj
+ *     fiber.raise(exception [, string [, array]]) -> obj
+ *
+ *  Raises an exception in the fiber at the point at which the last
+ *  <code>Fiber.yield</code> was called, or at the start if neither +resume+
+ *  nor +raise+ were called before.
+ *
+ *  With no arguments, raises a +RuntimeError+. With a single +String+
+ *  argument, raises a +RuntimeError+ with the string as a message.  Otherwise,
+ *  the first parameter should be the name of an +Exception+ class (or an
+ *  object that returns an +Exception+ object when sent an +exception+
+ *  message). The optional second parameter sets the message associated with
+ *  the exception, and the third parameter is an array of callback information.
+ *  Exceptions are caught by the +rescue+ clause of <code>begin...end</code>
+ *  blocks.
+ */
+static VALUE
+rb_fiber_raise(int argc, VALUE *argv, VALUE fib)
+{
+    VALUE exc = rb_make_exception(argc, argv);
+    return rb_fiber_resume(fib, -1, &exc);
+}
+
+/*
+ *  call-seq:
  *     fiber.transfer(args, ...) -> obj
  *
  *  Transfer control to another fiber, resuming it from where it last
@@ -2112,6 +2140,7 @@ Init_Cont(void) https://github.com/ruby/ruby/blob/trunk/cont.c#L2140
     rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
     rb_define_method(rb_cFiber, "initialize", rb_fiber_init, 0);
     rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
+    rb_define_method(rb_cFiber, "raise", rb_fiber_raise, -1);
     rb_define_method(rb_cFiber, "to_s", fiber_to_s, 0);
     rb_define_alias(rb_cFiber, "inspect", "to_s");
 }
Index: test/ruby/test_fiber.rb
===================================================================
--- test/ruby/test_fiber.rb	(revision 66609)
+++ test/ruby/test_fiber.rb	(revision 66610)
@@ -109,6 +109,15 @@ class TestFiber < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_fiber.rb#L109
       }
       fib.resume
     }
+    assert_raise(FiberError){
+      fib = Fiber.new{}
+      fib.raise "raise in unborn fiber"
+    }
+    assert_raise(FiberError){
+      fib = Fiber.new{}
+      fib.resume
+      fib.raise "raise in dead fiber"
+    }
   end
 
   def test_return
@@ -127,6 +136,37 @@ class TestFiber < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_fiber.rb#L136
     }
   end
 
+  def test_raise
+    assert_raise(ZeroDivisionError){
+      Fiber.new do
+        1/0
+      end.resume
+    }
+    assert_raise(RuntimeError){
+      fib = Fiber.new{ Fiber.yield }
+      fib.raise "raise and propagate"
+    }
+    assert_nothing_raised{
+      fib = Fiber.new do
+        begin
+          Fiber.yield
+        rescue
+        end
+      end
+      fib.resume
+      fib.raise "rescue in fiber"
+    }
+    fib = Fiber.new do
+      begin
+        Fiber.yield
+      rescue
+        Fiber.yield :ok
+      end
+    end
+    fib.resume
+    assert_equal(:ok, fib.raise)
+  end
+
   def test_transfer
     ary = []
     f2 = nil

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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