Una excepción es un evento que ocurre durante la ejecución de un programa y que interrumpe el flujo normal de las instrucciones. En Ruby, las excepciones se representan mediante objetos de la clase Exception
y sus subclases. Cuando ocurre una excepción, Ruby crea un objeto de excepción y lo lanza, lo que se denomina "raising an exception".
En Ruby, puedes lanzar una excepción utilizando el método raise
. Aquí hay un ejemplo simple:
def divide(a, b)
raise "Division by zero error" if b == 0
a / b
end
begin
divide(10, 0)
rescue => e
puts "An error occurred: #{e.message}"
end
En este ejemplo, la división por cero lanza una excepción con el mensaje "Division by zero error". El bloque begin...rescue
se utiliza para capturar y manejar la excepción.
begin...rescue
El bloque begin...rescue
es la estructura básica para manejar excepciones en Ruby. Aquí tienes un ejemplo básico:
begin
# Código que puede lanzar una excepción
rescue StandardError => e
# Código para manejar la excepción
puts "An error occurred: #{e.message}"
end
En este ejemplo, cualquier excepción que se lance dentro del bloque begin
y que sea una subclase de StandardError
será capturada por el bloque rescue
.
else
Ruby permite agregar una cláusula else
que se ejecutará si no ocurre ninguna excepción:
begin
# Código que puede lanzar una excepción
rescue StandardError => e
# Código para manejar la excepción
puts "An error occurred: #{e.message}"
else
# Código que se ejecuta si no ocurre ninguna excepción
puts "No errors occurred."
end
ensure
La cláusula ensure
se utiliza para especificar el código que debe ejecutarse sin importar si ocurre una excepción o no. Esto es útil para liberar recursos, cerrar archivos, etc.
begin
# Código que puede lanzar una excepción
rescue StandardError => e
# Código para manejar la excepción
puts "An error occurred: #{e.message}"
ensure
# Código que siempre se ejecuta
puts "This code always runs."
end
Puedes capturar excepciones específicas proporcionando el nombre de la clase de la excepción:
begin
# Código que puede lanzar una excepción
rescue ZeroDivisionError => e
# Manejo específico para la división por cero
puts "Cannot divide by zero: #{e.message}"
rescue ArgumentError => e
# Manejo específico para argumentos inválidos
puts "Invalid argument: #{e.message}"
end
En Ruby, puedes definir tus propias clases de excepción heredando de la clase StandardError
o cualquier otra subclase de Exception
.
class MyCustomError < StandardError; end
def risky_method
raise MyCustomError, "Something went wrong"
end
begin
risky_method
rescue MyCustomError => e
puts "Caught a custom error: #{e.message}"
end
En Ruby, puedes reintentar un bloque de código después de capturar una excepción utilizando la palabra clave retry
.
attempts = 0
begin
attempts += 1
puts "Trying to do something..."
raise "Temporary failure" if attempts < 3
puts "Success on attempt #{attempts}"
rescue
puts "An error occurred, retrying..."
retry if attempts < 3
end
A veces, después de capturar una excepción, es posible que desees relanzarla para que sea manejada en un nivel superior.
def risky_method
raise "An error occurred"
end
begin
begin
risky_method
rescue => e
puts "Caught an error: #{e.message}"
raise # Rethrowing the exception
end
rescue => e
puts "Handled rethrown error: #{e.message}"
end
1. No Capturar Excepciones Genéricas: Captura excepciones específicas para no atrapar inadvertidamente errores que no esperabas.
2. Manejo Adecuado de Recursos: Utiliza la cláusula ensure
para liberar recursos, cerrar archivos o realizar cualquier limpieza necesaria.
3. Proporcionar Información Útil: Asegúrate de que los mensajes de las excepciones sean claros y proporcionen suficiente información para entender el problema.
4. Evitar el Uso Excesivo de Excepciones: Utiliza excepciones para condiciones verdaderamente excepcionales. No utilices excepciones para el flujo normal del programa.
5. Documentar las Excepciones: Documenta las excepciones que tus métodos pueden lanzar y cómo deben ser manejadas.
Para finalizar, aquí tienes un ejemplo completo que ilustra varios conceptos discutidos:
class CustomError < StandardError; end
def process_file(filename)
raise CustomError, "File not found" unless File.exist?(filename)
file = File.open(filename, "r")
data = file.read
puts data
rescue CustomError => e
puts "Custom error: #{e.message}"
rescue StandardError => e
puts "Standard error: #{e.message}"
ensure
file.close if file
puts "File closed"
end
begin
process_file("non_existent_file.txt")
rescue => e
puts "An error occurred in the main program: #{e.message}"
end
Este ejemplo define una excepción personalizada CustomError
, la lanza si el archivo no existe, maneja diferentes tipos de excepciones y garantiza que el archivo se cierra correctamente utilizando la cláusula ensure
.
La gestión de excepciones en Ruby es una herramienta poderosa para escribir programas robustos y resilientes. Al comprender y aplicar estas técnicas, puedes manejar errores de manera efectiva, asegurando que tu código sea más confiable y mantenible.
Jorge García
Fullstack developer