Передача нескольких классов ошибок в условие спасения ruby ​​СУХОЙ модой - PullRequest
91 голосов
/ 25 апреля 2011

У меня есть код, который должен спасти несколько типов исключений в ruby:

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue FooException, BarException
  puts "rescued!"
end

Что я хотел бы сделать, так это каким-то образом сохранить список типов исключений, которые я хочу где-то спасти, и передать эти типы в условие восстановления:

EXCEPTIONS = [FooException, BarException]

и затем:

rescue EXCEPTIONS

Возможно ли это вообще, и возможно ли это без каких-либо по-настоящему хакерских звонков на eval? Я не надеюсь, учитывая, что я вижу TypeError: class or module required for rescue clause, когда я делаю попытку выше.

Ответы [ 2 ]

183 голосов
/ 26 апреля 2011

Вы можете использовать массив с оператором splat *.

EXCEPTIONS = [FooException, BarException]

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue *EXCEPTIONS
  puts "rescued!"
end

Если вы собираетесь использовать константу для массива, как указано выше (с EXCEPTIONS), обратите внимание, что вы не можете определить ее в определении, а также, если вы определяете ее в каком-то другом классе, вы должны обратиться к ней с его пространством имен. На самом деле, оно не должно быть константой.


Оператор Splat

Оператор splat * "распаковывает" массив в его положение, так что

rescue *EXCEPTIONS

означает то же самое, что и

rescue FooException, BarException

Вы также можете использовать его внутри литерала массива как

[BazException, *EXCEPTIONS, BangExcepion]

, что совпадает с

[BazException, FooException, BarException, BangExcepion]

или в позиции аргумента

method(BazException, *EXCEPTIONS, BangExcepion)

что означает

method(BazException, FooException, BarException, BangExcepion)

[] расширяется до вакансии:

[a, *[], b] # => [a, b]

Одна разница между ruby ​​1.8 и ruby ​​1.9 заключается в nil.

[a, *nil, b] # => [a, b]       (ruby 1.9)
[a, *nil, b] # => [a, nil, b]  (ruby 1.8)

Будьте осторожны с объектами, для которых определено to_a, так как to_a будет применяться в следующих случаях:

[a, *{k: :v}, b] # => [a, [:k, :v], b]

Для других типов объектов он возвращает сам себя.

[1, *2, 3] # => [1, 2, 3]
1 голос
/ 15 июня 2015

Я только столкнулся с этой проблемой и нашел альтернативное решение.В случае, если все ваши FooException и BarException будут настраиваемыми классами исключений, и особенно если они все тематически связаны, вы можете структурировать иерархию наследования так, чтобы они все наследовали от одного родительского класса, а затем спасать толькородительский класс.

Например, у меня было три исключения: FileNamesMissingError, InputFileMissingError и OutputDirectoryError, которые я хотел спасти одним оператором.Я создал другой класс исключений под названием FileLoadError, а затем настроил три вышеупомянутых исключения для наследования от него.Я тогда спас только FileLoadError.

Вот так:

class FileLoadError < StandardError
end

class FileNamesMissingError < FileLoadError
end

class InputFileMissingError < FileLoadError
end

class OutputDirectoryError < FileLoadError
end

[FileNamesMissingError,
 InputFileMissingError,
 OutputDirectoryError].each do |error| 
   begin  
     raise error
   rescue FileLoadError => e
     puts "Rescuing #{e.class}."
   end 
end
...