#6 Shortcut Blocks with Symbol to_proc
La strana sintassi nella linea del find nel codice riportato qui sotto, con il simbolo preceduto dal carattere ampersand, è detta Symbol to_proc ed è un qualcosa che Rails aggiunge a Ruby.
class Project < ActiveRecord::Base has_many :tasks def self.all_names find(:all).collect(&:name) end end
Useremo la facility Rails script/console
per spiegare come funziona. Per prima cosa, prendiamo un array di Project
.
asalicetti$ script/console Loading development environment (Rails 2.3.5) >> projects = Project.find(:all) => [#<Project id: 1, name: "Scrivi un altro ASCIIcast", created_at: "2010-04-12 12:32:40", updated_at: "2010-04-12 12:32:40">, #<Project id: 2, name: "Vai fuori a passeggio", created_at: "2010-04-12 12:35:20", updated_at: "2010-04-12 12:35:20">]
Ci sono due progetti e l’obiettivo è quello di ottenere un array contenente i nomi di tutti i progetti. Un modo per farlo sarebbe quello di usare il metodo collect
, che accetta un blocco e restituisce il name
di ogni Project
. Il metodo collect
iterata su di un array, esegue del codice (definito nel blocco) su ogni elemento dell’array, e restituisce un array contenente ogni risultato del codice del blocco eseguito su ogni singolo elemento dell’array originale.
>> projects.collect { |p| p.name } => ["Scrivi un altro ASCIIcast", "Vai fuori a passeggio"]
Symbol to_proc è una scorciatoia utilizzabile ogni volta in cui, come in questo caso, si vuole chiamare un metodo sull’oggetto che è mandato al blocco. Per fare ciò, si passa un parametro che inizia con un ampersand, seguito dal nome del metodo da invocare (nella sua forma simbolica):
>> projects.collect {&:name} => ["Scrivi un altro ASCIIcast", "Vai fuori a passeggio"]
Questa scorciatoia diventa particolarmente utile quando si vogliono combinare chiamate multiple:
>> projects.collect(&:name).collect(&:upcase) => ["SCRIVI UN ALTRO ASCIICAST", "VAI FUORI A PASSEGGIO"]
Ovviamente questa tecnica non è limitata al solo metodo collect
; più in generale, può essere applicata a qualsiasi metodo che accetta un blocco. Per esempio i metodi any?
e all?
possono usare questa scorciatoia per vedere se tutti (all) o almeno uno (any) dei progetti sono validi, o persino per salvare tutti i nostri progetti.
>> projects.all?(&:valid?) => true >> projects.any?(&:valid?) => true >> projects.each(&:save!) => [#<Project id: 1, name: "Scrivi un altro ASCIIcast", created_at: "2010-04-12 12:32:40", updated_at: "2010-04-12 12:32:40">, #<Project id: 2, name: "Vai fuori a passeggio", created_at: "2010-04-12 12:35:20", updated_at: "2010-04-12 12:35:20">]
Nonostante la sua sintassi un tantino strana, Symbol to_proc è molto utile se usata quando si ha da concatenare metodi con blocchi.