Tatsächlich gibt es einige andere Möglichkeiten, einer Klasse neue Methoden hinzuzufügen. Zum Beispiel können Sie auch die Methoden in einem Modul definieren und das Modul in die ursprüngliche Klasse mischen.
module ExtraMethods
def bar
end
end
Foo.class_eval { include ExtraMethods }
class Foo
include ExtraMethods
end
Es gibt kein wirklich besseres oder schlechteres. Die zwei (oder drei) Wege, die Sie erwähnten, haben ein unterschiedliches Verhalten und Sie möchten vielleicht das eine oder andere verwenden, je nach Ihrem Bedarf (oder Ihrer Präferenz). In den meisten Fällen ist dies subjektiv. In anderen Fällen hängt es wirklich davon ab, wie Ihr Code strukturiert ist.
Der Hauptzielunterschied zwischen dem erneuten Öffnen der Klasse vs class_eval
ist, dass die erste auch eine Klassendefinition ist, während die zweite die ursprüngliche Klasse bereits definiert erfordert.
In der Praxis kann das erneute Öffnen der Klasse in einigen Fällen zu unerwarteten Nebenwirkungen führen. Nehmen wir an, Sie haben Foo
in der Datei lib/foo.rb
mit einer Reihe von Methoden definiert. Dann öffnen Sie erneut Foo
in config/initializers/extra.rb
und fügen Sie die bar
Methode hinzu.
In verwenden Sie Foo
, aber statt lib/foo.rb
manuell benötigen Sie eine Autoload-Funktion.
Wenn extra.rb
vor lib/foo.rb
geladen wird, was passieren könnte, ist, dass die Foo
Klasse bereits in Ihrer Umgebung definiert ist, und der Code wird lib/foo.rb
nicht geladen werden. Was Sie haben werden, ist eine Foo
Klasse, die nur die bar
Erweiterung enthält, die Sie definiert haben, und nicht das Original Foo
eins. Wenn Sie also aus irgendeinem Grund die Klasse erneut öffnen, um einige Methoden hinzuzufügen, ohne sicherzustellen, dass die vollständige Originalklassendefinition zuerst (oder danach) geladen wird, kann Ihr Code brechen, wenn er auf Autoload angewiesen ist.
Umgekehrt ruft Foo.class_eval
eine Methode auf Foo
auf, daher erwartet es die ursprüngliche Foo
-Definition, die zu dem Zeitpunkt bereits vorhanden ist, an dem Sie versuchen, neue Methoden hinzuzufügen. Dadurch wird sichergestellt, dass beim Hinzufügen neuer Methoden die Klasse Foo
bereits definiert ist. Der wichtigste Unterschied besteht darin, dass das Wiedereröffnen der Klasse es Ihnen erlaubt (zu guter oder schlechter) Methoden zu einer Klasse hinzuzufügen, die noch nicht geladen wurde, während class_eval
erfordert, dass die Klasse bereits definiert wird.
Im Allgemeinen, wenn ich namespaced Unterklassen oder Klassen wiedereröffnen definiere ich volle Kontrolle über, bevorzuge ich den zweiten Ansatz wie in großen Codebasen hält es den Code wartungsfähiger. In der Tat verwende ich in der Regel Mixins, wenn ich Klassen von Drittanbietern erweitere, so dass ich die vollständige Vorfahrenkette der Methode behalten kann, wenn ich bestehende Methoden überschreiben muss.
['Foo # define_method'] (http://ruby-doc.org/core-2.0/Module.html#method-i-define_method) auch. – mudasobwa