2017-10-07 84 views
5

W Metaprogramming Ruby 2 w rozdziale 2 w sekcji „Udoskonalenia” znalazłem następujący fragment kodu Ruby:Ruby udoskonalenia pułapek

class MyClass 
    def my_method 
    "original my_method()" 
    end 

    def another_method 
    my_method 
    end 

end 

module MyClassRefinement 
    refine MyClass do 
    def my_method 
     "refined my_method()" 
    end 
    end 
end 

using MyClassRefinement 
MyClass.new.my_method # => "refined my_method()" 
MyClass.new.another_method # => "original my_method()" - How is this possible? 

Według autora:

Jednak rozmowy do another_method może Cię zaskoczyć: nawet jeśli zadzwonisz pod numer another_method po using, samo połączenie z my_method dzieje się przed using - dlatego nazywa oryginalną, nierafinowaną wersję metody.

To całkowicie mnie podnieca.

Dlaczego MyClass.new.another_method wyświetla "oryginalny my_method()" od czasu jego użycia po using MyClassRefinement i co autor próbuje tu powiedzieć?

Czy ktoś mógłby przedstawić bardziej intuicyjne/lepsze wyjaśnienie?

Dzięki.

+0

Prawdopodobnie dlatego, że ponowne odwzorowanie wprowadzone przez udoskonalenia dotyczy tylko określonego zakresu, a w obrębie tej oryginalnej definicji zakres pozostaje nienaruszony. – tadman

Odpowiedz

2

Najlepszym wyjaśnieniem znajdę to od the docs:

Udoskonalenia są leksykalny w zakresie. Zawężenia są aktywne tylko w zasięgu po wywołaniu using. Żaden kod przed instrukcją using nie będzie zawierał udoskonalenia.

To oznacza, że ​​twoja metoda zawężenia musi zostać wywołana gdzieś po połączeniu z numerem using. Znaczenie ma faktyczna lokalizacja wywołania metody, a nie sposób wywołania metody lub skąd metoda została wywołana.


Oto, co się dzieje.

  1. using tj using MyClassRefinement aktywuje my_method udoskonalenia.
  2. MyClass.new.my_method zostaje wykonany.
  3. method lookup wynika z dokładnego punktu wywołania:

Gdy poszukuje się sposobu na przykład do class C Ruby kontrole:

  • przypadku udoskonalenia są aktywne C w odwrotnej zamówienie zostało aktywowane
    • Przedłużone moduły z wyrafinowania dla C
    • rafinacja na C
    • zawarte w nim moduły z procesu oczyszczania dla C
  • W poprzedzany moduły C
  • C
  • zawarte w nim moduły C
  1. Udoskonalenia są aktywne i my_method zwraca kod z wyrafinowaniem "refined my_method()"
  2. MyClass.new.another_method jest wykonywany.
  3. method lookup powstaje z dokładnego punktu inwokacji.
  4. Udoskonalenia są aktywne w tym momencie wywołania, ale another_method nie jest wyrafinowanie, tak Ruby szuka another_method w klasie MyClass i znajdzie.
  5. Wewnątrz metody klasy another_method, metoda my_method została znaleziona i wywołana.
  6. method lookup powstaje z dokładnego punktu inwokacji.
  7. W momencie wywołania nie ma żadnych poprawek, ponieważ nie było żadnych połączeń z usingpowyżej linii (tj. Fizycznie przed), gdzie wywoływana jest my_method. Ruby szuka my_method w klasie MyClass i znajduje to.
  8. my_method zwraca kod z metody klasy "original my_method()".

Możemy wykonać proste porównanie. Powiedzmy, że mam jeden wyizolowany file.rb z następującego kodu:

puts puppy 
puppy = 'waggle' 

puppy nie może być używany, zanim zostanie zdefiniowany. Zmienna jest określana leksykalnie, a jej użycie zależy od lokalizacji jej definicji w izolowanym file.rb.

Podobnie wyrafinowanie nie można powoływać się, dopóki nie zostanie aktywowana poprzez using na poprzedniej linii (lub gdzieś fizycznie poprzednie w pliku kodu źródłowego). Udoskonalenie to lexically scoped.

From Wikipedia

W językach z zakresem leksykalnym (zwany również statyczny zakres), rozdzielczość nazwa zależy od lokalizacji w kodzie źródłowym i kontekstem leksykalnym w , który jest określony przez gdzie nazwana zmienna lub funkcja jest zdefiniowana ...

Rozdzielczość leksykalna może być określona podczas kompilacji i jest również znana jako wczesne wiązanie, podczas gdy rozdzielczość dynamiczna może być na ogół określona tylko w czasie wykonywania, a zatem jest znana jako późne wiązanie .


Twój specyficzny problem z udoskonaleń jest omówione w ostatnim odcinku this article. Autor wyjaśnia również, w jaki sposób fizyczna lokalizacja oświadczenia using w pliku określa, czy udoskonalenie jest aktywne.

+0

Dziękujemy! Teraz ma to sens. Ustalenie leksykalne było prawdziwym winowajcą. – kstratis

+0

... a twoje referencje bardzo pomogły! – kstratis

+0

Nie ma problemu :) Cieszę się, że pomogło –