Open Source im professionellen Einsatz
Linux-Magazin 01/2006
© photocase.com

© photocase.com

Domain Specific Languages in Ruby

Ruby spricht viele Sprachen

Domain Specific Languages vereinfachen die textbasierte Arbeit am Computer durch eine zusätzliche Abstraktionsstufe. Statt jedes Detail in einer allgemeinen Sprache auszuprogrammieren, genügen wenige Schlüsselwörter. Ruby enthält die nötigen Ausdrucksmittel für solche Vereinfachungen.

932

Die Aufgabe problemspezifischer Sprachen (Domain Specific Languages, DSL) ist es, möglichst intuitiv eine recht konkrete Aufgabe zu lösen. Dazu verwenden sie ein möglichst einfaches Vokabular, das zum Problemfeld passt und den Benutzer nicht überfordert. Solche kleinen Spezialsprachen haben in Unix eine lange Tradition, wie der Kasten "DSLs in der Praxis" beweist. Eine moderne Skriptsprache wie Ruby macht durch ihre flexible Syntax das Schreiben von Domain Specific Languages einfach.

Extern und intern

Eine DSL heißt extern, wenn ihre Verarbeitung die Umwandlung in eine andere Sprache oder einen speziellen Interpreter voraussetzt. Für externe DSLs kann der Entwickler eine eigene Syntax definieren, ohne sich den Regeln einer existierenden Sprache zu unterwerfen. Eine interne DSL bedient sich im Gegensatz dazu direkt der Ausdrucksmittel einer Programmiersprache.

Interne DSLs brauchen keinen eigenen Parser, die syntaktische Richtigkeit des Code überprüft der Compiler oder Interpreter. Die Entwicklungsumgebungen kennen die Sprachsyntax, rücken also beispielsweise korrekt ein und färben Sprachkonstrukte farbig.

Ruby eignet sich wegen ihrer vielfältigen Metaprogramming-Fähigkeiten, ihrer offenen Klassen und des flexiblen Objektmodells sehr gut zum Schreiben interner DSLs. Blocks erleichtern es beispielsweise, diese um eigene Sprachelemente zu erweitern und Anweisungen in einem festgelegten Kontext auszuführen. Auch die Möglichkeit, Syntaxelemente abzukürzen oder wegzulassen, erleichtert die Formulierung sauberer DSLs. Die folgenden Abschnitte stellen anhand einiger Beispiele die wichtigsten Sprachelemente für DSLs in Ruby vor.

Die Programmiersprache bietet diverse Möglichkeiten, um die syntaktische Komplexität zu minimieren. Dazu ein Beispiel im Stil der DSL von Switchtower, einem auf die Verteilung von Webanwendungen mit Ruby on Rails [1] spezialisierten Deployment-Tool. Die Switchtower-DSL lässt den Anwender Aufgaben definieren, die auf verschiedenen Servern laufen sollen:

task("backup", { "roles" => "db" })


Die Aufgabe bekommt mit dem ersten Parameter der Methode »task« den Namen »backup« zugeteilt. Manche Aufgaben sollen auf jedem Server ausgeführt werden, andere nur auf einzelnen. Die Parameter in Form eines Hash legen fest, dass die Aufgabe »backup« nur auf Servern mit der Rolle »db« laufen soll.

Besser: Weniger Klammern

In Ruby sind runde Klammern um die Variablen eines Methodenaufrufs nur zu setzen, wenn der Code sonst für den Interpreter nicht eindeutig wäre. So lässt sich die obige Aufgabe umformulieren: »task "backup", { "roles" => "db" }«. Ruby erkennt Hashes am Ende der Parameterliste auch ohne die sonst nötigen geschweiften Klammern. Das vereinfacht den Funktionsaufruf nochmals zu »task "backup", "roles" => "db"«.

Kommt in einem Ruby-Programm eine fixe Zeichenkette vor, empfiehlt es sich meist, sie durch ein Symbol zu ersetzen. Kommt das gleiche Symbol im Programm mehrfach vor, belegt es nur einmal Speicher und ist einfacher zu schreiben als eine normale Zeichenkette.

Statt der Anführungszeichen am Anfang und Ende des Strings ist nur ein führender Doppelpunkt notwendig. Das obige Beispiel reduziert sich damit auf »task :backup, :roles => :db«. Natürlich sind diese Änderungen kosmetischer Natur. Bei DSLs ist aber einfache Handhabung besonders wichtig, wozu auch ein klares Erscheinungsbild gehört.

Zu den wichtigsten Elementen von Ruby gehören Blocks, abgeschlossene Codebereiche, die eine Methode bei ihrem Aufruf übergeben bekommt. Im Normalfall folgt der Block nach der schließenden runden Klammer. Anfang und Ende des Blocks markieren entweder »do« und »end« oder geschweifte Klammern. Der Block läuft immer in dem Kontext ab, in dem er definiert wurde. In der Methode ruft die Anweisung »yield« den Block auf. Die Variablenzuweisung im Block findet zwischen Pipezeichen statt.

DSLs in der Praxis

Populäre Beispiele für Domain Specific Languages sind Regular Expressions, die SVG-Definition für Vektorgrafiken, der Pattern-Scanner Awk oder Konfigurationssprachen wie bei Sendmail. Allen ist gemeinsam, dass sie für einen speziellen Einsatzzweck optimiert sind. Im Unix-Bereich sind seit langem die beiden Tools Lex und Yacc auf das Erstellen und die Verarbeitung von Domain Specific Languages spezialisiert.

In der Ruby-Welt gibt es viele Beispiele für interne DSLs: Das Make-ähnliche Build-Tool Rake [2] verwendet eine DSL für die Konfiguration abhängiger Aufgaben. Das ORM-Paket Active Record [3] benutzt eine sehr einfache DSL zur Beschreibung der Beziehungen zwischen Datenbanktabellen.

Das Deployment-Werkzeug Switchtower [4] wiederum setzt eine DSL dazu ein, um notwendige Aktionen für die Verteilung einer Webanwendung zu definieren. Builder [5] schließlich ist ein Werkzeug für die Erzeugung von XML-Files und ein Stellvertreter für besonders dynamische DSLs: Das Tool fängt alle Aufruf einer Methode ab und wandelt sie in entsprechende XML-Tags um.

Blocks der Art »do |var| puts var end« lassen sich in einer DSL sehr gut verwenden, um in beschreibender Form Einstellungen vorzunehmen:

task :backup, :roles => :db do
  run "backup_command"
end


Eines der mächtigsten Features von Ruby sind die offenen Klassen. Damit ist es jederzeit möglich, Klassen und deren Methoden auch nach ihrer ursprünglichen Definition zu verändern. Das gilt sogar für die Ruby-Basisklassen. Ein gutes Beispiel für eine entsprechende Veränderung der Basisklassen findet sich im Active-Support-Modul [6]. Es überlädt unter anderem die Numeric-Klasse, um den Umgang mit Zeitangaben intuitiver zu gestalten:

class Numeric
  def minutes
    self * 60
  end
  def hours
    minutes * 60
  end
end


Als Beispiel wäre eine Anweisung der Form »5.minutes + 1.hours« denkbar. Eine kleine Änderung erhöht die Lesbarkeit der DSL noch einmal. Während »5.minutes« bereits sehr gut lesbar ist, trifft das auf »1.hours« nicht zu. Stattdessen wäre es passender, »1.hour« schreiben zu können. Da die bestehende Version programmtechnisch richtig funktioniert, fehlt nur eine Kopie der Methode. Das ist leicht mit der Ruby-Methode »alias« zu erreichen:

class Numeric
  def hours
    minutes * 60
  end
  alias :hour :hours
end

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Roter Stern

    Ruby ist eine objektorientierte Skriptsprache, die sich einen Platz zwischen den etablierten Sprachen Perl, Python und vielleicht auch PHP erobert. Ruby, eine Entwicklung aus Japan, hat auch einen gewissen Unterhaltungswert, was den Einstieg erleichtert.

  • Ruby

    Vom einzeiligen Kommando über maßgeschneiderte Skripte bis zum ausgewachsenen Konfigurationsmanager: Die freie Programmiersprache Ruby erweist sich als praktisches Schmuckstück für die Systemadministration und erledigt vieles in erstaunlich wenigen Zeilen.

  • Bücher

    Das Linux-Magazin bespricht zwei Bücher für anspruchsvolle Programmierer: Das erste enträtselt Domänen-spezifische Sprachen, das zweite möchte für besser strukturierten Ruby-Code sorgen.

  • Alles unter Kontrolle

    Bei jeder Änderung an einem Programm besteht die Gefahr, dass unbemerkt neue Fehler entstehen. Mit Unit-Tests kontrollieren Entwickler, ob alle Bausteine ihres Programms erwartungsgemäß funktionieren. Die Skriptsprache Ruby bringt von Haus aus ein leistungsfähiges Modul fürs Unit Testing mit.

  • Wie auf Schienen

    Die meisten Webbibliotheken machen 90 Prozent der Aufgaben einfach, den Rest schlichtweg unmöglich. Das in Ruby geschriebene Open-Source-Framework Rails bewahrt sich die notwendige Flexibilität, um auch die restlichen zehn Prozent auf die Bahn zu bringen.

comments powered by Disqus

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.