NAME
JavaScript::Shell - Run Spidermonkey shell from Perl
SYNOPSIS
use JavaScript::Shell;
use strict;
use warnings;
my $js = JavaScript::Shell->new();
##create context
my $ctx = $js->createContext();
$ctx->Set('str' => 'Hello');
$ctx->Set('getName' => sub {
my $context = shift;
my $args = shift;
my $firstname = $args->[0];
my $lastname = $args->[1];
return $firstname . ' ' . $lastname;
});
$ctx->eval(qq!
function message (){
var name = getName.apply(this,arguments);
var welcome_message = str;
return welcome_message + ' ' + name;
}
!);
my $val = $ctx->get('message' => 'Mamod', 'Mehyar')->value;
print $val . "\n"; ## prints 'Hello Mamod Mehyar'
$js->destroy();
DESCRIPTION
JavaScript::Shell will turn Spidermonkey shell to an interactive environment by connecting it to perl
With JavaScript::Shell you can bind functions from perl and call them from javascript or create functions in javascript then call them from perl
WHY
While I was working on a project where I needed to connect perl with javascript I had a lot of problems with existing javascript modules, they were eaither hard to compile or out of date, so I thought of this approach as an alternative.
Even though this sounds crazy to do, to my surprise it worked as expected - at least in my usgae cases
SPEED
JavaScript::Shell connect spidermonkey with perl through IPC bridge using IPC::Open2 so execution speed will never be as fast as using C/C++ bindings ported to perl directly
There is another over head when translating data types to/from perl, since it converts perl data to JSON & javascript JSON to perl data back again.
Saying that, the over all speed is acceptable and you can take some steps to improve speed like
- Data Transfer
-
Try to transfer small data chunks between processes when possible, sending large data will be very slow
- Buffer Data
-
As of version 0.02 JavaScript::shell has a new method for dealing with large strings passed to/from javascript, use this feature when ever you want to send large data "strings" -- see
buffer
- Minimize calls
-
Minimize number of calls to both ends, let each part do it's processing. for eaxmple:
##instead of $js->eval(qq! function East (){} function West (){} function North (){} function South (){} !); $js->call('East'); $js->call('West'); $js->call('North'); $js->call('South'); ##do this $js->eval(qq! function all () { East(); West(); North(); South(); } function East (){} function west (){} function North (){} function South (){} !); $js->call('all');
CONTEXT
Once you intiate JavaScript::Shell you can create as many contexts as you want, each context will has it's own scope and will not overlap with other created contexts.
my $js = JavaScript::Shell->new();
my $ctx = $js->createContext();
You can pass a hash ref with simple data to createContext
method as a sandbox object and will be copied to the context immediately
my $ctx->createContext({
Foo => 'Bar',
Foo2 => 'Bar2'
});
FUNCTIONS
new
Initiates SpiderMonkey Shell
createContext
creates a new context
run
This will run javascript code in a blocking loop until you call jshell.endLoop() from your javascript code
$js->Set('Name' => 'XXX');
$js->eval(qq!
for (var i = 0; i < 100; i++){
}
jshell.endLoop();
!);
$js->run();
##will never reach this point unless we call
## jshell.endLoop(); in javascript code as above
Set
Sets/Defines javascript variables, objects and functions from perl
## set variable 'str' with Hello vales
$ctx->Set('str' => 'Hello');
## set 'arr' Array Object [1,2,3,4]
$ctx->Set('arr' => [1,2,3,4]);
## set Associated Array Object
$ctx->Set('obj' => {
str1 => 'something',
str2 => 'something ..'
});
## set 'test' function
## caller will pass 2 arguments
## 1- context object
## 2- array ref of all passed arguments
$ctx->Set('test' => sub {
my $context = shift;
my $args = shift;
return $args->[0] . ' ' . $args->[1];
});
## javascript object creation style
$ctx->Set('obj' => {});
#then
$ctx->Set('obj.name' => 'XXX');
$ctx->Set('obj.get' => sub { });
...
get
get values from javascript code, returns a JavaScript::Shell::Value
Object
my $ret = $ctx->get('str');
print $ret->value; ## Hello
## remember to call value to get the returned string/object
get method will search your context for a matched variable/object/function and return it's value, if the name was detected for a function it will run this function first and then returns it's return value
$ctx->get('obj.name')->value; ## XXX
##you can pass variables when trying to get a function
$ctx->get('test' => 'Hi','Bye')->value; ## Hi Bye
##get an evaled script values
$ctx->get('eval' => qq!
var n = 2;
var x = 3;
n+x;
!)->value; #--> 5
call
Calling javascript functions from perl, same as get
but doesn't return any value
$ctx->call('test');
eval
eval javascript code
$ctx->eval(qq!
//javascript code
var n = 10;
for(var i = 0; i<100; i++){
n += 10;
}
...
!);
buffer
This function should be used only when dealing with passing large strings
$js->Set('largeStr' => sub{
my $js = shift;
my $args = shift;
##we have a very large string we need to pass to
##javascript
return $js->buffer('large string');
});
##javascript
var str = largeStr();
The same thing can be done when sending large strings from javascript to perl
//javascript
var str = 'very large string we need to pass to perl';
jshell.sendBuffer(str);
##perl
##to consume this string from perl just get it
my $str = $js->getBuffer();
onError
set error handler method, this method accepts a code ref only. When an error raised from javascript this code ref will be called with 2 arguments
JavaScript::Shell instance
error object - Hash ref
Error Hash has the folloing keys
message error message
type javascript error type: Error, TypeError, ReferenceError ..
file file name wich raised this error
line line number
stack string of the full stack trace
Setting error hnadler example
my $js = JavaScript::Shell->new();
$js->onError(sub{
my $self = shift;
my $error = shift;
print STDERR $error->{message} . ' at ' . $error->{line}
exit(0);
});
destroy
Destroy javascript shell / clear context
my $js = JavaScript::Shell->new();
my $ctx->createContext();
##clear context;
$ctx->destroy();
##close spidermonkey shell
$js->destroy();
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.16.2 or, at your option, any later version of Perl 5 you may have available.
COPYRIGHTS
Copyright (C) 2013 by Mamod A. Mehyar <mamod.mehyar@gmail.com>