Posted by wiktor on Oct 30, 2008 in
Ruby on Rails,
java,
jruby,
ruby

W poprzednich dwóch artykułach pokazałem jak zainstalować JRubiego oraz jak może Ruby z Javą rozmawiać. Czas rozpocząć przygodę z JRuby on Rails.
W tym artykule pokażę:
- jak stworzyć prostą aplikację typu CRUD w Ruby on Rails, która będzie korzystać z bazy danych MySQL,
- jak wdrożyć tą aplikację na serwerze Tomcat przy użyciu narzędzia Warbler.
Wymagania. Zakładam, że masz już zainstalowaną bazę danych MySQL 5.0.x. Potrzebny będzie także serwer Tomcat, który można stąd pobrać (w chwili pisania korzystałem z najnowszej wersji 6.0.18). Jeśli nie masz jeszcze zainstalowanego Ruby on Rails to wykonaj następujące polecenie:
# Na wszelki wypadek Ruby on Rails przyda się :)
$ jruby -S gem install rails warbler jruby-openssl --no-ri --no-rdoc |
Stworzenie prostej aplikacji
Czas napisać prostą aplikację. Jej funkcjonalność ograniczy się do dodawania, edytowania i usuwania wiadomości (dużo powiedziane, bo wiadomość będzie się składać tylko z łańcucha znaków
). Zaczynamy.
# Stworzenie szkieletu aplikacji
$ jruby -S rails rails_app
$ cd rails_app/
# Stworzenie modelu wiadomości oraz operacji CRUD dla niego
$ jruby -S script/generate scaffold message content:string
# i pozostaje konfiguracja dostępu do bazy danych - tego Rails jeszcze nie potrafią same zrobić :)
$ vim config/database.yml |
Moją konfigurację można zobaczyć poniżej. Nie należy zapomnieć stworzyć bazy danych w MySQLu (wystarczy tylko railsapp_development).
defaults: &defaults
adapter: mysql
username: root
password:
host: localhost
encoding: utf8
development:
database: railsapp_development
<<: *defaults
test:
database: railsapp_test
<<: *defaults
production:
database: railsapp_production
<<: *defaults
Aplikacja już napisana, baza danych skonfigurowana. Zostało jeszcze utworzenie odpowiednich tabelek w bazie danych i można już bawić się aplikacją.
[Bash]
# Jeśli nie było żadnego błędu po drodze to poniższa operacja powinna wykonać poprawnie
$ jruby -S rake db:migrate
(in /Users/wiktor/jruby/rails_app)
== 20081028224846 CreateMessages: migrating ===================================
– create_table(:messages)
-> 0.0049s
== 20081028224846 CreateMessages: migrated (0.0058s) ==========================
[/Bash]
Aplikację można już uruchomić poleceniem jruby -S script/server. Po wejściu na stronę http://localhost:3000 można zobaczyć środowisko uruchomienia aplikacji, a pod adresem http://localhost:3000/messages znajduje się przed chwilą stworzona, bardzo wyrafinowana aplikacja.

Wdrożenie Ruby on Rails na Tomcata
Żeby przygotować aplikacje Ruby on Rails do wdrożenia ją na Tomcata, należy użyć biblioteki Warbler. Została ona już zainstalowana poleceniem jruby -S gem install ... na samym początku artykułu.
Przez dłuższy czas obserwowałem rozwój Warblera. Kiedy projekt stawiał pierwsze kroki, przygotowanie aplikacji Ruby on Rails wiązało się ze starannym przygotowaniem pliku konfiguracyjnego, zadbaniem o odpowiednie sterowniki JDBC do bazy danych. Nie było to miłe zajęcie. Z tego powodu warto docenić, że obecnie przygotowanie aplikacji do wdrożenia na Tomcacie jest banalnie proste.
[Bash]
# Stworzenie pliku config/warble.rb.
$ jruby -S warble config
# Teraz należy w pliku config/warble.rb zamienić linijkę
# z # config.webxml.rails.env = ENV['RAILS_ENV'] || ‘production’
# na config.webxml.rails.env = ‘development’
# Przygotowanie aplikacji w postaci WAR.
$ jruby -S warble war
jar cf rails_app.war -C tmp/war .
# Gotowe?
$ ls -l rails_app.war
-rw-r–r– 1 wiktor wiktor 9800493 Oct 29 23:28 rails_app.war
# Mając już Tomcata uruchomionego możemy wdrożyć aplikację.
$ cp rails_app.war ../apache-tomcat-6.0.18/webapps/
[/Bash]
Aplikacja będzie dostępna pod adresem http://localhost:8080/rails_app, a bawić wiadomościami można się tutaj: http://localhost:8080/rails_app/messages.
Parę słów wyjaśnienia. Standardowo Warbler uruchamia aplikację w trybie produkcji. Jednym ze skutków jest to, że aplikacja będzie korzystać z bazy railsapp_production, a nie z railsapp_development, której do tej pory używaliśmy. Zmiana podyktowana była jedynie moją leniwością.
Warto też zauważyć, że cała aplikacja rails_app.war waży niecałe 10 MB. Co się tam znajduje? Otóż cała dystrybucja JRubiego, a także wszystkie zależności Ruby on Rails. Takie życie
. Zachęcam także do przestudiowania pliku config/warble.rb, poprzez który można konfigurować zachowanie aplikacji na serwerze Javowym.
Smacznego
.
Tags: java, jruby, ruby, Ruby on Rails
Posted by wiktor on May 9, 2008 in
java,
jruby,
ruby
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]
# Znane z Javy importowanie wygląda standardowo.
# Niestety importowanie z gwiazdką nie działa, więc import javax.swing.* poczęstuje nas błędem.
import javax.swing.JFrame
import javax.swing.JButton
# Składnia Ruby’iego została zachowana dla obiektów Javowych, widać to w tworzeniu nowego egzemplarza JFrame
# Warto zauważyć, że nawiasy są nieobowiązkowe. Poniższe wywołanie jest równoznaczne z JFrame.new(“…”)
frame = JFrame.new “Ruby swinguje z Java”
# Styl kodowania Ruby’iego zostaje zachowany także dla metod. W Javie lubimyTakPisać, a w Ruby’im trochę_inaczej.
# Poniższe wywołanie jest równoważne z frame.setSize(300, 300), które także byłoby poprawne.
frame.set_size 300, 300
# Gettery i settery Javowe są dostępne także w odmianie Ruby’iego.
# Poniższa linijka jest równoważna z frame.setAlwaysOnTop(true), które także byłoby poprawne.
frame.always_on_top = true
button = JButton.new “Nacisnij mnie”
# Blok kodu zostanie w locie przekształcony w klasę implementującą interfejs ActionListener. Niezłe!
# Jest to domyślne zachowanie JRuby’iego, jeśli parametrem jest interfejs z jedną metodą.
# Standardowo w Ruby’im używa się wcięć z 2 spacjami.
button.add_action_listener do |event|
# Przykład getterów ala Ruby. Równoznaczne z event.getSource().setText(“…”), które także jest OK.
event.source.text = “Nie naciskaj mnie ponownie!”
event.source.enabled = false
end
frame.add(button)
frame.show
[/Ruby]
Czas poczęstować Ciebie czytelniku jakimś smakołykiem. Oto on:
[Ruby]
# Rozszerzenie klasy Javowej String o mechanizm missing_method, czyli
# ta metoda zostanie wywołana, jeśli na obiekcie zostanie wywołana metoda, która
# nie została zdeklarowana.
JavaUtilities.extend_proxy “java.lang.String” do
def method_missing(symbol, *args)
puts “Kogo wolasz?”
end
end
txt = java.lang.String.new “Ala ma kota”
txt.hmmmm_jak_brzmiala_nazwa_tej_metody?() # => “Kogo wolasz?”
[/Ruby]
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).

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]
import org.jruby.RubyHash;
import javax.script.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import static java.lang.System.*;
public class RubyInJava {
public static void main(String[] args) {
// Od Java Scripting API żądamy silnik JRuby’iego
ScriptEngine rubyEngine = new ScriptEngineManager().getEngineByName(“jruby”);
ScriptContext context = rubyEngine.getContext();
List list = new ArrayList() {{
add(1); add(2); add(3); add(4);
}};
// Do środowiska JRuby’iego dodajemy globalną zmienną list
rubyEngine.put(“list”, list);
// Skrypt Ruby’iego, który będziemy wykonywać
StringBuilder script = new StringBuilder();
script.append(“puts ‘— Ruby —’ “).append(“\n”)
.append(“puts $list.inspect “).append(“\n”)
// JRuby do kolekcji Javowych dodaje typowe metody Ruby’iego dla kolekcji
.append(” $list.each { |item| “)
.append(” puts \”Element #{item}\” “)
.append(” } “).append(“\n”)
.append(” puts \”Suma: #{$list.inject { |sum, i| sum + i }}\” “).append(“\n”)
.append(“\n”)
.append(” $hash = { :ala => :ma, :co => :kota } “).append(“\n”);
// Wykonanie skryptu
try {
rubyEngine.eval(script.toString(), context);
} catch (ScriptException e) {
e.printStackTrace();
return;
}
out.println(“— Java —”);
// Pobranie zmiennej globalnej po wykonaniu skryptu
Object hashAsObject = rubyEngine.get(“hash”);
out.println(“Klasa: ” + hashAsObject.getClass());
RubyHash hash = (RubyHash) hashAsObject;
for (Object o : hash.entrySet()) {
Map.Entry entry = (Map.Entry) o;
System.out.println(entry.getKey() + ” => ” + entry.getValue());
}
}
}
[/Java]
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
.
Tags: java, jruby, ruby
Posted by wiktor on Apr 29, 2008 in
java,
jruby,
ruby
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]
# Upewnienie się, że jesteśmy w katalogu domowym
cd
# Tworzymy katalog jruby/
mkdir jruby
cd jruby
# Pobieramy dystrybucję JRuby’iego 1.1.1
wget http://dist.codehaus.org/jruby/jruby-bin-1.1.1.zip
unzip jruby-bin-1.1.1.zip
rm jruby-bin-1.1.1.zip
# Tworzymy jeszcze alias do skryptu uruchamiającego JRuby, który dodajemy do pliku .bashrc
echo “export JRUBY_HOME=\”$HOME/jruby/jruby-1.1.1\”" >> ~/.bashrc
source ~/.bashrc
echo “alias jruby=\”$JRUBY_HOME/bin/jruby\”" >> ~/.bashrc
source ~/.bashrc
# Przyda się jeszcze Ruby on Rails 
jruby -S gem install rails –no-ri –no-rdoc
[/Bash]
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]
# Do dodania do .bashrc lub .bash_login – co kto lubi
for f in $JRUBY_HOME/bin/*; do
f=$(basename $f)
case $f in jruby*|jirb*|*.bat|*.rb|_*) continue ;; esac
eval “alias j$f=’jruby -S $f’”
done
[/Bash]
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.
Tags: java, jruby, ruby
Posted by wiktor on Apr 19, 2008 in
Ruby on Rails,
java,
jruby,
ruby,
swing,
widget
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!
Tags: java, jruby, jug, rails, ruby
Posted by wiktor on Nov 18, 2007 in
Ruby on Rails,
java,
jruby,
ruby
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.
Posted by wiktor on Nov 13, 2007 in
Ruby on Rails,
java,
jruby,
ruby

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!