Ruby - Exceptions
L'exécution et l'exception vont toujours de pair. Si vous ouvrez un fichier qui n'existe pas, si vous n'avez pas géré correctement cette situation, votre programme est considéré comme de mauvaise qualité.
Le programme s'arrête si une exception se produit. Ainsi, les exceptions sont utilisées pour gérer divers types d'erreurs, qui peuvent survenir lors de l'exécution d'un programme et prendre les mesures appropriées au lieu d'arrêter complètement le programme.
Ruby fournit un mécanisme intéressant pour gérer les exceptions. Nous enfermons le code qui pourrait déclencher une exception dans un bloc de début / fin et utilisons des clauses de sauvetage pour indiquer à Ruby les types d'exceptions que nous voulons gérer.
Syntaxe
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# Other exceptions
ensure
# Always will be executed
end
Tout du début au sauvetage est protégé. Si une exception se produit lors de l'exécution de ce bloc de code, le contrôle est passé au bloc entre le sauvetage et la fin .
Pour chaque clause de secours dans le bloc de début , Ruby compare l'exception levée à chacun des paramètres à son tour. La correspondance réussira si l'exception nommée dans la clause de sauvetage est identique au type de l'exception actuellement levée ou est une superclasse de cette exception.
Dans le cas où une exception ne correspond à aucun des types d'erreur spécifiés, nous sommes autorisés à utiliser une clause else après toutes les clauses de sauvetage .
Exemple
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
file = STDIN
end
print file, "==", STDIN, "\n"
Cela produira le résultat suivant. Vous pouvez voir que STDIN est remplacé par le fichier car l' ouverture a échoué.
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
Utilisation de l'instruction retry
Vous pouvez capturer une exception en utilisant le sauvetage bloc, puis utiliser la nouvelle tentative instruction à exécuter commencer bloc depuis le début.
Syntaxe
begin
# Exceptions raised by this code will
# be caught by the following rescue clause
rescue
# This block will capture all types of exceptions
retry # This will move control to the beginning of begin
end
Exemple
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
fname = "existant_file"
retry
end
Voici le déroulement du processus -
- Une exception s'est produite lors de l'ouverture.
- Je suis allé à la rescousse. fname a été réaffecté.
- Par réessayer est allé au début du début.
- Ce fichier de temps s'ouvre avec succès.
- Continué le processus essentiel.
NOTE- Notez que si le fichier de nom remplacé n'existe pas, cet exemple de code réessaye indéfiniment. Soyez prudent si vous utilisez une nouvelle tentative pour un processus d'exception.
Utilisation de l'instruction rise
Vous pouvez utiliser raise déclaration à soulever une exception. La méthode suivante lève une exception chaque fois qu'elle est appelée. Son deuxième message sera imprimé.
Syntaxe
raise
OR
raise "Error Message"
OR
raise ExceptionType, "Error Message"
OR
raise ExceptionType, "Error Message" condition
Le premier formulaire re-déclenche simplement l'exception actuelle (ou un RuntimeError s'il n'y a pas d'exception actuelle). Ceci est utilisé dans les gestionnaires d'exceptions qui doivent intercepter une exception avant de la transmettre.
Le deuxième formulaire crée une nouvelle exception RuntimeError , définissant son message sur la chaîne donnée. Cette exception est ensuite soulevée dans la pile d'appels.
Le troisième formulaire utilise le premier argument pour créer une exception, puis définit le message associé sur le deuxième argument.
Le quatrième formulaire est similaire au troisième formulaire, mais vous pouvez ajouter n'importe quelle instruction conditionnelle comme à moins de lever une exception.
Exemple
#!/usr/bin/ruby
begin
puts 'I am before the raise.'
raise 'An error has occurred.'
puts 'I am after the raise.'
rescue
puts 'I am rescued.'
end
puts 'I am after the begin block.'
Cela produira le résultat suivant -
I am before the raise.
I am rescued.
I am after the begin block.
Un autre exemple montrant l'utilisation de rais -
#!/usr/bin/ruby
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
end
Cela produira le résultat suivant -
A test exception.
["main.rb:4"]
Utilisation de la déclaration ensure
Parfois, vous devez garantir que certains traitements sont effectués à la fin d'un bloc de code, indépendamment du fait qu'une exception ait été déclenchée. Par exemple, vous pouvez avoir un fichier ouvert à l'entrée du bloc et vous devez vous assurer qu'il se ferme à la sortie du bloc.
La assurer clause ne vient cela. s'assure va après la dernière clause de sauvetage et contient un morceau de code qui sera toujours exécuté lorsque le bloc se termine. Peu importe si le bloc se termine normalement, s'il lève et sauve une exception, ou s'il est terminé par une exception non interceptée, le bloc s'assure sera exécuté.
Syntaxe
begin
#.. process
#..raise exception
rescue
#.. handle error
ensure
#.. finally ensure execution
#.. This will always execute.
end
Exemple
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
ensure
puts "Ensuring execution"
end
Cela produira le résultat suivant -
A test exception.
["main.rb:4"]
Ensuring execution
Utilisation de l'instruction else
Si la clause else est présente, elle passe après les clauses de sauvetage et avant toute garantie .
Le corps d'une clause else n'est exécuté que si aucune exception n'est levée par le corps principal du code.
Syntaxe
begin
#.. process
#..raise exception
rescue
# .. handle error
else
#.. executes if there is no exception
ensure
#.. finally ensure execution
#.. This will always execute.
end
Exemple
begin
# raise 'A test exception.'
puts "I'm not raising exception"
rescue Exception => e
puts e.message
puts e.backtrace.inspect
else
puts "Congratulations-- no errors!"
ensure
puts "Ensuring execution"
end
Cela produira le résultat suivant -
I'm not raising exception
Congratulations-- no errors!
Ensuring execution
Le message d'erreur soulevé peut être capturé en utilisant $! variable.
Attraper et lancer
Bien que le mécanisme d'exception de relance et de sauvetage soit idéal pour abandonner l'exécution lorsque les choses tournent mal, il est parfois agréable de pouvoir sortir d'une construction profondément imbriquée pendant le traitement normal. C'est là que la capture et le lancer sont utiles.
Le catch définit un bloc étiqueté avec le nom donné (qui peut être un symbole ou une chaîne). Le bloc est exécuté normalement jusqu'à ce qu'un lancer soit rencontré.
Syntaxe
throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
OR
throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
Exemple
L'exemple suivant utilise un throw pour mettre fin à l'interaction avec l'utilisateur si '!' est tapé en réponse à n'importe quelle invite.
def promptAndGet(prompt)
print prompt
res = readline.chomp
throw :quitRequested if res == "!"
return res
end
catch :quitRequested do
name = promptAndGet("Name: ")
age = promptAndGet("Age: ")
sex = promptAndGet("Sex: ")
# ..
# process information
end
promptAndGet("Name:")
Vous devriez essayer le programme ci-dessus sur votre machine car il nécessite une interaction manuelle. Cela produira le résultat suivant -
Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby
Exception de classe
Les classes et modules standard de Ruby lèvent des exceptions. Toutes les classes d'exception forment une hiérarchie, avec la classe Exception en haut. Le niveau suivant contient sept types différents -
- Interrupt
- NoMemoryError
- SignalException
- ScriptError
- StandardError
- SystemExit
Il existe une autre exception à ce niveau, Fatal, mais l'interpréteur Ruby l'utilise uniquement en interne.
ScriptError et StandardError ont un certain nombre de sous-classes, mais nous n'avons pas besoin d'entrer dans les détails ici. L'important est que si nous créons nos propres classes d'exceptions, elles doivent être des sous-classes de la classe Exception ou de l'un de ses descendants.
Regardons un exemple -
class FileSaveError < StandardError
attr_reader :reason
def initialize(reason)
@reason = reason
end
end
Maintenant, regardez l'exemple suivant, qui utilisera cette exception -
File.open(path, "w") do |file|
begin
# Write out the data ...
rescue
# Something went wrong!
raise FileSaveError.new($!)
end
end
La ligne importante ici est augmenter FileSaveError.new ($!) . Nous appelons rais pour signaler qu'une exception s'est produite, en lui passant une nouvelle instance de FileSaveError, la raison étant que l'exception spécifique a provoqué l'échec de l'écriture des données.