ruby - 从 block 返回 - 从 block 内调用的方法返回?

标签 ruby

我正在尝试定义一个 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

有什么方法可以定义方法 goodbad 使 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/

相关文章:

ruby - 我如何在 Watir 中模拟私密浏览体验? ( Selenium )

ruby-on-rails - 安装带有 bundle 的 Factory Girl 3.3 会导致 Ruby 版本错误

Ruby Imap OpenSSL::SSL::SSLError:读取服务器证书 B:证书验证失败

ruby - SSLServer发生错误时显示客户端IP地址#accept

jquery - 在 Rails 中的文本字段失去焦点后立即保存数据

ruby - 无法通过 bundler 安装我自己的 gem,但可以使用 ruby​​gems 安装

ruby - 如何使用 Ruby 检查是否在 Selenium WebDriver 中选中了复选框

ruby - Rspec/Sinatra 模块化与经典风格

ruby - 是什么让 Rake 在 Ruby 中如此有用?

ruby-on-rails - 如何使用主动支持核心分机日期和时间