summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-catch/mrblib/catch.rb
diff options
context:
space:
mode:
authordearblue <[email protected]>2021-02-06 21:22:59 +0900
committerdearblue <[email protected]>2021-02-06 21:41:08 +0900
commit232e07ad618deff7bb438aa30e86da29b17c37cf (patch)
tree99cfd23c0f020410ddd06ba1be3972ded6eac1e3 /mrbgems/mruby-catch/mrblib/catch.rb
parentc6c632cf97719e7b2d7e1e574eec95dfc6a47d2d (diff)
downloadmruby-232e07ad618deff7bb438aa30e86da29b17c37cf.tar.gz
mruby-232e07ad618deff7bb438aa30e86da29b17c37cf.zip
Reimplement mruby-catch; ref #5321
When there is a corresponding tag, the `RBreak` object is used to make a global jump. Like CRuby, it can't be caught by `rescue`. It is also the same as CRuby that it can be canceled in the middle by `ensure`. ### How to find the corresponding tag with `throw` The called `catch` method remains in the call stack, and the tag also remains in the stack at that time. So it is possible to find the called location by searching the two. Note that no method can be given to the `proc` object specified in `RBreak`. Therefore, inside the `catch` method, the argument block is called in a seemingly meaningless closure. Also, as a countermeasure against `alias` etc., the `proc` object, which is the body of the `catch` method, is saved when mrbgem is initialized.
Diffstat (limited to 'mrbgems/mruby-catch/mrblib/catch.rb')
-rw-r--r--mrbgems/mruby-catch/mrblib/catch.rb16
1 files changed, 8 insertions, 8 deletions
diff --git a/mrbgems/mruby-catch/mrblib/catch.rb b/mrbgems/mruby-catch/mrblib/catch.rb
index 68b165c8d..c69cd125e 100644
--- a/mrbgems/mruby-catch/mrblib/catch.rb
+++ b/mrbgems/mruby-catch/mrblib/catch.rb
@@ -1,4 +1,4 @@
-class ThrowCatchJump < Exception
+class UncaughtThrowError < ArgumentError
attr_reader :_tag, :_val
def initialize(tag, val)
@_tag = tag
@@ -9,14 +9,14 @@ end
module Kernel
def catch(tag=Object.new, &block)
- block.call(tag)
- rescue ThrowCatchJump => e
- unless e._tag.equal?(tag)
- raise e
- end
- return e._val
+ # A double closure is required to make the nested `catch` distinguishable
+ # and because `break` goes back to `proc->upper`.
+ -> { -> { block.call(tag) }.call }.call
end
def throw(tag, val=nil)
- raise ThrowCatchJump.new(tag, val)
+ __throw(tag, val)
+ raise UncaughtThrowError.new(tag, val)
end
+
+ __preserve_catch_method
end