Una situazione ricorrente durante lo sviluppo di una applicazione è quella di utilizzare il valore ritornato da un metodo, il quale potrebbe in alcune circostanze ritornare l’oggetto nil.
Per esempio supponiamo di avere scritto un metodo search(keys) che cerca un oggetto in base ai parametri passati come argomento e ritorna nil se la ricerca fallisce.
Il nostro codice avrà più o meno questa forma:
r = search(keys) if r != nil # utilizziamo r bar(r) end
ovviamente cercheremo di essere sintetici
r = search(keys) bar(r) if r
ma quella variabile utilizzata solo per testare il risultato prima di utilizzarlo è una spina nel fianco …. ma ecco che ci vengono in aiuto i blocchi.
Rivediamo il funzionamento del nostro metodo search() affinchè questo passi direttamente il risultato (se è valido) al blocco associato al metodo:
def search(keys) # effettua la ricerce e assegna il risultato # a r, altrimenti assegna nil r = ....... # ora esegue il blocco se il risultato è valido yield r if r r # in ogni caso ritorno il risultato end # utilizzo del metodo search(keys) { |r| bar(r) }
e la magia è fatta.
Gli sviluppatori Ruby chiamano iteratori tutti quei metodi che utilizzano yield per invocare un blocco associato al metodo stesso, anche in quei casi in cui il metodo non effettua alcuna iterazione ma si limita a eseguire il blocco una sola volta.
Una situazione frequente in cui si usa un iteratore è quella in cui un metodo apre un file, passa il contenuto ad un blocco e poi chiude il file stesso:
def open_and_process(nf) f = file_open(nf) if f c = file_read(f) yield c file_close(f) end end
# che viene utilizzata in questo modo
open_and_process(nome_file) { |c| use_data(c) }
utilizzare questa modalità ha il vantaggio che confiniamo all’interno del metodo open_and_process tutte le problematiche legate all’apertura e alla chiusura del file e lasciamo all’utilizzatore il solo compito di utilizzare il dato letto all’interno del blocco.