JavaScript::Lite - Bare-bones interface to SpiderMonkey ECMAscript API
use JavaScript::Lite; my $js = JavaScript::Lite->new; $js->assign(numbers => [ 2, 4, 6, 8, 10 ]); $js->assign(start => 1); $js->eval(q{ function add_next() { var n; if(n = numbers.shift()) { start = start + n; return start; } else { return; } } }); while(my $next = $js->invoke("add_next")) { print "$next\n"; }
JavaScript::Lite is a bare-bones interface to the SpiderMonkey ECMAscript engine. It aims to provide as little functionality (and therefore as little overhead) as is neccessary to connect perl with ECMAscript. Efficiency is the goal here; the intended environments are places where you are going to be calling from perl into ECMAscript thousands (or millions) of times in succession (such as using ECMAscript to drive the NPC logic in a perl-based MMORPG, or writing a spam filter in perl where the end users can write custom spam rules in ECMAscript, or...)
JavaScript::Lite
NOTE: This is very, very alpha software. I intend to keep the API more-or-less stable, but there may be quirks, and new features will be added in future releases (so long as they do not slow the existing features down!).
If you want powerful, flexible, full-featured blending of ECMAscript with perl, please see the JavaScript package. So why would you want to use JavaScript::Lite?
JavaScript::Lite can run much, much faster than the JavaScript distribution. This is because the flexibility that JavaScript offers you comes at a cost; class/object translations are expensive, and due to the fact that each language has different memory management, allowing both perl to call ECMA, and ECMA to call perl can cause irrecoverable memory leaks (as can allowing complex data structures to flow in both directions); the ECMA garbage collector can be expensive to run (even in "maybe" mode), and just the additional overhead of tracking all of this object/function binding/linking can be expensive.
In other words, here are some more features;
Constructor; creates and returns a new JavaScript::Lite object (and underlying runtime/context). $max_mem is the maximum memory (in bytes) the JavaScript environment should be allowed to consume. Defaults to 1MB.
$max_mem
(If you go over this limit, JavaScript::Lite should raise an exception. Unfortunately, it doesn't yet... it causes a segmentation fault instead. :-( So be careful.)
Evaluate a block of JavaScript code, returning the result as a scalar. If $filename is specified, tells the javascript interpreter that the code came from this file. Otherwise, the default filename "(eval)" is used.
$filename
If the code fails to compile, an exception is raised, which must be cleared if you want to keep using your JavaScript context; see "clear_error" below.
clear_error
Note that this will not return JavaScript objects/structures; only strings, numbers, or undef.
Evaluate a block of ECMAscript, returning nothing. If you don't care about the return value of the script, this method works slightly faster than eval above. $filename is required.
eval
Reads the file $filename from your filesystem and evaluates it as ECMAscript, returning any scalar result.
Same as eval_file, except that no result is returned to perl.
eval_file
Invoke the global ECMAscript function called $name. Invoking methods on ECMAscript objects is not yet supported. Passing arguments into the ECMAscript function is not yet supported, but should be in the next release.
$name
Like eval, returns any scalar return value that the function may have returned.
Tell the SpiderMonkey garbage collector that it may run if it so wishes. If you don't do this every so often, your ECMAscript context will run out of memory and crash. This is not done automatically because even considering running the garbage collector can add significant overhead.
Clear any error condition that may have been raised in ECMAscript. You must do this if you want to continue using your JavaScript::Lite object after an eval or invoke raises an error.
invoke
Assign $value to the global ECMAscript variable $name. $value may be a scalar, hashref, arrayref, or any nested combination. The entire structure passed into $value will be copied into ECMAscript. Globs and coderefs are not supported. $value must not be a self-referencing structure, or else JavaScript::Lite will crash (see BUGS below).
$value
Assign $value to the property $name on the global ECMAscript object called $object. As with assign, $value may be a scalar, hashref, arrayref, or any nested combination.
$object
assign
$object must be a top-level ECMAscript global object. Nesting more than one layer deep (eg; "some_object.some.deep.property") is not supported. For that functionality, see the JavaScript distribution.
Run $callback every $interval branches in the javascript. Branches are caused by things such as for() or while() loop invocation. $callback should a a subroutine reference; if the subroutine returns a true value, the javascript will continue running. If it returns a false value or dies, the javascript will terminate and an exception will be thrown.
$callback
$interval
If you do not specify $interval, the callback will be executed during every branch in javascript. This will slow down the script considerably; for best results, you should use a value at least in the several thousands.
Explicitly resets the branch counter to zero
If your JavaScript::Lite object runs out of memory (as defined by $max_mem when you create the object), it can cause a segmentation fault. I want it to raise an exception instead, I just haven't figured out how yet. :-(
JavaScript::Lite does not detect self-referencing data structures. And since it tries to make a copy of the data you pass in, if you pass in a self-referencing structure, it will consume all available memory until it crashes. For example, this will always crash:
my $insane_hash = { foo => "bar" }; $insane_hash->{baz} = $insane_hash; $cx->assign(insane_hash => $insane_hash);
I haven't quite decided if this is a bug or a feature yet... there is RAM and CPU overhead in tracking self-referencing structures, so doing so would slow JavaScript::Lite down. If you need to use them, use the JavaScript module instead, which will let you bind directly to them instead of copying.
for the original JavaScript module.
for creating a situation where I would need to write this.
for hosting YAPC::NA 2008, where this was hacked together.
This is free software, you may use and distribute it under the same terms as perl itself.
This software uses mozilla's SpiderMonkey JSAPI for it's ECMAscript implementation, so in order for it to be useful to you, you must accept the terms of the mozilla license as well.
Tyler "Crackerjack" MacDonald <japh@crackerjack.net>
JavaScript, http://developer.mozilla.org/en/docs/SpiderMonkey
To install JavaScript::Lite, copy and paste the appropriate command in to your terminal.
cpanm
cpanm JavaScript::Lite
CPAN shell
perl -MCPAN -e shell install JavaScript::Lite
For more information on module installation, please visit the detailed CPAN module installation guide.