我正在尝试定义一个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_other_condition
bad
end
有没有什么方法可以定义阻止中断的方法good
和bad
?在上面的例子中,我想:
即。我想让上面的代码表现得好像我已经编写了这样的块:
result = test_block do
break true if some_condition
break true if some_other_condition
break false
end
将break
置于好/坏方法的定义中显然不起作用。是否有其他方法可以达到我想要的结果,还是我应该考虑一些完全不同的方法来解决这个问题?
答案 0 :(得分:3)
您可以在块中引发异常并捕获该异常。
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'