Excepciones

Lanzando una excepción

Una excepción es un tipo especial de objeto de la clase Exception. Lanzar una excepción significa parar la ejecución de un programa para salir del mismo o para tratar con el problema que se ha producido. Para tratar el problema hace falta raise; de no ser así, el programa termina y avisa del error. Lo que hará raise (lanzar), será lanzar una "excepción" para manejar el error.

Ruby tiene una serie de clases, Exception y sus hijas, que ayudan a manejar los errores que pueden ocurrir. La siguiente figura enseña la jerarquía en Ruby:

exceptionit5.jpg

Nota: la figura anterior es sacada del libro Programming Ruby.

def lanzar_excepcion
  puts 'Estoy antes del raise'
  raise 'Se ha producido un error' # lanza una excepción con el mensaje entre ''
  puts 'Estoy despues del raise'
end
 
lanzar_excepcion

El método raise procede del módulo Kernel. Por defecto, raise crea una excepción de la clase RuntimeError. Para lanzar una excepción de una clase específica, se puede poner el nombre de la clase como argumento de raise.

def inverse(x)
  raise ArgumentError, 'El argumento no es numerico' unless x.is_a? Numeric
  1.0 / x
end
puts inverse(2)
puts inverse('patata') # da un error que es manejado por raise

Hay que recordar que los métodos que actúan como preguntas, se les pone un ? al final: is_a? pregunta al objeto cuál es su tipo. Y unless cuando se pone al final de una instrucción, significa que NO se ejecuta cuando la expresión a continuación es verdadera.

Manejando una excepción

Para tratar una excepción, se pone el método que puede causar el error dentro de un bloque begin…end. Dentro de este bloque, se pueden poner varios rescue para cada tipo de error que pueda surgir:

def raise_and_rescue  
  begin  
    puts 'Estoy antes del raise'
    raise 'Un error ha ocurrido' # simulamos un error
    puts 'Estoy después del raise' 
  rescue  
    puts 'Estoy rescatado del error.'  
  end  
  puts 'Estoy después del bloque'
end  
 
raise_and_rescue

La salida es:

Estoy antes del raise
Estoy rescatado del error.
Estoy después del bloque

Observar que el código interrumpido por la excepción, nunca se ejecuta. Una vez que la excepción es manejada (por el rescue), la ejecución continúa inmediatamente después del bloque begin fuente del error.

Al escribir rescue sin parámetros, el parámetro StandardError se toma por defecto. En cada rescue se pueden poner varias excepciones a tratar. En el caso de poner múltiples rescues:

begin
  #
rescue UnTipoDeExcepcion
  #
rescue OtroTipoDeExcepcion
  #
else
  # Otras excepciones
end

Ruby compara la excepción que produce el error, con cada rescue hasta que sea del mismo tipo; o sea una superclase de la excepción. Si la excepción no concuerda con ningún rescue, usar else se encarga de manejarla.

Para saber acerca del tipo de excepción, hay que mapear el objeto Exception a una variable usando rescue:

begin
  raise 'Test de excepcion'
rescue Exception => e
  puts e.message            # Test de excepción
  puts e.backtrace.inspect   # ["nombre de fichero:linea de la excepción"]
end

Si además de manejar la excepción, se necesita que se ejecute un código, se usará la instrucción ensure: lo que haya en ese bloque, siempre se ejecutará cuando el bloque begin…end termine.

Excepciones más comunes

He aquí algunas excepciones más comunes, con la causa que las origina y un ejemplo:

  • RuntimeError - la excepción que se lanza por defecto. Ejemplo:
raise
  • NoMethodError - el objeto no puede manejar el mensaje/método que se le envía. Ej:
string = 'patata'
string.multiplicarse
  • NameError - el intérprete encuentra un identificador que no puede resolver ni como método, ni como variable. Ej:
a = variable_sin_definir
  • IOError - lectura de un stream cerrado, escribir a un sistema de sólo lectura y operaciones parecidas. Ej:
STDIN.puts("No escribas a STDIN!")
  • Errno::error - errores relaccionado con el fichero IO. Ej:
File.open(-12)
  • TypeError - un método recibe un argumento que no puede manejar. Ej:
a = 3 + "no puedo sumar un string a un número!"
  • ArgumentError - causado por un número incorrecto de argumentos. Ej:
def m(x)
end
m(1,2,3,4,5)

Ejemplo

begin  
  # Abre el fichero y lo lee
  File.open('origen.txt', 'r') do |f1|  
    while line = f1.gets  
      puts line  
    end  
  end  
 
  # Crea un nuevo fichero y escribe en él
  File.open('destino.txt', 'w') do |f2|  
    f2.puts "Creado por Satish"  
  end  
rescue Exception => msg  
  # dispone el mensaje de error 
  puts msg  
end
Si no se indica lo contrario, el contenido de esta página se ofrece bajo Creative Commons Attribution 3.0 License