2016-04-22 6 views
1

Ich habe eine Ruby-Klasse C, die einige Module von Drittanbietern enthält, sagen A und B.In Ruby, ist es möglich, ein Modul nach oben der Kette zu bewegen?

Modul A ist indirekt über C Klassenvererbungskette enthalten; gehe davon aus, dass ich keine Kontrolle darüber habe, wo A enthalten ist. Jetzt schließt CB direkt, aber B enthält ein weiteres Modul D die Funktionalität bereitzustellen, geschieht das auch von A, wie dies vorgesehen ist:

class C < Base 

    # Base includes A 

    include B # includes D 

    # methods in A overridden by D 

end  

Die Vorläuferkette geht etwas ähnliches (wo ... für Null oder mehrere andere Vorfahren, die nicht relevant für diese Diskussion sind):

C ... B ... D ... A 

ich möchte, dass die Funktionalität von A precdence über D nehmen: ich möchtebewegenso ist es vor D in der Vorläuferkette, wie folgt aus:

C ... A ... B ... D 

Ich habe einfach versucht, einschließlich A wieder, aber das hat nicht funktioniert. Gibt es eine Möglichkeit, dies zu tun?

+0

Haben Sie [Mo dule # prepend'] (http://ruby-doc.org/core-2.3.0/Module.html#method-i-prepend)? – Myst

+0

P.S. Ich meinte, "A" vorangestellt und dann "B" .... Auch - wird das Hierarchierisiko die 'B'-Implementierung nicht ändern (was sich auf den ursprünglichen Vererbungsfluss beziehen könnte)? – Myst

+0

Es würde dieses Risiko geben, aber in diesem speziellen Szenario weiß ich, dass das Risiko nicht da ist. Ich habe nur das Problem, weil B etwas beinhaltet, was es nicht sollte. – starfry

Antwort

2

Es ist nicht möglich, die Mixin-Hierarchie zu ändern, sobald sie eingerichtet ist. Und nur die Einschlussreihenfolge bestimmt die Hierarchie. Sie haben A in C (zum ersten Mal) schließen, nachdem Sie B in C sind, oder, wenn Sie A-C statt einschließlich es vorangestellt wird, dann wird es Vorrang vor D hat, auch wenn B in C später enthalten ist.

+0

Ich habe der Frage ein Klassenbeispiel hinzugefügt. Ich habe viele Permutationen von 'include A' und' preven A' ohne Erfolg ausprobiert. – starfry

+1

Sie können ein Modul nicht mehrfach in die gleiche Klasse einschließen oder vormerken. Wie ich geschrieben habe, ist der Zeitpunkt der Aufnahme/Vorverlegung ** zum ersten Mal ** wichtig. – sawa

+0

Ah, ich verstehe dich, es ist das erste Mal.Das ist, was ich dachte und ich zog die Schlussfolgerung, dass Sie bestätigen, dass es nicht möglich ist. – starfry

1

Natürlich können Sie. Ich mache es täglich und zweimal am Sonntag. Nun, irgendwie ...

module A 
    def hiya(str) 
    puts "ho #{str}" 
    end 
    def if_what? 
    end 
end 

module D 
    def hiya(str) 
    puts "hi #{str}" 
    end 
    def what_if? 
    end 
end 

module B 
    include D 
end 

class C 
    include A 
    include B 
end 

Wie erwartet:

C.ancestors 
    #=> [C, B, D, A, Object, Kernel, BasicObject] 
a = C.new 
    #=> #<C:0x007fc56324ed40> 
a.hiya("Lois") 
hi Lois 

Um A 's Instanzmethoden statt D' s rufen wir schreiben können:

(A.instance_methods & D.instance_methods).each { |m| D.send(:remove_method, m) } 

Mal sehen:

D.instance_methods 
    #=> [:hiya, :what_if?] 
(A.instance_methods & D.instance_methods).each { |m| D.send(:remove_method, m) } 
    #=> [:hiya] 
D.instance_methods 
    #=> [:what_if?] 
C.instance_methods.include?(:hiya) 
    #=> true 
a.hiya("Lois") 
ho Lois 
+0

Ich habe das versucht und es funktioniert, aber es ändert nicht die Vorfahrenkette - es entfernt die Methode aus dem Modul, die sich auf etwas anderes auswirkt, das es verwendet. Gibt es eine Möglichkeit, die Wirkung im Rahmen der Klasse "C" zu erreichen, so dass andere Klassen einschließlich "D" nicht betroffen sind? – starfry

+0

Das meinte ich mit "Naja, so ...". @sawa hatte bereits erklärt, dass die Ahnenkette nicht neu geordnet werden kann (die Antwort auf deine Frage), also gab es nichts mehr darüber zu sagen. Ich zeigte dir nur etwas, was du tun könntest, das die gleiche Wirkung hätte wie du willst machen. Ich verstehe nicht, was Sie mit anderen Klassen im Rahmen der Klasse "C" meinen. Klassen können keine Klassen enthalten. –

+0

Was ich meinte war, könnte die Methode Entfernung von 'D'l auf seine Aufnahme in die Klasse' C' beschränkt werden, so dass andere Klassen einschließlich 'D' nicht betroffen sind. Ich fragte nur, falls Sie etwas wussten, aber ich merke das es ist das gleiche "D" in allen Ahnenketten aller Klassen und dass eine Änderung von "D" alle Klassen mit "D" als Vorfahre betreffen würde. – starfry

Verwandte Themen