Ruby - Eccezioni
L'esecuzione e l'eccezione vanno sempre insieme. Se stai aprendo un file, che non esiste, se non hai gestito correttamente questa situazione, il tuo programma è considerato di cattiva qualità.
Il programma si interrompe se si verifica un'eccezione. Quindi le eccezioni vengono utilizzate per gestire vari tipi di errori, che possono verificarsi durante l'esecuzione di un programma e intraprendere l'azione appropriata invece di arrestare completamente il programma.
Ruby fornisce un bel meccanismo per gestire le eccezioni. Racchiudiamo il codice che potrebbe sollevare un'eccezione in un blocco di inizio / fine e usiamo clausole di salvataggio per dire a Ruby i tipi di eccezioni che vogliamo gestire.
Sintassi
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# Other exceptions
ensure
# Always will be executed
end
Tutto, dall'inizio al salvataggio, è protetto. Se si verifica un'eccezione durante l'esecuzione di questo blocco di codice, il controllo viene passato al blocco tra rescue e end .
Per ogni salvataggio clausola nel cominciare blocco, Ruby confronta l'Eccezione sollevata contro ciascuno dei parametri a loro volta. La corrispondenza avrà esito positivo se l'eccezione denominata nella clausola di salvataggio è la stessa del tipo dell'eccezione attualmente generata o è una superclasse di tale eccezione.
Nel caso in cui un'eccezione non corrisponda a nessuno dei tipi di errore specificati, siamo autorizzati a utilizzare una clausola else dopo tutte le clausole di salvataggio .
Esempio
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
file = STDIN
end
print file, "==", STDIN, "\n"
Questo produrrà il seguente risultato. Puoi vedere che STDIN è stato sostituito al file perché l' apertura non è riuscita.
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
Utilizzo dell'istruzione retry
È possibile catturare un'eccezione utilizzando salvataggio del blocco e quindi l'uso di tentativi istruzione da eseguire iniziare blocco fin dall'inizio.
Sintassi
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
Esempio
#!/usr/bin/ruby
begin
file = open("/unexistant_file")
if file
puts "File opened successfully"
end
rescue
fname = "existant_file"
retry
end
Quello che segue è il flusso del processo:
- Si è verificata un'eccezione all'apertura.
- Sono andato a salvare. fname è stato riassegnato.
- Riprovando è andato all'inizio dell'inizio.
- Questo file ora si apre correttamente.
- Ha continuato il processo essenziale.
NOTE- Notare che se il file di nome ricostituito non esiste, questo codice di esempio riprova all'infinito. Fai attenzione se utilizzi Riprova per un processo di eccezione.
Utilizzo dell'istruzione raise
È possibile utilizzare rilancio dichiarazione per sollevare un'eccezione. Il metodo seguente solleva un'eccezione ogni volta che viene chiamato. Il secondo messaggio verrà stampato.
Sintassi
raise
OR
raise "Error Message"
OR
raise ExceptionType, "Error Message"
OR
raise ExceptionType, "Error Message" condition
La prima forma solleva semplicemente nuovamente l'eccezione corrente (o un RuntimeError se non c'è eccezione corrente). Viene utilizzato nei gestori di eccezioni che devono intercettare un'eccezione prima di trasmetterla.
La seconda forma crea una nuova eccezione RuntimeError , impostando il suo messaggio sulla stringa data. Questa eccezione viene quindi sollevata nello stack di chiamate.
La terza forma utilizza il primo argomento per creare un'eccezione e quindi imposta il messaggio associato al secondo argomento.
La quarta forma è simile alla terza ma puoi aggiungere qualsiasi istruzione condizionale come a meno che non sollevi un'eccezione.
Esempio
#!/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.'
Questo produrrà il seguente risultato:
I am before the raise.
I am rescued.
I am after the begin block.
Un altro esempio che mostra l'uso del rilancio -
#!/usr/bin/ruby
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
end
Questo produrrà il seguente risultato:
A test exception.
["main.rb:4"]
Utilizzando la dichiarazione di sicurezza
A volte, è necessario garantire che alcune elaborazioni vengano eseguite alla fine di un blocco di codice, indipendentemente dal fatto che sia stata sollevata un'eccezione. Ad esempio, potresti avere un file aperto all'ingresso del blocco e devi assicurarti che venga chiuso quando il blocco esce.
La clausola di garanzia fa proprio questo. garantire va dopo l'ultima clausola di salvataggio e contiene una porzione di codice che verrà sempre eseguita al termine del blocco. Non importa se il blocco esce normalmente, se solleva e salva un'eccezione o se viene terminato da un'eccezione non rilevata, il blocco di sicurezza verrà eseguito.
Sintassi
begin
#.. process
#..raise exception
rescue
#.. handle error
ensure
#.. finally ensure execution
#.. This will always execute.
end
Esempio
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
ensure
puts "Ensuring execution"
end
Questo produrrà il seguente risultato:
A test exception.
["main.rb:4"]
Ensuring execution
Utilizzo dell'istruzione else
Se la clausola else è presente, va dopo le clausole di salvataggio e prima di qualsiasi garanzia .
Il corpo di una clausola else viene eseguito solo se non vengono sollevate eccezioni dal corpo principale del codice.
Sintassi
begin
#.. process
#..raise exception
rescue
# .. handle error
else
#.. executes if there is no exception
ensure
#.. finally ensure execution
#.. This will always execute.
end
Esempio
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
Questo produrrà il seguente risultato:
I'm not raising exception
Congratulations-- no errors!
Ensuring execution
Il messaggio di errore generato può essere catturato usando $! variabile.
Prendi e lancia
Mentre il meccanismo di eccezione di rilancio e salvataggio è ottimo per abbandonare l'esecuzione quando le cose vanno male, a volte è bello essere in grado di saltare fuori da qualche costrutto profondamente annidato durante la normale elaborazione. Qui è dove prendere e lanciare torna utile.
Il fermo definisce un blocco che è etichettato con il nome dato (che può essere un simbolo o una stringa). Il blocco viene eseguito normalmente fino a quando non si incontra un lancio.
Sintassi
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
Esempio
L'esempio seguente utilizza un lancio per terminare l'interazione con l'utente se "!" viene digitato in risposta a qualsiasi richiesta.
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:")
Dovresti provare il programma sopra sulla tua macchina perché necessita di interazione manuale. Questo produrrà il seguente risultato:
Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby
Eccezione di classe
Le classi ei moduli standard di Ruby sollevano eccezioni. Tutte le classi di eccezione formano una gerarchia, con la classe Eccezione in alto. Il livello successivo contiene sette diversi tipi:
- Interrupt
- NoMemoryError
- SignalException
- ScriptError
- StandardError
- SystemExit
C'è un'altra eccezione a questo livello, Fatal, ma l'interprete Ruby lo utilizza solo internamente.
Sia ScriptError che StandardError hanno un numero di sottoclassi, ma non è necessario entrare nei dettagli qui. La cosa importante è che se creiamo le nostre classi di eccezione, devono essere sottoclassi della classe Exception o di uno dei suoi discendenti.
Diamo un'occhiata a un esempio:
class FileSaveError < StandardError
attr_reader :reason
def initialize(reason)
@reason = reason
end
end
Ora, guarda il seguente esempio, che utilizzerà questa eccezione:
File.open(path, "w") do |file|
begin
# Write out the data ...
rescue
# Something went wrong!
raise FileSaveError.new($!)
end
end
La riga importante qui è raise FileSaveError.new ($!) . Chiamiamo raise per segnalare che si è verificata un'eccezione, passandogli una nuova istanza di FileSaveError, con il motivo che l'eccezione specifica ha causato il fallimento della scrittura dei dati.