2012-10-28 10 views
6

Używam Ruby 1.9.2 i klejnot Ruby on Rails v3.2.2. Chciałbym "zagnieżdżać" włączenie modułów, ponieważ korzystam z funkcji RoR ActiveSupport::Concern, ale mam wątpliwości, gdzie powinienem podać metodę include. To znaczy, mam następujący:Jak "zagnieździć" się włączenie modułów podczas korzystania z funkcji Ruby on Rails ActiveSupport :: Concern?

module MyModuleA 
    extend ActiveSupport::Concern 

    # include MyModuleB 

    included do 
    # include MyModuleB 
    end 
end 

Gdyby Oświadczam include MyModuleB w „ciele”/„kontekst”/„zakres” od MyModuleA lub należy stwierdzić, że w bloku included do ... end? Jaka jest różnica i czego powinienem się spodziewać?

+0

Pamiętaj, że nie jest to dobra praktyka w ogóle. Możesz uzyskać fałszywe zależności między kolejnością włączania modułów. – geekazoid

Odpowiedz

16

Jeśli umieścisz MyModuleB w "ciele" MyModuleA, to sam moduł zostanie rozszerzony o funkcje B. Jeśli umieścisz go w bloku included, zostanie on dołączony do klasy, która łączy się w MyModuleA.

Czyli:

module MyModuleA 
    extend ActiveSupport::Concern 
    include MyModuleB 
end 

produkuje coś takiego:

MyModuleA.send :include, MyModuleB 
class Foo 
    include MyModuleA 
end 

podczas

module MyModuleA 
    extend ActiveSupport::Concern 
    included do 
    include MyModuleB 
    end 
end 

produkuje coś takiego:

class Foo 
    include MyModuleA 
    include MyModuleB 
end 

Powodem tego jest to, że ActiveSupport::Concern::included jest analogiczna do:

def MyModuleA 
    def self.included(klass, &block) 
    klass.instance_eval(&block) 
    end 
end 

Kod w bloku included prowadzony jest w tym kontekście klasy, zamiast kontekście modułu. Tak więc, jeśli MyModuleB potrzebuje dostępu do klasy, do której jest wprowadzany, to chciałbyś ją uruchomić w bloku included. W przeciwnym razie jest to faktycznie to samo.

Poprzez demonstracji:

module A 
    def self.included(other) 
    other.send :include, B 
    end 
end 

module B 
    def self.included(other) 
    puts "B was included on #{other.inspect}" 
    end 
end 

module C 
    include B 
end 

class Foo 
    include A 
end 

# Output: 
# B was included on C 
# B was included on Foo 
+0

Dziękuję. Otworzyłem [nowe powiązane pytanie] (http://stackoverflow.com/questions/13110749/how-to-make-methods-added-by-inclusion-of-a-nested-module-to-be-instance) o metodach. – Backo

Powiązane problemy