Bom, eu acredito que algumas pessoas que começaram com a linguagem Ruby possam ter essa pergunta. O que, exatamente, são Eingenclass (ou, na nomenclatura mais comum, Singleton Classes)? O que, exatamente, retorna o método “metaclass”, do ActiveSupport? Bom, em primeiro lugar, é bom entender algumas coisas: o código a seguir:

class Exemplo
end

e1 = Exemplo.new
e2 = Exemplo.new
def e1.imprimir
  puts "Algo"
end

e1.imprimir #Imprime Algo
e2.imprimir #NoMethodError

Por que a primeira instância ganhou um método chamado “imprimir”, e a outra não? Para onde foi a definição deste método? Para dar a resposta, é necessário primeiro entender alguns conceitos importantes. Em primeiro lugar, sempre que um método é definido, ele é definido em uma classe, e a partir deste momento ele está disponível para ser chamado por uma instância. Este é um conceito interessante: embora, quando façamos códigos como:

class Exemplo2
  def self.somar(a, b)
    a + b
  end

  def um_metodo
    "um método"
  end
end

a tendência é chamar o método “somar” de “class method” ou “metodo da classe”, na verdade não é isso que acontece. Este método, na verdade, não foi definido na classe Exemplo2, e sim em outra classe da qual a classe Exemplo2 é apenas uma instância. Para os que conhecem melhor a estrutura de classes do Ruby, sabe que toda classe é uma instância da classe Class, e sabe também que definir um método como o “somar”, acima, não automaticamente adiciona esse método a todas as outras classes. É aí que entram as Eigenclasses

O conceito, na verdade, é bem simples: por padrão, uma classe qualquer, digamos, a classe “Exemplo”, apresentada acima, é uma instância da classe Class (que, por sua vez, é uma instância de si mesma… é um pouco confuso). Porém, toda classe, sem exceção, possui uma “Eingenclass” – o nome “Eigen” significa algo como “si mesma”. Como um exemplo simples, o diagrama das classes “Exemplo” e “Exemplo2” seria semelhante ao seguinte:

Diagrama Eingenclass

Encare as setas brancas como “tal classe é instância de” e as pretas como “tal classe herda de”. Tem coisas interessantes aí, tais como “Class herda de Object” e “Class é instância de si mesma”, mas o que realmente importa é o seguinte: o objeto “e1”, como é possível ver, ganhou uma “eigenclass” na solução de métodos (note que o diagrama, por mais incrível que pareça, está simplificado), e é a “eigenclass” é quem contém o método “imprimir()”. Note que isto também ocorre na classe “Exemplo2”, que contém uma “eingenclass” que contém o método “da classe”.

Acho que com isso, fica claro a definição, logo no início do meu post, que todo método declarado vai para uma instância. Por exemplo, o “class method” ou “método da classe” Exemplo2.somar, na verdade, foi para uma “eigenclass”, uma classe intermediária entre a classe Class e Exemplo2. Como Exemplo2 é uma instância da “eigenclass”, ela ganha o método “somar”.

Note também uma coisa interessante: o objeto “e2”, e a classe Exemplo não possuem “eigenclasses”. Isto ocorre porque uma “eigenclass” é criada por demanda, então se não houve necessidade, a “eingenclass” não é criada. Logo, nem a classe “Exemplo” nem o objeto “e2” possuem uma. Por fim, se for necessário exibir a “eigenclass” de uma classe ou objeto, é possível usar ou o comando “metaclass”, do ActiveSupport, ou o seguinte comando:

class Exemplo2
end
e = Exemplo2.new

eigenclass_exemplo2 = class << Exemplo2; self; end
eigenclass_e = class << e; self; end

O comando “class << ” define “self” como a eingenclass do objeto.

Agora, não esperem que um comando, como “e.instance_of?(eingenclass_e)” irá retornar “true”. Não é o que acontece, por mais estranho que isso pareça. Em linhas gerais, aparentemente Matz (criado da linguagem Ruby) não tinha certeza se Ruby suportaria “eigenclasses”, e por esse motivo elas ainda parecem meio deslocadas na linguagem.

Mas isso não muda o fato de que muitas coisas interessantes podem ser feitas com esse tipo de técnica.


1 Comment

mairon · 2010-10-12 at 20:18

muito bommm

parabens
abraco

Leave a Reply

Your email address will not be published. Required fields are marked *