Estes dias, estava vendo uns projetos antigos e lembrei de um framework bem legal para Java chamado ZK. O problema do ZK é que você consegue aproveitar o máximo dele quando você programa usando Servlets, e não usando o modelo ZUL dele. Lembrei de alguns projetos que fiz, de algumas coisas interessantes que ele fazia e também lembrei que eu cheguei a programar com Servlet em Ruby, e aqui vai como eu fiz mais esse trabalho para evitar Java. NOTA: Isso funciona com qualquer framework Java, seja ele ZK ou Echo2 ou qualquer outro, porque na verdade o que você faz é escrever algumas linhas de código de “cola” e depois passa o controle para o JRuby

A primeira coisa que você precisa é do JRuby instalado, e de um compilador Java. Crie seu projeto normalmente, e provavelmente você terá uma classe que será responsável por instanciar a primeira classe (janela, página, seja lá o que for) do seu Servlet. Nesse ponto que a “mágica” acontece. Para simplificar as coisas, que vou criar uma classe (chamada Inicial) que instanciará uma JFrame. Toda a JFrame será definida em JRuby.

O processo: Basicamente, o que faremos é o seguinte: Criaremos uma classe abstrata (Janela), e nesta classe criaremos uma função, que será usada pelo JRuby. Na classe de “cola”, instanciaremos um interpretador JRuby, rodaremos um código para instanciar a classe do Ruby e faremos um “casting” desse objeto para a classe abstrata. Primeiro, a classe abstrata:

Arquivo Janela.java:
import javax.swing.*;

public abstract class Janela extends JFrame {
        public abstract void exibir();
}

Até aqui, nenhum segredo. A classe extende JFrame (quando você for usar seu Framework, ela deverá extender a “Window” do seu framework) e possui um método abstrato “exibir”. Agora, a classe em JRuby

Arquivo ruby/janela.rb
java_import 'javax.swing.JFrame'
java_import 'javax.swing.JButton'
java_import 'javax.swing.JOptionPane'

class Janela < Java::Janela
  def exibir
    set_size 300, 200

    self.default_close_operation = JFrame::EXIT_ON_CLOSE
    self.title = 'Uma janela qualquer'
    show

    puts "Exibi uma janela!!!"
  end
end

Caso você não esteja acostumado com JRuby usando Swing, ignore os detalhes da implementação. O que é importante é pensar que você está criando uma classe JRuby, que herda de Java::Janela (a janela que definimos no Java), e cria um método “exibir”. Agora, vem o código mais complicado, a classe Inicial que instanciará a classe Ruby:

Arquivo Inicial.java:
import java.util.*;
import org.jruby.*;
import org.jruby.javasupport.*;
import org.jruby.runtime.builtin.*;

public class Inicial {
    public static void main(String[] args) {
        Ruby rubyRuntime;

        //Inicia os "load paths", para indicar aonde o JRuby procurará os "require"s
        List<String> pathsLoad = new ArrayList<String>();
        pathsLoad.add("ruby/");
        pathsLoad.add("ruby/lib");

        //Instancia os serviços do JRuby
        rubyRuntime = JavaEmbedUtils.initialize(pathsLoad);
        //Carrega o arquivo "janela.rb"
        rubyRuntime.getLoadService().load("janela.rb", false);

        //Roda um comando JRuby, e captura o resultado
        Object janela_rb = rubyRuntime.evalScriptlet("Janela.new");
        //Transforma na classe abstrata
        Janela janela = (Janela)JavaEmbedUtils.rubyToJava(rubyRuntime,
                                 (IRubyObject) janela_rb, Janela.class);

        janela.exibir();
    }
}

Aqui, a mágica acontece: Cria-se um rubyRuntime, cria-se uma lista com os loadPaths (aonde o Ruby buscará os “require”s, que no meu caso eu destinei para a pasta “ruby” e “ruby/lib”. Então, instancia-se o rubyRuntime, pede-se para ele carregar o arquivo “janela.rb”, roda-se um comando bem simples (“Janela.new”) e captura o resultado, depois convertemos isso para uma classe Java. Como não temos uma definição de classe mesmo para Ruby, fazemos um “casting” para o Janela (classe abstrata no Java) e então finalmente rodamos o código “exibir”. Aparentemente, as novas versões do JRuby tornarão isso mais fácil porque permitirão que os códigos JRuby sejam compilados para Bytecode (e esses Bytecodes serão realmente classes Java válidas), mas até o momento essa é a solução mais elegante para o problema.

Nota: não será possível carregar Gems ou bibliotecas instaladas no seu sistema, a não ser que elas sejam descompactadas na pasta “ruby/lib”.