Durch Erweiterungen der Basisklassen kann man das Grundverhalten von Ruby-Objekten und -Klassen fast beliebig ändern.
Im folgenden Beispiel wird Ruby um das aus
Java bekannte "`Schlüsselwort"' synchronized
erweitert. Mit ihm kann sichergestellt werden,
dass zum Beispiel in einer Buchhaltungsapplikation zwei Methoden
einzahlen und auszahlen niemals gleichzeitig ausgeführt werden.
require 'synchronized' # siehe unten
class Konto
def initialize(initialBetrag = 0)
@kontostand = initialBetrag
end
def einzahlen(betrag)
@kontostand += betrag
end
def auszahlen(betrag)
@kontostand -= betrag
end
synchronized :einzahlen, :auszahlen
end
Die dafür nötige Verwaltung von Mutex-Objekten erscheint aber nicht in
der Applikationslogik, sondern wird über den Aufruf von synchronized
von Ruby hinter den Kulissen erledigt.
require 'thread'
class Module
def synchronized(*methods)
if methods.size > 0 then
instance_eval("@@__dclmtx__ = Mutex.new")
# ein mutex-getter
module_eval <<-EOS
def __mutex__
if (@__mtx__.nil?) then
@@__dclmtx__.synchronize {
@__mtx__ = Mutex.new if @__mtx__.nil?
}
end
return @__mtx__
end
EOS
end
methods.each { | method |
synchronizeMethod(method.to_s)
}
end
private
def synchronizeMethod(method)
# Originalmethode
instance_eval(
"alias_method :__#{method}__, :#{method}")
# Synchronisierter Wrapper
module_eval <<-EOS
def #{method}(*args)
__mutex__.synchronize {
__#{method}__(*args)
}
end
EOS
end
end
Mit synchronized :einzahlen, :auszahlen wird
in der Klasse Konto und allen Subklassen ein klassenweit
gültiger "`declaration mutex"' @@__dclmtx__ erzeugt,
der sicherstellt, dass in jeder
Konto-Instanz nur ein Mutex-Objekt enthalten ist.
In der Methode synchronizeMethod werden die zu synchronisierenden
Methoden mit alias umbenannt und Wrapper-Methoden mit den Originalnamen
definiert, welche über die kontenbezogenen Mutex-Objekte dafür sorgen, dass
keine Kollisionen auftreten.