Die Programmiersprache Ruby (German Edition)
aufrufen
end
def load(*args)
ClassTrace::T << [args[0],caller[0]] # Merken, was wo geladen wurde
original_load(*args) # Originalmethode aufrufen
end
# Diese Hook-Methode wird jedes Mal aufgerufen, wenn eine
# neue Klasse definiert wird.
def Object.inherited(c)
ClassTrace::T << [c,caller[0]] # Merken, was wo definiert wurde
end
# Kernel.at_exit registriert einen Block, der beim Beenden des
# Programms ausgeführt wird. Wir verwenden ihn, um die
# gesammelten Datei- und Klassendaten zu melden
at_exit {
o = ClassTrace::OUT
o.puts "="*60
o.puts "Geladene Dateien und definierte Klassen:"
o.puts "="*60
ClassTrace::T.each do |what,where|
if what.is_a? Class # Klassendefinition (mit Hierarchie)
o.puts "Definiert: #{what.ancestors.join('<-')} at #{where}"
else # Laden einer Datei melden
o.puts "Geladen: #{what} at #{where}"
end
end
}
Listing 8.8 Das Laden von Dateien und die Definition von Klassen überwachen
8.11.2 Methodenverkettung zur Thread-Sicherheit
Zwei frühere Beispiele in diesem Kapitel haben sich mit Thread-Sicherheit beschäftigt. In Listing 8.2 wurde eine
synchronized
-Methode (basierend auf einer
Object.mutex
-Methode) definiert, die einen Block unter dem Schutz eines
Mutex
-Objekts ausführt. Danach wurde die Methode
synchronized
in Listing 8.5 so neu definiert, dass sie bei Aufruf ohne einen Block einen
SynchronizedObject
-Wrapper um ein Objekt zurückgibt, um den Zugriff auf jegliche Methoden zu schützen, die durch dieses Wrapper-Objekt aufgerufen werden. In Listing 8.9 erweitern wir die Methode
synchronized
erneut; wenn sie innerhalb einer Klassen- oder Moduldefinition aufgerufen wird, führt sie nun ein Alias-Verkettung der genannten Methoden durch, um Synchronisation hinzuzufügen.
Das Alias-Verkettung geschieht mithilfe unserer Methode
Module.synchronize_method
, die wiederum eine Helfermethode namens
Module.create_alias
einsetzt, um einen passenden Alias für jede gegebene Methode zu erzeugen (einschließlich Operatormethoden wie
+
).
Nach der Definition dieser neuen
Module
-Methoden definiert Listing 8.9 die Methode
synchronized
nochmals neu. Wenn die Methode innerhalb einer Klasse oder eines Moduls aufgerufen wird, ruft sie für jedes Symbol, das ihr übergeben wird,
synchronize_method
auf. Sie kann jedoch interessanterweise auch ohne Argumente aufgerufen werden; wenn sie auf diese Weise verwendet wird, fügt sie Synchronisation zu derjenigen Instanzmethode hinzu, die als nächste definiert wird – welche das auch sein mag. (Sie verwendet den Hook
method_added
, um eine Benachrichtigung zu empfangen, wenn eine neue Methode hinzugefügt wird.) Beachten Sie, dass der Code in diesem Beispiel von der Methode
Object.mutex
in Listing 8.2 und von der Klasse
SynchronizedObject
in Listing 8.5 abhängig ist.
# Module.synchronize_method führt Alias-Verkettung von Instanzmethoden
# durch, so dass sie die Instanz vor Ausführung synchronisieren.
class Module
# Dies ist eine Helferfunktion für Alias-Verkettung.
# Aus einem Methodennamen (als String oder Symbol)
# und einem Präfix einen eindeutigen Alias für die Methode erzeugen
# und den Namen des Alias als Symbol zurückgeben. Alle Satzzeichen
# im ursprünglichen Methodennamen werden in Zahlen konvertiert, damit
# Aliase für Operatoren möglich sind.
def create_alias(original, prefix="alias")
# Präfix vor Originalnamen setzen und Satzzeichen konvertieren
aka = "#{prefix}_#{original}"
aka.gsub!(/([\=\|\&\+\-\*\/\^\!\?\~\%\<\>\[\]])/) {
num = $1[0] # Ruby 1.8 Zeichen -> Code
num = num.ord if num.is_a? String # Ruby 1.9 Zeichen -> Code
'_' + num.to_s
}
# Unterstriche anhängen, bis ein nicht verwendeter Name entsteht
aka += "_" while method_defined? aka or private_method_defined? aka
aka = aka.to_sym # Aliasnamen in Symbol konvertieren
alias_method aka, original # Den eigentlichen Alias erzeugen
aka # Den Aliasnamen zurückgeben
end
# Alias-Verkettung der Methode zur Synchronisation
def synchronize_method(m)
# Zuerst einen Alias für die unsynchronisierte Version erstellen.
aka = create_alias(m, "unsync")
# Nun das Original neu definieren, um den Alias in einem syn-
# chronisierten Block aufzurufen. Wir wollen, dass die definierte
# Methode Blöcke annehmen kann, so dass wir define_method nicht
# verwenden können, sondern stattdessen mit class_eval einen
# String auswerten müssen. Beachten Sie, dass alles zwischen
# %Q{ und dem zugehörigen } ein String in doppelten Anführungs-
# zeichen und kein
Weitere Kostenlose Bücher