Возврат из блока - из метода, вызванного в блоке? - PullRequest
1 голос
/ 17 ноября 2010

Я пытаюсь определить 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, которые делают разрыв блока? В приведенном выше примере я хочу:

  • проверить, является ли some_condition истиной, и если это так, выйти из блока и вернуть ему значение true
  • проверить, является ли some_other_condition истиной, и если это так, выйти из блока и вернуть ему значение true
  • возвращает false из блока безоговорочно, если мы все еще в нем

т.е. Я хочу, чтобы приведенный выше код вел себя так, как будто я написал блок следующим образом:

result = test_block do
  break true if some_condition
  break true if some_other_condition
  break false
end

Вставка break в определение метода хороший / плохой, очевидно, не работает. Есть ли какой-то другой способ достичь желаемого результата или мне следует подумать о совершенно ином способе достижения этой цели?

1 Ответ

3 голосов
/ 17 ноября 2010

Вы можете вызвать исключение в блоке и перехватить это исключение.

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 (обновлено для передачи возвращаемого значениявместе)

1007 *
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...