Ruby Language
Des exceptions
Recherche…
Remarques
Une exception est un objet qui représente l'occurrence d'une condition exceptionnelle. En d'autres termes, cela indique que quelque chose s'est mal passé.
Dans Ruby, les exceptions sont souvent appelées erreurs . En effet, la classe Exception
base existe en tant qu'élément d'objet d'exception de niveau supérieur, mais les exceptions d'exécution définies par l'utilisateur sont généralement StandardError
ou des descendants.
Lever une exception
Pour générer une exception, utilisez le Kernel#raise
passant la classe et / ou le message d'exception:
raise StandardError # raises a StandardError.new
raise StandardError, "An error" # raises a StandardError.new("An error")
Vous pouvez également simplement transmettre un message d'erreur. Dans ce cas, le message est enveloppé dans une RuntimeError
:
raise "An error" # raises a RuntimeError.new("An error")
Voici un exemple:
def hello(subject)
raise ArgumentError, "`subject` is missing" if subject.to_s.empty?
puts "Hello #{subject}"
end
hello # => ArgumentError: `subject` is missing
hello("Simone") # => "Hello Simone"
Création d'un type d'exception personnalisé
Une exception personnalisée est toute classe qui étend Exception
ou une sous-classe d' Exception
.
En général, vous devez toujours étendre StandardError
ou un descendant. La famille des Exception
concerne généralement les erreurs de machine virtuelle ou de système, les récupérer peut empêcher une interruption forcée de fonctionner comme prévu.
# Defines a new custom exception called FileNotFound
class FileNotFound < StandardError
end
def read_file(path)
File.exist?(path) || raise(FileNotFound, "File #{path} not found")
File.read(path)
end
read_file("missing.txt") #=> raises FileNotFound.new("File `missing.txt` not found")
read_file("valid.txt") #=> reads and returns the content of the file
Il est courant de nommer des exceptions en ajoutant le suffixe d' Error
à la fin:
-
ConnectionError
-
DontPanicError
Toutefois, lorsque l'erreur est explicite, vous n'avez pas besoin d'ajouter le suffixe d' Error
car il serait redondant:
-
FileNotFound
vsFileNotFoundError
-
DatabaseExploded
vsDatabaseExplodedError
Gérer une exception
Utilisez le bloc begin/rescue
pour intercepter (sauver) une exception et la gérer:
begin
# an execution that may fail
rescue
# something to execute in case of failure
end
Une clause de rescue
est analogue à un bloc catch
dans une accolade comme C # ou Java.
Un rescue
brutal comme celui-ci sauve StandardError
.
Remarque: veillez à ne pas intercepter Exception
place de StandardError
par défaut. La classe Exception
inclut SystemExit
et NoMemoryError
et d'autres exceptions graves que vous ne souhaitez généralement pas intercepter. Toujours envisager d'attraper StandardError
(valeur par défaut) à la place.
Vous pouvez également spécifier la classe d'exception à récupérer:
begin
# an excecution that may fail
rescue CustomError
# something to execute in case of CustomError
# or descendant
end
Cette clause de secours n'acceptera aucune exception qui n'est pas une CustomError
.
Vous pouvez également stocker l'exception dans une variable spécifique:
begin
# an excecution that may fail
rescue CustomError => error
# error contains the exception
puts error.message # provide human-readable details about what went wrong.
puts error.backtrace.inspect # return an array of strings that represent the call stack
end
Si vous ne parvenez pas à gérer une exception, vous pouvez l'augmenter à tout moment dans un bloc de secours.
begin
#here goes your code
rescue => e
#failed to handle
raise e
end
Si vous voulez retenter votre begin
bloc, appelez retry
:
begin
#here goes your code
rescue StandardError => e
#for some reason you want to retry you code
retry
end
Vous pouvez être bloqué dans une boucle si vous attrapez une exception dans chaque tentative. Pour éviter cela, limitez votre retry_count
de retry_count
à un certain nombre d'essais.
retry_count = 0
begin
# an excecution that may fail
rescue
if retry_count < 5
retry_count = retry_count + 1
retry
else
#retry limit exceeds, do something else
end
Vous pouvez également fournir un else
bloc ou un bloc d’ ensure
. Un bloc else
sera exécuté lorsque le bloc de begin
termine sans qu'une exception soit lancée. Un bloc d’ ensure
sera toujours exécuté. Un bloc d' ensure
est analogue à un bloc finally
dans une accolade comme C # ou Java.
begin
# an execution that may fail
rescue
# something to execute in case of failure
else
# something to execute in case of success
ensure
# something to always execute
end
Si vous vous trouvez dans un bloc def
, module
ou class
, il n'est pas nécessaire d'utiliser l'instruction begin.
def foo
...
rescue
...
end
Gestion de plusieurs exceptions
Vous pouvez gérer plusieurs erreurs dans la même déclaration de rescue
:
begin
# an execution that may fail
rescue FirstError, SecondError => e
# do something if a FirstError or SecondError occurs
end
Vous pouvez également ajouter plusieurs déclarations de rescue
:
begin
# an execution that may fail
rescue FirstError => e
# do something if a FirstError occurs
rescue SecondError => e
# do something if a SecondError occurs
rescue => e
# do something if a StandardError occurs
end
L'ordre des blocs de rescue
est pertinent: le premier match est celui exécuté. Par conséquent, si vous placez StandardError
comme première condition et que toutes vos exceptions héritent de StandardError
, les autres instructions de rescue
ne seront jamais exécutées.
begin
# an execution that may fail
rescue => e
# this will swallow all the errors
rescue FirstError => e
# do something if a FirstError occurs
rescue SecondError => e
# do something if a SecondError occurs
end
Certains blocs ont une gestion implicite des exceptions comme def
, class
et module
. Ces blocs vous permettent d'ignorer l'instruction begin
.
def foo
...
rescue CustomError
...
ensure
...
end
Ajout d'informations à des exceptions (personnalisées)
Il peut être utile d'inclure des informations supplémentaires avec une exception, par exemple à des fins de journalisation ou pour permettre une gestion conditionnelle lorsque l'exception est interceptée:
class CustomError < StandardError
attr_reader :safe_to_retry
def initialize(safe_to_retry = false, message = 'Something went wrong')
@safe_to_retry = safe_to_retry
super(message)
end
end
En soulevant l'exception:
raise CustomError.new(true)
Récupérer l'exception et accéder aux informations supplémentaires fournies:
begin
# do stuff
rescue CustomError => e
retry if e.safe_to_retry
end