2010-12-10 11 views
26

Czytam sekcję METAPROGRAMOWANIE z programowania Ruby 1.9 i mam problemy ze zrozumieniem tego, co się dzieje wewnętrznie między class_eval/class_exec vs. instance_eval/instance_exec.Ruby def i instance_eval vs. class_eval

Więc przede wszystkim, moje rozumienie jest def dodaje metodę tabeli metoda self (obiekt klasy):

class A 
    puts self # => A 
    def foo; 42; end # added to the method table of self, so becomes an instance method 
end 
A.new.foo # => 42 

A jeśli używamy class_eval, mamy ten sam problem:

A.class_eval do 
    puts self # => A 
    def bar; 42; end # same as above 
end 
A.new.bar # => 42 

Ale jakoś w przypadku instance_eval, rzeczy są różne:

A.instance_eval do 
    puts self # => A 
    def baz; 42; end # added to the method table of an anonymous 
        # singleton class of self, so becomes a class method 
end 
puts A.baz # => 42 

s = 'string' 
s.instance_eval do ... end # same behavior, so now def creates an instance method 

Rozumiem różnicę funkcjonalną między class_eval i instance_eval.

Ale konteksty wewnątrz class_eval i instance_eval bloków wyglądać dokładnie tak samo do mnie - w szczególności self punkty do tego samego obiektu, a local_variables są takie same. Co więc dzieje się wewnątrz bloków (wewnętrznie), co powoduje, że def działa inaczej?

Czy mogę przeczytać dokumentację? RDoc dla instance_eval i class_eval nie pomaga. Patrząc na źródło, wydaje się, że instance_eval tworzy obiekt klasy singleton, podczas gdy class_eval nie - ale czy ta różnica jest widoczna poza kodem C, na poziomie Rubinowym?

Odpowiedz

31

Myślę, że twoje zamieszanie bierze się z faktu, że def nie zależy od obecnego ja, możesz pomyśleć o tym, że jest to "aktualna klasa", która ma swoje własne zasady.

Po twoich przykładów:

class A 
    # defs here go to A 
    puts self # => A 
    class << self 
    #defs here go to A's eigenclass 
    end 
end 

A.class_eval do 
    #defs here go to A 
end 

A.instance_eval do 
    #defs here go to A's eigenclass  
end 

s = "Hello World" 

class << s 
    #defs here go to s's eigenclass 
end 

Oto część rozdziału, który mówi o tym problemie i to całkiem jasne, o zachowanie

class_eval i instance_eval zarówno ustalonych siebie przez cały czas trwania blok. Jednak różnią się one sposobem, w jaki konfigurują one środowisko dla metody . class_eval ustawia rzeczy jakbyś był w ciele klasy definicji, więc definicje metoda będzie definiować metody instancji w przeciwieństwie nazywając instance_eval w klasie działa jakbyś pracy wewnątrz singleton klasy siebie. W związku z tym wszelkie zdefiniowane metody staną się metodami klasy .

Jedyne co warto dodać to, że możesz wywołać metodę instance_eval w dowolnym obiekcie, nie tylko w klasach, a zachowanie nie zmienia się, ale ma inne konsekwencje.

Niektóre istotne czytanie:

Ruby: instance_eval and class_eval method definitions

Chapter 4 of this most excelent series

+0

Hm, rozumiem - to ma sens. Czy istnieje sposób sprawdzenia tej "aktualnej klasy" w kodzie Ruby? –

+1

Myślę, że w 'A.instance_eval', miałeś napisać' #defs tutaj przejdź do A's eigenclass'? Czy jestem w błędzie? –

+0

To nie jest takie proste, opublikuję kilka istotnych linków w odpowiedzi –

3

Wystarczy dodać do użytkownika @ krusty.ar odpowiedź: def i define_method dodać metody do bieżącego metoda kontekście definicji (wierzę, że to, co to się nazywa, nie jestem pewien), nie do obecnego self.

Po prostu w środku ciała klasy, klasy lub singletonu, te dwie rzeczy są takie same.

Ale na przykład w treści skryptu (aka najwyższego poziomu), self jest obiektem main, ale bieżący kontekst definicji metody to Object.