Programmierung in Ruby

Der Leitfaden der Pragmatischen Programmierer

Standard Library



Mit Ruby mitgeliefert wird eine große und nützliche Bibliothek mit Modulen und Klassen. Dieses Kapitel enthält einige Beispiele der eher nützlichen.

Interessanterweise und anders als der Code aus den späteren Kapiteln wurden alle diese Bibliotheken in Ruby geschrieben. Man findet die Quellen im lib-Unterverzeichnis der Standard-Ruby-Distribution.

class Complex
Parent: Numeric
Version: 1.6

Index:

new Arithmetische Operationen <=> == abs abs2 arg conjugate image polar real to_f to_i to_r to_s


require "complex"
v1 = Complex(2,3) » Complex(2, 3)
v2 = 2.im » Complex(0, 2)
v1 + v2 » Complex(2, 5)
v1 * v2 » Complex(-6, 4)
v2**2 » Complex(-4, 0)
Math.sin(v1) » Complex(9.154499147, -4.16890696)
v1 < v2 » false
v2**2 == -4 » true

Konstanten
Complex::I 0 +1i

class methods
new Complex.new( a, b ) -> aComplex

Liefert a + bi.

Zusätzlich zum Complex.new-Konstruktor gibt es in der Complex-Bibliothek die Methode Numeric.im, mit aNumeric.im liefert sie 0 + aNumerici zurück. Außerdem werden komplexe Zahlen mit der globalen Methode Complex erzeugt, die ein oder zwei Argumente entgegen nimmt. Ihr Rückgabewert hängt vom Typ ihrer Argumente ab:

a b Ergebnis
Number Number a + bi
Complex 0 a
Complex Complex Complex( a.real - b.image, a.image + b.real )
Number Complex Complex( a - b.image, b.real )

instance methods
Arithmetische Operationen

Führt verschiedene arithmetrische Operationen mit ref aus.

ref + aNumeric-> aComplex Addition
ref - aNumeric-> aComplex Subtraktion
ref * aNumeric-> aComplex Multiplikation
ref / aNumeric-> aComplex Division
ref % aNumeric-> aComplex Rest
ref ** aNumeric-> aComplex Exponentiation (reelle und komplexe Hochzahl)

<=> ref <=> other-> -1, 0, +1

Liefert ref.abs <=>other.abs.

(An dieser Stelle muss der Übersetzer jedoch anmerken, dass mathematisch gesehen ein Vergleich von zwei komplexen Zahlen Unsinn ist. Es ist doch sehr verwirrend, wenn für zwei Zahlen ref <= other sowie ref >= other gilt und sie dann trotzdem nicht gleich sind. Ich bin der Meinung, wenn man ref.abs < other.abs haben will, dann soll man auch ref.abs < other.abs schreiben.)

== ref == anObject-> true or false

Liefert true, wenn anObject eine komplexe Zahl ist und Real- und Imaginärteil denen bei ref entsprechen. Liefert auch true, wenn anObject eine einfache Zahl ist und ref.real ist gleich anObject und ref.image ist null. Andernfalls wird versucht, anObject in eine komplexe Zahl umzuwandeln, und das Ergebnis verglichen.

abs ref.abs -> aFloat

Absolut-Wert.

abs2 ref.abs2 -> aFloat

Quadrat des Absolut-Werts.

arg ref.arg -> aFloat

Argument (Winkel von (1,0) aus).

conjugate ref.conjugate -> aComplex

Komplex-Konjugiert.

image ref.image -> aNumeric

Imaginärteil von ref.

polar ref.polar -> anArray

Liefert ein zwei-elementiges Array: [c.abs, c.arg].

real ref.real -> aNumeric

Realteil von ref.

to_f ref.to_f -> aComplex

Liefert Complex(real.to_f, image.to_f).

to_i ref.to_i -> aComplex

Liefert Complex(real.to_i, image.to_i).

to_r ref.to_r -> aComplex

Liefert Complex(real.to_r, image.to_r), wobei beide Teile der komplexen Zahl in eine rationale Zahl konvertiert werden.

to_s ref.to_s -> aString

String-Repräsentation von ref.

Zusätzlich werden die Math-Funktionen sqrt, exp, cos, sin, tan, log, log10 und atan2 erweitert, um ein Argument der Klasse Complex aufnehmen zu können.

class Date
Parent: Object
Version: 1.6

Index:

exist2? exist? existw? gregorian_leap? julian_leap? leap? new new1 new2 new3 neww today Accessors + -- << <=> === >> downto england gregorian italy jd julian leap? mjd newsg next ns? os? sg step succ to_s upto


require 'date'
d = Date.new(2000, 3, 31) » #<Date: 2451635,2299161>
[d.year, d.yday, d.wday] » [2000, 91, 5]
[d.month, d.mday] » [3, 31]
[d.cwyear, d.cweek, d.cwday] » [2000, 13, 5]
[d.jd, d.mjd] » [2451635, 51634.5]
(d << 1).to_s » "2000-02-29"
d.succ.to_s » "2000-04-01"
(d + 100).to_s » "2000-07-09"
d.leap? » true
Date.new(2000, 3, -10).to_s » "2000-03-22"
d1 = Date.neww(2000, 13, 7) » #<Date: 2451637,2299161>
d1.to_s » "2000-04-02"
[d1.cwday, d1.wday] » [7, 0]

Die date-Bibliothek implementiert die Klasse Date, die einen übersichtlichen Satz an Mitteln zur Verfügung stellt, um Datums zu speichern, zu manipulieren und zu konvertieren. Um die ganzen Optionen darzustellen, müssen wir aber erst einen kurzen historischen Umweg nehmen, damit einiege Begriffe klar werden.

Intern wird ein Datum als die Zahl eines julianischen Tages gespeichert, das ist die Anzahl der Tage seit Mittag des 1. Januar 4713 v.Chr. [Im Code findet man oft die Referenz auf das Jahr -4712. Weil es im astronomischen Kalender das Jahr Null gibt, ist das dasselbe wie 4713 v.Chr.] [Der Übersetzer: Julianisch heißt der Tag nach dem Namen des Vaters des Erfinders dieser Zählweise, das hat nichts mit Julius Cäsar und dem Julianischen Kalender zu tun. Weil der Erfinder diese Datumsnotierung für astronomische Beobachtungen ersonnen hat, geht ein Julianischer Tag auch von Mittag zu Mittag, damit nachts zur Beobachtungszeit für Astronomen kein Datumswechsel stört.] Die Regeln für die Konvertierung von Julianischer Tag in ein Kalenderdatum sind kompliziert, weil die Römer die Länge eines Jahres nicht ganz richtig abgeschätzt haben. Im Julianischen Kalender (auch Old Style oder O.S. genannt) ist jedes vierte Jahr ein Schaltjahr. In der Klasse Date gibt es Optionen, um Datums unter dieser Voraussetung zu konvertieren.

Im sechzehnten Jahrhundert waren die Ungenauigkeiten dieser Zählweise offensichtlich geworden. 1582 wurde mit einem Edikt von Papst Gregor XIII der New Style (N.S.) oder Gregorianische Kalender eingeführt, bei dem Jahre, die durch 100 teilbar waren, keine Schaltjahre mehr waren, außer sie waren auch durch 400 teilbar. Dieses System wurde von den meisten katholischen Ländern sofort übernommen, aber religiöse Differenzen verhinderten eine weitere Verbreitung. England (und mehrere andere Staaten) stellten erst 1752 um, andere Länder noch später. [Der Übersetzer: Deshalb fand die russische Oktoberrevolution für den Rest der Welt im November statt.] In der Klasse Date kann man den Stichtag auf 1582 einstellen (die Date::ITALY-Option), 1752 (Date::ENGLAND) oder ein anderes frei wählbares Datum.

Die Klasse Date unterstützt außerdem die Konvertierung zum modifizierten julianischen Tag (MJD). Die MJD-Zählung beginnt am 17. November 1858 um Mitternacht. Weil diese Werte ab Mitternacht und nicht ab Mittags gezählt werden, wird zum Konvertierungsfaktor noch ein halber Tag dazu gezählt.

Die folgende Beschreibung benutzt die Abkürzungen aus Tabelle Table 24.1 auf Seite 445.

Abkürzungen zum Beschreiben der Datums

Feld Bedeutung
cwday Ein ISO 8601 Kalender-Wochentag. 1 ist Montag, 7 ist Sonntag.
cweek Eine ISO 8601 Kalender-Woche. Woche 1 ist diejenige mit dem ersten Mittwoch (oder äquivalent dazu diejenige mit dem 4. Januar).
cwyear Ein ISO 8601 kalender-wochen-basiertes Jahr. Das kann vom year abweichen, weil es erst am ersten Montag anfängt.
jd Die Nummer des julianischen Tags --- die Anzahl der Tage seit dem 1. Januar, 4713 v.Chr. (mittags).
mday Der Tag des Monats (1..31).
mjd Die Nummer des modifizierten julianischen Tages.
mon Der Monat des Jahres (1..12).
sg Der Beginn der gregorianischen Korrektur: Date::ITALY (Default) für 1582, Date::ENGLAND für 1752 oder JULIAN, d.h. keine Korrektur. Man kann auch einen beliebigen julianischen Tag für diesen Parameter angeben, dann fängt die Korrektur an diesem Datum an.
wday Der Tag der Woche (0 ist Sonntag).
week Die Wochennummer des Jahres (1..53).
yday Der Tag des Jahres (1..366).
year Ein Jahr (1966, 2001 und so was).

Die Klasse Date liefert auch die konstanten Arrays Date::MONTHNAMES und Date::DAYNAMES, die man mit mon und wday indizieren kann, um die dazugehörenden englischen Namen zu bekommen.

Desweiteren liefert Date auch noch low-level Konvertierungs-Methoden:

civil_to_jd jd_to_civil
commercial_to_jd jd_to_commercial
ordinal_to_jd jd_to_ordinal
jd_to_mjd mjd_to_jd

Diese Methoden führen eine begrenzte Fehlerprüfung ihrer Parameter durch und werden hier nicht dokumentiert. Die etwas unglücklich benannten exist..? führen eine Konvertierung aus einem anderen Format in das Format julianischer Tag inklusive Fehlerprüfung durch. Diese Methoden normalisieren außerdem ihre Parameter.

mixins
Comparable: <, <=, ==, >=, >, between?

class methods
exist2? Date.exist2?( year, yday, sg=Date::ITALY) -> jd

Konvertiert ein year und yday in einen julianischen Tag, liefert nil im Fehlerfall.

exist? Date.exist?( year, mon, mday, sg=Date::ITALY) -> jd

Konvertiert ein year, mon und mday in einen julianischen Tag, bzw. nil falls die Parameter nicht stimmen.

existw? Date.existw?( cyear, cweek, cwday, sg=Date::ITALY) -> jd
Konvertiert ein cyear, cweek und cwday in einen julianischen Tag.

gregorian_leap? Date.gregorian_leap?( year ) -> true or false

Gregorianisches Schaltjahr: true falls year durch 4 teilbar, außer falls year durch 100 und nicht durch 400 teilbar.

julian_leap? Date.julian_leap?( year ) -> true or false

true falls year durch 4 teilbar.

leap? Date.leap?( year ) -> true or false

Synonym für Date.gregorian_leap?.

new Date.new( year=-4712, mon=1, mday=1, sg=Date::ITALY) -> aNewDate

Liefert ein Date für das angegebene year, mon und mday. Falls mon negativ ist, wird vom Ende des Jahres rückwärts gezählt. Falls mday negativ ist, wird vom Ende des Monats rückwärts gezählt.

new1 Date.new1( jd, sg=Date::ITALY) -> aNewDate

Erzeugt ein Date zum übergebenen julianischen Tag.

new2 Date.new2( year=-4712, yday=1, sg=Date::ITALY) -> aNewDate

Erzeugt ein Date zum übergebenen year und yday. Falls yday negativ ist, wird vom Ende des Jahres rückwärts gezählt.

new3 Date.new3( year=-4712, mon=1, mday=1, sg=Date::ITALY) -> aNewDate

Synonym für Date.new.

neww Date.neww( cyear=1582, cweek=41, cwday=5, sg=Date::ITALY) -> aNewDate

Erzeugt ein Date zum übergebenen cyear, cweek und cwday. Falls cweek negativ ist, wird vom Ende des Jahres rückwärts gezählt. Falls cwday negativ ist, wird vom Ende der Woche rückwärts gezählt.

today Date.today( sg=Date::ITALY) -> aNewDate

Liefert ein Date für Heute.

instance methods
Accessors ref.year -> year
ref.yday -> yday
ref.mjd -> mjd
ref.mon -> mon
ref.month -> mon
ref.mday -> mday
ref.day -> mday
ref.cwyear -> cwyear
ref.cweek -> cweek
ref.cwday -> cwday
ref.wday -> wday

Gibt die angegebenen Komponente von ref als Zahl zurück.

+ ref + anInteger-> aNewDate

Erzeugt ein neues Date anInteger Tage von ref.

-- ref-anInteger-> aNewDate
ref-anOtherDate-> anInteger

Die erste Form liefert ein neues Date anInteger Tage vor ref. Die zweite Form liefert die Anzahl der Tage zwischen ref und anOtherDate.

<< ref << anInteger-> aNewDate

Liefert ein neues Date, gebildet durch Subtraktion von anInteger Monaten von ref, dabei wird der Wert mday heruntergesetzt, falls die Monatsgrenze sonst überschritten wird.

<=> ref <=> anOther-> -1, 0, +1

anOther muss ein Numeric sein (dann gilt es als Nummer des julianischen Tags) oder ein Date. Liefert -1, 0, +1 falls ref kleiner als, gleich oder größer als anOther ist. Siehe Modul Comparable auf Seite 406.

=== ref === anOther-> true or false

anOther muss ein Numericsein (dann gilt es als Nummer des julianischen Tags) oder ein Date. liefert true, falls die Nummer des julianischen Tages von anOther dieselbe ist wie die von ref.

>> ref >> anInteger-> aNewDate

Liefert ein neues Date gebildet durch Addition von anInteger Monaten zu ref, der Wert von mday wird dabei falls nötig auf den letzen gültigen Tag des Monats zurück gesetzt.

downto ref.downto( aDateMin ) {| date | block }

-> ref

Ruft den Block auf mit Datums von ref runter bis aDateMin.

england ref.england -> aDate

Äquivalent zu ref.newsg(Date::ENGLAND).

gregorian ref.gregorian -> aDate

Äquivalent zu ref.newsg(Date::GREGORIAN).

italy ref.italy -> aDate

Äquivalent zu ref.newsg(Date::ITALY).

jd ref.jd -> jd

Liefert die Nummer des julianischen Tags für ref.

julian ref.julian -> aDate

Äquivalent zu ref.newsg(Date::JULIAN).

leap? ref.leap? -> true or false

Liefert true falls ref in einem Schaltjahr ist.

mjd ref.mjd -> mjd

Liefert die Nummer des modifizierten julianischen Tags für ref.

newsg ref.newsg( sg=Date::ITALY ) -> aNewDate

Liefert ein neues Date.

next ref.next -> aNewDate

Synonym für ref.succ.

ns? ref.ns? -> true or false

Liefert true falls ref nach der gregorianischen Korrektur liegt.

os? ref.os? -> true or false

Liefert true falls ref vor der gregorianischen Korrektur liegt.

sg ref.sg -> anInteger

Liefert die Nummer des julianischen Tages vom ersten Tag nach der gregorianischen Korrektur für das Objekt ref.

step ref.step( aDateLimit, step ) {| date | block }

-> ref

Ruft den Block auf mit Datums, die anfangen bei ref, jeweils erhöht werden um step Tage und enden bevor das Datum größer als aDateLimit ist (bzw. kleiner bei negativer Schrittweite).

succ ref.succ -> aNewDate

Liefert das Datum von ref plus einen Tag.

to_s ref.to_s -> aString

Liefert self als ``year-mon-mday.''

upto ref.upto( aDateMax ) {| date | block }

-> ref

Ruft den Block auf mit Datums von ref bis aDateMax.

Library: English

require "English"

$OUTPUT_FIELD_SEPARATOR = ' -- ' "waterbuffalo" =~ /buff/ print $LOADED_FEATURES, $POSTMATCH, $PID, "\n" print $", $', $$, "\n"
erzeugt:
English.rb -- alo -- 14806 --
English.rb -- alo -- 14806 --

Wenn man die Bibliotheks-Datei English in ein Ruby-Script einbindet, kann man globale Variablen wie $_ mit etwas weiniger kryptischen Namen ansprechen, wie sie in folgender Tabelle stehen.

$* $ARGV $" $LOADED_FEATURES
$? $CHILD_STATUS $& $MATCH
$< $DEFAULT_INPUT $. $NR
$> $DEFAULT_OUTPUT $, $OFS
$! $ERROR_INFO $\ $ORS
$@ $ERROR_POSITION $\ $OUTPUT_RECORD_SEPARATOR
$; $FIELD_SEPARATOR $, $OUTPUT_FIELD_SEPARATOR
$; $FS $$ $PID
$= $IGNORECASE $' $POSTMATCH
$. $INPUT_LINE_NUMBER $` $PREMATCH
$/ $INPUT_RECORD_SEPARATOR $$ $PROCESS_ID
$~ $LAST_MATCH_INFO $0 $PROGRAM_NAME
$+ $LAST_PAREN_MATCH $/ $RS
$_ $LAST_READ_LINE

module Find

Index:

find prune


require "find"
Find.find("/etc/passwd", "/var/spool/lp1", ".") do |f|
  Find.prune if f == "."
  puts f
end
erzeugt:
/etc/passwd
/var/spool/lp1
/var/spool/lp1/status
/var/spool/lp1/lock
/var/spool/lp1/.seq

Das Find-Modul unterstützt die top-down Traversierung für eine Menge aus Datei-Pfaden.

class methods
find ref.find( [aName]* ) {| aFileName | block }

Ruft den dazugehörenden Block auf, jeweils mit dem Namen von jeder Datei und jedem Verzeichnis, die in der Parameterliste aufgeführt sind, dann rekursiv in deren Unterverzeichnissen und so weiter.

prune ref.prune

Bricht die Bearbeitung der aktuellen Datei oder des aktuellen Verzeichnisses ab und beginnt die Schleife wieder bei dem nächsten Eintrag. Falls der aktuelle Eintrag ein Verzeichnis ist, wird nicht in diesem Verzeichnis weitergemacht. Sinnvoll ist das natürlich nur in einem mit Find::find verbundenen Block.

class File
Parent: IO
Version: 1.6

Index:

cmp compare copy cp install makedirs mkpath move mv rm_f safe_unlink syscopy


require 'ftools'
File.copy 'testfile', 'testfile1' » true
File.compare 'testfile', 'testfile1' » true

Die FTools-Bibliothek stellt mehrere Methoden für die eingebaute Klasse File zur Verfügung. Diese Methoden sind ganz nützlich bei Programmen, die Dateien verschieben oder kopieren, etwa Installations-Programme.

class methods
cmp ref.cmp( name1, name2, verbose=false ) -> true or false

Synonym für File.compare.

compare ref.compare( name1, name2, verbose=false ) -> true or false

Liefert true nur dann, wenn der Inhalt der Dateien name1 und name2 identisch ist.

copy ref.copy( fromName, toName, verbose=false ) -> true or false

Äquivalent mit dem Aufruf von File.syscopy, außer dass der Versuch auf $stderr protokolliert wird, falls verbose nicht false ist.

cp ref.cp( fromName, toName, verbose=false ) -> true or false

Synonym für File.copy.

install ref.install( fromName, toName, aMode=nil, verbose=false )

Kopiert die Datei fromName nach toName und benutzt dabei File.syscopy, außer toName gibt es schon und es hat den selben Inhalt wie fromName. Setzt den Modus der Ziel-Datei auf aMode, außer aMode ist nil.

makedirs ref.makedirs( [dirName]*[, aBoolean] )

Erzeugt die angegebenen Verzeichnisse, protokolliert jeden Versuch auf $stderr falls der letze Parameter true ist. Erzeugt auch übergeordnete Verzeichnisse, falls nötig.

mkpath ref.mkpath( [dirName]*[, aBoolean] )

Synonym für File.makedirs.

move ref.move( fromName, toName, verbose=false ) -> true or false

Ändert den Namen von fromName nach toName, protokolliert auf $stderr falls verbose nicht false ist.

mv ref.mv( fromName, toName, verbose=false ) -> true or false

Synonym für File.move.

rm_f ref.rm_f( [fileName]*[, aBoolean] ) -> anInteger

Synonym für File.safe_unlink (der Name weist auf das Unix-Kommando rm -f hin).

safe_unlink ref.safe_unlink( [fileName]*[, aBoolean] ) -> anInteger or nil

Entkoppelt (vernichtet) die angegebenen Dateien, protokolliert auf $stderr falls der letzte Parameter true ist. Die Methode versucht, alle Dateien vorher beschreibbar zu machen, damit kein Fehler durch das Vernichten von nur-lesbaren Dateien auftritt. Gibt die Anzahl der vernichteten Dateien zurück, oder nil im Fehlerfall.

syscopy ref.syscopy( fromName, toName ) -> true or false

Kopiert die Datei namens fromName nach toName. Falls toName ein Verzeichnis bezeichnet, so ist das Ziel eine Datei in diesem Verzeichnis mit demselben Dateinamen wie fromName. Nach dem Kopieren ist der Modus von toName der selbe wie der von fromName. Gibt im Erfolgsfall true zurück.

class GetoptLong
Parent: Object
Version: 1.6

Index:

new each error? error_message get get_option ordering ordering= quiet quiet= quiet? set_options terminate terminated?


# Call using "ruby example.rb --size 10k -v -q a.txt b.doc"

require 'getoptlong'

# specify the options we accept and initialize # the option parser

opts = GetoptLong.new(   [ "--size",    "-s",            GetoptLong::REQUIRED_ARGUMENT ],   [ "--verbose", "-v",            GetoptLong::NO_ARGUMENT ],   [ "--query",   "-q",            GetoptLong::NO_ARGUMENT ],   [ "--check",   "--valid", "-c", GetoptLong::NO_ARGUMENT ] )

# process the parsed options

opts.each do |opt, arg|   puts "Option: #{opt}, arg #{arg.inspect}" end

puts "Remaining args: #{ARGV.join(', ')}"
erzeugt:
Option: --size, arg "10k"
Option: --verbose, arg ""
Option: --query, arg ""
Remaining args: a.txt, b.doc

Die Klasse GetoptLong liefert eine Auflösung der Kommandozeilen-Optionen im GNU-Stil. Optionen dürfen sein: ein Minuszeichen (`-') gefolgt von einem Zeichen oder zwei Minuszeichen (`--') gefolgt von einem Namen (die lange Option). Lange Optionen dürfen gekürzt werden solange sie noch eindeutig bleiben.

Eine spezielle interne Option kann mehrere externe Repräsentationen besitzen. Zum Beispiel sieht die Option für den ausführlichen Output so aus: -v, --verbose oder --details. Einige Optionen nehmen auch einen dazugehörenden Wert entgegen.

Jede interne Option wird an GetoptLong als Array weitergegeben, das Strings enthält, die die externen Formen der Option bezeichnen, sowie ein Flag. Das Flag (NO_ARGUMENT, REQUIRED_ARGUMENT oder OPTIONAL_ARGUMENT) gibt an, wie GetoptLong mit einem dazugehörenden Argument umgehen soll.

Falls die Umgebungs-Variable POSIXLY_CORRECT gesetzt ist, müssen alle Optionen in der Kommandozeile vor Nicht-Optionen kommen. Andernfalls und als Default-Einstellung wird GetoptLong die Kommandozeile sortieren und die Optionen an den Anfang setzen. Diese Verhalten kann man ändern, indem man GetoptLong#ordering= setzt, und zwar auf eine der Konstanten PERMUTE, REQUIRE_ORDER oder RETURN_IN_ORDER. POSIXLY_CORRECT darf nicht überschrieben werden.

Konstanten

Konstanten für Optionen
NO_ARGUMENT Eine Option, die keine Argumente erwartet.
OPTIONAL_ARGUMENT Eine Nicht-Option, die nach dieser Option kommt, wird als Argument dieser Option genutzt.
REQUIRED_ARGUMENT Nach dieser Option muss ein Argument kommen.
Konstanten für alles
PERMUTE Optionen und ihre Argumente werden an den Anfang der Komanndozeile geschoben.
REQUIRE_ORDER Optionen und ihre Argumente müssen am Anfagn der Kommandozeile stehen. Nach der ersten Nicht-Option werden keine Optionen mehr akzeptiert.
RETURN_IN_ORDER Liefert die Optionen in der Reihenfolge zurück, in der sie in der Kommandozeile stehen.

class methods
new GetoptLong.new( [options]* ) -> ref

Liefert einen neuen Options-Parser. Alle options werden an ref.set_options weitergegeben.

instance methods
each ref.each {| anOption, anArgument | block }

Durchläuft eine Schleife und ruft dabei GetoptLong#get auf, übergibt die zurückgegebene Option und das Argument an den angeschlossenen Block. Die Schleife endet, falls get für anOption nil zurückliefert.

error? ref.error? -> anException

Liefert ein Exception-Objekt, das jeden aufgetretenen Felhler dokumentiert, oder nil falls es keinen Fehler gab.

error_message ref.error_message -> aString

Liefert den Text der letzten Fehlermeldung.
get ref.get -> [ anOption, anArgument ]

Liefert die nächste Option, zusammen mit einem dazu gehörenden Argument. Wenn es kein Argument gibt, wird nil für anArgument zurück gegeben. Wenn keine nicht abgehandelten Optionen mehr übrig sind oder wenn ein Fehler bei der Abarbeitung der Optionen aufgetreten ist, so wird, falls quiet gesetzt ist, nil für anOption zurückgegeben. Andernfalls, wenn ein Fehler auftrat, wird eine Meldung an $stderr geschickt und eine Exception (eine Unterklasse von StandardError) wird ausgelöst.

Der zurückgegebene Options-String ist die erste Option, die im dazugehörenden an set_options übergebenen Array stand.

get_option ref.get_option -> [ anOption, anArgument ]

Synonym für GetoptLong#get.

ordering ref.ordering -> aFixnum

Liefert die aktuelle Ordnung.

ordering= ref.ordering = aFixnum

Bestimmt die Ordnung, das ist eine von PERMUTE, REQUIRE_ORDER oder RETURN_IN_ORDER. Wird stillschweigend ignoriert, falls die Umgebungsvariable POSIXLY_CORRECT gesetzt ist. Die Ordnung darf nicht mehr verändert werden, wenn die Options-Abarbeitung schon angefangen hat.

quiet ref.quiet -> true or false

Liefert den aktuellen Werte des quiet-Attributs.

quiet= ref.quiet = true or false

Setzt den aktuellen Wert des quiet-Attributs. Wenn auf false gesetzt, werden alle aurtretenden Fehler nach $stderr geschickt.

quiet? ref.quiet? -> true or false

Synonym für GetoptLong#quiet.

set_options ref.set_options( [anOptArray]* ) -> ref

Jeder Parameter ist ein Array, das eine einzelne interne Option bezeichnet. Das Array enthält einen oder mehrere Strings, die die externe(n) Form(en) der Option bezeichnen, und eines der Flags NO_ARGUMENT, OPTIONAL_ARGUMENT oder REQUIRED_ARGUMENT. Für Anwendungsbeispiele siehe den Beispiel-Code auf Seite 452.

terminate ref.terminate -> ref

Beendet die Options-Abarbeitung. Alle noch übrigen Argumente werden zurück nach ARGV geschrieben. Das kann innerhalb von GetoptLong#each aufgerufen werden oder auch alleinstehend. Wenn wir zum Beipiel das folgende Programm mit ``ruby example.rb --size 10k -v -term -q a.txt b.doc'' aufrufen, bleibt -q und die Dateinamen in ARGV stehen.

require 'getoptlong'

opts = GetoptLong.new(   [ "--size",    "-s",            GetoptLong::REQUIRED_ARGUMENT ],   [ "--verbose", "-v",            GetoptLong::NO_ARGUMENT ],   [ "--term",    "-t",            GetoptLong::NO_ARGUMENT ],   [ "--query",   "-q",            GetoptLong::NO_ARGUMENT ],   [ "--check",   "--valid", "-c", GetoptLong::NO_ARGUMENT ]   )

opts.each do |opt, arg|   puts "Option: #{opt}, arg #{arg.inspect}"   opts.terminate if (opt == '--term') end

puts "Remaining args: #{ARGV.join(', ')}"
erzeugt:
Option: --size, arg "10k"
Option: --verbose, arg ""
Option: --term, arg ""
Remaining args: -q, a.txt, b.doc

terminated? ref.terminated? -> true or false

Liefert true, wenn die Options-Abarbeitung beendet ist.

module mkmf

Index:

create_makefile dir_config find_library have_func have_header have_library


Die mkmf-Bibliothek wird von Ruby-Erweiterungs-Modulen benutzt, um Makefiles zu erzeugen. Wenn man eine Erweiterung schreibt, erzeugt man ein Programm namens ``extconf.rb''. Das kann ganz einfach aussehen, etwa:

require 'mkmf'
create_makefile("Test")

Nach dem Starten erzeugt dieses Script ein Makefile passend auf die Ziel-Plattform. mkmf enthält verschiedene Methoden zum Auffinden von Bibliotheken und Einbinden von Dateien und um Compiler-Flags zu setzen.

Mehr Informationen über das Erzeugen von Erweiterungs-Modulen gibt es im Kapitel 17 ab Seite 171.

Konstanten

PLATFORM unterschiedlich Ein konstanter String, der die Plattform beschreibt, auf der Ruby läuft, etwa ``mswin32'' oder ``i686-linux.''
$CFLAGS Globale Variable für Compiler-Flags.
$LDFLAGS Globale Variable für Linker-Flags.

instance methods
create_makefile create_makefile( target )

Erzeugt ein Makefile für eine Erweiterung namens target. Wenn diese Methode nicht aufgerufen wird, dann wird auch kein Makefile erzeugt.

dir_config dir_config( name )

Sucht nach den Optionen der Verzeichnis-Konfiguration für name, die als Argumente zu diesem Programm oder bei der ursprünglichen Erstellung von Ruby angegeben waren. Diese Argumente können so aussehen:

--with-name-dir=directory
--with-name-include=directory
--with-name-lib=directory

Die angegebenen Verzeichnisse werden zum passenden Such-Pfad (include oder link) im Makefile hinzugefügt.

find_library find_library( name, function, [path]+ ) -> true oder false

Das selbe wie have_library, sucht zusätzlich in den angegebenen Verzeichnissen.

have_func have_func( function ) -> true oder false

Wenn die genannte Funktion in der Standard-Compile-Umgebung existiert, so wird die Direktive -DHAVE_FUNCTION zum Compile-Kommando im Makefile hinzugefügt und true zurück gegeben.

have_header have_header( header ) -> true oder false

Wenn die angegebene Header-Datei im Standard-Such-Pfad gefunden werden kann, so wird die Direktive -DHAVE_HEADER zum Compile-Kommando im Makefile hinzugefügt und true zurück gegeben.

have_library have_library( library, function ) -> true or false

Wenn die agegebene Funktion in der genannten Bibliothek, die im Standard-Such-Pfad oder in einem mit dir_config hinzugefügten Verzeichnis liegen muss, existiert, so wird die Bibliothek zum Link-Kommando im Makefile hinzugefügt und true zurück gegeben.

module ParseDate

Index:

parsedate


Im ParseDate-Modul wird nur eine einzige Methode definiert, ParseDate::parsedate, die einen Datums- und/oder Zeit-String in seine Bestandteile auflöst. Dabei benutzt sie Methoden, die eine große Vielfalt an Datums- und Zeit-Formaten behandelt, inclusive einer Untermenge von ISO 8601, Unix-ctime und die meisten gebräuchlichen geschriebenen Varianten. Die folgende Tabelle gibt einige Beispiele. 

StringGuess? yy mm dd hh min sec zone wd
1999-09-05 23:55:21+0900 F 1999 9 5 23 55 21 +0900 --
1983-12-25 F 1983 12 25 -- -- -- -- --
1965-11-10 T13:45 F 1965 11 10 13 45 -- -- --
10/9/75 1:30pm F 75 10 9 13 30 -- -- --
10/9/75 1:30pm T 1975 10 9 13 30 -- -- --
Mon Feb 28 17:15:49 CST 2000 F 2000 2 28 17 15 49 CST 1
Tue, 02-Mar-99 11:20:32 GMT F 99 3 2 11 20 32 GMT 2
Tue, 02-Mar-99 11:20:32 GMT T 1999 3 2 11 20 32 GMT 2
12-January-1990, 04:00 WET F 1990 1 12 4 0 -- WET --
4/3/99 F 99 4 3 -- -- -- -- --
4/3/99 T 1999 4 3 -- -- -- -- --
10th February, 1976 F 1976 2 10 -- -- -- -- --
March 1st, 84 T 1984 3 1 -- -- -- -- --
Friday F -- -- -- -- -- -- -- 5

class methods
parsedate ref.parsedate( aString, guessYear=false )
-> [ year, mon, mday, hour, min, sec, zone, wday ]

Parst einen String, der ein Datum und/oder eine Zeit enthält. Liefert ein Array von Fixnum-Objekten, das die verschiedenen Komponenten enthält. nil wird für Felder zurückgegeben, die nicht aufgelöst werden können. Falls das Ergebnis ein Jahr enthält, das kleiner als 100 ist und guessYear ist true, dann liefert parsedate als Jahr den Wert year plus 2000 falls year kleiner als 69 ist, andernfalls year plus 1900.

Library: profile

Die profile-Bibliothek schreibt nach $stderr eine Übersicht mit der Anzahl der Aufrufe von und der verbrachten Dauer in jeder Methode eines Ruby-Programms. Der Output wird nach der Gesamtdauer der Methoden sortiert. Dieses Profiling kann von der Kommandozeile aus angeschaltet werden mit der -rprofile-Option oder von innerhalb des Programms durch Angabe von require für das profile-Modul.

require 'profile'
def ackerman(m, n)
  if m == 0 then  n+1
  elsif n == 0 and m > 0 then ackerman(m-1, 1)
  else ackerman(m-1, ackerman(m, n-1))
  end
end
ackerman(3,3)

erzeugt:
 time   seconds   seconds    calls  ms/call  ms/call  name
 70.77     2.30      2.30     2432     0.95    41.42  Object#ackerman
 14.46     2.77      0.47     3676     0.13     0.13  Fixnum#==
  9.54     3.08      0.31     2431     0.13     0.13  Fixnum#-
  4.92     3.24      0.16     1188     0.13     0.13  Fixnum#+
  0.31     3.25      0.01       57     0.18     0.18  Fixnum#>
  0.00     3.25      0.00        1     0.00     0.00  Module#method_added
  0.00     3.25      0.00        1     0.00  3250.00  #toplevel

class PStore
Parent: Object
Version: 1.6

Index:

new [ ] [ ]= abort commit path root? roots transaction


Die Klasse PStore stellt transaktionsgesicherte, datei-basierte Speicherung von Ruby-Objekten zur Verfügung. Das folgende Beispiel speichert zwei Hierarchien in einem PStore. Das erste, mit dem Schlüssel ``names'', ist ein Array aus Strings. Das zweite, mit dem Schlüssel ``tree'', ist ein einfacher binärer Baum.

require "pstore"

class T   def initialize(val, left=nil, right=nil)     @val, @left, @right = val, left, right   end   def to_a     [ @val, @left.to_a, @right.to_a ]   end end

store = PStore.new("/tmp/store") store.transaction do    store['names'] = [ 'Douglas', 'Barenberg', 'Meyer' ]    store['tree']  = T.new('top',                       T.new('A', T.new('B')),                       T.new('C', T.new('D', nil, T.new('E')))) end

# now read it back in

store.transaction do    puts "Roots: #{store.roots.join(', ')}"    puts store['names'].join(', ')    puts store['tree'].to_a.inspect end
erzeugt:
Roots: names, tree
Douglas, Barenberg, Meyer
["top", ["A", ["B", [], []], []], ["C", ["D", [], ["E", [], []]], []]]

Jedes PStore kann mehrere Objekt-Hierarchien speichern. Jede Hierarchie besitzt eine Wurzel, die durch einen Schlüssel (oftmals ein String) gekennzeichnet wird. Am Anfang einer PStore-Transaction werden diese Hierarchien aus einer Datei gelesen und dem Ruby-Programm zur Verfügung gestellt. Am Ende der Transaction werden die Hierarchien wieder zurück in die Datei geschrieben. Alle Änderungen an den Objekten dieser Hierarchien werden daher auf Platte gespeichert, um bei der nächsten Transaction, die diese Datei benutzt, wieder gelesen zu werden.

Im Normalfall wird ein PStore-Objekt erzeugt und dann ein- oder mehrmals benutzt, um eine Transaction zu kontrollieren. Innerhalb des Rumpfes einer Transaction werden alle Objekt-Hierarchien, die vorher gesichert waren, wieder zugänglich gemacht, und alle Änderungen an Objekt-Hierarchien und alle neuen Hierarchien werden zum Schluss zurück auf Platte geschrieben.

class methods
new PStore.new( aFilename ) -> aPStore

Liefert ein neues PStore-Objekt, das zur angegebenen Datei gehört. Wenn die Datei schon existiert, muss sie vorher schon mit PStore geschrieben worden sein.

instance methods
[ ] ref[ anObject ] -> anOtherObject

Zugriff auf die Wurzel --- Liefert die Wurzel einer Objekt-Hierarchie zum Objekt anObject. Eine Exception wird ausgelöst, wenn für anObject kein Wurzelobjekt existiert.

[ ]= ref[ anObject ] = anOtherObject-> anOtherObject

Wurzel-Erzeugung --- Setzt anOtherObject als Wurzel der Objekt-Hierarchie, die durch anObject angesprochen wird.

abort ref.abort

Beendet diese Transaction, alle Änderungen an der Objekt-Hierarchie gehen verloren.

commit ref.commit

Beendet die aktuelle Transaction, sichert die Obejkt-Hierarchien in der dazugehörenden Datei.

path ref.path -> aString

Liefert den Namen der mit dieser Transaction verbundenen Datei.

root? ref.root?( anObject ) -> true or false

Liefert true falls anObject der Schlüssel einer Wurzel in diesem Speicherbereich ist.

roots ref.roots -> anArray

Liefert die Schlüssel zu den Wurzel-Objekten, die zu diesem Speicherbereich gehören.

transaction ref.transaction {| ref | block }

-> anObject

Wenn die zu ref gehörende Datei existiert, wird aus ihr in der Objekt-Hierarchie gelesen. Dann wird der zugehörige Block ausgeführt, wobei ref übergeben wird. Der Block kann dann über diesen Parameter auf die Wurzeln der Hierarchien zugreifen und so die geschützten Objekte erreichen. Falls der Block PStore#abort aufruft oder eine Exception auslöst, werden keine Daten zurück in die Datei geschrieben. Anderenfalls, wenn er PStore#commit aufruft oder normal beendet wird, werden die Objekt-Hierarchien in die Datei zurück geschrieben. Der Rückgabewert ist der Rückgabewert des Blocks.

class Tempfile
Parent: [IO]
Version: 1.6

Index:

new open close open path


require "tempfile"
tf = Tempfile.new("afile")
tf.path » "/tmp/afile14822.0"
tf.puts("Cosi Fan Tutte") » nil
tf.close » nil
tf.open » #<File:0x4016e3c0>
tf.gets » "Cosi Fan Tutte\n"
tf.close(true) » #<File:0x4016e3c0>\n0x40187c30

Die Klasse Tempfile erzeugt verwaltete temporäre Dateien. Obwohl sie sich genauso wie andere IO.Objekte auch verhalten, werden temporäre Dateien automatisch vernichtet, wenn ein Ruby-Programm beendet wird. Wenn man erstmal ein Tempfile-Objekt erzeugt hat, kann man die darunter liegende Datei immer wieder öffnen und schließen.

Die Klasse Tempfile wird nicht direkt von der Klasse IO abgeleitet. Stattdessen gibt sie die Aufrufe an ein File-Objekt weiter. Aus Sicht des Programmieres verhält es sich, mit Ausnahme der unüblichen new, open, und close Ausdrücke, als wäre es ein IO-Objekt.

class methods
new Tempfile.new( basename, tmpdir=<see below> ) -> ref

Erzeugt eine temporäre Datei im angegebenen Verzeichnis. Der Dateiname wird gebildet aus dem basename, der aktuellen Prozess-Id und (als Extension) einer eindeutigen laufenden Nummer. Wenn kein tmpdir-Parameter angegeben ist, wird defaultmäßig eine der Umgebungsvariablen TMPDIR, TMP, oder TEMP genommen, oder das Verzeichnis /tmp.

Die Datei wird dann im Modus ``w+'' geöffnet, das ermöglicht Lesen und Schreiben und zerstört eventuell vorher schon vorhandenen Inhalt (siehe Tabelle 22.5 auf Seite 331).

open Tempfile.open( basename, tmpdir ) -> ref

Synonym für Tempfile.new.

instance methods
close ref.close( final=false )

Schließt ref. Falls final true ist, wird die zu Grunde liegende Datei zerstört. Falls final false ist, darf man ref später wieder öffnen. Auf jeden Fall wird die zu Grunde liegende Datei bei Programmende zerstört.

open ref.open

Öffnet ref wieder im Modus ``r+'', welcher Lesen und Schreiben ermöglicht, aber keinen schon vorhandenen Inhalt löscht.

path ref.path -> aString

Liefert den vollständigen Pfad für die zu Grunde liegende Datei.

class Mutex
Parent: Object
Version: 1.6

Index:

lock locked? synchronize try_lock unlock


require 'thread'
sema4 = Mutex.new

a = Thread.new {   sema4.synchronize {     # access shared resource   } }

b = Thread.new {   sema4.synchronize {     # access shared resource   } }

Mutex implementiert ein einfaches Semaphore, das man zur Koordinierung des Zugriffs auf gemeinsame Daten bei mehreren gleichzeitigen Threads nehmen kann.

instance methods
lock ref.lock -> ref

Versucht die Blockierung zu ergattern und wartet, wenn sie noch nicht verfügbar ist.

locked? ref.locked? -> true or false

Liefert true, falls diese Blockierung momentan schon von einem Thread gehalten wird.

synchronize ref.synchronize { block }-> ref

Greift sich eine Blockierung (mit Mutex#lock), lässt den Block laufen und gibt die Blockierung wieder frei, wenn der Block fertig ist.

try_lock ref.try_lock -> true or false

Versucht sich eine Blockierung zu greifen und kehrt sofort zurück. Liefert true, falls die Blockierung erhalten wurde.

unlock ref.unlock -> ref or nil

Gibt eine Blockierung wieder frei. Lieert nil falls ref nicht blockiert war.

class ConditionVariable
Parent: Object
Version: 1.6

Index:

broadcast signal wait


require 'thread'
mutex = Mutex.new
resource = ConditionVariable.new

a = Thread.new {   mutex.synchronize {     # Thread 'a' braucht jetzt resource     resource.wait(mutex)     # 'a' kann nun resource haben   } }

b = Thread.new {   mutex.synchronize {     # Thread 'b' ist fertig mit resource     resource.signal   } }

ConditionVariable-Objekte erweitern die Klasse Mutex. Mit Condition-Variablen kann man innerhalb von kritischen Bereichen einfach abwarten, bis eine Resource zur Verfügung steht (siehe die Abhandlung auf Seite 119).

instance methods
broadcast ref.broadcast

Weckt alle Threads auf, die auf diese Blockierung warten.

signal ref.signal

Weckt den ersten Thread auf, der auf diese Blockierung wartet.

wait ref.wait( aMutex ) -> aMutex

Gibt die über aMutex gehaltene Blockierung auf und wartet dann; beim Aufwachen wird die Blockierung wieder geholt.

Library: timeout

require "timeout"

for snooze in 1..2   puts "About to sleep for #{snooze}"   timeout(1.5) do     sleep(snooze)   end   puts "That was refreshing" end
erzeugt:
About to sleep for 1
That was refreshing
About to sleep for 2
/tc/usr/lib/ruby/1.6/timeout.rb:37: execution expired (TimeoutError)
	from prog.rb:5:in `timeout'
	from prog.rb:5
	from prog.rb:3:in `each'
	from prog.rb:3

Die timeout-Methode nimmt als einzelnen Parameter die Timeout-Periode entgegen, sowie einen Block. Der Block wird ausgeführt während der Timer gleichzeitig läuft. Falls der Block vor dem Timeout fertig ist, liefert timeout true. Andernfalls wird eine TimeoutError-Exception ausgelöst.

class WeakRef
Parent: Delegator
Version: 1.6

Index:

new weakref_alive?


require "weakref"

ref = "fol de rol" puts "Initial object is #{ref}" ref = WeakRef.new(ref) puts "Weak reference is #{ref}" ObjectSpace.garbage_collect puts "But then it is #{ref}"
erzeugt:
Initial object is fol de rol
Weak reference is fol de rol
n finals=>1
0x40188a7c
n finals=>0
prog.rb:8: Illegal Reference - probably recycled (WeakRef::RefError)

In Ruby werden Objekte nicht für die Garbage-Collection freigegeben, wenn es immer noch Referenzen auf sie gibt. Normalerweise ist das eine gute Sache --- es wäre äußerst unschön, wenn Objekte sich einfach in Luft auflösen, während man sie noch benutzt. Andererseits braucht man manchmal etwas mehr Flexibilität. Man will zum Beispiel den Inhalt von oft benutzten Dateien als Cache im Speicher halten. Je mehr Dateien man einliest, desto größer wird dann der Cache. Irgendwann wird dann der Speicher knapp, der Garbage-Collecter wird aufgerufen, aber die Objekte im Cache werden alle von der Cache-Verwaltung referenziert und können deshalb nicht vernichtet werden.

Eine Weak-Reference (schwache Referenz) verhält sich ganz genau wie ein normales Objekt mit einer wichtigen Ausnahme --- das referenzierte Objekt kann Opfer der Garbage-Collection werden, selbst wenn noch eine Referenz darauf existiert. Wenn man in dem Cache-Beispiel die gecacheten Dateien über Weak-References anspricht, so können sie durch den Garbage-Colletor vernichtet werden, wenn der Speicherplatz knapp wird, und der Rest der Applikation hat wieder genug davon.

Natürlich sind Weak-References nicht ganz so einfach zu behandeln. Da das referenzierte Objekt jederzeit vom Garbage-Collector vernichtet werden kann, muss der Code, der darauf zugreift, erst sicherstellen, dass die Referenzen auch noch gültig sind. Dafür gibt es zwei Techniken. Zunächst kann man das Objekt ganz normal ansprechen. Jeder Versuch, ein vom Garbage-Collector vernichtetes Objekt zu referenzieren, löst eine WeakRef::RefError-Exception aus, die man dann behandeln kann.

Ein anderer Zugang liegt in der Benutzung der WeakRef#weakref_alive?-Methode, um die Gültigkeit einer Referenz vor ihrer Benutzung zu prüfen. Die Garbage-Collection muss natürlich währenddessen und während darauf folgender Zugriffe auf das Objekt ausgeschaltet bleiben. In einem Programm mit nur einem Thread kann man das etwa wie folgt machen:

ref = WeakRef.new(someObject)
#
# .. some time later
#

gcWasDisabled = GC.disable if ref.weakref_alive?   # do stuff with 'ref' end GC.enable unless gcWasDisabled

class methods
new WeakRef.new( anObject ) -> ref

Erzeugt eine Weak-Reference auf anObject und liefert diese zurück. Alle weiteren Referenzen auf anObject sollten dann über ref laufen.

instance methods
weakref_alive? ref.weakref_alive? -> true or false

Liefert false, wenn das über ref referenzierte Objekt schon vom Garbage-Collector vernichtet wurde.


Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Übersetzung: Jürgen Katins
Für das englische Original:
© 2000 Addison Wesley Longman, Inc. Released under the terms of the Open Publication License V1.0. That reference is available for download.
Diese Lizenz sowie das Original vom Herbst 2001 bilden die Grundlage der Übersetzung
Es wird darauf hingewiesen, dass sich die Lizenz des englischen Originals inzwischen geändert hat.
Für die deutsche Übersetzung:
© 2002 Jürgen Katins
Der Copyright-Eigner stellt folgende Lizenzen zur Verfügung:
Nicht-freie Lizenz:
This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
Freie Lizenz:
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".