Lektion 18 - Gib ihr dein Ruby!
Peter hat ein Programm in Ruby für Livia entwickelt und möchte es ihr zum Geburtstag schenken. Livia leidet an Unpünktlichkeit. Also hat er die letzten Tage vor dem großen Fest damit verbracht, ihr eine Zeitansage in Ruby zu schreiben. Den Quellcode teilte er auf zwei Dateien auf. Nun steht er vor der Frage, wie er ihr seine kreativen Zeilen zukommen lässt. Soll er beide Dateien als Anhang an seine Glückwunsch E-Mail kleben? Soll er sie gemeinsam in eine Zipdatei packen? In dieser Lektion lernst du, wie du deine coolen Programme an andere weitergibst. Der Quellcode zu dieser Lektion befindet sich wie immer im Downloadbereich.
Peter entscheidet sich für den Standardweg, um sein Rubyprogramm als Packet für Livia verfügbar zu machen: er erstellt ein GEM (engl. Edelstein) mit Hilfe von RubyGems, dem Packetsystem für Ruby.
Mit RubyGems kann man aber nicht nur ein Packet einer Ruby Anwendung erstellen, sondern diese Packete auch auf dem lokalen Computer verwalten, d.h. neue Gems installieren, bestehende deinstallieren, nach neuen suchen oder ein existierendes Gem auf eine neue Version updaten.
Konkret gesprochen ist ein Gem eine einzige Datei, genauer eine Archivdatei, die eine oder mehrere Dateien in komprimierter Form enthält. Die Erstellung so einer Datei erfordert den RubyGems Packetmanager.
Der Befehl gem auf der Kommandozeile teilt dir leicht mit, ob RubyGems bei dir bereits verfügbar ist.
C:\entwicklung> gem
RubyGems is a sophisticated package manager for Ruby. This is a
basic help message containing pointers to more information.
Usage:
gem -h/--help
gem -v/--version
gem command [arguments...] [options...]
Examples:
gem install rake
gem list --local
gem build package.gemspec
gem help install
Further help:
gem help commands list all 'gem' commands
gem help examples show some examples of usage
gem help <COMMAND> show help on COMMAND
(e.g. 'gem help install')
Further information:
http://rubygems.rubyforge.org
Der Packetmanager kommt gewöhnlich mit der Installation von Ruby auf dein System. Andernfalls musst du ihn zu Fuß installieren.
Peter hat einiges zu tun. Er teilt sich die Arbeit folgendermaßen ein:
- Das Zeitansageprogramm entwickeln
- Das Programm für den Ruby GEM Packetmanager vorbereiten. Dazu wird eine bestimmte Verzeichnisstruktur
wie folgt angelegt:
- Unterverzeichnis lib mit der Datei zeitansage.rb
- Unterverzeichnis bin mit der Datei wie_spaet (das ist eine Rubydatei, aber ohne Endung .rb)
- README Datei anlegen, die das Programm beschreibt
- LICENSE Datei anlegen, die die Software Lizenz zum Programm enthält
- Das Gem mit Hilfe des RubyGems Packetmanagers aus einer GEM-Spezifikation erzeugen
- Testinstallation auf seinem lokalen Computer ausprobieren
Das Zeitansageprogramm
Peters Progrämmchen ist recht einfach. Es besteht aus der Klasse Zeitansage, deren Konstruktor (Methode initialize) eine Liste mit den Anreden und ein Muster für die Ausgabe der Uhrzeit erhält.
class Zeitansage
def initialize(anreden, zeitmuster)
@anreden = anreden
@zeitmuster = zeitmuster
end
def es_ist
zeit = Time.now.strftime(@zeitmuster)
"#{anrede} #{zeit}"
end
private
def anrede
text = ""
unless @anreden.nil?
idx = zufalls_zahl(@anreden.length)
text = @anreden[idx]
end
text
end
# Liefert keine wirkliche Zufallszahl, für diese
# Zwecke hier ist es aber ausreichend.
def zufalls_zahl(max)
(max > 0) ? (Time.now.sec % max) : 0
end
end
Peter überlegt sich ein paar Anreden, wie etwa Hallo Livia! oder Oh, meine Prinzessin!” und legt sie in einer Liste anreden ab.
anreden = [
"Hallo Livia!",
"Hi Livia!",
"Liebe Livia!",
"Oh, meine Prinzessin!",
"Wozu willst du das schon wieder wissen?",
"Sollte ich dir lieber eine Armbanduhr schenken?",
"Ich sag nichts ohne meinen Rubyinterpreter!",
]
Bei der Ausgabe der Zeit ist er weniger kreativ und wählt folgendes Muster:
muster = "Es ist %H:%M Uhr."
Die Prozentzeichen jeweils gefolgt von einem Buchstaben sind Platzhalter, die später dann mit den entsprechenden Werten der Zeit oder Datum ersetzt werden. So wird %H durch den Wert der Stunden und %M durch den Wert der Minuten ersetzt. Es gibt noch viel mehr solche Platzhalter für Zeit und Datum.
Ein Objekt der Klasse Zeitansage wird mit der Liste der Anreden und dem Zeitausgabemuster zum Leben erweckt und schon ist das Programm wie_spaet für Livias Geburtstag fertig!
require 'zeitansage'
anreden = [
"Hallo Livia!",
"Hi Livia!",
"Liebe Livia!",
"Oh, meine Prinzessin!",
"Wozu willst du das schon wieder wissen?",
"Sollte ich dir lieber eine Armbanduhr schenken?",
"Ich sag nichts ohne meinen Rubyinterpreter!",
]
muster = "Es ist %H:%M Uhr."
z = Zeitansage.new(anreden, muster)
puts z.es_ist
Das Programm für den Ruby GEM Packetmanager vorbereiten
Dafür legt Peter zuerst eine Verzeichnisstruktur an, wie sie der Packetmanager verlangt. Das ausführbare Programm kommt in eine endungslose Datei wie_spaet in das Unterverzeichnis bin, die Klasse Zeitansage in eine separate Datei zeitansage.rb in das Unterverzeichnis lib.
Livia wird sicher in seinem Programmcode herumstöbern. Peter entschließt sich, ihr eine README Datei zu hinterlassen, sodass sie sich leichter in den komplexen Code einarbeiten kann.
= wie_spaet -- Ein Ruby Programm zur Zeitansage
Dieses Softwarepacket enthält 'wie_spaet', ein einfaches
Rubyprogramm, dass die aktuelle Uhrzeit ausgibt.
wie_spaet hat die folgenden Features:
* Anreden: Die Zeitansage kann mit einer Liste von Anreden initialisiert
werden. Aus der Liste wird bei jedem Aufruf mehr oder wenig zufällig
eine Anrede ausgewählt.
* Zeitausgabe: Das Ausgabeformat der Zeitansage kann ein mit den
üblichen Platzhaltern für die Zeit- und Datumswerte versehene
Zeichenkette sein.
== Download
Die aktuelle Version von 'wie_spaet' gibt es unter
* http://www.rubykids.de
== Installation
=== GEM Installation
wie_spaet kann als GEM gedownloaded werden und wird anschließend
mit folgendem Befehl installiert (je nach Version):
gem install wie_spaet-0.0.1.gem
== Verwendung von wie_spaet
=== Direkte Verwendung
Ist wie_spaet installiert, kann es einfach auf der
Kommandozeile aufgerufen werden:
C:\> wie_spaet
Jedes Softwarepacket, das man an andere weitergeben möchte benötigt eine Lizenz, damit für alle klar ist, ob die Software frei verwendet werden darf, ob sie etwas kostet oder ob man zu jeder Verwendung den Urheber um Erlaubnis fragen oder ihm gar noch was dafür bezahlen muss.
Peter ist da sehr großzügig und möchte sein Programm natürlich als OpenSource Software zur freien Nutzung aller Welt (insbesondere Livia) zur Verfügung stellen. Er kann sich aber nicht recht entschließen, welche OpenSource Lizenz die passende ist und erfindet kurzer Hand seine eigene.
Copyright (C) 2008 Peter @ www.rubykids.de
Peter's Geburtstags-Lizenz
Version 1.0, Februar 2008
Hiermit hat jeder, der eine Kopie dieser Software erhält, die Erlaubnis,
sie kostenfrei unter den folgenden Bedingungen uneingeschränkt zu verwenden,
zu kopieren, zu verändern, zu veröffentlichen und weiterzugeben:
* Der obige Copyright Hinweis und diese Erlaubnis muss in allen Kopien
und Teilen der Software enthalten sein.
* Der Empfänger der Software ist ein Kind, oder fühlt sich wie ein Kind,
oder kann sich zumindest während der Verwendung der Software
wie ein Kind benehmen.
Die Verzeichnisstruktur sieht bisher etwa folgendermaßen aus:

GEM mit Packetmanager und Spezifikation erzeugen
Die sogenannte Spezifikation legt genau fest, welche Teile aus der oben angelegten Verzeichnisstruktur mit in das Packet übernommen werden sollen. Die Spezifikation ist gewöhnlicher Rubycode in einer Datei mit der Endung gemspec, Peter nennt sie wie_spaet.gemspec.
spec = Gem::Specification.new
spec.name = "wie_spaet"
spec.version = "0.0.1"
spec.authors = ["rubykids"]
spec.summary = "Sagt dir die Zeit."
spec.homepage = "http://www.rubykids.de/"
spec.description = "Waehlt zufaellig eine Anrede und sagt dir die Zeit."
spec.files = [ "README", "LICENSE", "bin/wie_spaet", "lib/zeitansage.rb"]
spec.executables = ["wie_spaet"]
spec.rdoc_options = ["--charset", "UTF-8", "--line-numbers",
"--inline-source", "--main", "README", "--title",
"wie_spaet -- Sagt dir die Zeit!", "--all"]
spec.has_rdoc = true
spec.extra_rdoc_files = ["README", "LICENSE", "bin/wie_spaet"]
Jede GEM-Spezifikation zu einem RubyGems Packet sieht etwa so aus. Zuerst wird ein Objekt der Klasse Gem::Specification in der Variablen spec angelegt (was die Doppelpunkte im Klassennamen bedeuten haben wir noch nicht behandelt, das kommt noch).
Dann werden einige Attribute dieses Objektes gesetzt. Es gibt zwingend notwendige Attribute wie etwa name und version und optionale. Was die Attribute genau bedeuten ist aus ihren Bezeichnungen eigentlich meistens klar. Wir können sie hier nicht im Detail besprechen. Du kannst Genaueres aber gerne in einem Rubybuch oder im Online RubyGems Manual nachlesen.
Die Datei mit der GEM-Spezifikation legt Peter ganz oben in der Verzeichnisstruktur neben LICENSE und README ab und ruft dann in diesem Verzeichnis an der Kommandozeile den Packetmanager für RubyGems auf, um endlich das Packet für den Geburtstag zu schnüren:
C:\entwicklung\lektion_18>gem build wie_spaet.gemspec
Successfully built RubyGem
Name: wie_spaet
Version: 0.0.1
File: wie_spaet-0.0.1.gem
Es entsteht eine Datei wie_spaet-0.0.1.gem. In dieser Datei schlummert sein gesamtes Rubyprogramm, für Livia.
Sobald Livia das GEM erhält, kann sie es installieren:
C:\livia\geschenke>gem install wie_spaet-0.0.1.gem
Successfully installed wie_spaet, version 0.0.1
Installing ri documentation for wie_spaet-0.0.1...
Installing RDoc documentation for wie_spaet-0.0.1...
und nachschauen, ob es wirklich installiert ist:
C:\livia\geschenke>gem list --local wie_spaet
*** LOCAL GEMS ***
wie_spaet (0.0.1)
Sagt dir die Zeit.
und es natürlich verwenden:
C:\livia\geschenke>wie_spaet
Oh, meine Prinzessin! Es ist 23:31 Uhr.
Was mit dem GEM nach dem Installieren passiert

Bei der Installation des GEM landet das gesamte Packet im
Verzeichnisbaum der Rubyinstallation im Zweig ruby\lib\ruby\gems\1.8.
im Unterordner wie_spaet-0.0.1.
Zusätzlich wird für die Datei wie_spaet aus dem bin Verzeichnis eine korrespondierende, an der Kommandozeile ausführbare Datei im bin Verzeichnis der Rubyinstallation abgelegt. Diese Datei wie_spaet.cmd kann dann direkt an der Kommandozeile mit wie_spaet aufgerufen werden.
Die GEM Spezifikationsdatei wie_spaet.gemspec taucht separat im
Verzeichnis ruby\lib\ruby\gems\1.8\specifications auf.
Nachdem nun Peter die Installation überprüft hat, ist er mit seinem GEM zufrieden, findet bei seiner Lieblingsfloristin gegenüber noch ein paar hübsche Blumen, kopiert sein Gem auf einen USB-Stick und versteckt ihn zusammen mit einer Grußkarte in dem Strauß. Die Angst, Livia könnte in seinem Geburtstagsgeschenk einen Bug finden, schüttelt er ab als die Haustür hinter ihm ins Schloß fällt. Wird sich Livia freuen? Na bestimmt!
