Abstract |
---|
Die Skriptsprache Ruby hat ihre Wurzeln in Japan, ist aber vor einiger Zeit in die USA und auch nach Europa hinübergeschwappt. Die Sprache bietet eine ganze Reihe von innovativen und überraschenden Features, es lohnt sich also ein näherer Blick. Es ist natürlich klar, dass in einem halbstündigen Vortrag weder eine komplette Spracheinführung gegeben, noch eine vollständige übersicht über die Features von Ruby geboten werden kann. Stattdessen zeige ich Ihnen exemplarisch, was alles mit Ruby machbar ist. Ziel soll es also nicht sein, nach Ende des Vortrags den Raum als fortgeschrittener Ruby-Programmierer zu verlassen, vielmehr möchte ich Ihr Interesse für eine faszinierende neue Sprache wecken. |
Während ein Großteil der populären Skriptsprachen amerikanischen Ursprungs sind, hat Ruby seine Wurzeln auf einem ganz anderen Kontinent. Der Erschaffer von Ruby, Yukihiro Matsumoto, lebt und arbeitet in Japan. So ist es auch zu erklären, dass Ruby insbesondere in Japan eine große Anwenderbasis hat; neueren Untersuchungen zufolge ist es dort sogar populärer als Pyton.
Die Sprache wurde im Jahr 1993 das erste Mal der Öffentlichkeit zugänglich gemacht und hat dann langsam aber sicher immer weitere Kreise gezogen. Dennoch dauerte es sieben weitere Jahre, bis 2000 Ruby auch in USA Fuß fassen konnte; der Sprung über den großen Teich nach Europa war und ist der nächste logische Schritt. Ruby-Vater Matsumoto bevorzugt es sowieso, mit seinem auch für Nicht-Asiaten einfach zu merken und auszusprechenden Namen "Matz" angesprochen zu werden. Matz übrigens ist nicht nur sehr sympathisch, er ist sich auch nicht zu schade sich in Usenet-Diskussionen selbst einzuschalten und Fragen persönlich zu beantworten (wenn nicht ein Mitglied aus der engagierten Ruby-Community schneller war). Im Vergleich zu manch anderer Programmiersprache ist das ein wahrer Segen.
Die ursprüngliche Intention von Ruby war, eine Alternative zu Perl zu entwickeln. Während Perl-Anhänger ihre Lieblingsskriptsprache als Schweizer Taschenmesser ansehen, bezeichnen Kritiker sie als "Schweizer Kettensäge". Ruby hat sich einige der Annehmlichkeiten von Perl geborgt und diese in die Sprachsyntax übernommen. Auch Python, das ja wie gesagt in Japan schon überholt wurde, diente als Meßlatte die es zu überwinden galt.
Was viele Anhänger von OOP (Objektorientierter Programmierung) freuen wird: Alles in Ruby ist ein Objekt. Bei aller berechtigten Kritik an dem übermäßigen Einsatz von OOP, die Vorteile liegen auf der Hand; ein sehr strukturiertes Programmieren ist möglich. Die daraus resultierenden Nachteile sind jedoch auch nahe liegend, insbesondere in Sachen Geschwindigkeit; mit Perl und Python hält Ruby zwar mit, gegen kompilierte Programme kommt Ruby jedoch nicht an.
In Ruby werden Variablennamen ohne Dollarzeichen oder einen anderen Identifikator eingeleitet:
i = 0
x, y = 3, 4
Die
letzte Anweisung ist eine parallele Zuweisung; x
wird der Wert 3,
y
der Wert 4 zugewiesen.
Mit
puts
wird in der Konsole ein Text ausgegeben:
puts Math.sqrt(x*x+y*y)
Als Ausgabe erscheint 5.0.
Als
Kontrollstruktur stehen while
-Schleifen und if
-Bedingungen zur Verfügung.
Folgender Code gibt drei Mal das Wort "Linuxtag" aus:
i=0
while i<3
puts "Linuxtag\n"
i = i + 1
end
Und
hier ein Beispiel für if
:
os = "Win32"
if os == "Linux"
puts "Linuxfreund"
else
puts "Linuxfeind"
end
Codeblöcke
werden entweder durch geschweifte Klammern abgegeben, oder es werden dem
Sprachschatz von BASIC ähnliche Schlüsselwörter verwendet; ein end
beendet den
Block. Das sieht dann ungefähr so aus:
def LinuxBlock
yield
end
Das
Kommando yield
führt ein anzugebendes Kommando aus. Der obige Block kann durch
Angabe des Blocknamens (hinter def) aufgerufen werden; als Parameter wird
innerhalb von runden Klammern ein oder mehrere Befehle angegeben. Mit puts
beispielsweise wird ein beliebiger Text ausgegeben:
LinuxBlock
{ puts "Linuxtag 2002" }
Funktionsblöcke können auch die Funktion von den Funktions-Sprachelementen anderer Sprachen übernehmen, beispielsweise hier zur Berechnung der Fakultät einer Zahl:
def Fak(n)
if n<0
return "nix da!"
else
produkt = 1
while n>1
produkt = produkt * n
n = n - 1
end
return produkt
end
end
puts(Fak(6))
Wie
zu sehen, wird mit return
ein Rückgabewert angegeben und der Codeblock
verlassen. Als Ergebnis wird wie erwartet 720 ausgegeben.
Die
kurze übersicht über Sprachspezifika soll mit einem kleinen Ausflug in die
objektorientierte Welt beendet werden. Klassen werden mit dem Schlüsselwort
class
eingeleitet, die einzelnen Klassenmethoden mit dem Schlüsselwort def
bestimmt. Dabei kann eine Methode als Konstruktur eingesetzt werden, wenn sie
den Namen initialize
trägt. Eigenschaften der Klasse erhalten als Präfix
den Klammeraffen - genauer gesagt wird damit ausgedrückt, dass die Variable nur lokal sichtbar ist:
class Steuer
def initialize(steuersatz)
@steuersatz = steuersatz
end
def brutto(betrag)
return betrag * (1+@steuersatz)
end
def netto(betrag)
return betrag / (1 + @steuersatz)
end
end
st = Steuer.new(0.16)
puts st.brutto(125)
puts st.netto(290)
Die Ausgabewerte sind 145.0 und 250.
Ein Muss für jede fortschrittliche Programmiersprache sind entweder mächtige Funktionen zur Behandlung von Strings oder gleich reguläre Ausdrücke. Ruby bietet insbesondere im letzteren Bereich Funktionalität, hier ein kleines Beispiel:
name = gets
/(\w+), (\w+)/ =~ name
puts "Sie heißen #{$2} #{$1}!"
Bei der Eingabe "Matsumoto, Yukihiro" würde also "Sie heißen Yukihiro Matsumoto" ausgegeben würden.
Dateizugriff
mit Ruby ist ebenfalls einfach. Durch File.new()
wird eine Verbindung zu einer
Datei geöffnet; als zweiter Parameter wird der Zugriffsmodus angegeben
(beispielsweise "r"
zum Lesen, "w" zum Schreiben):
zaehler = 0
handle = File.new("dateiname", "r")
handle.each_line do |zeile|
zaehler = zaehler+1
puts zaehler.to_s + ": " + zeile
end
Die
angegebene Datei wird zeilenweise eingelesen und zusammen mit der Zeilennummer
ausgegeben. Die Methode to_s()
einer Zahl wandelt diese übrigens in einen
String um.
Ruby
ist multithreadfähig, was an einem etwas fortgeschrittenen Beispiel erklärt
werden soll. Im Modul net/http
, das mit require "net/http"
eingebunden werden kann, sind Funktionalitäten zum Laden von Daten über eine HTTP-Verbindung
angegeben. Das folgende Beispiel holt nun mehrere Webseiten, und zwar parallel.
Dies wird realisiert, indem verschiedene Threads eingerichtet werden:
require "net/http"
urls = ["http://www.microsoft.com", "http://www.linuxtag.org"]
threads = []
for el in urls
threads.push(Thread.new(el)) { |url|
stream = Net::HTTP.new(url, 80) #Port 80
puts "Hole #{url} ..."
status, html = h.get("/", nil)
puts "#{url} empfangen!"
}
end
threads.each { |t| t.join }
Wie in der Ausgabe zu sehen ist (zumindest in den meisten Fällen), wird zwar die Homepage von Microsoft als erstes abgerufen, zuerst empfangen wird jedoch die des Linuxtag e.V., entweder aufgrund der geringeren Dateigröße oder infolge einer besseren Anbindung.
Mit minimalen Anpassungen können Ruby-Programme auch als Shell-Skripten benutzt werden; der Sprachumfang des japanischen Newcomers übertrifft freilich den vieler Shells bei weitem. Durch das Einfügen des korrekten Pfads zum Ruby-Interpreter nach dem She-Bang wird das Skript direkt von Ruby ausgeführt, zumindest falls der Benutzer Ausführungsrechte für die Datei hat. Standard-Dateiendung für Ruby-Skripte ist .rb.
#!/usr/bin/env ruby
puts "Ich bin ein Shell-Skript"
Ruby dient aber nicht nur zum Konsolen-Modus. Mit der Tk-Komponente (der letzte Teil in Tcl/Tk) können Benutzeroberflächen gestaltet werden. Diese sind dann zwar plattformunabhängig, die Geschwindigkeit nativer Oberflächen kann damit jedoch natürlich nicht erreicht werden. Hier ein kleines Beispiel, das ein einfaches Fenster samt Schaltfläche erzeugt. Ein Klick auf die Schaltfläche beendet das Ruby-Skript.
require "tk"
form = TkRoot.new { title "GUI mit Ruby" }
zeile1 = TkFrame.new(form)
zeile2 = TkFrame.new(form)
ausgabe = TkLabel.new(zeile1) do
text "Linuxtag 2002"
pack
end
button = TkButton.new(zeile2) do
text "Ende"
command { proc exit }
pack
end
zeile1.pack
zeile2.pack
Tk.mainloop
Außer Tk können noch andere Graphical Toolkits eingesetzt werden, beispielsweise Gtk.
Zu guter Letzt wollen wir noch einen kurzen Blick auf den Web-Einsatz von Ruby werfen. Im CGI-Modus lässt sich beispielsweise die Dateiendung .rb mit dem Ruby-Interpreter verknüpfen. Sie müssen jedoch den kompletten HTTP-Header selbst erzeugen, also insbesondere den MIME-Typ von Hand erzeugen. Hier ein minimales Beispiel:
#!/usr/bin/env ruby
print "Content-type: text/html\n\n"
print "<html>"
print "<title>Ruby goes WWW</title>"
print "<body>Ruby goes WWW!</body>"
print "</html>"
Auf dieser Basis können nun etwas komplexere Skripten erstellt werden. Beispielsweise können Formulardaten eingelesen und ausgewertet werden. Dazu geben wir ein einfaches HTML-Formular aus, das per GET verschickt wird:
#!/usr/bin/env ruby
print "Content-type: text/html\n\n"
print "<html>"
print "<title>Ruby goes WWW</title>"
print "<body><form>"
print "<input type=\"text\" name=\"Name\" />"
print "<input type=\"submit\" />"
if ENV["QUERY_STRING"]
ENV["QUERY_STRING"].grep(/(.*)=(.*)/)
if $2
print "<br />" + $2.to_s
end
end
print "</body></html>"
Die Querystring (also alles, was hin der einem Fragezeichen an den URL angehängt worden ist, wird in einen Teil links von einem Gleichheitszeichen und rechts von einem Gleichheitszeichen getrennt. Rechts davon steht der Wert, der in das Textfeld eingegeben worden ist.
Wem
das ganze zu umständlich ist, wird eventuell mit dem CGI
-Modul von Ruby
glücklich, das in etwa Lincoln Steins CGI.pm
für Perl entspricht. Damit lassen
sich sehr bequem HTML-Seiten erstellen. Nachfolgendes Listing entspricht in
etwa dem Vorgängerskript, ist jedoch deutlich bequemer:
#!/usr/bin/env ruby
require "CGI"
ausgabe = CGI.new("html3")
ausgabe.out {
ausgabe.html {
ausgabe.head {
ausgabe.title { "Ruby goes WWW" }
} +
ausgabe.body {
ausgabe.form {
ausgabe.text_field("Name") +
ausgabe.submit("Abschicken")
} +
ausgabe.br + ausgabe["Name"].first.to_s
}
}
}
In diesem Vortrag konnten die Möglichkeiten von Ruby nur angeschnitten werden; die umfangreiche Modulbibliothek bietet weitaus mehr. Die Frage ist, welche Chancen Ruby in Zukunft hat. Zumindest im Webbereich haben die etablierten Konkurrenten, allen voran PHP, noch die Nase vorn; einige der Funktionalitäten sind für Ruby noch nicht implementiert worden. Das soll Sie aber nicht davon abhalten, selbst erste Schritte in der Sprache zu unternehmen. Wer weiß, vielleicht erstellen Sie in Zukunft all Ihre Shellskripten in Ruby, oder Sie setzen Matz' Sprache in der Tat für Webapplikationen ein. Das erklärte Ziel des Vortrags, Interesse für die Materie zu wecken, ist hoffentlich gelungen.
Über den Autor:
Christian Wenz ist Autor von über zwei Dutzend Computerbüchern
mit dem Schwerpunkt Webprogrammierung, Verfasser von Artikeln in Fachzeitschriften (u.a. c't,
Internet World) sowie regelmäßig Speaker auf Konferenzen. Zu seinen erfolgreichsten
Publikationen gehören unter anderem das "Web Publishing Kompendium"
(Markt + Technik) sowie diverse Veröffentlichungen zu PHP (Addison-Wesley, Markt+Technik).