[Tradução] Três Contextos Implícitos em Ruby
Posted on November 16, 2009
[Tradução] Três Contextos Implícitos em Ruby
A desenvolvedora japonês @yugui escreveu um grande complemento ao artigo anterior sobre metaprogramação do Yehuda, que traduzo logo abaixo:
Yehuda Katz escreveu um artigo sobre self e metaclass. Nesse artigo ele disse que Person.instance_eval associa a metaclass de Person para self para uma classe Person, mas isso é obviamente errado.
1 2 |
class Person; end Person.instance_eval{ p self } #=> Person |
Como mencionei em um artigo antigo, embora eu deva me desculpar por estar escrito em japonês, Ruby sempre tem 3 contextos implícitos: self, o chamado ‘klass’ e o ponto constante de definição. Yehuda está confundindo self com ‘klass’.
self
self é o self que você conhece. É o receptor padrão de invocação de método. Sempre existe um self.
1 2 3 4 5 6 7 8 9 10 11 12 |
p self # mostra "main" class Foo def bar(a = (p self)) end end foo = Foo.new foo.bar # mostra "#<Foo:0x471004>" class Foo class Baz < (p self; self) # mostra "Foo" end end |
No nível superior, uma instância especial de Object chamada “main” é o self. Onde quer que esteja, você pode recuperar o self a partir da pseudovariável self.
Se você invocar um método sem explicitar um receptor, self receberá essa invocação.
o chamado ‘klass’
Eu chamei o conceito de ‘klass’ no artigo antigo, mas não sei se é o melhor nome. É a classe padrão sobre o qual o método é definido. Agora gostaria de chamá-lo “definidor padrão”.
Ruby sempre segura a referência a uma classe assim como ao self. Mas não há maneira de recuperá-lo diretamente. É mais implícito que self. Se você definir um método sem dar um receptor específico, em outras palavras, se definir um método com o jeito sintático normal de definir métodos, o definidor padrão terá o método como um método de instância.
Exemplos:
No nível superior, Object é a classe. Então funções globais são igualmente métodos de instância na classe Object como você já sabe.
1 2 |
def hoge; end Kernel.instance_method(:hoge) #=> #<UnboundMethod: Object#hoge> |
Aliás, “hoge”, “fuga”, “piyo” é japonês para “foo”, “bar”, “baz”.
A sintaxe class muda ambos os self e o definidor padrão para a classe que está agora sendo definida.
1 2 3 4 |
class T def hoge; end end T.instance_method(:hoge) #=> #<UnboundMethod: T#hoge> |
Em um corpo normal de método, self é o receptor de invocação de métodos e o definidor padrão é a classe sintaticamente fora dela, agora ela é T.
1 2 3 4 5 6 7 8 9 |
class T def hoge def fuga; end end end t = T.new t.hoge t.method(:fuga) #=> #<Method: T#fuga> T.instance_method(:fuga) #=> #<UnboundMethod: T#fuga> |
Não confunda isso com def self.fuga, uma definição de método singleton. Quando você dá uma definição de método a um receptor, o método será adicionado à eigenclass do receiver.
U não tem um método de instância chamado fuga porque fuga é um método singleton de u.
Onde quer que esteja, existe um definidor padrão. Quando executa um valor padrão, o definidor padrão é a classe externa assim como no corpo do método.
Em outras palavras, a definição class muda o definidor padrão mas não a definição de método.
família eval
O que o instance_eval faz é:
- mudar o
selfpara o receptor doinstance_eval - mudar o definidor padrão para o eigenclass do receptor
- se o receptor não tiver um eigenclass ainda, cria um.
- executa o bloco dado
1 2 3 4 5 6 7 |
o = Object.new o.instance_eval do p self #=> #<Object:0x454f24> def hoge; end end o.method(:hoge) #=> #<Method: #<Object:0x454f24>.hoge> Object.instance_method(:hoge) # raises a NameError "undefined method `hoge' for class `Object'" |
Vamos lá:
Como o instance_eval muda o definidor padrão do eigenclass para $o, então fuga e piyo serão métodos singleton de $o
Oops, esqueci de mencionar que:
1 |
RUBY_VERSION #=> "1.9.1". |
Ruby 1.8 age de maneira mais léxica, então você acabará tendo o contrário:
1 2 3 4 |
$o.method(:fuga) # raises a NameError $o.method(:piyo) # raises a NameError T.instance_method(:fuga) #=> #<UnboundMethod: T#fuga> T.instance_method(:piyo) #=> #<UnboundMethod: T#piyo> |
Em Ruby 1.8, o definidor padrão no corpo do método é baseado lexicamente na definição da classe externa. De qualquer forma, tanto no Ruby 1.8 quanto 1.9, instance_eval muda self para o receptor, o definidor padrão a seu eigenclass.
Finalmente, class_eval muda ambos self e o definidor padrão para o receptor:
| self | definidor padrão | |
| class_eval | o receptor | o receptor |
| instance_eval | o receptor | eigenclass do receptor |
No meu artigo antigo eu discuti sobre Kernel#eval e instance_eval/class_eval com execução de Strings.
definição de constantes
Quando você vê uma variável de instância, ela é uma variável da instância de self. Quando você usa uma variável de classe, ela é uma variável de classe da classe de self; ou o próprio self quando self é uma classe.
Mas constantes se comportam de maneira diferente. É outro contexto implícito de Ruby. O Ruby Core Team chama esse conceito de “cref”.
Discutiremos esse conceito de “cref” em outro artigo.
blog comments powered by Disqus
Archives
- February 12(2)
- December 11(1)
- November 11(4)
- October 11(6)
- September 11(5)
- August 11(1)
- July 11(5)
- May 11(4)
- April 11(11)
- March 11(4)
- February 11(3)
- January 11(4)
- December 10(9)
- November 10(2)
- October 10(10)
- September 10(4)
- August 10(6)
- July 10(14)
- June 10(16)
- May 10(8)
- April 10(14)
- March 10(9)
- February 10(6)
- January 10(14)
- December 09(10)
- November 09(10)
- October 09(7)
- September 09(19)
- August 09(4)
- July 09(12)
- June 09(7)
- May 09(12)
- April 09(11)
- March 09(9)
- February 09(9)
- January 09(12)
- December 08(14)
- November 08(20)
- October 08(15)
- September 08(18)
- August 08(25)
- July 08(13)
- June 08(21)
- May 08(29)
- April 08(27)
- March 08(12)
- February 08(32)
- January 08(31)
- December 07(27)
- November 07(30)
- October 07(25)
- September 07(28)
- August 07(16)
- July 07(15)
- June 07(16)
- May 07(7)
- April 07(13)
- March 07(8)
- February 07(9)
- January 07(24)
- December 06(17)
- November 06(17)
- October 06(15)
- September 06(38)




