Já falamos em artigos anteriores como delegar chamadas de métodos usando SimpleDelegator e Sobrescrevendo method_missing
na implementação de design patterns como Presenter e Decorator em uma aplicação Ruby on Rails. Vamos mostrar como podemos implementar uma solução utilizando o delegate_missing_to
. Sugerimos que você leia os artigos anteriores caso tenha interesse em compreender melhor os design patterns e como foram feitas as implementações do method_missing
ou do SimpleDelegator. Caso contrário, pode continuar a leitura.
Em resumo, relembrando o contexto do exemplo descrito nos artigos anteriores, temos duas classes, Rental
, que representa uma locação de um carro, e RentalPresenter
, que vai preparar informações de Rental
para visualização nas views. Para que RentalPresenter
consiga executar plenamente sua função, é importante que a classe seja capaz de responder aos mesmos métodos que Rental
. Com esse objetivo em mente, podemos implementar algumas estratégias como Herança ou usar SimpleDelegator, por exemplo. Outra possibilidade, como demonstramos neste artigo, seria sobrescrever method_missing
na classe RentalPresenter
:
class RentalPresenter
attr_reader :rental
def initialize(rental)
@rental = rental
end
def status
"A locação está com status: #{@rental.status}"
end
def method_missing(method_name, *args, &block)
@rental.public_send(method_name, *args, &block)
end
def respond_to_missing?(method_name, include_private = false)
@rental.respond_to?(method_name, include_private)
end
end
Implementando o método method_missing
em RentalPresenter
conseguimos controlar o comportamento do método, repassando as chamadas de métodos que não estão implementados para @rental
. Utilizando essa estratégia é necessário também implementar o método respond_to_missing?
, como descrito neste artigo.
Mas esse mesmo resultado poderia ser obtido utilizando o método delegate_missing_to
na classe:
class RentalPresenter
delegate_missing_to: :@rental
attr_reader :rental
def initialize(rental)
@rental = rental
end
def status
"A locação está com status: #{@rental.status}"
end
end
Você pode usar o delegate_missing_to
passando a ele métodos, variáveis de instância, constantes etc. O delegate_missing_to
repassa as chamadas de métodos que não estão implementados na classe para o objeto designado, neste caso @rental
. Dessa forma o código fica muito mais enxuto e não é necessária nenhuma implementação secundária para tratar possíveis erros. Além disso, uma vantagem que essa estratégia apresenta em comparação com o uso do SimpleDelegator é que semanticamente o delegate_missing
torna muito mais clara a intenção de sua implementação.
Existe também a opção de utilizar o delegate
. Para o presente exemplo, no lugar de delegate_missing_to
, bastaria incluir delegate :nome_do_metodo, to: :@rental
. No entanto, seria necessário incluir cada um dos métodos faltantes e sempre que um método for adicionado a Rental
a classe RentalPresenter
precisaria ser atualizada.
Quando nossa intenção é apenas delegar todos os métodos faltantes para um alvo específico, o delegate_missing_to
faz o trabalho necessário de forma bastante simples e direta.