Gestione delle Eccezioni: rescue
Un programma in esecuzione può passare attraverso vari problemi inaspettati . Un file che vorrebbe leggere potrebbe non esistere; il disco potrebbe essere pieno quando desidera salvare dei dati; l'utente potrebbe fornirgli dei dati inaccettabili.
ruby> file = open("un_file")
ERR: (eval):1:in `open': No such file or directory - some_file
Un programma robusto gestirà tali situazioni sensibilmente e in maniera elegante. Rispettare queste aspettative potrebbe esserre un compito esasperante. Dai programmatori C ci si aspetta che controllino il risultato di ogni chiamata di sistema che potrebbe possibilmente fallire, e che decidano immediatamente cosa fare:
FILE *file = fopen("un_file" , "r");
if (file == NULL) {
fprintf( stderr, "Il file non esiste ." );
exit(1);
}
byte_letti = fread( buf, 1, byte_desiderati, file );
if (byte_letti != byte_desiderati ) {
/* effettua ulteriori gestioni delle eccezioni... */
}
...
Questa è una pratica talmente noiosa che i programmatori tendono a curarsene sempre meno ed a dimenticarla, ed il risultato è un programma che non gestisce bene le eccezioni. D'altra parte, fare il lavoro per bene può rendere i programmi difficili da leggere , poiché c'è così tanta roba per le gestione degli errori da nascondere il codice significativo.
In ruby, come in molti linguaggi moderni, possiamo gestire le
eccezioni per blocchi di codice in modo [compartimentato],
ottenendo un risultato sorprendentemente efficiente ma senza
caricare in modo eccessivo il programmatore o chiunque tenti
di leggere il codice in seguito. Il blocco di codice
segnalato con begin viene eseguito finchè
non c'è un'eccezione, che causa il
trasferimento del controlload un blocco di gestione
dell'eccezione, che viene segnalato da
rescue. Se non c'è un eccezione, il
codice rescue non viene usato. Il metodo
seguente restituisce la prima linea di un file di testo, o
nil se c'è un eccezione:
def prima_linea( filename )
begin
file = open("un_file")
info = file.gets
file.close
info # l'ultima cosa valutata è il valore di ritorno
rescue
nil # non possiamo leggere il file? Allora non restituiamo una stringa
end
end
Ci saranno volte in cui vorremo essere in grado di aggirare un problema in maniera creativa . Qui, se il file desiderato fosse stato indisponibile, avremmo potuto usare lo standard input ad esempio:
begin
file = open("un_file")
rescue
file = STDIN
end
begin
# ... processa l'input ...
rescue
# ... e gestiamo ogni altra eccezioni qui.
end
retry può essere usato insieme al codice
in rescue per ricominciare il codice in
begin ancora. Esso ci permette di riscrivere il
codice dell'esempio precedente in maniera leggermente
più compatta:
fname = "un_file" begin file = open(fname) # ... processa l'input ... rescue fname = "STDIN" retry end
In ogni caso, c'è un difetto qui. Un file non
esistente farà si che questo codice entri in un ciclo
infinito. Avrete bisogno di stare attenti per simili
trappolenell'uso di retry per la gestione
delle eccezioni.
Ogni libreria di ruby solleva un'eccezione se accadono
degli errori, e potete sollevare esplicitamente delle
eccezioni anche voi dal vostro codice. Per sollevare un
eccezione usate raise. Accetta un argomento, che
dovrebbe essere una stringa che descrive l'eccezione.
L'argomento è opzionale ma non dovrebbe essere
omesso. Si potrà accedere in seguito ad esso tramite
la variabile globale speciale $!.
ruby> raise "errore di prova"
test error
ruby> begin
| raise "prova2"
| rescue
| print "Erroe: " ,$!, ""
| end
Errore: prova2
nil