The send
method allows you to dynamically call methods on any object.
For example, suppose you have a class defined as follows:
class Usuario
def initialize(nome, email)
@nome = nome
@email = email
end
def nome
@nome
end
def email
@email
end
end
This class defines 3 methods: one initialization (which receives 2 arguments: name and email), and 2 accessors for the attributes name and email.
We can use it as follows:
marcos = Usuario.new('Marcos', '[email protected]')
marcos.name # => 'Marcos'
marcos.email # => '[email protected]'
The send
method can be used as follows:
marcos.send(:name) # => "Marcos"
marcos.send(:email) # => "[email protected]"
We can call any method of the object this way:
marcos.send(:class) # => Usuario
'100'.send(:to_f) # => 100.0
'Stack Overflow'.send(:upcase) # => "STACK OVERFLOW"
'Stack Overflow'.send(:downcase) # => "stack overflow"
This allows some interesting techniques, such as calling a different method on an object based on some input, without the need for a string of if
's and else
' s. For example, this code:
def acessar_atributo_1(nome_atributo)
if nome_atributo == 'nome'
objeto.nome
elsif nome_atributo == 'email'
objeto.email
elsif nome_atributo == 'idade'
objeto.idade
end
end
could be replaced by this much more concise version:
def acesso_atributo_dinamico(nome_atributo)
objeto.send(nome_atributo.to_sym) # Convertemos o argumento do tipo String para um Symbol antes de passar adiante
end
This code however has a loophole: the first version (with if
's) only allowed the 3 methods ( nome
, email
and idade
to be accessed); the second however allows any past method name to be accessed, which can be an unwanted condition. A good practice is, before calling the send
method, make sure that the argument passed is the name of a method that we should allow access to:
def acesso_atributo_dinamico(nome_atributo)
if [:nome, :email, :idade].include?(nome_atributo)
objeto.send(nome_atributo.to_sym) # Convertemos o argumento do tipo String para um Symbol antes de passar adiante
end
end