JRuby Velocity
19 January 2007
I had a need yesterday to play around with velocity in order to explore some stuff on templating and macros. I like velocity's simple template language, but this was one of those times where I wasn't using it in the context of some Java or .NET work. At that point working with velocity becomes a bit of a pain as you have to setup the context and run the processor in Java.
This kind of situation calls for a scripting language, my preferred scripting language is Ruby, and thus I thought this was a great case for trying JRuby. My conclusion is that it works a treat, but I'll bore you with the details.
I downloaded JRuby and unpacked it in
/usr/local/lib
with a symlink so I could get to it with
/usr/local/lib/jruby
.
I then put a simple redirecting shell into
/usr/local/bin
JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun JRUBY_HOME=/usr/local/lib/jruby /usr/local/lib/jruby/bin/jruby “$@”
I could then run JRuby.
$ jruby -v ruby 1.8.5 (0) [java]
(Actually it took me ages to get that to work, I eventually found the bug between the chair and the keyboard. I'm too embarrassed to tell you what it was.)
To run velocity you have to add it to JRuby's classpath.
CLASSPATH=path/to/velocity-dep-1.4.jar export CLASSPATH jruby “$@”
To help run velocity I wrote a little helper class.
require 'java' class VelocityLauncher def initialize context, template @context = context @template = template end include_class 'org.apache.velocity.app.Velocity' include_class 'org.apache.velocity.VelocityContext' include_class 'java.io.StringWriter' def run vc = VelocityContext.new(@context) writer = StringWriter.new Velocity.init Velocity.evaluate(vc, writer, "LOG", @template) return writer.getBuffer end end
Now I can take write a little template:
This is an announcement from $host Our chief weapons are: #foreach ($w in $weapons) - $w #end
To populate it, all I need is a ruby hash, which is easy to make.
ct = {'host' => 'Cardinal Fang', 'weapons' => ['Fear', 'Surprise', 'Ruthless Efficiency']} template = File.readlines('template.txt').join puts VelocityLauncher.new(ct, template).run
I can imagine extending this to a nice command line runner for velocity which would take a context file of the form:
host = 'Cardinal Fang' weapons = ['Fear', 'Surprise', 'Ruthless Efficiency']
But I don't need that yet, so I'll do it another day (and I'm pretty sure what the binding for 'another day' is).