Die Programmiersprache Ruby (German Edition)
stellt eine leistungsfähige Möglichkeit zur Verfügung, beliebige Aufrufe für ein Objekt abzufangen und zu verarbeiten. Die Methode
const_missing
von
Module
erfüllt eine ähnliche Funktion für den Konstanten-Lookup-Algorithmus und erlaubt uns das Berechnen oder nachlässige Initialisieren von Konstanten on-the-fly. Die nachfolgenden Beispiele demonstrieren beide Methoden.
8.9.1 Unicode-Codepunktkonstanten mit const_missing
Listing 8.3 definiert ein
Unicode
-Modul, das eine Konstante für jeden Unicode-Codepunkt von
U+0000
bis
U+10FFFF
zu definieren scheint. Die einzige praktische Möglichkeit, so viele Konstanten zu unterstützen, besteht darin, die Methode
const_missing
zu verwenden. Der Code geht von der Annahme aus, dass eine einmal referenzierte Konstante wahrscheinlich erneut verwendet wird, so dass die Methode
const_missing Module.const_set
aufruft, um für jeden berechneten Wert eine echte Konstante zu definieren, auf die verwiesen werden kann.
# Dieses Modul stellt Konstanten bereit, die UTF-8-Strings für alle
# Unicode-Codepunkte definieren. Es verwendet const_missing, um
# sie bei Bedarf zu definieren.
# Beispiele:
# copyright = Unicode::U00A9
# euro = Unicode::U20AC
# infinity = Unicode::U221E
module Unicode
# Diese Methode erlaubt uns die bequeme Definition von Unicode-
# Codepunktkonstanten.
def self.const_missing(name) # Undefinierte Konstante als Symbol
# Überprüfen, ob der Konstantenname die richtige Form hat.
# Großes U, gefolgt von Hexzahl zwischen 0000 und 10FFFF
if name.to_s =~ /^U([0-9a-fA-F]{4,5}|10[0-9a-fA-F]{4})$/
# $1 ist die gefundene Hexadezimalzahl. In Integer konvertieren.
codepoint = $1.to_i(16)
# Die Zahl mit Array.pack-Magie in UTF-8-String konvertieren.
utf8 = [codepoint].pack("U")
# Den UTF-8-String unveränderlich machen.
utf8.freeze
# Eine echte Konstante für schnelleres Nachschlagen
# definieren und diesmal den UTF-8-Text zurückgeben.
const_set(name, utf8)
else
# Einen Fehler für Konstanten in der falschen Form auslösen.
raise NameError, "Unbekannte Konstante: Unicode::#{name}"
end
end
end
Listing 8.3 Unicode-Codepunkt-Konstanten mit const_missing
8.9.2 Tracing von Methodenaufrufen mit method_missing
Weiter oben in diesem Kapitel haben wir eine Erweiterung der Klasse
Hash
mithilfe von
method_missing
demonstriert. Jetzt, in Listing 8.4 , demonstrieren wir, wie man die Verwendung von
method_missing
von einem Objekt an ein anderes Objekt delegiert. In diesem Beispiel tun wir dies, um Tracking-Meldungen für das Objekt auszugeben.
Listing 8.4 definiert die Instanzmethode
Object.trace
und die Klasse
TracedObject
. Die Methode
trace
gibt eine Instanz von
TracedObject
zurück, um Aufrufe abzufangen, zu überwachen und an das überwachte Objekt zu delegieren. Sie könnten sie wie folgt verwenden:
a = [1,2,3].trace("a")
a.reverse
puts a[2]
puts a.fetch(3)
Dies erzeugt die folgende Tracing-Ausgabe:
Aufruf: a.reverse() in trace1.rb:66
Rückgabe: [3, 2, 1] aus a.reverse an trace1.rb:66
Aufruf: a.fetch(3) in trace1.rb:67
Fehler: IndexError:index 3 out of array in a.fetch
Beachten Sie, dass Listing 8.4 neben
method_missing
auch
Module.instance_methods
,
Module.undef_method
und
Kernel.caller
demonstriert.
# Rufen Sie die Methode trace eines beliebigen Objekts auf, um
# ein neues Objekt zu erhalten, das sich genau wie das Original
# verhält, aber alle Methodenaufrufe für das Objekt überwacht.
# Wenn Sie mehr als ein Objekt überwachen, geben Sie einen Namen
# an, der in der Ausgabe erscheinen soll. Standardmäßig werden
# Nachrichten an STDERR gesendet, aber Sie können jeden Stream
# (oder jedes Objekt, das Strings als Argumente für << akzeptiert)
# angeben.
class Object
def trace(name="", stream=STDERR)
# Ein TracedObject zurückgeben, das alles andere an uns delegiert.
TracedObject.new(self, name, stream)
end
end
# Diese Klasse verwendet method_missing zum Tracing von Methoden-
# aufrufen und delegiert diese dann an ein anderes Objekt. Sie löscht die
# meisten ihrer eigenen Instanzmethoden, damit sie method_missing
# nicht im Weg stehen. Beachten Sie, dass nur Methoden überwacht
# werden, die durch das TracedObject aufgerufen werden. Wenn das
# Delegate-Objekt Methoden in sich selbst aufruft, findet für diese
# Aufrufe kein Tracing statt.
class TracedObject
# Definition aller nichtkritischen öffentlichen Instanzmethoden aufheben.
# Achten Sie auf die Verwendung von Module.instance_methods und
# Module.undef_method.
Weitere Kostenlose Bücher