Pasar múltiples clases de error a la cláusula de rescate de Ruby en una forma DRY

Tengo algunos códigos que necesitan rescatar múltiples tipos de excepciones en ruby:

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

Lo que me gustaría hacer es almacenar de alguna manera la lista de tipos de excepción que quiero rescatar en algún lugar y pasar esos tipos a la cláusula de rescate:

 EXCEPTIONS = [FooException, BarException] 

y entonces:

 rescue EXCEPTIONS 

¿Es esto posible, y es posible sin algunas llamadas realmente hack-y para eval ? No tengo esperanza dado que estoy viendo TypeError: class or module required for rescue clause cuando bash lo anterior.

Puede utilizar una matriz con el operador splat * .

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

Si va a utilizar una constante para la matriz como se indica anteriormente (con EXCEPTIONS ), tenga en cuenta que no puede definirla dentro de una definición, y también si la define en alguna otra clase, debe referirse a ella con su espacio de nombres. En realidad, no tiene que ser una constante.


Operador Splat

El operador splat * “desempaqueta” una matriz en su posición para que

 rescue *EXCEPTIONS 

significa lo mismo que

 rescue FooException, BarException 

También puedes usarlo dentro de un array literal como

 [BazException, *EXCEPTIONS, BangExcepion] 

que es lo mismo que

 [BazException, FooException, BarException, BangExcepion] 

o en una posición de argumento

 method(BazException, *EXCEPTIONS, BangExcepion) 

lo que significa

 method(BazException, FooException, BarException, BangExcepion) 

[] expande a la vacuidad:

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

Una diferencia entre ruby ​​1.8 y ruby ​​1.9 es con nil .

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

Tenga cuidado con los objetos en los que se define to_a , ya que to_a se aplicará en tales casos:

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

Con otros tipos de objetos, se devuelve.

 [1, *2, 3] # => [1, 2, 3] 

Me acabo de encontrar con este problema y encontré una solución alternativa. En el caso de que su FooException y BarException sean clases de excepción personalizadas y, en particular, si todas están relacionadas temáticamente, puede estructurar su jerarquía de herencia de modo que todas heredarán de la misma clase principal y luego rescaten solo a la clase principal.

Por ejemplo, tuve tres excepciones: FileNamesMissingError , InputFileMissingError y OutputDirectoryError que quería rescatar con una statement. Hice otra clase de excepción llamada FileLoadError y luego configuré las tres excepciones anteriores para heredarlas. Entonces rescaté solo FileLoadError .

Me gusta esto:

 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