[Post+Video] Ruby Forwardable module

Muitas vezes criamos classes que utilizam métodos já existentes em classes descendentes, por exemplo, sizefirstlast, dentre muitos outros. Na maioria das vezes para que as instâncias das nossas classes utilizem esses métodos, precisamos encapsulamos em novos métodos, no entanto é possível fazer isso de uma forma muito mais simples usando o módulo Forwardable. Ficou confuso? Não se preocupa que vamos explicar tudo! 😉

Para que tudo fique mais simples, vamos partir do exemplo abaixo.

class Habilidade
attr :habilidades
  def initialize
@habilidades = [:comer, :dormir, :jogar]
end
end
jackson = Habilidade.new
puts "A primeira tarefa de Jackson é: #{jackson.habilidades.first}"
> A primeira tarefa de Jackson é: comer

Perceba que tivemos que usar <objeto>.<atributo>.<método> para usar o método “first” que é um método que todos os Arrays possuem, correto?

Você vai concordar comigo que isso fiou meio feio e soa estranho quando usamos assim, não é verdade?

Uma forma de melhorar é encapsularmos isso em um método de instância. Vejamos:

class Habilidade
attr :habilidades
  def initialize
@habilidades = [:comer, :dormir, :jogar]
end
  def primeira_tarefa
@habilidades.first
end
end
jackson = Habilidade.new
puts "A primeira tarefa de Jackson é: #{jackson.primeira_tarefa}"
> A primeira tarefa de Jackson é: comer

Acredito que assim já melhora um pouco, não é?

Mas, “sofremos” por ter que criar um método pra encapsular apenas um método que já existe, apenas para que nosso código não ficasse “feio”. Sendo assim, o Ruby nos dá a possibilidade de usar o módulo Forwardable, que tem a função exatamente de repassar um método adiante com um nome diferente. Vejamos:

require 'forwardable'
class Habilidade
attr :habilidades

extend Forwardable
  def_delegator :@habilidades, :first, :primeira_tarefa
  def initialize
@habilidades = [:comer, :dormir, :jogar]
end
end
jackson = Habilidade.new
puts "A primeira tarefa de Jackson é: #{jackson.primeira_tarefa}"
> A primeira tarefa de Jackson é: comer

Olha que legal! Tivemos o mesmo resultado e usamos algo muito mais inteligente. Veja os passos:

  • Importamos a biblioteca forwardable
  • Extendemos Forwadable
  • Depois usamos o método def_delegator passando o atributo (@habilidades), depois o método que queremos acessar do atributo (:first)e por fim, qual o novo nome que queremos para esse método (:primeira_tarefa).

Simples não? 🙂

Além do método def_delegator também é possível usar o def_delegatorspara encaminhar vários métodos de uma forma mais simples, sem dar um novo nome, veja:

require 'forwardable'
class Habilidade
attr :habilidades

extend Forwardable
  def_delegator :@habilidades, :first, :primeira_tarefa
def_delegators :@habilidades, :last, :size
  def initialize
@habilidades = [:comer, :dormir, :jogar]
end
end
jackson = Habilidade.new
puts "A primeira tarefa de Jackson é: #{jackson.primeira_tarefa}"
puts "A última tarefa de Jackson é: #{jackson.last}"
puts "A quantidade total de tarefas de Jackson é: #{jackson.size}"
> A primeira tarefa de Jackson é: comer
> A última tarefa de Jackson é: jogar
> A quantidade total de tarefas de Jackson é: 3

Perceba nesse caso que apenas delegamos os métodos last e size, evitando assim que usássemos jackson.habilidades.last e jackson.habilidades.size.

Enfim, ainda existem mais alguns métodos que podem ser explorados no módulo Forwardable e que podem ser consultados na documentação oficial (https://ruby-doc.org/stdlib-2.4.0/libdoc/forwardable/rdoc/Forwardable.html)

É isso, gente!

Caso tenha ficado alguma dúvida, aproveita e assiste ao vídeo que fiz sobre esse assunto. 😉



Mais uma vez espero que tenham gostado e qualquer dúvida não hesite em deixar seu comentário logo aí abaixo.

Aproveitando, cadastre-se em nossa newsletter semanal, curta nossa página no facebook e siga-nos nas redes sociais.

Um abraço e até a próxima! 😉