Retour au cours

gestion des erreurs et exceptions

Objectifs

  • Comprendre ce qu’est une exception et comment elle interrompt le flux d’un programme.
  • Intercepter des exceptions spécifiques avec les blocs begin et rescue.
  • Garantir l’exécution d’un code de nettoyage avec le bloc ensure.
  • Déclencher ses propres erreurs avec raise.

Un programme robuste doit être capable de gérer les situations inattendues. En Ruby, les erreurs sont gérées via un mécanisme d’exceptions.

Qu’est-ce qu’une exception ?

Une exception est un objet qui signale qu’une erreur s’est produite. Par exemple :

  • Essayer de diviser par zéro (ZeroDivisionError).
  • Essayer d’appeler une méthode sur nil (NoMethodError).
  • Essayer d’ouvrir un fichier qui n’existe pas (Errno::ENOENT).

Si une exception est “levée” (raised), et qu’elle n’est pas “attrapée” (rescued), le programme s’arrête brutalement et affiche un message d’erreur.

Intercepter les exceptions : begin et rescue

C’est l’équivalent du try...catch dans d’autres langages.

  • Le code qui pourrait échouer est placé dans un bloc begin.
  • Le code de gestion de l’erreur est placé dans un bloc rescue.
begin
  # On tente une opération risquée
  puts "Tentative de division par zéro..."
  resultat = 10 / 0
  puts "Cette ligne ne sera jamais atteinte."
rescue
  # Ce bloc est exécuté si une erreur se produit dans le 'begin'
  puts "Oups ! Une erreur s'est produite."
end

puts "Le programme continue après le bloc."

Intercepter une exception spécifique

Il est de bonne pratique d’être précis sur le type d’erreur que l’on veut intercepter. Cela évite de masquer des bugs inattendus.

begin
  puts "Tentative de division..."
  resultat = 10 / 0
rescue ZeroDivisionError => e
  # On intercepte SEULEMENT les erreurs de division par zéro
  # La variable 'e' contient l'objet de l'exception
  puts "Erreur interceptée : #{e.message}"
rescue TypeError => e
  # On pourrait intercepter un autre type d'erreur ici
  puts "Erreur de type : #{e.message}"
end

Le bloc ensure : Le nettoyage garanti

Le code placé dans un bloc ensure est toujours exécuté, qu’il y ait eu une exception ou non. C’est l’endroit parfait pour s’assurer que des ressources sont bien libérées (comme fermer un fichier ou une connexion réseau).

fichier = nil
begin
  fichier = File.open("mon_fichier.txt", "w")
  fichier.puts "Hello"
  raise "Une erreur imprévue !" # On simule une erreur
rescue => e
  puts "Erreur gérée : #{e.message}"
ensure
  # Ce bloc s'exécute toujours
  puts "Dans le bloc 'ensure'."
  if fichier
    fichier.close
    puts "Fichier fermé."
  end
end

(Rappel : File.open avec un bloc gère déjà cela automatiquement, mais c’est un bon exemple du principe de ensure).

Déclencher ses propres erreurs : raise

Vous pouvez vous-même lever des exceptions avec la commande raise.

def set_age(age)
  if age < 0
    raise "L'âge ne peut pas être négatif."
  end
  @age = age
end

begin
  set_age(-5)
rescue => e
  puts "Erreur : #{e.message}" # => "Erreur : L'âge ne peut pas être négatif."
end

Bonnes pratiques

  • Soyez spécifique : Interceptez les erreurs les plus précises possible (rescue ZeroDivisionError), et non la classe Exception générique.
  • Ne sauvez pas de tout : N’utilisez pas rescue pour masquer des erreurs de logique dans votre programme. Il sert à gérer des situations exceptionnelles et externes (une connexion réseau qui coupe, un fichier manquant…).
  • Utilisez ensure pour garantir le nettoyage des ressources.

Exercices

  1. Division par zéro :

    • Écrivez un script qui demande deux nombres à l’utilisateur et affiche le résultat de leur division.
    • Utilisez begin...rescue pour intercepter la ZeroDivisionError et afficher un message d’erreur clair si l’utilisateur entre 0 comme deuxième nombre.
  2. Lecture de fichier robuste :

    • Créez une méthode qui prend un nom de fichier en argument et qui essaie de lire son contenu.
    • Utilisez rescue pour gérer le cas où le fichier n’existe pas (l’exception est Errno::ENOENT) en affichant “Le fichier n’a pas été trouvé.”
  3. Nettoyage garanti :

    • Modifiez le script de l’exercice 2.
    • Ajoutez un bloc ensure qui affiche toujours “Fin de la tentative de lecture.” à la fin, que le fichier ait été trouvé ou non.