我正在尝试定义一个 DSL,其中在 Ruby 的 block 中指定了规则(在本例中,规则定义了某些东西是“好”还是“坏”)。以下是我想做的(大大简化的)版本:
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
使 block 中断?在上面的例子中,我想:
- 检查 some_condition 是否为真,如果是,则跳出 block 并让它返回真
- 检查 some_other_condition 是否为真,如果是,则跳出 block 并让它返回真
- 如果我们仍在其中,则无条件地从 block 中返回 false
即我想让上面的代码表现得像我这样写 block :
result = test_block do
break true if some_condition
break true if some_other_condition
break false
end
将break
放在好/坏方法的定义中显然是行不通的。有没有其他方法可以达到我想要的结果,或者我应该考虑一些完全不同的方法吗?
最佳答案
您可以在 block 中引发异常并捕获该异常。
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
的示例(感谢@jleedev!)而不是 raise/rescue
(已更新以传递返回值):
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'
关于ruby - 从 block 返回 - 从 block 内调用的方法返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4205528/