Polyglot Grails

I have been playing around with using different JVM languages in Grails lately. For example, Clojure is really easy to integrate into Grails via the plugin. The simple fact that you can do this in Grails by just installing one little plugin is pretty cool! So, I decided it would be fun to create a Grails app that uses as many languages as possible, ha! There’s absolutely no good reason to do this other than it’s kind of fun!

There aren’t any Ruby or Python plugins for Grails yet, so I just add them as dependencies manually. I’m actually using JRuby and Jython though, which are implementations of these languages specifically for the JVM. For JavaScript, Rhino which comes bundled with JDK 6. The end goal is to have one Grails controller (a Groovy class) that uses Ruby, Python, JavaScript and Clojure (note at bottom about why Scala wasn’t included).

First, we need to setup our polyglot Grails application!

  • grails create-app polyglot
  • cd polyglot
  • grails install-plugin clojure

// grails-app/conf/BuildConfig.groovy dependencies {   runtime 'org.jruby:jruby:1.6.4'   runtime 'org.python:jython-standalone:2.5.2' }

Then we need to create three Grails files (a controller, unit test and integration test). Why an integration test and unit test? Well, this is simply because it is not possible (at least right now) to test Clojure code via the plugin in unit tests. There is a property (clj) injected into Grails artifacts (our controller in this case), but it only works in integration tests. The rest of the languages can be tested in a unit test though.

  • grails-app/controllers/polyglot/TestController.groovy
  • test/unit/polyglot/TestControllerUnitTests.groovy
  • test/integration/polyglot/TestControllerIntegrationTests.groovy

Next, we need a simple problem we want to try out in all languages. I’m a math nerd, so I’m simply going to make sure that the value of PI is the same in all languages. Here’s my controller:

package polyglot import javax.script.* class TestController {   def javascript() {     def engine = new ScriptEngineManager().getEngineByName("JavaScript")     render engine.eval("Math.PI")   }   def ruby() {     def engine = new ScriptEngineManager().getEngineByName("jruby")     render engine.eval("Math::PI")   }   def python() {     def engine = new ScriptEngineManager().getEngineByName("python")     engine.eval("import math")     render engine.eval("math.pi")   }   def clojure() {     render clj.pi   } }

As you can see, I’m using the ScriptEngine class that comes with Java 6 to invoke the Ruby, Python and JavaScript languages. You could just as easily have put the code in separate Ruby, Python, JavaScript files, but I’m just keeping it simple for this example. The only real difference is that for Python you need to import math first. The Clojure implementation is in a separate file because the plugin automatically adds a folder under src and hooks into Grails events to compile. Here’s the Clojure code:

; src/clj/pi.clj (ns grails) (def pi Math/PI)

We can certainly test the controller by viewing these actions in a browser to make sure all the languages are working, but the whole point is to make sure they are all the same, right? So, I’m going to write actual tests that compare the value returned from the actions for each language against the value of PI in Groovy! Here’s my unit tests:

package polyglot @TestFor(TestController) class TestControllerTests {   void testJavaScript() {     controller.javascript()     assertEquals response.text, Math.PI.toString()   }   void testRuby() {     controller.ruby()     assertEquals response.text, Math.PI.toString()   }   void testPython() {     controller.python()     assertEquals response.text, Math.PI.toString()   } }

And here’s the integration test for Clojure:

Page 1 of 2 | Next page