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
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
Okay, Update Lösung dann. Es ist nur ein bisschen komplexer – Burke
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