Ruby Excepciones

Las excepciones y la ejecución siempre están relacionadas. Si abre un archivo que no existe y no maneja adecuadamente esta situación, su programa se considera de baja calidad.

Si ocurre una excepción, el programa se detiene. Las excepciones se utilizan para manejar varios tipos de errores que pueden ocurrir durante la ejecución del programa, de modo que se puedan tomar las acciones adecuadas sin que el programa se detenga por completo.

Ruby proporciona un mecanismo perfecto para manejar excepciones. Podemosbegin/endadjuntar el código que podría lanzar una excepción dentro de un bloque, y usarrescuela cláusula para decirle a Ruby exactamente qué tipo de excepción manejar.

Sintaxis

begin #begin raise.. #lanzar excepción rescue [ExceptionType = StandardException] #capturar el tipo de excepción especificado, el valor predeterminado es StandardException $! #representa la información de la excepción $@ #representa la ubicación del código donde ocurrió la excepción else #otras excepciones .. ensure #pase lo que pase, entre en este bloque de código end #end

desdebeginllegarrescueTodo lo que está dentro de ... está protegido. Si ocurre una excepción durante la ejecución del bloque, el control se transfiere arescueyendel bloque entre ...

Parabegincada ... en el bloquerescuecláusula, Ruby compara la excepción lanzada con cada parámetro por turno. Si la excepción nombrada en la cláusula rescue es del mismo tipo que la excepción actualmente lanzada, o es una clase padre de esa excepción, entonces la coincidencia es exitosa.

Si la excepción no coincide con todos los tipos de error especificados, podemos después de todas lasrescuecláusulas usar unaelsecláusula.

Ejemplo

#!/usr/bin/ruby begin file = open("/unexistant_file") if file puts "File opened successfully" end rescue file = STDIN end print file, "==", STDIN, "\n"

El resultado de ejecutar el ejemplo anterior es. Puede ver que,STDINreemplazó afile, porqueabrirfalló.

#<IO:0xb7d16f84>==#<IO:0xb7d16f84>

UsoretrySentencia

Puede usarrescuebloque para capturar excepciones, y luego usarretrysentencia para ejecutar desde el principiobeginbloque.

Sintaxis

begin #La excepción lanzada por este código será capturada por la cláusula rescue siguiente rescue #Este bloque capturará todos los tipos de excepciones retry #Esto moverá el control al inicio de 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 proceso de manejo:

  • Ocurre una excepción al abrir.
  • Salta a rescue. fname se reasigna.
  • Mediante retry, salta al inicio de begin.
  • Esta vez el archivo se abre correctamente.
  • Continúa el proceso básico.

Nota:Si el archivo renombrado no existe, el código de este ejemplo intentará infinitamente. Por lo tanto, al manejar excepciones, use retry con precaución.retry。

UsoraiseSentencia

Puede usarraisela sentencia para lanzar excepciones. El siguiente método lanza una excepción al ser invocado. Su segundo mensaje será mostrado.

Sintaxis

raiseoraise "Error Message"oraise ExceptionType, "Error Message"oraise ExceptionType, "Error Message" condition

La primera forma simplemente vuelve a lanzar la excepción actual (si no hay una excepción actual, lanza un RuntimeError). Esto se usa en manejadores de excepciones que necesitan explicar la excepción antes de pasarla.

La segunda forma crea una nuevaRuntimeErrorexcepción, establece su mensaje como la cadena dada. Luego, la excepción se lanza a la pila de llamadas.

La tercera forma usa el primer parámetro para crear una excepción y luego establece el mensaje asociado como el segundo parámetro.

La cuarta forma es similar a la tercera; puede agregar cualquier condición adicional (por ejemplo,unless) para lanzar 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.'

El resultado de ejecutar el ejemplo anterior es:

I am before the raise.  
I am rescued.  
I am after the begin block.  

Otra demostraciónraiseun ejemplo de uso:

Ejemplo

#!/usr/bin/ruby begin raise 'A test exception.' rescue Exception => e puts e.message puts e.backtrace.inspect end

El resultado de ejecutar el ejemplo anterior es:

A test exception.
["main.rb:4"]

UsoensureSentencia

A veces, ya sea que se lance una excepción o no, debe garantizar que algún procesamiento se complete al final del bloque de código. Por ejemplo, es posible que haya abierto un archivo al entrar, y al salir del bloque, debe asegurarse de cerrarlo.

ensureEso es exactamente lo que hace la cláusula ensure. ensure se coloca después del último rescue e incluye un bloque de código que siempre se ejecuta cuando el bloque termina. No importa si el bloque sale normalmente, lanza y maneja una excepción, o termina debido a una excepción no capturada,ensureel bloque ensure siempre se ejecutará.

Sintaxis

begin #.. proceso #.. lanzar excepción rescue #.. manejar error ensure #.. asegurar la ejecución al final #.. esto siempre se ejecutará end

Ejemplo

begin raise 'A test exception.' rescue Exception => e puts e.message puts e.backtrace.inspect ensure puts "Ensuring execution" end

El resultado de ejecutar el ejemplo anterior es:

A test exception.
["main.rb:4"]
Ensuring execution

UsoelseSentencia

Si se proporcionaelsecláusula, generalmente se colocarescuedespués de la cláusula rescue, y antes de cualquierensureantes.

elseEl cuerpo de la cláusula else solo se ejecuta si el cuerpo del código no lanzó una excepción.

Sintaxis

begin #.. proceso #.. lanzar excepción rescue #.. manejar error else #.. si no hay excepción, ejecutar ensure #.. asegurar la ejecución al final #.. esto siempre se ejecutará end

Ejemplo

begin #Lanzar '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

El resultado de ejecutar el ejemplo anterior es:

I'm not raising exception
Congratulations-- no errors!
Ensuring execution

Usando la variable $! se puede capturar el mensaje de error lanzado.

Catch y Throw

El mecanismo de excepciones de raise y rescue puede abandonar la ejecución cuando ocurre un error; a veces es necesario salir de estructuras profundamente anidadas durante el procesamiento normal. En ese momento, catch y throw son útiles.

catchSe define un bloque que usa el nombre dado (puede ser Symbol o String) como etiqueta. El bloque se ejecuta normalmente hasta que se encuentra un throw.

Sintaxis

throw :lablename #.. esto no se ejecutará catch :lablename do #.. el catch que coincida se ejecutará al encontrar un throw endothrow :lablename condition #.. esto no se ejecutará catch :lablename do #.. el catch que coincida se ejecutará al encontrar un throw end

Ejemplo

En el siguiente ejemplo, si el usuario escribe '!' en respuesta a cualquier mensaje, se usa un throw para terminar la interacción con el usuario.

Ejemplo

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: ") # .. #Información de procesamiento end promptAndGet("Name:")

El programa anterior requiere interacción manual; puede probarlo en su computadora. El resultado de ejecutar el ejemplo anterior es:

Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby

Clase Exception

Las clases y módulos estándar de Ruby lanzan excepciones. Todas las clases de excepción forman una jerarquía, incluyendo la clase Exception en la parte superior. El siguiente nivel contiene siete tipos diferentes:

  • Interrupt
  • NoMemoryError
  • SignalException
  • ScriptError
  • StandardError
  • SystemExit

Fatal es otra excepción en ese nivel, pero el intérprete de Ruby solo la usa internamente.

ScriptError y StandardError tienen algunas subclases, pero aquí no necesitamos conocer esos detalles. Lo más importante es crear nuestras propias clases de excepción; deben ser subclases de la clase Exception o de sus descendientes.

Veamos un ejemplo:

Ejemplo

class FileSaveError < StandardError attr_reader :reason def initialize(reason) @reason = reason end end

Ahora, vea el siguiente ejemplo, que usará la excepción anterior:

Ejemplo

File.open(path, "w") do |file| begin #Escribir datos ... rescue #Ocurrió un error raise FileSaveError.new($!) end end

Aquí, la línea más importante es raiseFileSaveError.new($!). Llamamos a raise para indicar que ha ocurrido una excepción, pasándola a una nueva instancia de FileSaveError, ya que la excepción específica causó que la escritura de datos fallara.

Otras extensiones