Die Programmiersprache Ruby (German Edition)
Block ist.
#
class_eval %Q{
def #{m}(*args, &block)
synchronized(self) { #{aka}(*args, &block) }
end
}
end
end
# Diese globale Methode synchronized kann nun auf drei verschiedene
# Arten verwendet werden.
def synchronized(*args)
# Fall 1: mit einem Argument und einem Block das Objekt
# synchronisieren und den Block ausführen
if args.size == 1 && block_given?
args[0].mutex.synchronize { yield }
# Fall 2: mit einem Argument, das kein Symbol und kein
# Block ist, einen SynchronizedObject-Wrapper zurückgeben
elsif args.size == 1 and not args[0].is_a? Symbol and not block_given?
SynchronizedObject.new(args[0])
# Fall 3: bei Aufruf für ein Modul ohne Block Alias-Verkettung der
# genannten Methoden durchführen, um Synchronisation hinzu-
# zufügen oder bei Aufruf ohne Argumente Alias-Verkettung
# der als Nächstes definierten Methode durchführen
elsif self.is_a? Module and not block_given?
if (args.size > 0) # Die genannten Methoden synchronisieren
args.each {|m| self.synchronize_method(m) }
else
# Wenn keine Methoden angegeben wurden, die als Nächstes
# definierte Methode synchronisieren
eigenclass = class< # Eigenklasse zur Definition von Klassenmethoden verwenden
eigenclass.class_eval do
# method_added zur Benachrichtigung über nächste
# Methodendefinition verwenden
define_method :method_added do |name|
# Zuerst diese Hook-Methode verwenden
eigenclass.class_eval { remove_method :method_added }
# Danach die soeben hinzugefügte Methode synchronisieren
self.synchronize_method name
end
end
end
# Fall 4: jeder andere Aufruf ist ein Fehler
else
raise ArgumentError, "Falsche Argumente für synchronize()"
end
end
Listing 8.9 Alias-Verkettung für Thread-Sicherheit
8.11.3 Methodenverkettung für Tracing
Listing 8.10 ist eine Variante von Listing 8.4 , die das Tracing benannter Methoden eines Objekts ermöglicht. In Listing 8.4 wurden Delegation und
method_missing
verwendet, um eine
Object.trace
-Methode zu definieren, die ein überwachendes Wrapper-Objekt zurückgibt. Diese Version verwendet Chaining, um Methoden eines Objekts an Ort und Stelle zu ändern. Sie definiert
trace!
und
untrace!
, um das Chaining benannter Methoden eines Objekts durchzuführen beziehungsweise aufzuheben.
Das Interessanteste an diesem Beispiel ist, dass es das Chaining auf andere Weise durchführt als Listing 8.9 ; es definiert einfach Singleton-Methoden für das Objekt und verwendet innerhalb der Singletons
super
, um mit der ursprünglichen Methodendefinition zu verketten. Es werden keine Methoden-Aliase erzeugt.
# Die Instanzmethoden trace! und untrace! für alle Objekte erzeugen.
# trace! "verkettet" die genannten Methoden durch die Definition von
# Singleton-Methoden, die Tracing-Funktionalität hinzufügen und
# dann super verwenden, um die Originalmethode aufzurufen.
# untrace! löscht die Singleton-Methoden, um das Tracing zu
# entfernen.
class Object
# Tracing der angegebenen Methoden, Ausgabe an STDERR senden
def trace!(*methods)
@_traced = @_traced || [] # Die Tracing-Methoden merken
# Wenn keine Methoden angegebenen wurden, alle Public-
# Methoden verwenden, die direkt (nicht durch Vererbung)
# von der Klasse des Objekts definiert werden
methods = public_methods(false) if methods.size == 0
methods.map! {|m| m.to_sym } # Strings in Symbole konvertieren
methods -= @_traced # Tracing-Methoden entfernen
# Sofort zurückkehren, wenn nichts zu tun ist
return if methods.empty?
# Methoden zu den Tracing-Methoden hinzufügen
@_traced |= methods
# Tracing der Tatsache, dass wir mit dem Tracing dieser
# Methoden beginnen
STDERR << "Tracing #{methods.join(', ')} von #{object_id}\n"
# Singleton-Methoden werden in der Eigenclass definiert
eigenclass = class << self; self; end
methods.each do |m| # Für jede Methode m
# Eine Singleton-Version der Methode m mit Tracing definieren.
# Tracing-Informationen ausgeben und super verwenden, um die
# Instanzmethode aufzurufen, die überwacht wird.
# Wir wollen, dass die definierten Methoden in der Lage sind,
# Blöcke entgegenzunehmen, so dass wir nicht define_method
# verwenden können, sondern stattdessen einen String auswerten
# müssen.
# Beachten Sie, dass alles zwischen %Q{ und dem zugehörigen }
# ein String in doppelten Anführungszeichen und kein Block ist.
# Beachten Sie auch, dass es hier zwei Ebenen der String-Inter-
# polation gibt. #{} wird interpoliert, wenn die
Weitere Kostenlose Bücher