o parâmetro '&' (Ampersand)
Para que serve o & antes de um parâmetro em Ruby?
O & antes de algum parâmetro é utilizado basicamente de duas formas:
1 Na definição de um método:
def awesome_method &block
yield if block_given?
end
2 Antes da chamada de um método:
awesome_method ¶meter
A primeira forma serve para deixar explícito que o seu método recebe um bloco.
Já a segunda forma funciona assim:
pega o parâmetro, chama o método to_proc
e o passa como bloco, idependente de o método ter deixado o bloco explícito ou não. Então basta que o objeto passado responda a to_proc
. Você ja deve ter visto parecido com isso:
@users.map &:name
E uma coisa que sempre quis saber é “como um símbolo passado como parâmetro irá no exemplo acima irá retornar o nome de todos usuários?”.
Pesquisei um pouco, e achei como isso é feito
Símbolos implementam o to_proc
, tá e dai, como funciona esse to_proc`?
class Symbol
# ...
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
# ...
Ainda um pouco confuso? Vamos destrinchar esse código então.
vamos chamar o to_proc
para o símbolo :name
#...
Proc.new do |obj, *args|
obj.send :name, *args
end
#...
o map
passa como parâmetro para o bloco um item da coleção, nesse caso um user, vamos adicioná-lo no código, e já que apenas um argumento é passado podemos remover o *args
para simplificar.
#...
Proc.new do |user|
user.send :name # => equivalente a user.name
end
#...
Mais simples agora? O método send
envia para o user a mensagem :name
, porque na verdade em Ruby metódos não são chamados, são mensagens enviadas ao objeto.
o resultado final seria algo equivalente a isso:
@users.map do |user|
user.send :name # ou user.name
end
Caso queira saber mais sobre o ampersand: Ruby ampersand parameter demystified