Rinaldi Fonseca

Ruby Extend Self

23 de abril de 2011

É comum encontrarmos instruções como: extend self em códigos Ruby.
Quem é iniciante na linguagem normalmente acha isso um pouco estranho.
Neste post citarei algumas utilidades para esta técnica.

Inicialmente é importante compreender o que realmente acontece quando usamos o extend self.

Considere o seguinte código:

module MyModule
 def hello
   "hello"
 end
end
 
class MyClass
 extend MyModule
end
 
puts MyClass.hello

Basicamente estamos realizando o mixin de class methods. Ou seja, com o extend, os métodos definidos no módulo estarão disponíveis na classe MyClass(que por sua vez é um objeto). Por este motivo é que acessamos MyClass.hello ao invés de primeiramente criarmos um objeto da classe MyClass.
Isso seria necessário se utilizássemos o include, ao invés do extend.

Agora o que aconteceria se utilizássemos o extend self dentro de nosso módulo conforme o código abaixo?

module MyModule
extend self 
def hello
   "hello"
 end
end

Quem é self? Neste caso self é o próprio MyModule. Logo seria o mesmo que escrevêssemos: extend MyModule.

Com isso, o método hello também estará disponível no objeto MyModule(que é uma instância da classe Module).

Isso nos permite escrever:

MyModule.hello

O que podemos fazer com isso?

1) Esta abordagem facilita nosso trabalho no momento de testarmos, pois podemos isolar nosso módulo/classe e testar seu comportamento de forma separada. Não precisaríamos por exemplo, realizar um include/extend em alguma outra classe/objeto somente para este fim.

2) Uma alternativa para implementar o Singleton Pattern.

Considere o seguinte código:

require "singleton"
 
class MyLib
 include Singleton
 
 def initialize
   @var = "hello"
 end
 
 def hello
   puts @var
 end
end
 
MyLib.instance.hello  #=>hello

Estamos apenas implementando o Singleton Pattern em uma classe.

Utilizando o extend self podemos ter basicamente o mesmo comportamento:

module MyLib
 extend self
 
 def var
   @var ||= "hello"
 end
 
 def hello
   puts var
 end
end
 
MyLib.hello #=> hello

Obs: a intenção não é substituir uma implementação pela outra, mas sim mostrar alguns recursos da linguagem que nos permitem resolver determinados problemas de maneiras diferentes. Inclusive esta é uma das filosofias do Ruby.

Nenhum Comentário »

Nenhum comentário ainda.

Feed RSS dos comentários deste post URL de TrackBack

Deixe um comentário

Spam protection by WP Captcha-Free