Thoughts on embedding JRuby January 28, 2011
I covered the initial JRuby-Lift integration on the LiftJR blog.
When trying to get this running, we did a bit of research. The blogs and wiki posts were high-level or had too many options, so we ended up figuring things out using JRuby's excellent JavaDoc. However, a "working man's guide" to embedding JRuby would have been useful. I hope that you find this helpful:
- Import the right packages (org.jruby.*, org.jruby.embed.*, org.jruby.runtime.builtin.* )
- Instantiate your "Scripting Container". Pass in LocalContextScope.THREADSAFE as the ScriptingContainer constructor's parameter if you want thread safety (you probably do.)
- Use the scriptingContainer to eval the contents of an input stream (like a file with a class definition): scriptingContainer.parse(inputStream, filename).run()
- Get a handle to the jruby runtime: jrubyScriptingContainer.getProvider().getRuntime() and the thread context: runtime.getCurrentContext()
- Use the 'runtime' for getting a class by name, creating a new symbol and other global operations. Calling runtime.fastNewSymbol("pants") from java/scala will return a handle to :pants in your ruby environment. runtime.fastGetClass("ActiveRecord::Base") would return a handle to the relevant class.
- You use the thread context when actually invoking methods on objects. myRubyClass.callMethod(threadContext, methodName, Array(arg1, arg2...) )
- The JRuby has done an awesome job with getting the java interfaces right with the JRuby objects. However, sometimes you just want a plain old java object. Every RubyObject has a .toJava method; use it to get back the java equivalent of your ruby structure: .toJava(classOf[Boolean])
That should be enough to get you started. Let me know if you have any questions.