#6 Shortcut Blocks with Symbol to_proc
La extraña sintaxis en la línea del find que vemos debajo, con un ampersand y un symbol, se llama Symbol to_proc y es algo que Rails agrega a Ruby.
class Project < ActiveRecord::Base has_many :tasks def self.all_names find(:all).collect(&:name) end end
Utilizaremos script/console
de Rails para explicar como funciona. Primero, busquemos un arreglo de Project
s.
Laa-Laa:todo eifion$ script/console Loading development environment (Rails 2.2.2) >> projects = Project.find(:all) => [#<Project id: 1, name: "Write another ASCIIcast", created_at: "2008-12-29 09:32:47", updated_at: "2008-12-29 09:32:47">, #<Project id: 2, name: "Go out walking", created_at: "2008-12-29 09:33:04", updated_at: "2008-12-29 09:33:04">]
Hay dos proyectos y queremos devolver un arreglo de todos los nombres de los proyectos. Una manera de hacerlo sería usando el método collect
, que toma un bloque (block), y devuelve el nombre de cada proyecto. El método collect
itera a través de un arreglo, ejecuta algún código sobre cada ítem en el arreglo, y devuelve un arreglo que contiene cada resultado del código ejecutado sobre cada ítem en el arreglo original.
>> projects.collect { |p| p.name } => ["Write another ASCIIcast", "Go out walking"]
Symbol to_proc permite utilizar un atajo cuando se desea realizar una llamada a un método contra el objeto que se envía al bloque. Para hacer esto, se le pasa un parámetro que comienza con un ampersand (&) seguido por el nombre del método como símbolo (symbol):
>> projects.collect {&:name} => ["Write another ASCIIcast", "Go out walking"]
Esto es más útil cuando se quiere combinar múltiples llamadas a métodos:
>> projects.collect(&:name).collect(&:upcase) => ["WRITE ANOTHER ASCIICAST", "GO OUT WALKING"]
Esta técnica no se limita al método collect
; puede aplicarse a cualquier método que tome un bloque. Por ejemplo, los métodos any?
y all?
pueden utilizar este atajo para ver si todos (all) o cualquier proyecto (any) son válidos, o incluso para guardar todos nuestros proyectos.
>> projects.all?(&:valid?) => true >> projects.any?(&:valid?) => true >> projects.each(&:save!) => [#<Project id: 1, name: "Write another ASCIIcast", created_at: "2008-12-29 09:32:47", updated_at: "2008-12-29 09:32:47">, #<Project id: 2, name: "Go out walking", created_at: "2008-12-29 09:33:04", updated_at: "2008-12-29 09:33:04">]
A pesar de su sintaxis un poco extraña, symbol to_proc es muy útil cuando se necesita encadenar métodos entre sí con bloques.