Lever et sauver des exceptions en Ruby

Comment lever et sauver des exceptions en Ruby

Les exceptions sont un élément fondamental de la programmation en Ruby, permettant aux développeurs de gérer les erreurs avec élégance et de garantir des applications robustes et tolérantes aux pannes. Le mécanisme de gestion des exceptions de Ruby est à la fois intuitif et puissant, permettant aux développeurs de lever des erreurs lorsque quelque chose ne va pas et de les sauver pour éviter que l'application ne tombe en panne. Dans ce guide de 2000 mots, nous allons explorer comment lever et sauver des exceptions en Ruby, en couvrant les bases, les techniques avancées, les meilleures pratiques et des exemples concrets.

Que sont les exceptions en Ruby ?

En Ruby, les exceptions sont des objets qui représentent des erreurs ou des conditions inattendues au cours de l'exécution d'un programme. Lorsqu'une erreur survient, comme une tentative de division par zéro, l'accès à un fichier inexistant ou une défaillance du réseau, Ruby lève une exception. Si elle n'est pas gérée, l'exception entraîne la fin du programme avec un message d'erreur.

Le système d'exception de Ruby est construit autour de la fonction Exception qui constitue la racine de la hiérarchie des exceptions. Des sous-classes comme StandardError, RuntimeError, ArgumentError, et Pas d'erreur de méthode pour gérer des types d'erreurs spécifiques. Les développeurs peuvent également définir des classes d'exceptions personnalisées pour représenter les erreurs spécifiques à une application.

La gestion des exceptions en Ruby s'articule autour de deux actions clés :

  • Élevage: Déclenchement d'une exception en cas d'erreur.
  • Sauvetage: Rattraper et gérer les exceptions pour éviter les pannes de programme.

Voyons comment lever et sauver des exceptions de manière efficace.

Lever des exceptions en Ruby

Lever une exception consiste à signaler qu'une erreur ou une condition inattendue s'est produite. Ruby fournit la fonction élever (et son alias échouer) pour déclencher des exceptions.

Le élever Méthode

La manière la plus simple de lever une exception est d'utiliser la fonction élever sans arguments, ce qui soulève un Erreur d'exécution (une sous-classe de Erreur standard):

rubis
lever
# => RuntimeError : exception non gérée

Vous pouvez également fournir un message d'erreur :

rubis
raise "Quelque chose s'est mal passé !"
# => RuntimeError : Quelque chose n'a pas fonctionné !

Pour lever une classe d'exception spécifique, il faut passer la classe comme premier argument et le message comme second :

rubis
raise ArgumentError, "Entrée invalide fournie"
# => ArgumentError : Entrée invalide fournie

Classes d'exceptions personnalisées

Pour les applications plus complexes, vous pouvez définir des classes d'exceptions personnalisées pour représenter des erreurs spécifiques. Les exceptions personnalisées héritent de la classe Erreur standard ou l'une de ses sous-classes pour assurer la compatibilité avec le comportement par défaut de Ruby en matière de sauvetage.

Exemple:

ruby
class AuthenticationError  AuthenticationError : Informations d'identification non valides

En définissant Erreur d'authentificationvous pouvez traiter les erreurs liées à l'authentification séparément des erreurs génériques.

Soulever des exceptions motivées

Ruby permet d'attacher une " cause " à une exception, ce qui est utile pour le débogage. La cause est l'exception originale qui a conduit à l'exception actuelle. Utilisez l'option exception pour y accéder :

rubis
begin
  raise "Erreur d'origine"
rescue => e
  raise "Nouvelle erreur" # L'erreur d'origine est conservée comme cause
end

Vous pouvez en vérifier la cause à l'aide de e.cause:

rubis
commencer
  begin
    raise "Erreur d'origine"
  rescue => e
    raise "Nouvelle erreur"
  end
rescue => e
  puts e.message # => Nouvelle erreur
  puts e.cause.message # => Erreur initiale
end

Sauvetage des exceptions

Le sauvetage des exceptions vous permet d'attraper et de gérer les erreurs de manière élégante, évitant ainsi à votre programme de se bloquer. Ruby utilise la fonction début/sauvetage pour gérer les exceptions.

Le commencer/sauvetage Bloc

La structure de base d'un début/sauvetage est un bloc :

rubis
commencer
  # Code susceptible de soulever une exception
sauver
  # Gérer l'exception
end

Exemple:

rubis
begin
  résultat = 10 / 0
sauvetage
  met "Une erreur s'est produite !"
end
# Sortie : Une erreur s'est produite !

Par défaut, sauvetage prises Erreur standard et ses sous-classes. Si vous ne spécifiez pas de classe d'exception, cela équivaut à rescue StandardError.

Traitement des exceptions spécifiques

Pour gérer des exceptions spécifiques, spécifiez la classe d'exception dans la directive sauvetage clause :

rubis
begin
  result = 10 / 0
rescue ZeroDivisionError
  puts "Impossible de diviser par zéro !"
rescue ArgumentError
  puts "Argument non valide fourni !"
end
# Sortie : Impossible de diviser par zéro !

Vous pouvez également capturer l'objet de l'exception pour l'examiner plus en détail :

rubis
begin
  raise ArgumentError, "Entrée invalide"
rescue ArgumentError => e
  puts "Erreur : #{e.message}"
end
# Sortie : Erreur : Entrée non valide

En utilisant autre et garantir

Ruby fournit deux clauses supplémentaires pour la gestion des exceptions :

  • autre: S'exécute si aucune exception n'est levée.
  • garantir: S'exécute indépendamment de l'apparition d'une exception, ce qui est utile pour les tâches de nettoyage.

Exemple:

rubis
begin
  puts "Performing operation..."
  result = 10 / 2
rescue ZeroDivisionError
  puts "Impossible de diviser par zéro !"
else
  puts "Opération réussie : #{résultat}"
assurer
  met "Nettoyage..."
end
# Sortie :
# Exécution de l'opération...
# Opération réussie : 5
# Nettoyage...

Si une exception se produit :

rubis
begin
  puts "Performing operation..."
  result = 10 / 0
rescue ZeroDivisionError
  puts "Impossible de diviser par zéro !"
else
  puts "Opération réussie : #{résultat}"
assurer
  met "Nettoyage..."
end
# Sortie :
# Exécution de l'opération...
# Impossible de diviser par zéro !
# Nettoyage...

Le réessayer Mot-clé

Le réessayer Le mot-clé permet de réessayer le commencer après qu'une exception a été levée. C'est utile pour des scénarios tels que la réitération de requêtes réseau qui ont échoué.

Exemple:

rubis
tentatives = 0
début
  tentatives += 1
  puts "Tentative #{attempts}"
  raise "Échec de la connexion"
secours
  réessayer si tentatives < 3
  puts "Abandon après #{attempts} tentatives"
end
# Sortie :
# Tentative 1
# Tentative 2
# Tentative 3
# Abandon après 3 tentatives

Utilisez les tentatives avec précaution pour éviter les boucles infinies.

Bonnes pratiques pour le traitement des exceptions

  1. Exceptions spécifiques au sauvetage: Éviter les objets nus sauvetage Les clauses d'exclusion, car elles englobent toutes les clauses d'exclusion. Erreur standard et peut cacher des erreurs inattendues. Précisez les exceptions exactes auxquelles vous vous attendez.
    rubis
    # Bad
    commencer
      # Code
    sauvetage
      # Attrape tout
    fin
    
    # Bon
    commencer
      # Code
    rescue ArgumentError, TypeError
      # Gestion des erreurs spécifiques
    fin
  2. Les blocs de sauvetage doivent être de petite taille: Ne recouvrir que le code susceptible de soulever une exception. Cela permet d'améliorer la lisibilité et d'éviter d'attraper des erreurs sans rapport avec le sujet.
  3. Fournir des messages d'erreur pertinents: Lorsque vous soulevez des exceptions, incluez des messages clairs et exploitables pour faciliter le débogage.
  4. Utiliser des exceptions personnalisées pour la logique du domaine: Créez des classes d'exceptions personnalisées pour les erreurs spécifiques à l'application afin de rendre votre code plus expressif et plus facile à maintenir.
  5. Éviter la surutilisation des exceptions pour le contrôle des flux: Les exceptions sont destinées à des cas exceptionnels, et non à contrôler le déroulement du programme. Utilisez les conditionnelles pour les scénarios attendus.
    rubis
    # Bad
    commencer
    value = hash[:key]
    rescue
    valeur = nil
    end
    
    # Bon
    value = hash[:key] || nil
  6. Ressources pour le nettoyage avec garantir: Utilisation garantir pour fermer les fichiers, les connexions à la base de données ou d'autres ressources, même si une exception se produit.

Exemples concrets

Traitement des fichiers

La lecture d'un fichier peut soulever des exceptions telles que Errno::ENOENT (fichier introuvable) ou Errno::EACCES (autorisation refusée). Voici comment les traiter :

rubis
begin
  File.open("nonexistent.txt", "r") do |file|
    puts file.read
  end
rescue Errno::ENOENT
  puts "Fichier non trouvé !"
rescue Errno::EACCES
  met "Permission refusée !"
ensure
  met "Opération de fichier terminée".
end
# Sortie : Fichier introuvable !
# Opération de fichier terminée.

Appels de l'API

Lorsque vous effectuez des requêtes HTTP, vous pouvez rencontrer des erreurs de réseau ou des réponses non valides. L'utilisation de la fonction httparty gemme :

ruby
nécessite 'httparty'

begin
  response = HTTParty.get('https://api.example.com/data')
rescue HTTParty::Error => e
  puts "Échec de la requête API : #{e.message}"
rescue SocketError
  puts "Erreur de réseau : Impossible de se connecter au serveur"
else
  puts "Réponse reçue : #{response.body}"
fin

Gestion personnalisée des exceptions dans une classe

Voici un exemple de classe qui traite les paiements et utilise des exceptions personnalisées :

ruby
class PaymentError < StandardError ; end
class InsufficientFundsError < PaymentError ; end
class InvalidCardError  card.balance
    card.balance -= amount
    puts "Le paiement de #{montant} a été traité avec succès"
  fin

  private
  def valid_card ?(card)
    card.number.length == 16
  end
end

classe Carte
  attr_accessor :nombre, :solde
  def initialize(number, balance)
    @number = nombre
    @balance = balance
  end
fin

card = Card.new("1234567890123456", 50)
processeur = PaymentProcessor.new

begin
  processor.process_payment(100, card)
rescue InsufficientFundsError => e
  met "Erreur : #{e.message}"
rescue InvalidCardError => e
  met "Erreur : #{e.message}"
end
# Sortie : Erreur : Pas assez de fonds

Gestion avancée des exceptions

Sauvegardes emboîtées

Vous pouvez nicher début/sauvetage pour gérer les exceptions à différents niveaux :

rubis
commencer
  begin
    raise "Erreur interne"
  rescue
    met "Erreur interne"
    raise "Erreur extérieure"
  end
sauvetage
  puts "Erreur extérieure détectée"
fin
# Sortie :
# Erreur interne détectée
# Erreur extérieure détectée

Hiérarchie des exceptions

Il est essentiel de comprendre la hiérarchie des exceptions de Ruby. Les classes clés sont les suivantes :

  • ExceptionM: Classe racine pour toutes les exceptions.
  • Erreur standard: Valeur par défaut pour sauvetage sans classe ; la plupart des exceptions intégrées en héritent.
  • Erreur d'exécution: Valeur par défaut pour élever sans classe.
  • NoMethodError, ArgumentError, TypeErroretc. : types d'erreurs spécifiques.

Pour attraper toutes les exceptions (y compris les exceptions nonErreur standard comme Sortie du système), utiliser sauver l'exception:

rubis
commencer
  exit
sauver l'exception
  met "Sortie prise"
end
# Sortie : Sortie capturée

En utilisant rescue_from dans Rails

Dans Ruby on Rails, vous pouvez utiliser rescue_from dans les contrôleurs pour gérer les exceptions de manière globale :

ruby
classe ApplicationController < ActionController::Base
  rescue_from ActiveRecord::RecordNotFound, with : :not_found

  private

  def not_found
    render file : 'public/404.html', status : :not_found
  end
end

Cette approche centralise la gestion des exceptions pour des contrôleurs spécifiques.

Les pièges à éviter

  1. Rattraper toutes les exceptions à l'aveugle: Utilisation sauvetage sans spécifier de classe d'exception peut cacher des bogues.
  2. Surutilisation réessayer: Le fait de réessayer indéfiniment peut conduire à des boucles infinies ou masquer des problèmes sous-jacents.
  3. Ignorer les détails de l'exception: Inspectez toujours l'objet de l'exception (e.message, e.backtrace) pour le débogage.
  4. Levée des erreurs non standard: Éviter de soulever des exceptions qui n'héritent pas de Erreur standardIls ne seront pas pris en compte par défaut. sauvetage clauses.
  5. Ne pas nettoyer les ressources: Oublier d'utiliser garantir peut laisser des fichiers ou des connexions ouverts.

Conclusion

Lever et sauver des exceptions en Ruby est un moyen puissant de gérer les erreurs et de construire des applications robustes. A l'adresse RailsCarma, l'un des principaux Société de développement Ruby on RailsNous utilisons ces techniques pour créer des solutions fiables et faciles à maintenir. En utilisant les élever pour signaler des erreurs, sauvetage pour les attraper, et des outils tels que réessayer, sinon, et garantirGrâce aux exceptions, les développeurs peuvent gérer les erreurs de manière efficace. Les classes d'exceptions personnalisées et les clauses de sauvetage spécifiques ajoutent de la clarté et de la précision à votre code. Le respect des meilleures pratiques, telles que le sauvetage d'exceptions spécifiques, la réduction de la taille des blocs de sauvetage et l'utilisation de messages d'erreur significatifs, garantit la maintenance et la fiabilité du code.

Qu'il s'agisse d'opérations sur des fichiers, d'appels d'API ou de logique spécifique à un domaine, le système de gestion des exceptions de Ruby offre la flexibilité nécessaire pour traiter les erreurs avec élégance. En maîtrisant ces techniques et en évitant les pièges les plus courants, RailsCarma aide les entreprises à créer des applications Ruby résilientes qui gèrent les erreurs en toute confiance.

Articles Similaires

À propos de l'auteur du message

Laissez un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *


fr_FRFrench