a log of my experiments with the rhino javascript engine, maybe even including getting some actual work done

Monday, October 15, 2007

readDir

Once you got rhino up and running, one of the first things you'd want to be able to do is read and write files. Out of the box, rhino doesn't offer too much in this department. To load javascript code from files, you got:

load(["foo.js", ...]) Load JavaScript source files named by
string arguments.



Good enough for a start - you can write some library functions/objects/whatever and load them as needed. A far cry from what one would really like to have, which is some sort of module framework, but still. What's sorely missing is some facility for autoloading some initialization code on startup, I haven't yet figured out how to do that. Maybe later.

To load data from files, there is

readFile(fileName [, encoding])
Returns the content of the file as a string.
Encoding of the string can be optionally specified.
readUrl(url [, encoding])
Similar to readFile, reads the contents of the url.



Not bad - but there are still many times when you would want to read the list of file names in a directory, optionally filtered by a wildcard pattern (or better - a regexp) and process them in a loop, or something. So let's get started on a stdio object, containing a readDir function and with time, hopefully, more of the missing file i/o functionality:

this.stdio = {

get moduleName() { return 'stdio'; },

readDir : /* string[] */
function ( /* string */ path,
/* opt RegExp */ filterRx
)
{
var f = new java.io.File( path );
var jlist = f.list(); // a java String[]
if ( jlist === null )
{
return null; // path is not a directory
}
var list = [];
if ( arguments.length > 1 )
{
list = jlist.filter( RegExp.prototype.test, filterRx );
} else
{
list = [].concat( jlist );
}
list = list.map(String);
return list; // a js array of js strings
}

};
(Ok, trying to format code in Blogger is painful).

Note that the job gets done by reaching into a Java class (java.io.File). But what Java code returns are Java (not Javascript) data types. So I put some effort into conversion: a handy way to convert a Java array into a Javascript one is by concating it with the empty array; but at that point, the array still contains Java strings (represented by somewhat opaque JS objects), in practice this means the entries don't have quite the same methods you would expect in JS strings. This is fixed by applying the Javascript String function, which (to remind you) when called not as a constructor, essentially calls the toString method of its argument.

2 comments:

Anonymous said...

Yes, I like the idea too of JavaScript for utility scripting, but miss all the built in libraries you get in with other scripting languages.

dr.bob said...

The point is, with rhino you can use all of Java's standard libraries, and essentially any jar file you can grab. The downside? Java's sickeningly baroque and convoluted APIs don't fit in very well with scripting as they usually are.

Fortunately, it's not hard to make wrappers around those APIs that work just like you want them to, and you only need to do it once (and you can code it all in Javascript). Maybe even you'll find sometimes that somebody has already done it for you (when and if the idea catches on).