EIn Ruby-Interpreter in Java - das kann doch nur Spielerei sein? Keineswegs: Der Artikel zeigt, wie JRuby die Vorteile zweier Programmiersprachen vereint, und liefert Beispielcode, der den Einstieg erleichtert.
JRuby ist eine 100-prozentige Java-Implementierung eines Ruby-Interpreters. Sie weist zwar nicht alle Funktionen von Ruby auf, verfügt aber dennoch über die meisten der eingebauten Klassen dieser Sprache. ZDNet demonstriert, wie JRuby die positiven Eigenschaften von Java und Ruby kombiniert. Außerdem liefert der Artikel einige wichtige Tipps und ein erstes längeres Code-Beispiel.
Es verseht sich von selbst, dass man sich sowohl mit Java als auch mit Ruby auskennen muss, um optimal mit JRuby zu arbeiten. Reine Java-Programmierer sollten also vielleicht erst einmal die einführenden[1] Artikel[2] zu Ruby[3] lesen, die gleichzeitig die Grenzen dessen abstecken, was hier erläutert wird.
Wo bekommt man JRuby?
Um mit JRuby zu arbeiten, empfiehlt es sich zunächst, die aktuelle Version des Archivs jruby-bin über die Codehaus-Website[4] zu beschaffen. Es enthält alles, was benötigt wird. Dannach muss die Archivdatei an einem beliebigen Ort extrahiert und der Pfad-Variablen your-jruby-dir/bin hinzugefügt werden.
Nun sollte Folgendes ausgeführt werden können:
jruby -v ruby 1.8.5 (2007-08-23 rev 4201) [ppc-jruby1.0.1]
Erste Arbeitsschritte
Zunächst wird die interaktive Konsole verwendet, die mit diesem Befehl aufgerufen wird:
jirb irb(main):001:0>
Da es sich bei JRuby um einen Ruby-Interpreter handelt, können beliebige Ruby-Programmzeilen ausgeführt werden.
Das ist soweit keine Überraschung. Doch der wahre Grund, diese Zeilen so auszuführen, statt mit dem nativen Ruby-Interpreter, besteht darin, sich Java zunutze zu machen. Nun kommt das Java-Framework ins Spiel:
irb(main):003:0> require 'java' => true
Der Versuch, einfach einige Standardzeilen Java-Code auszuführen, funktioniert jedoch nicht.
Um das Hello world-Beispiel zum Laufen zu bringen, muss man weit zurückdenken. Es geht um ein paar Angelegenheiten, die einem bei Java bereits selbstverständlich geworden sind.
Ein Besuch auf einer API-Seite[5], die wohl viele seit langem nicht mehr gesehen haben, bringt die Lösung: System ist ja ein Element des java.lang-Pakets, out ist ein Feld von System und println stellt wiederum eine Methode von out dar.
Deshalb ist für einen korrekten Aufruf Folgendes erforderlich:
irb(main):005:0> java.lang.System::out.println("Hello World")
Hello World
=> nil
Um die Sache interessanter zu machen - auch das funktioniert:
irb(main):005:0> java.lang.System.out.println("Hello World")
Hello World
=> nil
Und um zu zeigen, dass man Ruby und Java in derselben Zeile verwenden kann:
irb(main):006:0> puts java.lang.System::err.println("Hello World")
Hello World
nil
=> nil
Bis jetzt wurde die Java-Methode zur Übergabe von Parametern verwendet. Dank Ruby kann man jedoch die Klammern weglassen.
irb(main):007:0> java.lang.System::out.println "Hello World" Hello World => nil
Ein weiterer Vorteil von Ruby liegt darin, dass man leicht Einblick in Objekte erlangen kann. Die Reflection-API von Java wird dadurch quasi überflüssig.
Um einen Überblick über alle Methoden zu erhalten, muss einfach die methods-Funktion des Objekts aufgerufen werden, so wie man es auch in Ruby tun würde.
Auf ähnliche Weise lassen sich auch die Konstanten ausfindig machen:
irb(main):009:0> java.lang.Math.constants => ["PI", "E"]
Oder die Vorläufer einer Klasse:
irb(main):011:0> java.lang.Math.ancestors => [Java::JavaLang::Math, Java::JavaLang::Object,
ConcreteJavaProxy, JavaProxy, JavaProxyMethods, Object, Kernel]
Sogar der Typ der Klasse lässt sich so anzeigen:
irb(main):012:0> java.lang.Math.class => Class irb(main):013:0> java.lang.class => Module
Das Ausschreiben der vollständigen Namen von Paketen ist ermüdend. Um eine Klasse zu importieren, lässt sich auch die Funktion include_class einsetzen.
irb(main):015:0> include_class java.lang.System => Java::JavaLang::System
Die Klasse lässt sich dann genauso verwenden, als hätte man eine Anweisung in Java importiert.
irb(main):016:0> System.out.println("Wir wurden importiert")
Wir wurden importiert
=> nil
Das Importieren einer Klasse schlägt jedoch fehl, wenn versucht wird, eine Klasse zu laden, die im Ruby-Namensraum bereits existiert.
irb(main):014:0> include_class java.lang.Math (eval):1 warning: already initialized constant Math => Java::JavaLang::Math
Die Lösung liegt hier in der Umbenennung der Klasse. In diesem Fall wird aus der Klasse Math die Klasse JMath.
irb(main):017:0> include_class('java.lang.Math')
{|package,name| "J#{name}"}
=> ["java.lang.Math"]
Diese kann dann folgendermaßen eingesetzt werden:
Einige Änderungen sind dafür erforderlich:
- Konvertieren der Syntax new <Object>(par1,par2) zu <Object>.new(par1,par2)
- Zugriff auf Felder mit der Syntax GridBagConstraints::HORIZONTAL anstelle von GridBagConstraints.HORIZONTAL
- Entfernen des alten Arrays zur Konstruktion der JCombo-Box:
String[] options = {"all", "any"}; modeCombo = new JComboBox(options);Hierdurch wird die Combo-Box mit einem Ruby-Objekt bestückt, und die JCombo-Box verträgt das nicht. Um das zu umgehen, fügt man die Elemente einzeln hinzu.modeCombo = JComboBox.new modeCombo.addItem "all" modeCombo.addItem "any"
- Die für Java typische, wortreiche Methode zum Verlassen des Programms, wenn das Fenster geschlossen wird, ändert sich von:
addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });zu einem einfachen:window.defaultCloseOperation = JFrame::EXIT_ON_CLOSE
- Die main-Methode wird entfernt.
Der vollständige Code lautet somit:
Wenn man aus diesem Listing eine Datei macht, lässt sich diese folgendermaßen in JRuby aufrufen:
jruby testwin.rb
Oberflächlich besteht kein Unterschied zwischen der JRuby- und der Java-Version des Codes. Neben der offensichtlichen Performancebeeinträchtigung durch die Verwendung von JRuby besteht ein klarer Vorteil darin, dass Code mit gleicher Funktionalität weit schneller geschrieben werden kann.
Es lässt sich schon jetzt mit Spannung auf die Geschwindigkeitsverbesserungen warten, die sich ergeben werden, wenn JRuby einen JIT-Compiler erhält. Doch in der Zwischenzeit kann man, falls die Geschwindigkeit nicht so wichtig ist, schon einmal das eine oder andere mit JRuby ausprobieren.
URLs in diesem Artikel:
[1] = http:/
[2] = http:/
[3] = http:/
[4] = http:/
[5] = http:/
[6] = http:/