Quantcast
Channel: Bobby Warner » grails
Viewing all articles
Browse latest Browse all 13

Polyglot Grails

$
0
0

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:

package polyglot
class TestControllerIntegrationTests extends GroovyTestCase {
  void testClojure() {
    def test = new TestController()
    test.clojure()
    assertEquals test.response.contentAsString, Math.PI.toString()
  }
}

And there we have it! A Grails application that calculates PI in Clojure, Ruby, Python and JavaScript as well as ensures PI in these languages is the same as PI in Groovy! Hope you enjoyed reading!

As a side note, there also is a Scala plugin for Grails, but I unfortunately could not get it to work with Grails 2.0.0.M2. I keep getting the following error when I try to compile Scala source code via the plugin.

Could not compile Scala sources: BuildException: Compile failed because of an internal compiler error (object scala not found.)

If anybody who has successfully used the Scala plugin with Grails 2.0 has any suggestions for what I might be doing wrong, please leave a comment.


Viewing all articles
Browse latest Browse all 13

Trending Articles