O método eval
é bastante poderoso, mas deve ser usado com cautela por trazer possíveis brechas de segurança. Ele avalia strings com expressões Ruby e as executa, como no exemplo abaixo:
puts eval "1 + 2 * 3"
7
# => nil
Note como a expressão descrita na string é lida e executada como código.
O eval
pode também avaliar e executar strings com código complexo:
eval("def hello; puts 'Hello!'; end")
# => :hello
hello
Hello!
No exemplo acima, o método eval
recebe uma string cujo código, quando
executado, define o método hello
. Essa funcionalidade é extremamente poderosa,
já que podemos manipular strings e executar código Ruby por meio delas. No
entanto, isso pode ser perigoso caso essas strings sejam, por exemplo, enviadas
ou manipuladas por usuários de uma aplicação, pode acontecer algo parecido com um ataque
de injeção SQL.
Uma coisa interessante desse método é que ele interpreta variáveis de seu escopo, então, é possível fazer coisas como:
a_text = "Este é um texto"
eval("a_text.split(' ')")
=> ["Este", "é", "um", "texto"]
Como este método pode abrir brechas de segurança, seu uso não é recomendado. Além disso, existem outras maneiras de obter os mesmos resultados que não dependem do eval
. Em Ruby existe o public_send
, que permite chamar outros métodos cujo nome você possui na forma de string ou symbol, e o define_method
, que, como o nome diz, permite definir métodos de instância.
Vamos considerar, por exemplo, que temos uma string "2 + 3" e queremos realizar esse cálculo. Poderíamos fazer algo como:
operation = "2 + 3".split(' ')
operation[0].to_i.public_send(operation[1], operation[2])
# => 5
Considere agora que precisamos criar um método com um nome definido em uma string. Podemos utilizar o define_method
:
nome = "nome_do_metodo"
define_method(nome) { |n| puts "#{ n }" }
# => :nome_do_metodo
nome_to_metodo("Criei um método")
Criei um método
# => nil
Conclusão
Metaprogramação é parte integrada na linguagem de programação Ruby e, apesar de existirem alternativas melhores, o método eval
é uma das ferramentas que permite um código manipular outros códigos. Em Ruby, encontramos também o class_eval
e o instance_eval
, que oferecem formas diferentes de avaliar strings ou blocos de código. Você pode ver mais sobre essas alternativas nos links abaixo.