Ruby - Excepciones
La ejecución y la excepción siempre van juntas. Si está abriendo un archivo, que no existe, si no manejó esta situación correctamente, se considera que su programa es de mala calidad.
El programa se detiene si ocurre una excepción. Por lo tanto, las excepciones se utilizan para manejar varios tipos de errores, que pueden ocurrir durante la ejecución de un programa y tomar la acción apropiada en lugar de detener el programa por completo.
Ruby proporciona un buen mecanismo para manejar excepciones. Incluimos el código que podría generar una excepción en un bloque de inicio / fin y usamos cláusulas de rescate para decirle a Ruby los tipos de excepciones que queremos manejar.
Sintaxis
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# Other exceptions
ensure
# Always will be executed
end
Todo, desde el principio hasta el rescate, está protegido. Si ocurre una excepción durante la ejecución de este bloque de código, el control se pasa al bloque entre el rescate y el final .
Para cada cláusula de rescate en el bloque de inicio , Ruby compara la excepción planteada con cada uno de los parámetros por turno. La coincidencia tendrá éxito si la excepción nombrada en la cláusula de rescate es el mismo que el tipo de la excepción lanzada actualmente, o es una superclase de esa excepción.
En el caso de que una excepción no coincida con ninguno de los tipos de error especificados, se nos permite usar una cláusula else después de todas las cláusulas de rescate .
Ejemplo
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
file = STDIN
end
print file, "==", STDIN, "\n"
Esto producirá el siguiente resultado. Puede ver que STDIN se sustituye al archivo porque no se pudo abrir .
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
Usar declaración de reintento
Se puede capturar una excepción el uso de rescate del bloque y el uso de reintento sentencia que debe ejecutarse comienzan bloque desde el principio.
Sintaxis
begin
# Exceptions raised by this code will
# be caught by the following rescue clause
rescue
# This block will capture all types of exceptions
retry # This will move control to the beginning of begin
end
Ejemplo
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
fname = "existant_file"
retry
end
El siguiente es el flujo del proceso:
- Se produjo una excepción al abrir.
- Fui a rescatar. fname fue reasignado.
- Reintentar fue al principio del comienzo.
- Este archivo de tiempo se abre correctamente.
- Continuó el proceso esencial.
NOTE- Observe que si el archivo de nombre reemplazado no existe, este código de ejemplo se reintenta infinitamente. Tenga cuidado si usa Reintentar para un proceso de excepción.
Usar declaración de aumento
Puede usar una declaración de aumento para generar una excepción. El siguiente método genera una excepción cada vez que se llama. Se imprimirá su segundo mensaje.
Sintaxis
raise
OR
raise "Error Message"
OR
raise ExceptionType, "Error Message"
OR
raise ExceptionType, "Error Message" condition
El primer formulario simplemente vuelve a generar la excepción actual (o un RuntimeError si no hay una excepción actual). Esto se usa en manejadores de excepciones que necesitan interceptar una excepción antes de pasarla.
El segundo formulario crea una nueva excepción RuntimeError , estableciendo su mensaje en la cadena dada. Esta excepción luego se genera en la pila de llamadas.
El tercer formulario usa el primer argumento para crear una excepción y luego establece el mensaje asociado al segundo argumento.
La cuarta forma es similar a la tercera, pero puede agregar cualquier declaración condicional como a menos que genere una excepción.
Ejemplo
#!/usr/bin/ruby
begin
puts 'I am before the raise.'
raise 'An error has occurred.'
puts 'I am after the raise.'
rescue
puts 'I am rescued.'
end
puts 'I am after the begin block.'
Esto producirá el siguiente resultado:
I am before the raise.
I am rescued.
I am after the begin block.
Un ejemplo más que muestra el uso de raise -
#!/usr/bin/ruby
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
end
Esto producirá el siguiente resultado:
A test exception.
["main.rb:4"]
Usar declaración de garantía
A veces, debe garantizar que se realice algún procesamiento al final de un bloque de código, independientemente de si se generó una excepción. Por ejemplo, puede tener un archivo abierto al ingresar al bloque y debe asegurarse de que se cierre cuando el bloque sale.
La garantizar cláusula hace precisamente esto. asegurar va después de la última cláusula de rescate y contiene un fragmento de código que siempre se ejecutará cuando finalice el bloque. No importa si las salidas de bloque normalmente, si eleva y libra una excepción, o si se ha interrumpido por una excepción no detectada, al asegurar bloque conseguirá ejecutar.
Sintaxis
begin
#.. process
#..raise exception
rescue
#.. handle error
ensure
#.. finally ensure execution
#.. This will always execute.
end
Ejemplo
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
ensure
puts "Ensuring execution"
end
Esto producirá el siguiente resultado:
A test exception.
["main.rb:4"]
Ensuring execution
Usando la instrucción else
Si la cláusula else está presente, va después de las cláusulas de rescate y antes de cualquier seguro .
El cuerpo de una cláusula else se ejecuta solo si el cuerpo principal del código no genera excepciones.
Sintaxis
begin
#.. process
#..raise exception
rescue
# .. handle error
else
#.. executes if there is no exception
ensure
#.. finally ensure execution
#.. This will always execute.
end
Ejemplo
begin
# raise 'A test exception.'
puts "I'm not raising exception"
rescue Exception => e
puts e.message
puts e.backtrace.inspect
else
puts "Congratulations-- no errors!"
ensure
puts "Ensuring execution"
end
Esto producirá el siguiente resultado:
I'm not raising exception
Congratulations-- no errors!
Ensuring execution
El mensaje de error generado se puede capturar usando $! variable.
Atrapar y lanzar
Si bien el mecanismo de excepción de aumento y rescate es excelente para abandonar la ejecución cuando las cosas salen mal, a veces es bueno poder saltar de alguna construcción profundamente anidada durante el procesamiento normal. Aquí es donde atrapar y lanzar son útiles.
La captura define un bloque que está etiquetado con el nombre de pila (que puede ser un símbolo o una cadena). El bloqueo se ejecuta normalmente hasta que se encuentra un lanzamiento.
Sintaxis
throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
OR
throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
Ejemplo
El siguiente ejemplo usa un lanzamiento para terminar la interacción con el usuario si '!' se escribe en respuesta a cualquier solicitud.
def promptAndGet(prompt)
print prompt
res = readline.chomp
throw :quitRequested if res == "!"
return res
end
catch :quitRequested do
name = promptAndGet("Name: ")
age = promptAndGet("Age: ")
sex = promptAndGet("Sex: ")
# ..
# process information
end
promptAndGet("Name:")
Debería probar el programa anterior en su máquina porque necesita interacción manual. Esto producirá el siguiente resultado:
Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby
Excepción de clase
Las clases y módulos estándar de Ruby generan excepciones. Todas las clases de excepción forman una jerarquía, con la clase Exception en la parte superior. El siguiente nivel contiene siete tipos diferentes:
- Interrupt
- NoMemoryError
- SignalException
- ScriptError
- StandardError
- SystemExit
Hay otra excepción a este nivel, Fatal, pero el intérprete de Ruby solo lo usa internamente.
Tanto ScriptError como StandardError tienen varias subclases, pero no necesitamos entrar en detalles aquí. Lo importante es que si creamos nuestras propias clases de excepción, deben ser subclases de la clase Exception o de una de sus descendientes.
Veamos un ejemplo:
class FileSaveError < StandardError
attr_reader :reason
def initialize(reason)
@reason = reason
end
end
Ahora, mire el siguiente ejemplo, que usará esta excepción:
File.open(path, "w") do |file|
begin
# Write out the data ...
rescue
# Something went wrong!
raise FileSaveError.new($!)
end
end
La línea importante aquí es subir FileSaveError.new ($!) . Llamamos a raise para señalar que se ha producido una excepción, pasándole una nueva instancia de FileSaveError, con la razón de que la excepción específica provocó que la escritura de los datos fallara.