1

I'm trying to embed and evaluate ruby code from within a Java application. Instead of putting jruby-complete.jar in my classpath, I need to be able to use jruby environment that's installed with rvm. I can execute basic kernel code, but I'm having issues requiring standard libraries (fileutils, tmpdir, etc.).

I created the test file below that uses a JRuby installed via RVM, anyone should be able to compile+run it if you have a local rvm + jruby installation (change JRUBY_VERSION to a version installed). I realize the jruby.jar I'm referencing isn't the same as jruby-complete.jar, but I'm hoping there is a way to load standard libraries without downloading an external jar.

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.logging.Logger;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Test {
    private final static Logger LOG = Logger.getAnonymousLogger();
    private final static String JRUBY_VERSION = "jruby-1.6.7";

    public static void main(String[] args) throws Throwable {
        final String rvmPath = System.getenv("HOME") + "/.rvm/rubies/";
        addFileToClasspath(rvmPath + JRUBY_VERSION + "/lib/jruby.jar");

        final ScriptEngine rubyEngine = new ScriptEngineManager().getEngineByName("jruby");
        rubyEval(rubyEngine, "puts 'hello world!'"); // works
        rubyEval(rubyEngine, "require 'tempfile'");  // fails to load 'tmpdir'
        rubyEval(rubyEngine, "require 'fileutils'"); // fails to load 'fileutils'
    }

    private static void rubyEval(ScriptEngine rubyEngine, final String code) {
        try {
            rubyEngine.eval(code);
        } catch (final Throwable e) { LOG.throwing(Test.class.getName(), "rubyEval", e); };
    }

    public static void addFileToClasspath(final String path) throws Throwable {
        final File file = new File(path);
        final URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        final Class<?> sysclass = URLClassLoader.class;
        final Method method = sysclass.getDeclaredMethod("addURL", new Class<?>[] {URL.class});
        method.setAccessible(true);
        method.invoke(sysloader, new Object[] {file.toURI().toURL()});
    }
}

1 Answer 1

1

On an rvm installation, the core ruby files are installed alongside the jruby.jar (here for JRuby 1.7.2):

sebastien@greystones:~$ cd .rvm/rubies/jruby-1.7.2/
sebastien@greystones:~/.rvm/rubies/jruby-1.7.2$ find . -name fileutils.rb
./lib/ruby/1.8/fileutils.rb
./lib/ruby/1.9/fileutils.rb
sebastien@greystones:~/.rvm/rubies/jruby-1.7.2$ find . -name tmpdir.rb
./lib/ruby/1.8/tmpdir.rb
./lib/ruby/1.9/tmpdir.rb

You therefore need to add the correct ruby folder (which depends on the ruby version) to the classpath, for example:

    final String rvmPath = System.getenv("HOME") + "/.rvm/rubies/";
    addFileToClasspath(rvmPath + JRUBY_VERSION + "/lib/jruby.jar");

    // Here, add folder to classpath.
    System.setProperty("org.jruby.embed.class.path", rvmPath + JRUBY_VERSION + "/lib/ruby/1.9");
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.