How to force a LocalJumpError on return in Ruby?
My function bar
gets a block, and I'd like to run this block without allowing it to return
. How do I do that by modifying only bar
below, and keeping everyth开发者_高级运维ing else, including foo
, intact?
def bar()
yield
end
def foo()
bar do
p "it"
return # This works. But I'd like to get LocalJumpError.
end
end
foo
Well, you get a LocalJumpError
when you try and pass a block with a return
to a Proc
(as opposed to a lambda
).
You can get away with not changing foo
except for how it's called, if you do something like
def bar()
Proc.new
end
def foo()
bar do
p "it"
return
end
end
foo[]
That gives a LocalJumpError
.
Anyway, this article might help.
Edit: A return
in a proc will return from the outer method, not from the anonymous method in the block. You might be able to set a flag that you can check in bar
to see if it returned prematurely:
bar_finished = false
def bar(&block)
proc = Proc.new &block
l.call
bar_finished = true
end
Then, if a return
is in the block passed to bar
, bar_finished
will still be false. Not sure if adding a non-local variable like this is an option, but if so, you could track returns from the block and throw whatever exception you want if it happens.
If there's some "cleaning up" code you want done after yield
, then you may want to use begin
and then ensure
.
Based on suggestions in other answers, I have managed to solve the problem:
def bar()
has_returned = true
begin
x = yield
has_returned = false
x
rescue
has_returned = false
raise
ensure
raise LocalJumpError if has_returned
end
end
def foo()
bar do
p "it"
return # This makes bar raise a LocalJumpError.
end
end
foo
精彩评论