fibers/raising.rb
tests/_examples/fibers/raising.rb in the metorex repository.
# A fiber that has not started, or has run out, takes no exception.
unborn = Fiber.new { true }
begin
unborn.raise()
rescue FiberError => error
p(error.message)
end
dead = Fiber.new { true }
dead.resume()
begin
dead.raise()
rescue FiberError => error
p(error.message)
end
# One that handed control on by a transfer raises where it stands.
root = Fiber.current
parked = Fiber.new do
begin
root.transfer()
rescue RuntimeError => error
[:rescued, error.message]
end
end
parked.transfer()
p(parked.raise("into the transfer"))
# One part-way through resuming another passes it on to that one, and the
# exception comes back out through both.
low = Fiber.new { root.transfer() }
high = Fiber.new { low.resume() }
high.transfer()
begin
high.raise(RuntimeError, "through the resumer")
rescue RuntimeError => error
p(error.message)
end
p([low.alive?(), high.alive?()])
# Raised on the fiber that resumed the one running, it is raised at once.
outer = nil
inner = Fiber.new { outer.raise("back up") }
outer = Fiber.new { inner.resume() }
begin
outer.resume()
rescue RuntimeError => error
p(error.message)
end
# Another thread cannot raise in a fiber, which stays usable.
waiting = Fiber.new { Fiber.yield(); :resumed }
waiting.resume()
Thread.new do
begin
waiting.raise()
rescue FiberError => error
p(error.message)
end
end.join()
p(waiting.resume())
Output:
"cannot raise exception on unborn fiber"
"attempt to resume a terminated fiber"
[:rescued, "into the transfer"]
"through the resumer"
[false, false]
"back up"
"fiber called across threads"
:resumed