From:

Spicing Up Embedded JavaScript

One thing that I absolutely adore is the sheer embeddability of JavaScript. It's a (comparatively) simple language that is fiercely flexible. I tend to liken JavaScript to water - alone it's painfully simple but it can take the form of its container - and mixing it with anything enhances its flavor.

Since JavaScript, alone, is so dumb (we've become spoiled by browsers which provide DOM, setTimeout/setInterval, and even a global object reference - none of which are necessarily required my an ECMAScript implementation) we must rely upon the spice of 'larger' languages to help it gain some taste.

We can start by taking a look at some of the most popular languages that are available today: Python, Perl, PHP, Ruby, and Java -- all of which have, at least, one embeddable JavaScript interpreter.

One thing is the same in all the interpreter implementations, as well, they all have the ability to introduce (at least) simple objects into interpreter (from the parent language) and extract values again. Sometimes this may be as simple as executing a JavaScript function and getting its return value (which is often translated from its internal JavaScript form back into the native language).

There's a couple points upon which I like to evaluate the embeddability of a JavaScript interpreter, specifically:

  1. Object Translation:If objects/values are passed to/from the interpreter to/from the native language - is that translation handled automatically?
  2. Simplicity:How hard is it to get up-and-running? (Is extra compilation required or is it written using native language code?)
  3. Bleed-through:Can JavaScript communicate to the base language or is it a one-way-street?

The first point is the easiest one to find compatibility with - virtually all embeddable JavaScript interpreters do some form of object translation. Some do it better (like JE and Rhino) but it generally shouldn't be a problem for simple scripts.

PHP

» PHPJS

A flexible, pure-PHP, JavaScript interpreter that even accepts compiling to an intermediary bytecode. There is no bleed-through but good object translation.

include "js.php";

# Introduce a new JavaScript function, named print,
# which calls a PHP function
functionshow ($msg) {
echo "$msg\n";
}

$jsi_vars["print"]= "show";

# Add in a new pure-JavaScript function which calls
# our previously-introduced print function
jsc::compile ("function alert(msg){ print('Alert:' + msg); }");

# Prints out 'Alert: text'
js_exec ("alert('text');");

» J2P5: Pure-PHP ECMAScript Engine

Probably the simplest of the available interpreters - there doesn't appear to be a clear way of communicating from JavaScript-to-PHP (or vice versa). Although, it is implemented in pure-PHP which allows for some nice cross-platform compatibility.

include "js/js.php";

$script= <<<EOD
print("Hello from JavaScript");
EOD;

js::run($script);

Perl

» JavaScript::SpiderMonkey

An embedding of Mozilla's SpidermonkeyJavaScript engine into Perl. Since it uses Spidermonkey it'll require that extra source code and compilation. Object translation is good but there's no bleed-through (JavaScript calling native Perl functionality that isn't explicitly defined).

useJavaScript::SpiderMonkey;

# Instantiate the interpreter
my $j= JavaScript::SpiderMonkey-> new();

# Introduce a new JavaScript function, named print,
# which calls a Perl function
$j->function_set("print", sub { print @_, "\n" } );

# Add in a new pure-JavaScript function which calls
# our previously-introduced print function
$j->eval("function alert(msg){ print('Alert:' + msg); }");

# Prints out 'Alert: text'
$j->eval("alert('text');");

» JE: Pure-Perl ECMAScript Engine

A pure-Perl JavaScript engine - shows incredible promise (probably my favorite new engine in addition to Rhino). Has tremendous potential (including the ability to serialize the runtime environment!).

useJE;

# Instantiate the interpreter
my $j= newJE;

# Introduce a new JavaScript function, named print,
# which calls a Perl function
$j->new_function(print=> sub { print @_, "\n" } );

# Add in a new pure-JavaScript function which calls
# our previously-introduced print function
$j->eval("function alert(msg){ print('Alert:' + msg); }");

# Prints out 'Alert: text'
$j->method(alert => "text");

# So does this
$j->eval("alert('text');");

# Introduce the ability to do remote requests
useNet::FTP;

$j->bind_class( package=> "Net::FTP", name => "FTP" );

# Execute native Perl functionality (FTP module)
# directly from JavaScript
$j->eval(<<'--end--');
var connect= newFTP ("ftp.mozilla.org");
connect.get("index.html");
--end--

Note the extreme bleed-through that you can achieve with JE (in addition to excellent object translation).

Java

» Rhino

Probably one of the most famous embeddable JavaScript implementations. Implemented in pure Java has excellent object translation and perfect bleed-through. The bleeding can even be controlled explicitly at runtime (to create a more confined environment).

In the following code (using in some of the jQuery build system) two functions are defined which utilize a number of native Java packages - all without ever writing a single line of Java code.

importPackage(java.io);

functionwriteFile (file, stream ) {
varbuffer = newPrintWriter ( newFileWriter (file ) );
buffer. print(stream );
buffer. close();
}

functionread (file ) {
varf = newFile (file);
varreader = newBufferedReader (newFileReader (f));
varline = null;
varbuffer = newjava. lang.StringBuffer(f.length());
while( (line = reader.readLine())!= null) {
buffer. append(line);
buffer. append("\n");
}
returnbuffer. toString();
}

Python

» Python-Spidermonkey

Previously this was one of the most depressing embedding efforts (and, really, the only one available for Python) but it has since had some new life blown into it - which is much appreciated. It supports decent object translation and bleed-through (including the ability to call native classes, much like in JE).

fromspidermonkey importRuntime

j = RunTime().new_context()

# Introduce a new JavaScript function, named print,
# which calls a Python function
j. bind_callable("print", lambdamsg: print(msg));

# Add in a new pure-JavaScript function which calls
# our previously-introduced print function
j. eval_script("function alert(msg){ print('Alert:' + msg); }");

# Prints out 'Alert: text'
j. eval_script("alert('text');");

Ruby

While there was a previous effort to embed Spidermonkey in Ruby it is largely defunct now, superseded by the new (strangely named) Johnson project.

» Johnson

This is a, relatively, new project that's working to completely overhaul how communication is currently done in-between Ruby and JavaScript (using Spidermonkey to power the engine). There is complete bleed-through: Ruby can dig in and manipulate JavaScript objects at run-time and JavaScript can call back and access native Ruby functionality. Additionally they're examining the ability to provide native browser environments using the env.jsscript that I created last year. While the cross-platform ease-of-use isn't there yet the project absolutely has a ton of potential.

require "johnson"

j = Johnson::Runtime.new

# Introduce a new JavaScript function, named print,
# which calls a Ruby function
j. print= lambda {|msg| puts msg};

# Add in a new pure-JavaScript function which calls
# our previously-introduced print function
j. evaluate("function alert(msg){ print('Alert:' + msg); }");

# Prints out 'Alert: text'
j. evaluate("alert('text');");

Update:Another example of Johnson in action from John Barnette:

require "johnson"

classMonkey
defeat
puts "Nom, nom, nom, bananas!"
end
end

j = Johnson::Runtime.new

# toss a monkey into the runtime
m = Monkey. new
j [:m]= m

# add a JSland function to our monkey...
j. evaluate("m.chow = function() { this.eat() }")

# ...and now it's available as an instance method on our native Ruby object!
m. chow

There's a ton of potential in all of these projects - providing interesting features for blurring the lines in-between JavaScript and different host languages. For your next project it should be pretty easy to find a solution to embedding JavaScript as your quick-and-dirty scripting language of choice.

Related Articles

Relatd Projects

zionedit

An intuitive, very configurable, uncluttered programmer's editor based on the awesome Scintilla component & wxWidgets. Supports C/C++, C#, Java, SQL, CSS, HTML(JavaScript,PHP etc), Python, Perl, Ruby, Lisp, Fortran, Assembly, Batch, Makefile --for Win32
lipermi
LipeRMI is a light weight framework which provide full remote method invocation calls between VMs. Its totally independent from native Java RMI and uses a Internet approach to make any communication (using only one socket per client; unidirecional).
niffty
Niffty is a Java applet which allows a composer to display NIFF formatted music notation on a web page. The user can format the page and print it using the browser's own Print function and, with the right Java version, play it as MIDI.
kwartz
Kwartz - a template system for Ruby/PHP/Java which realized the concepot of `Separation of Presentation Logic from Presentation Data (SoPL/PD)'.
bitext2tmx
Bitext2tmx is a cross-platform program (in Java) to align the sentences of two plain text files which are mutual translations and generate a TMX translation memory for use in computer-assisted translation; a companion to the OmegaT translation program.
virtualmock
VirtualMock is a Unit Testing tool. It uses Junit, Aspect-Oriented Programming (AOP) and the Mock Objects testing approach. Through AOP, it supports features which are not possible with other pure-java mock object frameworks.
log4js2
Logger For JavaScript , Via Java Applet or HTML Div or status bar or alert .
omseek
Omseek has been renamed to Xapian. Xapian is a Search Engine Library, written in C++ with bindings for Perl, Python, PHP, Java, Tcl, C# and Ruby. It allows you to easily add advanced indexing and search facilities to your applications. See xapian.org
Crank

Crank is a master/detail, CRUD, and annotation driven validation framework built with JPA, JSF, Facelets and Ajax. It allows developers to quickly come up with JSF/Ajax based CRUD listings and Master/Detail forms from their JPA annotated Java objects.

Crank uses a lot of the new JSF features from Facelets, Ajax4JSF, etc. that will be used in JSF 2.0. Crank is a use case analysis of what is possible with the new JSF 2.0 stack.

The validation piece does server-side validation, Ajax validation or just emitted JavaScript validation based on Java annotations, property files, XML files, or database tables. Currently works with JSF, Spring MVC and Spring Webflow.

The framework is named Crank as in: "crank out, to make or produce in a mass-production, effortless, or mechanical way: She's able to crank out one (CRUD listing) after another" and "crank up: to get started or ready", "to stimulate, activate, or produce", and most importantly "to increase one's efforts, output, etc.: Industry began to crank up after the new (CRUD framework became our corporate standard)." http://www.dictionary.com

The CRUD framework has support for JPAenabled DAO objects. The CRUD framework implements a Detached Criteria API/DSL similar to Hibernates (R) Criteria API except it works with JPA. The Detached Criteria API/DSL (DCAD) could be ported to other frameworks for example Hibernate, iBatis, etc.

The CRUD framework has a controller that is framework neutral as well. Currently there is an example the uses JSF to quickly create CRUD listings and master detail forms as follows:

opensub
This program is more one facilitie to help the subtitle translation work. This program works translating SRT subtitle files line by line by sending the speaks to the google language tools and filling the with the new one translated.