2015-11-21 21 views
8

Próbuję lepiej zrozumieć, jak moduły się rozszerzają i wzajemnie uwzględniają.Ruby: moduły rozszerzające/zawierające moduły

Say mam moduł :

module A 
    def learned_from_A 
    true 
    end 
end 

A.instance_methods # [:learned_from_A] 

mieszam swój worek sztuczek w B:

module B 
    extend A 
end 

B.learned_from_A # true 

ja naiwnie próba nadania C wszystkiemu B ma :

module C 
    extend B 
end 

C.learned_from_A # NoMethodError 

Myślę, że owinąłem to. Gdy B rozciąga kopie metod przykład są związane z B przez B. klasy jednoelementowy:

B.singleton_methods # [:learned_from_A] 

Podczas : learned_from_A jest wywoływalny na B, nie jest jednym z B jest przykład sposoby, tak jeśli C rozciąga B, : learned_from_A to nie skopiowany do C.


Jeśli B miał zamiast zawarte, kopie metod przykład byłby już zostały zaliczone własnych metod instancji przez B.

module B 
    include A 
end 

B.instance_methods # [:learned_from_A] 

Następnie C może rozciągać B, i wszystkie sposoby przykład przez B (włącznie : learned_from_A) będą skopiowane i związany C.

module C 
    extend B 
end 

C.singleton_methods # [:learned_from_A] 

Aby : learned_from_A wywoływalny zarówno BiC, B może rozciągać i obejmują .

module B 
    include A 
    extend A 
end 

B.instance_methods # [:learned_from_A] 
B.singleton_methods # [:learned_from_A] 

module C 
    extend B 
end 

C.instance_methods # [] 
C.singleton_methods # [:learned_from_A] 

bardziej realistycznie, jeśli chcę metody „s być wpłacone na B, a dla B zdefiniować inną metodę własnych, i móc mieszać cały repertuar do C, nie mogę tego zrobić:

module B 
    extend A 
    include A 

    def self.buzz 
    true 
    end 
end 

module C 
    extend B 
end 

B może udostępniać tylko swoje metody instancji, a nie pojedyncze metody. Tak, aby metodę zarówno wpłacone na B i udostępniania do innych obiektów, musi być zdefiniowana jako metody instancji i przedłużony do B samego:

module B 
    extend A 
    include A 

    extend self 

    def buzz 
    true 
    end 
end 

module C 
    extend B 
end 

Było sporo prób i błąd w łączeniu tego wszystkiego. Czy to dokładny sposób patrzenia na to, co się dzieje?

+0

Czy istnieje sposób na uproszczenie pytania? Nawet jeśli miałbyś to wyjaśnić, z różnymi debugowanymi scenariuszami. – onebree

+0

Myślę, że możesz pomylić zmianę zakresu jaźni, gdy rozszerzasz A wewnątrz B, a następnie spodziewasz się, że C będzie miał A. Zmieniasz zakres. Istnieje również #prepend, który można wywołać. Aby zobaczyć, jak zmieniają się te zakresy, wywołaj metodę $ antenowe w klasie. –

+1

Wygląda na to, że chcesz zadzwonić zarówno do mamy, jak i córki o tej samej nazwie: P –

Odpowiedz

2

mieszam swój worek sztuczek do B

To zdanie i Twoje pytanie w ogóle mnie, że istnieje trochę nieporozumienie w pojęciu include/extend rzeczy. Przepraszam z góry, ponieważ nie w pełni rozumiem pytanie.

Na przykład masz taki moduł:

module A 
    def a 
    puts "a" 
    end 

    def self.b 
    puts "b" 
    end 
end 

Jak widać istnieją 2 rodzaje metod:

  • singleton_methods
  • instance_methods

Oto najprostszy sposób, aby pokazać, że rzeczywiście różnią:

A.singleton_methods 
=> [:b] 
A.instance_methods 
=> [:a] 
A.a 
NoMethodError: undefined method `a' for A:Module 
A.b 
b 
=> nil 

Jeśli nie include A Upraszczając dodajesz swoje wystąpienie metody bieżącego modułu instancji metody. Po przeprowadzeniu operacji uproszczonej extend A dodaje się metody instancji do metod bieżącego modułu singleton.

module B 
    include A 
end 

module C 
    extend A 
end 

B.instance_methods 
=> [:a] 
B.singleton_methods 
=> [] 
C.instance_methods 
=> [] 
C.singleton_methods 
=> [:a] 

Jeszcze jedna rzecz do powiedzenia to, że można extend self ale nie include self jako że nie ma żadnego sensu, a także podnieść wyjątek.

module D 
    extend self 

    def a 
    puts "a" 
    end 

    def self.b 
    puts "b" 
    end 
end 

D.singleton_methods 
=> [:b, :a] 
D.instance_methods 
=> [:a] 
D.a 
a #no error there because we have such singleton method 
=> nil 

Sądzę, że te rzeczy mogą ci pomóc.Jest wiele pytań dotyczących extend/include na StackOverflow, które możesz sprawdzić (example).

+1

Dobra odpowiedź! Przypuszczam, że pewnie coś przypadkowo się zmieniło. Jedno z powyższych stwierdzeń powinno brzmieć: "Kiedy robisz" rozszerzenie A' w sposób uproszczony, dodajesz jego metody ** instancji ** do bieżącego modułu ** metody singleton **. " (* "instancja" * i "* singleton *" są zamieniane w odpowiedzi) – ivan

+0

@ivan Dzięki, dobry punkt. –