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/