2016-05-26 16 views
2

Betrachten Sie das folgende Ruby-Beispiel einer Klasse, die ein Modul enthält, das eine Klassen- und Instanzmethode definiert, und eine zweite Klasse, die die erste Klasse erbt.Kann ein Ruby-Modul Klassenmethoden definieren, so dass sie auch funktionieren, wenn das Modul verschachtelt ist?

module Z 
    def self.included(base) 
    class << base 
     def classmethod 
     puts "Hello, I'm #{__method__} in #{self}" 
     end 
    end 
    end 
    def instancemethod 
    puts "Hello, I'm #{__method__} in #{self}" 
    end 
end 

class A 
    include Z 
end 

class B < A 
end 

A.classmethod 
A.new.instancemethod 
B.classmethod 
B.new.instancemethod 

Die Ausgabe ist wie erwartet: Klassen und Instanzen verfügen über die vom Modul definierten Methoden.

Hello, I'm classmethod in A 
Hello, I'm instancemethod in #<A:0x85f4c10> 
Hello, I'm classmethod in B 
Hello, I'm instancemethod in #<B:0x85f4968> 

Betrachten Sie nun das Szenario, in dem das obige Modul in einem anderen Modul enthalten ist, welche Klassen umfassen statt:

module Y 
    include Z 
end 

class C 
    include Y 
end 

class D < C 
end 

Y.classmethod 
C.classmethod 
C.new.instancemethod 
D.classmethod 
D.new.instancemethod  

Die Instanzmethoden arbeiten, aber die Klassenmethoden auf C und D nicht (die ist stattdessen definiert, wo es nicht gewünscht ist, auf dem Intermediate-Modul Y).

Kann Z das Modul modifed werden, so dass Klassenmethoden zur Klasse hinzugefügt werden C eher als das Zwischenmodul, Y?

Das ursprüngliche Szenario (d. H. Wo das Modul nicht verschachtelt ist) sollte auch weiterhin wie oben funktionieren.

+0

Aufruf 'include' auf einem' module' dass Zufälliges vorheriges Einfügen von etwas bedeutet nicht, dass Sie die 'include'-Abhängigkeit erhalten, um sich zu verketten. Das Einbinden eines Moduls in ein Modul entspricht nicht ganz dem, was Sie erwarten. – tadman

+0

Würdest du eine Antwort akzeptieren, die etwas anderes als 'include Z' beinhaltet? – Raffael

+1

'ActiveSupport :: Concern 'kann Ihnen hier helfen (sowohl Z als auch Y müssten es erweitern). Ist das eine Option für dich? – Raffael

Antwort

0

Versuchen Sie es.

module Y 
    def self.included(base) 
    Z.included(base) 
    end 
end 

class C 
    include Y 
end 

class D < C 
end 

Y.classmethod 
    #=> NoMethodError: undefined method `classmethod' for Y:Module 

C.classmethod 
    #=> Hello, I'm classmethod in C 

C.new.instancemethod 
    #=>Hello, I'm instancemethod in #<C:0x007ff58403d370> 

D.classmethod 
    #=> Hello, I'm classmethod in D 

D.new.instancemethod  
    #=> Hello, I'm instancemethod in #<D:0x007ff5842478f0> 

Vier von fünf sind nicht schlecht, oder? Ich habe jetzt keine Zeit mehr, aber werde sehen, ob ich Y.classmethod zum Arbeiten bekommen kann. Vielleicht hat ein Leser einen Vorschlag.

+0

Das ist großartig. 'Y.classmethod' wird nicht benötigt. Ich werde das morgen testen. Ich habe so etwas gemacht, aber ich muss etwas falsch gemacht haben. Es erfordert, dass "Y" geändert wird, aber ich bezweifle, dass das vermieden werden kann. – starfry

0

@ cary-swoveland Idee mich dazu gebracht, dies zu versuchen, die das ursprüngliche Problem löst: Es ist eine Modifikation Z, das funktioniert, wenn es verschachtelt ist:

module Z 
    def self.included(base) 
    class << base 
     def classmethod 
     puts "Hello, I'm #{__method__} in #{self}" 
     end 
     def included(base) 
     Z.included(base) 
     end 
    end 
    end 
    def instancemethod 
    puts "Hello, I'm #{__method__} in #{self}" 
    end 
end