Die Programmiersprache Ruby (German Edition)
Gültigkeitsbereichs gelten und daher während dieser Phase des Konstanten-Lookups nicht berücksichtigt werden. Die Klassenmethode
Module.nesting
liefert die Liste mit Klassen und Modulen zurück, die in diesem Schritt durchsucht werden — in der entsprechenden Suchreihenfolge.
Wenn im lexikalischen Gültigkeitsbereich keine Konstantendefinition gefunden wird, versucht Ruby als Nächstes, die Konstante in der Vererbungshierarchie aufzulösen, indem es die Vorfahren der Klasse oder des Moduls prüft, in der oder dem die Konstante referenziert wird. Die Methode
ancestors
der enthaltenden Klasse oder des Moduls liefert die Liste der Klassen und Module zurück, die in diesem Schritt durchsucht werden.
Wenn in der Vererbungshierarchie keine Kosntantendefinition gefunden wird, werden die Konstantendefinitionen auf oberster Ebene geprüft.
Wenn für die gewünschte Konstante keine Definition gefunden werden kann, wird die Methode
const_missing
für die Klasse oder das Modul aufgerufen — sofern es eine gibt — um damit eventuell einen Wert für die Konstante zu ermitteln. Dieser Hook
const_missing
wird in Kapitel 8 behandelt und Listing 8.3 macht die Verwendung deutlich.
Es gibt ein paar Punkte beim Algorithmus zum Lookup von Konstanten, auf die hingewiesen werden soll:
Konstanten, die in umhüllenden Modulen gefunden werden, werden gegenüber Modulen bevorzugt, die eingebunden sind.
Die Module, die von einer Klasse eingebunden werden, werden durchsucht, bevor die Superklasse der Klasse an der Reihe ist.
Die Klasse
Object
ist Teil der Vererbungshierarchie aller Klassen. Konstanten auf oberster Ebene, die außerhalb einer Klasse oder eines Moduls definiert wurden, verhalten sich wie Methoden auf oberster Ebene: Sie sind implizit in
Object
definiert. Wenn eine Konstante auf oberster Ebene innerhalb einer Klasse referenziert wird, wird sie deshalb im Rahmen des Suchens in der Vererbungshierarchie aufgelöst. Wenn die Konstante hingegen innerhalb einer Moduldefinition referenziert wird, ist eine explizite Prüfung von
Object
notwendig, nachdem die Vorfahren des Moduls durchsucht wurden.
Das Modul
Kernel
ist ein Vorfahr von
Object
. Daher verhalten sich Konstanten, die in
Kernel
definiert sind, wie Konstanten auf oberster Ebene. Sie können aber durch echte Konstanten auf oberster Ebene überschrieben werden, da diese in
Object
definiert sind.
Listing 7.1 definiert und löst Konstanten in sechs verschiedenen Gültigkeitsbereichen auf und führt den oben beschriebenen Algorithmus zur Namensauflösung von Konstanten vor.
module Kernel
# Konstanten definiert in Kernel
A = B = C = D = E = F = "definiert in Kernel"
end
# Konstanten auf oberster Ebene oder "global", definiert in Object
A = B = C = D = E = "definiert auf oberster Ebene"
class Super
# Konstanten definiert in einer Superklasse
A = B = C = D = "definiert in Superklasse"
end
module Included
# Konstanten definiert in einem eingebundenen Modul
A = B = C = "definiert in eingebundenem Modul"
end
module Enclosing
# Konstanten definiert in einem umhüllenden Modul
A = B = "definiert in umhüllendem Modul"
class Local < Super
include Included
# Lokal definierte Konstante
A = "definiert lokal"
# Die Liste der durchsuchten Module in Suchreihenfolge
# [Enclosing::Local, Enclosing, Included, Super, Object, Kernel]
search = (Module.nesting + self.ancestors + Object.ancestors).uniq
puts A # Ausgabe: "definiert lokal"
puts B # Ausgabe: "definiert in umhüllendem Modul"
puts C # Ausgabe: "definiert in eingebundenem Modul"
puts D # Ausgabe: "definiert in Superklasse"
puts E # Ausgabe: "definiert auf oberster Ebene"
puts F # Ausgabe: "definiert in Kernel"
end
end
Listing 7.1 Namensauflösung von Konstanten
----
[ 27 ] Wenn Sie Java-Programmierer sind, mag das überraschend für Sie sein. Java-Klassen definieren spezielle Konstruktormethoden für die Initialisierung, die nicht vererbt werden. In Ruby ist
initialize
eine normale Methode und wird wie jede andere Methode vererbt.
[ 28 ] Die Methode
Class.new
ist eine Ausnahme – sie wird an so gut wie jede neue Klasse, die Sie definieren, vererbt und dort aufgerufen.
[ 29 ] Um das C-Programmierern deutlicher zu machen:
load
und
require
sind anders als die C-Direktive
#include
. Näher heran an deren Verhalten kommt man, wenn man der globalen Funktion
eval
den Inhalt einer Datei übergibt:
eval(File.read(filename))
. Aber selbst das ist nicht gleich, da
eval
keine lokalen Variablen setzt.
Kapitel 8.
Weitere Kostenlose Bücher