Setting up Rhino

I've been using the Rhino engine more and more to run command-line scripts, fiddle and try things out. But my setup has taken shape slowly, and it wasn't much fun to be honest when I first got started.

I'm on a mac (Leopard), and here's how I've got it now:

  1. Download the Rhino .jar file, you'll find it inside the latest (binary) release.
  2. Drop it in your {user}/Library/java/Extensions folder (create it if it doesnt already exist). That way its automatically added to your classpath whenever you run java, so no need for -jar cmdline params to pull it in (and the classpath insanity that brings).
  3. I made a shell script to invoke rhino and aliased that, but actually you could simply alias the one-liner it contains:
    1
    java jline.ConsoleRunner org.mozilla.javascript.tools.shell.Main "$@"

    To make an alias, in my ~/.profile I've got the following:
    1
    alias rhino='~/utils/runjs.sh'
  4. Now, in your terminal, you just type '
    1
    rhino
    ' and it puts you into an interactive shell where you can load files, write js statements and see the results instantly.

But, Rhino's shell is frankly, a crappy user experience. Its got no history, no cursor movement at all. You can just type and hit enter. If you screw something up you have to type it all over again. And the whole beauty of writing *javascript* like this is that you can load a .js library repeatedly as you work on it and try calling its functions. But its a PITA out of the box.

Look again at that java cmd-line I'm using to run rhino and you'll see its using jline. This enlightening post on Taming the Rhino finally brought happiness to my rhino shell by introducing me to jline

You download jline and again, drop the .jar file into your Library/java/Extensions folder. Now the interactive shell is much more shell-like. You have a history on the up arrow, you can back up and move around the current line to edit, and do more scripting and less typing in general.

To run a particular .js file and exit, you do '

1
rhino yourfile.js
'. Further cmd-line parameters populate the
1
arguments
object in your script, so
1
rhino script.js filename1 filename2 myoption=true
would populate
1
arguments
like this:

[
filename1,
filename2,
myoption=true
]

FWIW I use a pattern like this to wrap my script body:

(function(scriptArgs) {
function main() {
// process scriptArgs,
// e.g. split on = to get name/value pairs
// and populate an options object
}
main();
})(Array.prototype.slice.apply(arguments));

Back in the shell, you can load, try, load again, try again:

$ jeltz:trunk sfoster$ rhino
Rhino 1.7 release 1 2008 03 06
js> load("lib/docblock.js");
js: "lib/docblock.js", line 7: uncaught JavaScript runtime exception: ReferenceError:\
"lang" is not defined. at lib/docblock.js:7 at lib/docblock.js:5 at <stdin>:2

js> load(“lib/langUtils.js”);
js: “<stdin>”, line 3: Couldn’t open file “lib/langUtils.js”.
js> load(“lib/langUtil.js”);
js> load(“lib/docblock.js”);
js> var p = docblock.getParser();
js> p.parse(“/** @author sfoster */“);
TAG:author:sfoster
js> quit();
jeltz:trunk sfoster$

Try it, I think you'll like it.