← Ruby EspañolChapter 09 of 13

Manejo de Errores

## Objetivos de Aprendizaje - Manejar excepciones con begin-rescue - Usar ensure para limpieza - Lanzar excepciones personalizadas - Crear clases de excepciones personalizadas ## Jerarquia de Excepciones ```text Exception ├── StandardError │ ├── ArgumentError │ ├── NameError │ ├── NoMethodError │ ├── TypeError │ ├── RuntimeError │ └── ... └── SystemExit ``` ## Manejo Basico de Excepciones ### begin-rescue ```ruby begin resultado = 10 / 0 rescue puts "Ocurrio un error" end ``` ### Con Variable de Error ```ruby begin resultado = 10 / 0 rescue => e puts "Error: #{e.class} - #{e.message}" end ``` ### Multiples Clausulas rescue ```ruby begin # Codigo que podria fallar resultado = operacion_riesgosa rescue ArgumentError => e puts "Argumento invalido: #{e.message}" rescue NoMethodError => e puts "Metodo no encontrado: #{e.message}" rescue => e puts "Error inesperado: #{e.message}" end ``` ### rescue como Modificador ```ruby resultado = operacion_riesgosa rescue valor_por_defecto ``` ## Ensure `ensure` se ejecuta ocurra o no una excepcion: ```ruby begin archivo = File.open("ejemplo.txt", "r") contenido = archivo.read rescue Errno::ENOENT => e puts "Archivo no encontrado: #{e.message}" ensure archivo.close if archivo end ``` ## Retry `retry` re-ejecuta el bloque begin: ```ruby intentos = 0 begin intentos += 1 conectar_servicio rescue ErrorDeConexion if intentos < 3 puts "Reintentando... (intento #{intentos})" retry else puts "Fallo despues de #{intentos} intentos" end end ``` ## Raise ### Lanzar Errores Estandar ```ruby def dividir(a, b) raise ArgumentError, "El divisor no puede ser cero" if b == 0 a / b end ``` ### Lanzar Excepciones Personalizadas ```ruby def retirar(monto) raise "Fondos insuficientes" if monto > @saldo @saldo -= monto end # Mejor: usar clase de excepcion especifica class ErrorFondosInsuficientes < StandardError def initialize(saldo, monto) super("No se puede retirar #{monto}, el saldo es #{saldo}") end end def retirar(monto) raise ErrorFondosInsuficientes.new(@saldo, monto) if monto > @saldo @saldo -= monto end ``` ## Clases de Excepciones Personalizadas ```ruby class ErrorValidacion < StandardError attr_reader :campo def initialize(mensaje, campo = nil) super(mensaje) @campo = campo end end def validar_edad(edad) unless edad.is_a?(Integer) raise ErrorValidacion.new("La edad debe ser un entero", :edad) end unless edad >= 0 raise ErrorValidacion.new("La edad no puede ser negativa", :edad) end end ``` ## Catch y Throw No son excepciones - se usan para control de flujo: ```ruby resultado = catch(:encontrado) do [1, 2, 3, 4, 5].each do |n| throw(:encontrado, n * 2) if n == 3 end nil end puts resultado # 6 ``` ## Metodos de Excepciones ```ruby begin 10 / 0 rescue => e puts e.class # ZeroDivisionError puts e.message # divided by 0 puts e.backtrace # Array de cadenas de ubicacion puts e.backtrace.first # Primera linea del trace end ``` ## Mejores Practicas ### No Suprimir Excepciones ```ruby # Mal begin hacer_algo rescue # No hacer nada - ignorar silenciosamente end # Bien begin hacer_algo rescue SomeError => e manejar_error(e) end ``` ### Lanzar Temprano, Capturar Tarde ```ruby # Lanzar excepciones temprano (fallar rapido) def procesar_usuario(datos) raise ArgumentError, "Datos de usuario requeridos" if datos.nil? # ... resto del procesamiento end # Capturar excepciones al nivel apropiado def importar_usuarios usuarios.each do |datos_usuario| begin procesar_usuario(datos_usuario) rescue ErrorValidacion => e registrar_advertencia("Saltando usuario invalido: #{e.message}") end end end ``` ### Usar Excepciones Especificas ```ruby # Mal - demasiado generico begin File.open(archivo_datos) rescue # Manejar error end # Bien - excepcion especifica begin File.open(archivo_datos) rescue Errno::ENOENT puts "Archivo de datos no encontrado" rescue Errno::EACCES puts "Permiso denegado" end ``` ## Patrones de Manejo de Excepciones ### Patron nil ```ruby def encontrar_usuario(id) begin Usuario.find(id) rescue ActiveRecord::RecordNotFound nil end end # O con modificador rescue def encontrar_usuario(id) Usuario.find(id) rescue nil end ``` ### Patron Valor por Defecto ```ruby config = begin YAML.load_file("config.yml") rescue Errno::ENOENT {} end ``` ### Patron de Registro ```ruby require 'logger' logger = Logger.new(STDOUT) begin operacion_riesgosa rescue => e logger.error("#{e.class}: #{e.message}") logger.debug(e.backtrace.join("\n")) raise # Relanzar despues de registrar end ``` ## Resumen - `begin...rescue...ensure` maneja excepciones - `rescue ErrorType => e` captura errores especificos - `raise` lanza una excepcion - `ensure` ejecuta codigo de limpieza siempre - `retry` re-ejecuta el bloque begin - `catch/throw` para control de flujo no exception - Crear excepciones personalizadas subclaseando `StandardError` - Siempre manejar excepciones especificas, no todas las excepciones - Usar `ensure` para limpieza (cerrar archivos, etc.)

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →