standard - Pasar múltiples clases de error a la cláusula de rescate de ruby de manera SECA
ruby exception backtrace (2)
Tengo un código que necesita rescatar varios 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 de alguna manera almacenar la lista de tipos de excepciones 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 a eval
? No tengo esperanzas dado que estoy viendo TypeError: class or module required for rescue clause
cuando intento lo anterior.
Me encontré con este problema y encontré una solución alternativa. En el caso de que su FooException
y BarException
sean todas clases de excepciones personalizadas y particularmente si están relacionadas temáticamente, puede estructurar su jerarquía de herencia de modo que todas ellas hereden de la misma clase primaria y luego rescaten solo la clase principal.
Por ejemplo, tenía tres excepciones: FileNamesMissingError
, InputFileMissingError
y OutputDirectoryError
que quería rescatar con una declaración. Hice otra clase de excepción llamada FileLoadError
y luego configuré las tres excepciones anteriores para heredar de ella. Luego 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
Puede usar 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 usar una constante para la matriz como se indica arriba (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.
El operador splat *
"desempaqueta" una matriz en su posición para que
rescue *EXCEPTIONS
significa lo mismo que
rescue FooException, BarException
También puede usarlo dentro de una matriz literal como
[BazException, *EXCEPTIONS, BangExcepion]
que es lo mismo que
[BazException, FooException, BarException, BangExcepion]
o en una posición de discusión
method(BazException, *EXCEPTIONS, BangExcepion)
lo que significa
method(BazException, FooException, BarException, BangExcepion)
[]
expande a vacío
[a, *[], b] # => [a, b]
Una diferencia entre ruby 1.8 y ruby 1.9 es 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 se aplicará to_a
en tales casos:
[a, *{k: :v}, b] # => [a, [:k, :v], b]
Con otros tipos de objetos, se devuelve a sí mismo.
[1, *2, 3] # => [1, 2, 3]