Ruby 从块返回-从块内调用的方法返回?
我试图定义一个DSL,其中在Ruby中的块中指定了规则(为了本例,这些规则定义了某些东西是“好的”还是“坏的”)。以下是我想做的(非常简化的)版本:Ruby 从块返回-从块内调用的方法返回?,ruby,Ruby,我试图定义一个DSL,其中在Ruby中的块中指定了规则(为了本例,这些规则定义了某些东西是“好的”还是“坏的”)。以下是我想做的(非常简化的)版本: def test_block # Lots of other code is_good = yield # ... should give me true or false # Lots of other code end test_block do good if some_condition good if some_
def test_block
# Lots of other code
is_good = yield # ... should give me true or false
# Lots of other code
end
test_block do
good if some_condition
good if some_other_condition
bad
end
我有没有办法定义使块中断的方法good
和bad
?在上面的示例中,我想:
- 检查某个条件是否为真,如果为真,则跳出该块并使其返回真
- 检查某些其他条件是否为真,如果为真,则跳出该块并使其返回真
- 如果我们仍然在块中,则无条件地从块返回false
result = test_block do
break true if some_condition
break true if some_other_condition
break false
end
将
break
放在好/坏方法的定义中显然是行不通的。是否有其他方法可以达到我想要的结果,或者我应该考虑一些完全不同的方法来实现这一点?您可以在块中引发异常并捕获该异常
module Tester
class Breaker < Exception; end
class GoodBreak < Breaker; end
class BaadBreak < Breaker; end
end
def test_block(name)
begin
yield
rescue Tester::Breaker=>e
case e
when Tester::GoodBreak then puts "All is well with #{name}"
when Tester::BaadBreak then puts "BAD STUFF WITH #{name}"
else raise
end
end
end
def good; raise Tester::GoodBreak; end
def bad; raise Tester::BaadBreak; end
test_block('early out') do
good if true
good if puts("NEVER SEE THIS") || true
bad
end
test_block('simple pass') do
good if false
good if puts("SEE THIS FROM PASS TEST") || true
bad
end
test_block('final fail') do
good if false
good if puts("SEE THIS BUT PUTS IS NIL")
bad
end
#=> All is well with early out
#=> SEE THIS FROM PASS TEST
#=> All is well with simple pass
#=> SEE THIS BUT PUTS IS NIL
#=> BAD STUFF WITH final fail
非常相关:这可能是
throw
/catch
的一个更好的应用程序,因为您将它们用于流控制。(或致电/cc.Heh。)@jledev没错!我已经很久没用了。这是免费的Ruby编程第一版。谢谢@Phrogz和@jleedev-我曾想过使用raise,但在被告知异常只适用于“非常糟糕的情况”(tm)后,我有点害怕了。)但是,抛出
/捕获
的方法感觉不那么错误!
def test_block(name)
result = catch(:good){ catch(:bad){ yield } }
puts "Testing #{name} yielded '#{result}'", ""
end
def good; throw :good, :good; end
def bad; throw :bad, :bad; end
test_block('early out') do
good if true
good if puts("NEVER SEE THIS") || true
bad
end
test_block('simple pass') do
good if false
good if puts("SEE THIS FROM PASS TEST") || true
bad
end
test_block('final fail') do
good if false
good if puts("SEE THIS BUT PUTS IS NIL")
bad
end
#=> Testing early out yielded 'good'
#=>
#=> SEE THIS FROM PASS TEST
#=> Testing simple pass yielded 'good'
#=>
#=> SEE THIS BUT PUTS IS NIL
#=> Testing final fail yielded 'bad'