JRuby #02 - Ruby rozmawia z Javą, Java rozmawia z Ruby’im

napisane przez wiktor, 17:44 05-09-2008

Krok drugi: integracja

W poprzednim poście opisywałem proces instalacji JRuby'iego tak, żeby korzystanie z niego było proste. Czas wziąć na warsztat integrację Ruby'iego z Javą i odwrotnie.

Ruby rozumie Javę

Kiedy JRuby interpretuje skrypt Ruby'iego to mogą tam być używane wszystkie klasy Javowe. Chcemy, żeby skrypt korzystał z naszej wcześniej utworzonej biblioteki w Javie? Nie ma problemu, dołączamy ją do CLASSPATH i możemy z poziomu Ruby'iego z niej korzystać. Integracja została przedstawiona na poniższych przykładach. Dołożyłem wszelkich starań, aby komentarze były wyczerpujące.

Uruchommy interakcyjną konsolę JRuby'iego: jruby -S jirb i następnie pobawmy się kodem:

RUBY:
  1. # Znane z Javy importowanie wygląda standardowo.
  2. # Niestety importowanie z gwiazdką nie działa, więc import javax.swing.* poczęstuje nas błędem.
  3. import javax.swing.JFrame
  4. import javax.swing.JButton
  5.  
  6. # Składnia Ruby'iego została zachowana dla obiektów Javowych, widać to w tworzeniu nowego egzemplarza JFrame
  7. # Warto zauważyć, że nawiasy są nieobowiązkowe. Poniższe wywołanie jest równoznaczne z JFrame.new("...")
  8. frame = JFrame.new "Ruby swinguje z Java"
  9.  
  10. # Styl kodowania Ruby'iego zostaje zachowany także dla metod. W Javie lubimyTakPisać, a w Ruby'im trochę_inaczej.
  11. # Poniższe wywołanie jest równoważne z frame.setSize(300, 300), które także byłoby poprawne.
  12. frame.set_size 300, 300
  13.  
  14. # Gettery i settery Javowe są dostępne także w odmianie Ruby'iego.
  15. # Poniższa linijka jest równoważna z frame.setAlwaysOnTop(true), które także byłoby poprawne.
  16. frame.always_on_top = true
  17.  
  18. button = JButton.new "Nacisnij mnie"
  19.  
  20. # Blok kodu zostanie w locie przekształcony w klasę implementującą interfejs ActionListener. Niezłe!
  21. # Jest to domyślne zachowanie JRuby'iego, jeśli parametrem jest interfejs z jedną metodą.
  22. # Standardowo w Ruby'im używa się wcięć z 2 spacjami.
  23. button.add_action_listener do |event|            
  24.   # Przykład getterów ala Ruby. Równoznaczne z event.getSource().setText("..."), które także jest OK.
  25.   event.source.text = "Nie naciskaj mnie ponownie!"
  26.   event.source.enabled = false
  27. end
  28.  
  29.  
  30. frame.add(button)
  31. frame.show

Czas poczęstować Ciebie czytelniku jakimś smakołykiem. Oto on:

RUBY:
  1. # Rozszerzenie klasy Javowej String o mechanizm missing_method, czyli
  2. # ta metoda zostanie wywołana, jeśli na obiekcie zostanie wywołana metoda, która
  3. # nie została zdeklarowana.
  4. JavaUtilities.extend_proxy "java.lang.String" do
  5.   def method_missing(symbol, *args)
  6.     puts "Kogo wolasz?"
  7.   end
  8. end
  9.  
  10. txt = java.lang.String.new "Ala ma kota"
  11.  
  12. txt.hmmmm_jak_brzmiala_nazwa_tej_metody?()  # => "Kogo wolasz?"

Java rozumie Ruby'iego

Ruby może zostać wpleciony w kod Javy na 3 sposoby:

  • poprzez Scripting API (wprowadzone z Javą 6, JSR 223, unifikacja silników skryptowych używanych w Javie), szczegóły: https://scripting.dev.java.net,
  • poprzez Beans Scripting Framework (standard wprowadzany przez Apache Jakarta), szczegóły: http://jakarta.apache.org/bsf,
  • bezpośrednio odwołując się do interpretera JRuby'iego.

Zajmiemy się tylko pierwszą opcją. Będziemy do tego potrzebowali opakowania silnika JRuby'iego dla javax.script, które znajdziemy tutaj (najlepiej wersję 1.1.3).

jruby-scripting-api

Powyższa grafika przedstawia zależności w Java Scripting API. Z naszego kodu będziemy odwoływać się wyłącznie do klas javax.script.*, żądać silnika JRuby'iego (jruby-engine.jar), który z kolei sam już będzie odpowiednio wywoływał interpreter JRuby'iego.

Czas podwinąć rękawy i trochę pokodować.

JAVA:
  1. import org.jruby.RubyHash;
  2. import javax.script.*;
  3. import java.util.List;
  4. import java.util.ArrayList;
  5. import java.util.Map;
  6. import static java.lang.System.*;
  7.  
  8. public class RubyInJava {
  9.  
  10.     public static void main(String[] args) {
  11.         // Od Java Scripting API żądamy silnik JRuby'iego
  12.         ScriptEngine rubyEngine = new ScriptEngineManager().getEngineByName("jruby");
  13.         ScriptContext context = rubyEngine.getContext();
  14.  
  15.         List<Integer> list = new ArrayList<Integer>() {{
  16.             add(1); add(2); add(3); add(4);  
  17.         }};
  18.  
  19.         // Do środowiska JRuby'iego dodajemy globalną zmienną list
  20.         rubyEngine.put("list", list);
  21.  
  22.         // Skrypt Ruby'iego, który będziemy wykonywać
  23.         StringBuilder script = new StringBuilder();
  24.         script.append("puts '--- Ruby ---'                                  ").append("\n")
  25.               .append("puts $list.inspect                                   ").append("\n")
  26.               // JRuby do kolekcji Javowych dodaje typowe metody Ruby'iego dla kolekcji
  27.               .append(" $list.each { |item|                                 ")
  28.               .append("   puts \"Element #{item}\"                          ")
  29.               .append(" }                                                   ").append("\n")
  30.               .append(" puts \"Suma: #{$list.inject { |sum, i| sum + i }}\" ").append("\n")
  31.               .append("\n")
  32.               .append(" $hash = { :ala => :ma, :co => :kota }               ").append("\n");
  33.  
  34.         // Wykonanie skryptu
  35.         try {
  36.             rubyEngine.eval(script.toString(), context);
  37.         } catch (ScriptException e) {
  38.             e.printStackTrace();
  39.             return;
  40.         }
  41.  
  42.         out.println("--- Java ---");
  43.  
  44.         // Pobranie zmiennej globalnej po wykonaniu skryptu
  45.         Object hashAsObject = rubyEngine.get("hash");
  46.         out.println("Klasa: " + hashAsObject.getClass());
  47.  
  48.         RubyHash hash = (RubyHash) hashAsObject;
  49.         for (Object o : hash.entrySet()) {
  50.             Map.Entry entry = (Map.Entry) o;
  51.             System.out.println(entry.getKey() + " => " + entry.getValue());
  52.         }
  53.     }
  54. }

Aby uruchomić powyższy kawałek kodu trzeba mieć w CLASSPATH: jruby.jar oraz jruby-engine.jar.

Powyższe przykłady ilustrują, że ludzie pracujący nad JRuby'im wykonali kawał dobrej roboty, żeby łączenie Javy z Ruby'im było bezstresowe dla developerów. Takie połączenie dwóch światów daje nam nowe możliwości: tworzenie mini-języków dla aplikacji Javowych, aplikacje Swingowe w Ruby'im, nie wspominając o Ruby on Rails, a dla Ruby'istów dostępny jest cały ekosystem Javy :).

JRuby #01 - Jak zainstalować, żeby się pobawić?

napisane przez wiktor, 21:27 04-29-2008

JRuby #01 - Instalacja

Ten post otwiera serię artykułów poświęconych JRuby'iemu, czyli implementacji Ruby'iego na platformę Javy. Nikomu raczej nie trzeba przedstawiać nikogo z tej pary :). Na warsztat weźmiemy JRuby 1.1.1.

Zacznijmy od instalacji. Wszystkie poniższe komendy shella można bez problemu wykonać na MacOSie lub Linuksie/Uniksie. Jeśli ktoś pracuje pod Windowsem to polecam zainstalowanie Cygwina. Zatem do dzieła!

Uwaga: dystrybucja JRuby'iego zostanie zainstalowana w ~/jruby.

BASH:
  1. # Upewnienie się, że jesteśmy w katalogu domowym
  2. cd
  3.  
  4. # Tworzymy katalog jruby/
  5. mkdir jruby
  6. cd jruby
  7.  
  8. # Pobieramy dystrybucję JRuby'iego 1.1.1
  9. wget http://dist.codehaus.org/jruby/jruby-bin-1.1.1.zip
  10. unzip jruby-bin-1.1.1.zip
  11. rm jruby-bin-1.1.1.zip
  12.  
  13. # Tworzymy jeszcze alias do skryptu uruchamiającego JRuby, który dodajemy do pliku .bashrc
  14. echo "export JRUBY_HOME=\"$HOME/jruby/jruby-1.1.1\"">> ~/.bashrc
  15. source ~/.bashrc
  16. echo "alias jruby=\"$JRUBY_HOME/bin/jruby\"">> ~/.bashrc
  17. source ~/.bashrc
  18.  
  19. # Przyda się jeszcze Ruby on Rails :)
  20. jruby -S gem install rails --no-ri --no-rdoc

Ponieważ JRuby może się kłócić z obecną na komputerze dystrybucją Ruby'iego (u mnie tak było) to zaleca się poprzedzanie wywoływania programów w ten sposób: jruby -S nazwa_polecenia, np. jruby -S gem list - wtedy nie kłóci się nam z poleceniem gem z standardowej dystrybucji Ruby'iego.

Dla mnie ciągłe poprzedzanie poleceń poprzez jruby -S ... jest żmudne wolałem skorzystać z wiki projektu JRuby, gdzie przedstawili ciekawy trick.

BASH:
  1. # Do dodania do .bashrc lub .bash_login - co kto lubi :)
  2.  
  3. for f in $JRUBY_HOME/bin/*; do
  4.      f=$(basename $f)
  5.      case $f in jruby*|jirb*|*.bat|*.rb|_*) continue ;; esac
  6.      eval "alias j$f='jruby -S $f'"
  7. done

Powyższy skrypt tworzy aliasy dla wszystkich poleceń np. gem, rails w postaci jgem, jrails. Prefiks j jednoznacznie mówi, o co chodzi.

Teraz czas na chwilkę zabawy.

# Zobaczmy, jaką wersję mamy
$ jruby -v
ruby 1.8.6 (2008-04-22 rev 6555) [i386-jruby1.1.1]

# Zabawy z konsolą jirb
$ jruby -S jirb
irb(main):001:0> out = java.lang.System.out
=> #<Java::JavaIo::PrintStream:0xe33255 @java_object=java.io.PrintStream@7dcc23>
irb(main):002:0> out.println "Hello World!"
Hello World!
=> nil

Tak zaopatrzeni możemy spokojnie wyruszyć na przygodę z JRuby'im. Niedługo kolejne artykuły poświęcone JRuby'iemu.

Prezentacja JRuby on Rails na bis w Krakowie

napisane przez wiktor, 15:13 04-19-2008

Już w najbliższy czwartek będę w Krakowie dawał prezentację o JRuby'im w ramach PJUG. Szczegóły wydarzenia tutaj. Gdzie, o której?

24 kwietnia 2008 (czwartek), godz. 19:00 - 20:30
Akademia Górniczo-Hutnicza
Al. Mickiewicza 30, sala 429 C2

Czego można się spodziewać? Będzie to odświeżona wersja mojego show o JRuby'im (prezentacja i prawdziwe kodowanie na żywo), które debiutowało podczas WarsJava'07. Przez ostatnie pół roku się dużo zmieniło i będzie to odzwierciedlone na mojej prezentacji:

  • będzie użyta najnowsza wersja Ruby on Rails 2.0,
  • architektura REST, czyli architektura zorientowana na zasoby,
  • ilość zmian w aplikacji RoR, żeby uruchomić pod JRuby dramatycznie zmalała,
  • sposób wdrażania aplikacji RoR na serwery aplikacyjne został uproszczony,
  • i oczywiście nie zabraknie AJAXa ;).

Zapraszam!

Garść linków do debaty o językach dynamicznych i Scali

napisane przez wiktor, 21:28 01-24-2008

Dziś dość króciutko. Tylko linki, ale za to bardzo smakowite.

  • Can Dynamic Languages Scale?
    Notka na TheServerSide dotycząca niepowodzenia projektu Chandler wywołała bardzo ciekawą dyskusję. Treść niusa nie jest istotna, tylko komentarze. Znajdziemy tam wszystko: obrzucanie się błotem, argumenty ad personam, tezy niczym nie podparte, czyli genialną i kulturalną dyskusję ;). Uwaga! Występują tam celebryci ze światka developerskiego: Bill Burke i Cedric Beust. Nieprawdaż, że brakuje serwisu pudelek.developers.com? :)
  • Invasion Of The Dynamic Language Weenies
    Dość dobra rozprawa o językach dynamicznych o bardzo prowokacyjnym tytule. Dobra lektura - tylko troszeczkę stronnicza ;). Warto poświęcić trochę czasu na poczytanie odnośników z linkografii do wpisu.
  • The busy Java developer's guide to Scala
    Tytuł mówi sam za siebie. Ted Neward, znany gawędziarz na wielu konferencjach, barwnym językiem opisuje pierwsze kroki ze Scalą. Miła czytanka.

Notatki z warsztatu “JRuby on Rails”

napisane przez wiktor, 22:01 11-18-2007

Dziękuje wszystkim, którzy pojawili się na mojej prezentacji/warsztacie podczas WarsJava. Była ona na prawdę udana, a dyskusja po prezentacji trwała ponad pół godziny! Dziękuje jeszcze raz wszytkim za obecność. Udostępniam poniżej slajdy z prezentacji (poniżej), kod aplikacji stworzonej podczas warsztatu oraz życzenie załączam moje notatki/scenariusz prezentacji.

Warsztaty Javowe: JRuby on Rails, czyli łączenie Javy i Rubiego

napisane przez wiktor, 15:53 11-13-2007

Duke + Ruby + Rails = Java ;)

Już w najbliższą sobotę o godzinie 11:00 będę dawał prezentację "JRuby on Rails, czyli łączenie Javy i Rubiego" na WarsJava - I Warszawskie Warsztaty Javowe organizowane przez Warszawa JUG. Warsztaty będą miały miejsce na MIMUWie. I co najważniejsze: WSTĘP WOLNY :).

Podczas warsztatów pokażę:

  • jak stworzyć prostą aplikację w Ruby on Rails,
  • jak korzystać z kodu Javy z poziomu Ruby'iego,
  • jak korzystać ze sterowników JDBC do łączenia się z bazą danych,
  • jak integrować stworzoną aplikacją z istniejącą aplikacją JEE (JMS, serwer aplikacji JBoss),
  • jak wdrażać aplikacje oparte o Ruby on Rails.

Zapraszam!


Wiktor Gworek Nazywam się Wiktor Gworek i jestem gospodarzem tego bloga.
Przeczytaj więcej o mnie »