Gestion des exceptions : rescue
Un programme en cours d’exécution peut rencontrer des problèmes inattendus. Tel fichier qu’il veut lire n’existe pas ; le disque est plein au moment où il veut sauver des données ; les saisies de l’utilisateur sont inadéquates…
ruby> fichier = open("tel_fichier")
ERR: (eval):1:in `open': No such file or directory - tel_fichier
Un programme robuste gérera ces situations avec bon sens et amabilité. Atteindre cet objectif peut être une tâche éprouvante. Les programmeurs C sont supposés vérifier le résultat de tout appel système qui pourrait éventuellement échouer, et décider sur le champ ce qui soit être fait :
FILE *file = fopen("tel_fichier "r");
if (file == NULL) {
fprintf( stderr, "Ficher absent.\n" );
exit(1);
}
bytes_read = fread( buf, 1, bytes_desired, file );
if (bytes_read != bytes_desired ) {
/* ici, un traitement d'erreur ... */
}
...
C’est une tâche de programmation si ennuyeuse que les programmeurs tendent à devenir imprudents et à la négliger, et le résultat est un programme qui ne gère pas bien les erreurs. D’un autre côté, faire ce qu’il faut peut rendre les programmes difficiles à lire, parce que beaucoup de code de gestion d’erreur noie le code directement utile.
En ruby, comme en beaucoup de langages modernes, on peut gérer les exceptions relatives à un bloc de code d’un façon compartimentée, ce qui permet de faire face aux surprises d’une façon efficace, sans trop charger ni le programmeur ni quiconque aura à relire le source. Le bloc de code commençant par begin s’exécute jusqu’à ce que survienne une exception, qui provoque le transfert du contrôle vers le bloc de gestion des exceptions, qui suit le mot rescue (secours). Si aucune exception ne survient, le code de secours n’est pas exécuté. La méthode qui suit retourne la première ligne d’un fichier texte, ou nil si une exception survient :
def première_ligne( nom_de_fichier )
begin
file = open("un_fichier")
info = file.gets
file.close
info # La dernière chose évaluée est la valeur retournée
rescue
nil # On ne peut pas lire le fichier ? Alors retourne nil
end
end
Il y a des circonstances où on voudrait pouvoir contourner un problème d’une façon constructive. Ici, si le fichier est indisponible, on essaie l’entrée standard à sa place… :
begin
file = open("un_fichier")
rescue
file = STDIN
end
begin
# ... traite l'entrée ...
rescue
# ... et traite les autres exceptions ici.
end
retry (réessaie) peut être utilisé dans le code de secours pour tenter de réexécuter ce qui a échoué le coup d’avant. Ceci nous permet de réécrire l’exemple précédent d’une façon un peu plus compacte :
fname = "un_fichier"
begin
file = open(fname)
# ... traite l'entrée ...
rescue
fname = "STDIN"
retry
end
Seulement, il y a une faille. Si le fichier n’existe pas on va boucler indéfiniment. Il faut penser à éviter ce genre d’écueils si vous utilisez retry pour gérer les exceptions.
Les librairies de ruby soulèvent des exceptions si une erreur survient, et vous pouvez aussi déclencher volontairement une exception dans votre propre code. Pour soulever une exception, utilisez raise (soulever). On peut lui passer un argument, qui est une chaîne décrivant l’exception. Cet argument est optionnel mais ne devrait pas être omis. On y a accès via la variable globale spéciale $!.
ruby> raise "erreur test"
test error
ruby> begin
| raise "test 2"
| rescue
| print "Une erreur est survenue: ",$!, "\n"
| end
Une erreur est survenue: test 2
nil
Précédent : GDU : Constantes de classe Suivant : GDU : Gestion des exceptions : ensure


