2012-04-04 4 views

Antwort

1

Wenn das Überschreiben vorhandener Funktionen hier eine schwierige Anforderung darstellt, müssen diese vorhandenen Methoden in einem Modul definiert sein, das ebenfalls enthalten ist.

class SomeClass 
    include DefaultBehaviour 
end 

module DefaultBehaviour 
    def run 
    puts "ran default" 
    end 
end 

module AlternateBehaviour 
    def run 
    puts "ran alternate" 
    end 
end 

SomeClass.class_eval { 
    include AlternateBehaviour 
} 

SomeClass.new.run #=> "ran alternate" 

Der Grund dafür ist wegen der Ruby-Methode Lookup-Pfad.

Es beginnt als SomeClass -> Objekt.

Wenn Sie AlternateBehaviour einschließen, wird SomeClass -> AlternateBehaviour -> Object. Daher haben Methoden, die direkt in SomeClass definiert sind, Vorrang.

Wenn diese Methoden jedoch auf DefaultBehaviour definiert sind, wird der Suchpfad SomeClass -> AlternateBehaviour -> DefaultBehaviour -> Object, sodass Ihre alternative Methode Priorität hat. Das zuletzt verwendete Modul hat die höchste Priorität.

In dem Fall, dass Sie nicht die Kontrolle der ursprünglichen Klasse, können Sie stattdessen:

module AlternateBehaviour 
    def self.included(base) 
    base.send(:remove_method, :run) 
    end 

    def run 
    puts "ran alternate" 
    end 
end 

Obwohl an diesem Punkt beginnt man sich zu fragen, ob Sie nur besser sein könnten von

tun
SomeClass.class_eval { 
    def run 
    "ran alternate" 
    end 
end 
+0

Die Komplikation kommt, wenn die Klassenmethode, die ich versuche zu überschreiben, in irgendeinem 3rd Party Engine Code liegt, den ich nicht in Modul umbauen kann ... :(Sonst funktioniert deine Lösung ... – alexs333

+0

Okay, Update Lösung dann. Es ist nur ein bisschen komplexer – Burke

+0

Warum müssen Sie class_eval verwenden?Sie können die Methodendefinitionen einfach direkt in class_eval ablegen. Wenn Sie möchten, dass die Ersetzungsmethoden an anderer Stelle gespeichert werden, können Sie ein Modul erstellen, das die vorhandenen Methoden vor dem Definieren von Ersetzungen entfernt. – Burke

0

Versuchen Sie mit include und extend, beide erklärt here. Sie arbeiten nur mit Modulen; Sie nur kann nicht Superklassen einer Klasse in Ruby ändern/hinzufügen, nachdem es bereits erstellt wurde.

Nur ein Problem: Sie können nicht bereits vorhandene Methoden in einer Klasse für die in dem dritten Kommentar zu diesem Beitrag erläuterten Klasse überschreiben.

Weitere Informationen finden Sie unter this Thema.

+0

Wie würde ich in der Situation gehen, wenn ich bereits eine Klasse habe und möchte es Methoden aus, was im externen Modul definiert ist überschreiben? – alexs333

+0

Aktualisiere Beitrag ... – Jwosty

+0

Module funktionieren nicht, um die in der Klasse selbst angegebene Funktionalität zu überschreiben, da Ruby die Vererbungshierarchie zurückverfolgt, um Methoden zu finden, und eine Methode fügt dieses Modul einfach in die Hierarchie direkt über der Klasse ein. Die Klasse selbst ist immer noch der erste Ort, der überprüft wird. ... obwohl ich Jwosty immer noch zustimmen würde, dass dies die richtige Lösung für dieses Problem ist. Wenn Sie Methoden, die bereits für die Klasse definiert sind, wirklich überschreiben müssen, können Sie dies lösen, indem Sie sie auf ihrem eigenen Modul definieren. – Burke