Ruby - Ausnahmen

Die Ausführung und die Ausnahme gehören immer zusammen. Wenn Sie eine Datei öffnen, die nicht vorhanden ist, und wenn Sie diese Situation nicht richtig behandelt haben, wird Ihr Programm als von schlechter Qualität angesehen.

Das Programm stoppt, wenn eine Ausnahme auftritt. Daher werden Ausnahmen verwendet, um verschiedene Arten von Fehlern zu behandeln, die während einer Programmausführung auftreten können, und um geeignete Maßnahmen zu ergreifen, anstatt das Programm vollständig anzuhalten.

Ruby bietet einen guten Mechanismus, um Ausnahmen zu behandeln. Wir fügen den Code, der eine Ausnahme auslösen könnte, in einen Anfangs- / Endblock ein und verwenden Rettungsklauseln , um Ruby die Arten von Ausnahmen mitzuteilen, die wir behandeln möchten.

Syntax

begin  
# -  
rescue OneTypeOfException  
# -  
rescue AnotherTypeOfException  
# -  
else  
# Other exceptions
ensure
# Always will be executed
end

Alles von Anfang bis zur Rettung ist geschützt. Wenn während der Ausführung dieses Codeblocks eine Ausnahme auftritt, wird die Steuerung zwischen Rettung und Ende an den Block übergeben .

Für jede Rettungsklausel im beginnen Block vergleicht Ruby den erhöhten Ausnahme gegen jeden der Parameter der Reihe nach . Die Übereinstimmung ist erfolgreich, wenn die in der Rettungsklausel genannte Ausnahme dem Typ der aktuell ausgelösten Ausnahme entspricht oder eine Oberklasse dieser Ausnahme ist.

Für den Fall, dass eine Ausnahme keinem der angegebenen Fehlertypen entspricht, dürfen wir nach allen Rettungsklauseln eine else- Klausel verwenden .

Beispiel

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
      file = STDIN
end
print file, "==", STDIN, "\n"

Dies führt zu folgendem Ergebnis. Sie können sehen, dass STDIN die Datei ersetzt, weil das Öffnen fehlgeschlagen ist.

#<IO:0xb7d16f84>==#<IO:0xb7d16f84>

Retry-Anweisung verwenden

Sie können eine Ausnahme mit erfassen Rettungsblock und dann Verwendung Retry - Anweisung auszuführen , beginnen Block von Anfang an .

Syntax

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

Beispiel

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
   fname = "existant_file"
   retry
end

Das Folgende ist der Ablauf des Prozesses -

  • Beim Öffnen ist eine Ausnahme aufgetreten.
  • Ging zu retten. fname wurde neu zugewiesen.
  • Durch einen erneuten Versuch ging es an den Anfang des Anfangs.
  • Diese Zeitdatei wird erfolgreich geöffnet.
  • Fortsetzung des wesentlichen Prozesses.

NOTE- Beachten Sie, dass dieser Beispielcode unendlich oft wiederholt wird, wenn die Datei mit dem neu ersetzten Namen nicht vorhanden ist. Seien Sie vorsichtig , wenn Sie verwenden Wiederholungs für einen Ausnahmeprozess.

Raise-Anweisung verwenden

Sie können die Anweisung raise verwenden , um eine Ausnahme auszulösen. Die folgende Methode löst bei jedem Aufruf eine Ausnahme aus. Die zweite Nachricht wird gedruckt.

Syntax

raise 

OR

raise "Error Message" 

OR

raise ExceptionType, "Error Message"

OR

raise ExceptionType, "Error Message" condition

Das erste Formular löst einfach die aktuelle Ausnahme erneut aus (oder einen RuntimeError, wenn keine aktuelle Ausnahme vorliegt). Dies wird in Ausnahmebehandlungsroutinen verwendet, die eine Ausnahme abfangen müssen, bevor sie weitergeleitet werden.

Das zweite Formular erstellt eine neue RuntimeError- Ausnahme und setzt die Nachricht auf die angegebene Zeichenfolge. Diese Ausnahme wird dann im Aufrufstapel ausgelöst.

Das dritte Formular verwendet das erste Argument, um eine Ausnahme zu erstellen, und setzt dann die zugehörige Nachricht auf das zweite Argument.

Das vierte Formular ähnelt dem dritten Formular, Sie können jedoch eine beliebige bedingte Anweisung hinzufügen, es sei denn , Sie möchten eine Ausnahme auslösen.

Beispiel

#!/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.'

Dies führt zu folgendem Ergebnis:

I am before the raise.  
I am rescued.  
I am after the begin block.

Ein weiteres Beispiel für die Verwendung von Raise -

#!/usr/bin/ruby

begin  
   raise 'A test exception.'  
rescue Exception => e  
   puts e.message  
   puts e.backtrace.inspect  
end

Dies führt zu folgendem Ergebnis:

A test exception.
["main.rb:4"]

Verwenden Sie sure-Anweisung

Manchmal müssen Sie sicherstellen, dass am Ende eines Codeblocks eine gewisse Verarbeitung erfolgt, unabhängig davon, ob eine Ausnahme ausgelöst wurde. Beispielsweise kann beim Eintritt in den Block eine Datei geöffnet sein, und Sie müssen sicherstellen, dass sie beim Beenden des Blocks geschlossen wird.

Die Sicherungsklausel macht genau das. Stellen Sie sicher, dass die letzte Rettungsklausel verwendet wird und einen Codeabschnitt enthält, der immer ausgeführt wird, wenn der Block beendet wird. Es spielt keine Rolle, ob der Block normal beendet wird, ob er eine Ausnahme auslöst und rettet oder ob er durch eine nicht erfasste Ausnahme beendet wird, der Sicherstellungsblock wird ausgeführt.

Syntax

begin 
   #.. process 
   #..raise exception
rescue 
   #.. handle error 
ensure 
   #.. finally ensure execution
   #.. This will always execute.
end

Beispiel

begin
   raise 'A test exception.'
rescue Exception => e
   puts e.message
   puts e.backtrace.inspect
ensure
   puts "Ensuring execution"
end

Dies führt zu folgendem Ergebnis:

A test exception.
["main.rb:4"]
Ensuring execution

Verwenden der else-Anweisung

Wenn die else- Klausel vorhanden ist, folgt sie den Rettungsklauseln und bevor sie sichergestellt wird .

Der Hauptteil einer else- Klausel wird nur ausgeführt, wenn vom Hauptteil des Codes keine Ausnahmen ausgelöst werden.

Syntax

begin 
   #.. process 
   #..raise exception
rescue 
   # .. handle error
else
   #.. executes if there is no exception
ensure 
   #.. finally ensure execution
   #.. This will always execute.
end

Beispiel

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

Dies führt zu folgendem Ergebnis:

I'm not raising exception
Congratulations-- no errors!
Ensuring execution

Ausgelöste Fehlermeldung kann mit $ erfasst werden! Variable.

Fangen und werfen

Während der Ausnahmemechanismus von Erhöhen und Speichern großartig ist, um die Ausführung abzubrechen, wenn etwas schief geht, ist es manchmal schön, während der normalen Verarbeitung aus einem tief verschachtelten Konstrukt herausspringen zu können. Hier bieten sich Fangen und Werfen an.

Der catch definiert einen Block, der mit dem angegebenen Namen gekennzeichnet ist (dies kann ein Symbol oder eine Zeichenfolge sein). Der Block wird normal ausgeführt, bis ein Wurf auftritt.

Syntax

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

Beispiel

Im folgenden Beispiel wird ein Wurf verwendet, um die Interaktion mit dem Benutzer zu beenden, wenn '!' wird als Antwort auf eine Eingabeaufforderung eingegeben.

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:")

Sie sollten das oben genannte Programm auf Ihrem Computer ausprobieren, da eine manuelle Interaktion erforderlich ist. Dies führt zu folgendem Ergebnis:

Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby

Klassenausnahme

Rubys Standardklassen und Module lösen Ausnahmen aus. Alle Ausnahmeklassen bilden eine Hierarchie, wobei die Klasse Exception oben steht. Die nächste Stufe enthält sieben verschiedene Typen -

  • Interrupt
  • NoMemoryError
  • SignalException
  • ScriptError
  • StandardError
  • SystemExit

Es gibt eine weitere Ausnahme auf dieser Ebene: Fatal, aber der Ruby-Interpreter verwendet dies nur intern.

Sowohl ScriptError als auch StandardError haben eine Reihe von Unterklassen, aber wir müssen hier nicht auf die Details eingehen. Wichtig ist, dass beim Erstellen eigener Ausnahmeklassen Unterklassen entweder der Klasse Exception oder einer ihrer Nachkommen sein müssen.

Schauen wir uns ein Beispiel an -

class FileSaveError < StandardError
   attr_reader :reason
   def initialize(reason)
      @reason = reason
   end
end

Schauen Sie sich nun das folgende Beispiel an, in dem diese Ausnahme verwendet wird:

File.open(path, "w") do |file|
begin
   # Write out the data ...
rescue
   # Something went wrong!
   raise FileSaveError.new($!)
end
end

Die wichtige Zeile hier ist das Erhöhen von FileSaveError.new ($!) . Wir rufen Raise auf, um zu signalisieren, dass eine Ausnahme aufgetreten ist, und übergeben ihm eine neue Instanz von FileSaveError. Der Grund dafür ist, dass eine bestimmte Ausnahme das Schreiben der Daten fehlgeschlagen hat.