Ruby Language
Excepciones
Buscar..
Observaciones
Una excepción es un objeto que representa la ocurrencia de una condición excepcional. En otras palabras, indica que algo salió mal.
En Ruby, las excepciones a menudo se conocen como errores . Esto se debe a que la clase de Exception
base existe como un elemento de objeto de excepción de nivel superior, pero las excepciones de ejecución definidas por el usuario generalmente son StandardError
o descendientes.
Levantando una excepción
Para generar una excepción, use Kernel#raise
pasando la clase de excepción y / o el mensaje:
raise StandardError # raises a StandardError.new
raise StandardError, "An error" # raises a StandardError.new("An error")
También puede simplemente pasar un mensaje de error. En este caso, el mensaje se envuelve en un RuntimeError
:
raise "An error" # raises a RuntimeError.new("An error")
Aquí hay un ejemplo:
def hello(subject)
raise ArgumentError, "`subject` is missing" if subject.to_s.empty?
puts "Hello #{subject}"
end
hello # => ArgumentError: `subject` is missing
hello("Simone") # => "Hello Simone"
Creando un tipo de excepción personalizado
Una excepción personalizada es cualquier clase que amplíe Exception
o una subclase de Exception
.
En general, siempre debe extender StandardError
o un descendiente. La familia de Exception
suele ser por errores de máquinas virtuales o del sistema, al rescatarlos se puede evitar que una interrupción forzada funcione como se espera.
# Defines a new custom exception called FileNotFound
class FileNotFound < StandardError
end
def read_file(path)
File.exist?(path) || raise(FileNotFound, "File #{path} not found")
File.read(path)
end
read_file("missing.txt") #=> raises FileNotFound.new("File `missing.txt` not found")
read_file("valid.txt") #=> reads and returns the content of the file
Es común nombrar excepciones agregando el sufijo de Error
al final:
-
ConnectionError
-
DontPanicError
Sin embargo, cuando el error se explica por sí mismo, no es necesario agregar el sufijo de Error
porque sería redundante:
-
FileNotFound
vsFileNotFoundError
-
DatabaseExploded
vsDatabaseExplodedError
Manejando una excepción
Use el bloque de begin/rescue
para capturar (rescatar) una excepción y manejarla:
begin
# an execution that may fail
rescue
# something to execute in case of failure
end
Una cláusula de rescue
es análoga a un bloque catch
en un lenguaje con llaves como C # o Java.
Un simple rescue
como este rescata a StandardError
.
Nota: tenga cuidado de evitar la captura de Exception
lugar del StandardError
predeterminado. La clase de Exception
incluye SystemExit
y NoMemoryError
y otras excepciones serias que normalmente no desea capturar. Siempre considere capturar StandardError
(el predeterminado) en su lugar.
También puede especificar la clase de excepción que debe ser rescatada:
begin
# an excecution that may fail
rescue CustomError
# something to execute in case of CustomError
# or descendant
end
Esta cláusula de rescate no detectará ninguna excepción que no sea CustomError
.
También puede almacenar la excepción en una variable específica:
begin
# an excecution that may fail
rescue CustomError => error
# error contains the exception
puts error.message # provide human-readable details about what went wrong.
puts error.backtrace.inspect # return an array of strings that represent the call stack
end
Si no pudo manejar una excepción, puede elevarla en cualquier momento en un bloque de rescate.
begin
#here goes your code
rescue => e
#failed to handle
raise e
end
Si desea reintentar su bloque de begin
, llame a retry
:
begin
#here goes your code
rescue StandardError => e
#for some reason you want to retry you code
retry
end
Puede quedar atrapado en un bucle si detecta una excepción en cada reintento. Para evitar esto, limite su retry_count
a un cierto número de intentos.
retry_count = 0
begin
# an excecution that may fail
rescue
if retry_count < 5
retry_count = retry_count + 1
retry
else
#retry limit exceeds, do something else
end
También puede proporcionar un bloque else
o un bloque ensure
. Se ejecutará un bloque else
cuando el bloque de begin
se complete sin una excepción lanzada. Siempre se ejecutará un bloque de ensure
. Un bloque de ensure
es análogo a un bloque finally
en un lenguaje de llaves como C # o Java.
begin
# an execution that may fail
rescue
# something to execute in case of failure
else
# something to execute in case of success
ensure
# something to always execute
end
Si se encuentra dentro de una def
, module
o bloque de class
, no es necesario utilizar la instrucción begin.
def foo
...
rescue
...
end
Manejando múltiples excepciones
Puedes manejar múltiples errores en la misma declaración de rescue
:
begin
# an execution that may fail
rescue FirstError, SecondError => e
# do something if a FirstError or SecondError occurs
end
También puede agregar múltiples declaraciones de rescue
:
begin
# an execution that may fail
rescue FirstError => e
# do something if a FirstError occurs
rescue SecondError => e
# do something if a SecondError occurs
rescue => e
# do something if a StandardError occurs
end
El orden de los bloques de rescue
es relevante: la primera coincidencia es la ejecutada. Por lo tanto, si coloca StandardError
como la primera condición y todas sus excepciones heredan de StandardError
, las otras declaraciones de rescue
nunca se ejecutarán.
begin
# an execution that may fail
rescue => e
# this will swallow all the errors
rescue FirstError => e
# do something if a FirstError occurs
rescue SecondError => e
# do something if a SecondError occurs
end
Algunos bloques tienen un manejo de excepciones implícito como def
, class
y module
. Estos bloques le permiten omitir la instrucción begin
.
def foo
...
rescue CustomError
...
ensure
...
end
Agregando información a excepciones (personalizadas)
Puede ser útil incluir información adicional con una excepción, por ejemplo, para fines de registro o para permitir el manejo condicional cuando se detecta la excepción:
class CustomError < StandardError
attr_reader :safe_to_retry
def initialize(safe_to_retry = false, message = 'Something went wrong')
@safe_to_retry = safe_to_retry
super(message)
end
end
Levantando la excepción:
raise CustomError.new(true)
Capturando la excepción y accediendo a la información adicional proporcionada:
begin
# do stuff
rescue CustomError => e
retry if e.safe_to_retry
end