Die Programmiersprache Ruby (German Edition)
# Modul B importiert A.
class C; include B; end; # Klasse C importiert Modul B.
C < B # => true: C enthält B.
B < A # => true: B enthält A.
C < A # => true
Fixnum < Integer # => true: Alle Fixnums sind Integer.
Integer < Comparable # => true: Integers sind Comparable.
Integer < Fixnum # => false: Nicht alle Integer sind Fixnums.
String < Numeric # => nil: Strings sind keine Zahlen.
A.ancestors # => [A]
B.ancestors # => [B, A]
C.ancestors # => [C, B, A, Object, Kernel]
String.ancestors # => [String, Enumerable, Comparable, Object, Kernel]
# Achtung: In Ruby 1.9 ist String nicht mehr Enumerable.
C.include?(B) # => true
C.include?(A) # => true
B.include?(A) # => true
A.include?(A) # => false
A.include?(B) # => false
A.included_modules # => []
B.included_modules # => [A]
C.included_modules # => [B, A, Kernel]
Dieser Code demonstriert
include?
, eine öffentliche Instanzmethode, die von der Klasse
Module
definiert wird. Aber er enthält auch zwei Aufrufe der Methode
include
(ohne Fragezeichen), die eine private Instanzmethode von
Module
ist. Als private Methode kann sie nur implizit für
self
aufgerufen werden, was ihre Verwendung auf den Rumpf einer
class
- oder
module
-Definition beschränkt. Diese Verwendung der Methode
include
, als sei sie ein Schlüsselwort, ist ein Beispiel für Metaprogrammierung in Rubys Kernsyntax.
Eine mit der privaten Methode
include
verwandte Methode ist die öffentliche Methode
Object.extend
. Diese Methode erweitert ein Objekt, indem sie die Instanzmethoden eines jeden der angegebenen Module zu Singleton-Methoden des Objekts macht:
module Greeter; def hi; "Hallo"; end; end # Ein albernes Modul
s = "String-Objekt"
s.extend(Greeter) # hi als Singleton-Methode zu s hinzufügen
s.hi # => "Hallo"
String.extend(Greeter) # hi als Klassenmethode zu String hinzufügen
String.hi # => "Hallo"
Die Klassenmethode
Module.nesting
hat nichts mit Modulimport oder Vorfahren zu tun; stattdessen gibt sie ein Array zurück, das die Verschachtelung von Modulen am aktuellen Standort angibt.
Module.nesting[0]
ist die aktuelle Klasse oder das aktuelle Modul,
Module.nesting[1]
ist die enthaltende Klasse oder das enthaltende Modul, und so weiter:
module M
class C
Module.nesting # => [M::C, M]
end
end
8.1.2 Klassen und Module definieren
Klassen und Module sind Instanzen der Klasse
Class
beziehungsweise
Module
. Als solche können Sie sie dynamisch erzeugen:
M = Module.new # Ein neues Modul M definieren
C = Class.new # Eine neue Klasse C definieren
D = Class.new(C) { # Eine Unterklasse von C definieren,
include M # die das Modul M importiert
}
D.to_s # => "D": Klasse erhält durch Magie konstanten Namen.
Ein nettes Feature von Ruby ist, dass dynamisch erzeugte Module oder Klassen, die einer Konstante zugewiesen werden, den Namen der Konstante als Namen des Moduls beziehungsweise der Klasse verwenden (und ihn in ihren
name
- und
to_s
-Methoden zurückgeben).
8.2 Strings und Blöcke auswerten
Eines der mächtigsten und einleuchtendsten reflektiven Features von Ruby ist die Methode
eval
. Wenn Ihr Ruby-Programm einen String mit gültigem Ruby-Code erzeugen kann, kann die Methode
Kernel.eval
diesen Code auswerten:
x = 1
eval "x + 1" # => 2
eval
ist eine sehr leistungsfähige Funktion, aber solange sie nicht tatsächlich ein Shell-Programm (wie irb ) schreiben, das vom User eingegebene Zeilen mit Ruby-Code ausführt, werden Sie sie wahrscheinlich nicht benötigen. (Und in einem Netzwerkkontext ist es so gut wie nie sicher,
eval
mit Text aufzurufen, der von einem User empfangen wurde, da er Schadcode enthalten könnte.) Unerfahrenen Programmierern passiert es manchmal, dass sie
eval
als Krücke verwenden. Wenn Sie sich selbst dabei ertappen, dass Sie es in Ihrem Code verwenden, sollten Sie überprüfen, ob es eine Möglichkeit gibt, es zu vermeiden. Trotz alledem gibt es einige andere nützliche Einsatzgebiete für
eval
und
eval
-ähnliche Methoden.
8.2.1 Bindungen und eval
Ein
Binding
-Objekt repräsentiert den Zustand von Rubys Variablenbindungen zu einem bestimmten Zeitpunkt. Das Objekt
Kernel.binding
gibt die an der Stelle des Aufrufs gültigen Bindungen zurück. Sie können ein
Binding
-Objekt als zweites Argument an
eval
übergeben, und der String, den Sie angeben, wird im Kontext dieser Bindungen ausgewertet. Wenn wir beispielsweise eine Instanzmethode definieren, die ein
Binding
-Objekt zurückgibt, das die Variablenbindungen innerhalb eines Objekts repräsentiert, dann können wir diese Bindungen
Weitere Kostenlose Bücher