Czytałem kilka artykułów o metodach mieszania Rubiego, extend
i include
i nadal nie jestem do końca pewien co do tego zachowania. Rozumiem, że extend
doda metody instancji danego modułu jako metody singleton do modułu wykonującego rozszerzenie i że include
będzie zasadniczo dołączać zawartość modułu (metody, stałe, zmienne) do tego, co robi, włączając, definiując efektywnie ich w odbiorniku.Mieszanki rubinowe: rozszerz i włącz
Jednak po kilku majsterkowaniu, próbując zrozumieć, jak to się przejawi, mam kilka pytań. Oto moja konfiguracja testowania:
module Baz
def blorg
puts 'blorg'
end
end
module Bar
include Baz
def blah
puts 'blah'
end
end
module Foo
extend Bar
end
class Bacon
extend Bar
end
class Egg
include Bar
end
Tak jak bym się spodziewał, moduł Bar
zyskuje metody instancji zdefiniowane w Baz
(#blorg
), jak gdyby one zostały zdefiniowane w sobie ze względu na metodę integracji, a klasy Bacon
zyski metody singleton Bacon::blah
i Bacon::blorg
według rozszerzenia.
Bacon.blah # => blah
Bacon.blorg # => blorg
I klasa Egg
zyski metodach określonych w Bar
(#blah
a teraz #blorg
) jako metody instancji.
Egg.new.blah # => blah
Egg.new.blorg # => blorg
Dostaję to wszystko, więc to dobrze.
Jednak nie rozumiem odpowiedzi uzyskanych dzięki zastosowaniu metod #ancestors
i #is_a?
.
Bacon.ancestors # => [Bacon, Object, Kernel, BasicObject]
Bacon.is_a? Bar # => true
Egg.ancestors # => [Egg, Bar, Baz, Object, Kernel, BasicObject]
Egg.is_a? Bar # => false
Wydaje się, że rozszerzenie modułu powoduje sposób #is_a?
powrotu true
po zapytaniu o modułu i nie dodaje się do protoplastów klasy i vice versa w odniesieniu do integracji: przodkowie klasa zawiera moduły dołączone, ale metoda #is_a?
zwraca false
podczas zapytania. Dlaczego to się dzieje?
+1 za świetny format tego pytania. – sargas