Doubt about using send () in ruby

2

The general idea of OO is that each object can react differently to the same message. In ruby, I noticed that it is possible to use the send () method and that every object in Ruby has this method.

So, I can do something like: object.send (: method)

But what I do not understand is: what is the advantage of passing a symbol to the method? Are symbols immutable, and do they save a key to the method? no type key = > value? Or do they allocate and leave in memory the variables used in the method all the time the program is running?

    
asked by anonymous 11.10.2015 / 22:20

1 answer

5

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
    
13.10.2015 / 05:23