Module
Module erfüllen in Ruby zwei Zwecke: Namensräume und Mix-in-Funktionalität.
Ein Namensraum kann verwendet werden, um Code nach Paketen oder Funktionalitäten zu organisieren, was gemeinsame Namen vor Interferenzen durch andere Pakete schützt. Zum Beispiel bietet der IRB-Namensraum Funktionalitäten für irb, die Kollisionen für den gemeinsamen Namen „Context“ verhindern.
Mix-in-Funktionalität ermöglicht das Teilen gemeinsamer Methoden über mehrere Klassen oder Module hinweg. Ruby kommt mit dem Mix-in-Modul Enumerable, das viele Enumerationsmethoden basierend auf der each-Methode bereitstellt, und Comparable ermöglicht den Vergleich von Objekten basierend auf der <=>-Vergleichsmethode.
Beachten Sie, dass es viele Ähnlichkeiten zwischen Modulen und Klassen gibt. Neben der Möglichkeit, ein Modul als Mix-in zu verwenden, gilt die untenstehende Beschreibung von Modulen auch für Klassen.
Moduldefinition
Ein Modul wird mit dem Schlüsselwort module erstellt.
module MyModule # ... end
Ein Modul kann beliebig oft neu geöffnet werden, um Funktionalität hinzuzufügen, zu ändern oder zu entfernen.
module MyModule def my_method end end module MyModule alias my_alias my_method end module MyModule remove_method :my_method end
Das Neueröffnen von Modulen (oder Klassen) ist eine sehr mächtige Funktion von Ruby, aber es ist am besten, nur Module zu öffnen, die Ihnen gehören. Das Neueröffnen von Modulen, die Ihnen nicht gehören, kann zu Namenskollisionen oder schwer zu diagnostizierenden Fehlern führen.
Verschachtelung
Module können verschachtelt werden.
module Outer module Inner end end
Viele Pakete erstellen ein einziges äußerstes Modul (oder Klasse), um einen Namensraum für ihre Funktionalität bereitzustellen.
Sie können auch innere Module mit :: definieren, vorausgesetzt, die äußeren Module (oder Klassen) sind bereits definiert.
module Outer::Inner::GrandChild end
Beachten Sie, dass dies einen NameError auslöst, wenn Outer und Outer::Inner nicht bereits definiert sind.
Dieser Stil hat den Vorteil, dass der Autor die Einrückung reduzieren kann. Anstelle von 3 Einrückungsebenen ist nur eine notwendig. Der Geltungsbereich der Konstantenauflösung ist jedoch anders, wenn ein Namensraum mit dieser Syntax anstelle der ausführlicheren Syntax erstellt wird.
Scope
self
self bezieht sich auf das Objekt, das den aktuellen Geltungsbereich definiert. self ändert sich beim Betreten einer anderen Methode oder beim Definieren eines neuen Moduls.
Constants
Zugängliche Konstanten sind je nach Modulverschachtelung (welche Syntax zur Definition des Moduls verwendet wurde) unterschiedlich. Im folgenden Beispiel ist die Konstante A::Z von B aus zugänglich, da A Teil der Verschachtelung ist.
module A Z = 1 module B p Module.nesting #=> [A::B, A] p Z #=> 1 end end
Wenn Sie jedoch :: verwenden, um A::B zu definieren, ohne es in A zu verschachteln, wird eine Ausnahme NameError ausgelöst, da die Verschachtelung A nicht einschließt.
module A Z = 1 end module A::B p Module.nesting #=> [A::B] p Z #=> raises NameError end
Wenn eine Konstante auf der obersten Ebene definiert ist, können Sie ihr :: voranstellen, um darauf zu verweisen.
Z = 0 module A Z = 1 module B p ::Z #=> 0 end end
Methoden
Informationen zur Methodendefinition finden Sie in der Syntaxdokumentation für Methoden.
Klassenmethoden können direkt aufgerufen werden. (Dies ist etwas verwirrend, aber eine Methode eines Moduls wird oft als „Klassenmethode“ anstelle von „Modulmethode“ bezeichnet. Sehen Sie auch Module#module_function, das eine Instanzmethode in eine Klassenmethode umwandeln kann.)
Wenn eine Klassenmethode eine Konstante referenziert, verwendet sie dieselben Regeln wie die Referenzierung außerhalb der Methode, da der Geltungsbereich derselbe ist.
Instanzmethoden, die in einem Modul definiert sind, sind nur aufrufbar, wenn sie inkludiert werden. Diese Methoden haben über die Ahnenliste Zugriff auf die Konstanten, die zum Zeitpunkt ihrer Inklusion definiert wurden.
module A Z = 1 def z Z end end include A p self.class.ancestors #=> [Object, A, Kernel, BasicObject] p z #=> 1
Sichtbarkeit
Ruby hat drei Arten der Sichtbarkeit. Der Standard ist public. Eine öffentliche Methode kann von jedem anderen Objekt aufgerufen werden.
Die zweite Sichtbarkeit ist protected. Beim Aufruf einer geschützten Methode muss der Sender die Klasse oder das Modul erben, das die Methode definiert. Andernfalls wird ein NoMethodError ausgelöst.
Geschützte Sichtbarkeit wird am häufigsten verwendet, um == und andere Vergleichsmethoden zu definieren, bei denen der Autor den Zustand eines Objekts nicht für jeden Aufrufer preisgeben möchte und ihn nur auf geerbte Klassen beschränken möchte.
Hier ist ein Beispiel
class A def n(other) other.m end end class B < A def m 1 end protected :m end class C < B end a = A.new b = B.new c = C.new c.n b #=> 1 -- C is a subclass of B b.n b #=> 1 -- m called on defining class a.n b # raises NoMethodError A is not a subclass of B
Die dritte Sichtbarkeit ist private. Eine private Methode kann nur innerhalb der besitzenden Klasse ohne Empfänger oder mit einem literalen self als Empfänger aufgerufen werden. Wenn eine private Methode mit einem anderen Empfänger als einem literalen self aufgerufen wird, wird eine NoMethodError ausgelöst.
class A def without m end def with_self self.m end def with_other A.new.m end def with_renamed copy = self copy.m end def m 1 end private :m end a = A.new a.without #=> 1 a.with_self #=> 1 a.with_other # NoMethodError (private method `m' called for #<A:0x0000559c287f27d0>) a.with_renamed # NoMethodError (private method `m' called for #<A:0x0000559c285f8330>)
alias und undef
Sie können Methoden auch aliasen oder undefinieren, aber diese Operationen sind nicht auf Module oder Klassen beschränkt. Informationen dazu finden Sie im Abschnitt über sonstige Syntax.
Klassen
Jede Klasse ist auch ein Modul, aber im Gegensatz zu Modulen kann eine Klasse nicht in ein anderes Modul (oder eine andere Klasse) als Mix-in übernommen werden. Wie ein Modul kann eine Klasse als Namensraum verwendet werden. Eine Klasse erbt auch Methoden und Konstanten von ihrer Oberklasse.
Definition einer Klasse
Verwenden Sie das Schlüsselwort class, um eine Klasse zu erstellen.
class MyClass # ... end
Wenn Sie keine Oberklasse angeben, erbt Ihre neue Klasse von Object. Sie können von einer anderen Klasse erben, indem Sie < gefolgt von einem Klassennamen verwenden.
class MySubclass < MyClass # ... end
Es gibt eine spezielle Klasse BasicObject, die als leere Klasse konzipiert ist und ein Minimum an integrierten Methoden enthält. Sie können BasicObject verwenden, um eine unabhängige Vererbungsstruktur zu erstellen. Weitere Details finden Sie in der Dokumentation zu BasicObject.
Genau wie Module können auch Klassen neu geöffnet werden. Beim Neueröffnen einer Klasse können Sie deren Oberklasse weglassen. Die Angabe einer anderen Oberklasse als in der vorherigen Definition führt zu einem Fehler.
class C end class D < C end # OK class D < C end # OK class D end # TypeError: superclass mismatch for class D class D < String end
Vererbung
Jede Methode, die in einer Klasse definiert ist, kann von ihrer Unterklasse aufgerufen werden.
class A Z = 1 def z Z end end class B < A end p B.new.z #=> 1
Dasselbe gilt für Konstanten.
class A Z = 1 end class B < A def z Z end end p B.new.z #=> 1
Sie können die Funktionalität einer Methode der Oberklasse überschreiben, indem Sie die Methode neu definieren.
class A def m 1 end end class B < A def m 2 end end p B.new.m #=> 2
Wenn Sie die Funktionalität der Oberklasse aus einer Methode aufrufen möchten, verwenden Sie super.
class A def m 1 end end class B < A def m 2 + super end end p B.new.m #=> 3
Wenn super ohne Argumente verwendet wird, werden die Argumente verwendet, die an die Methode der Unterklasse übergeben wurden. Um keine Argumente an die Methode der Oberklasse zu senden, verwenden Sie super(). Um spezifische Argumente an die Methode der Oberklasse zu senden, übergeben Sie diese manuell, z. B. super(2).
super kann beliebig oft in der Methode der Unterklasse aufgerufen werden.
Singleton-Klassen
Die Singleton-Klasse (auch bekannt als Metaklasse oder Eigenklasse) eines Objekts ist eine Klasse, die Methoden nur für diese Instanz enthält. Sie können auf die Singleton-Klasse eines Objekts zugreifen, indem Sie class << object wie folgt verwenden.
class C end class << C # self is the singleton class here end
Am häufigsten wird die Singleton-Klasse wie folgt aufgerufen.
class C class << self # ... end end
Dies ermöglicht die Definition von Methoden und Attributen für eine Klasse (oder ein Modul), ohne def self.my_method schreiben zu müssen.
Da Sie die Singleton-Klasse jedes Objekts öffnen können, bedeutet dies, dass dieser Codeblock
o = Object.new def o.my_method 1 + 1 end
diesem Codeblock entspricht.
o = Object.new class << o def my_method 1 + 1 end end
Beide Objekte haben eine my_method, die 2 zurückgibt.