Mojo-Phantom
view release on metacpan or search on metacpan
lib/Mojo/Phantom.pm view on Meta::CPAN
package Mojo::Phantom;
use Mojo::Base -base;
our $VERSION = '0.12';
$VERSION = eval $VERSION;
use Mojo::Phantom::Process;
use Mojo::File;
use Mojo::JSON;
use Mojo::Template;
use Mojo::URL;
use JavaScript::Value::Escape;
use constant DEBUG => $ENV{MOJO_PHANTOM_DEBUG};
use constant CAN_CORE_DIE => !! CORE->can('die');
use constant CAN_CORE_WARN => !! CORE->can('warn');
has arguments => sub { [] };
has base => sub { Mojo::URL->new };
has bind => sub { {} };
has cookies => sub { [] };
has package => 'main';
has 'setup';
has sep => '--MOJO_PHANTOM_MSG--';
has no_exit => 0;
has note_console => 0;
has 'exe';
has template => <<'TEMPLATE';
% my ($self, $url, $js) = @_;
// Setup perl function
function perl() {
var system = require('system');
var args = Array.prototype.slice.call(arguments);
system.stdout.writeLine(JSON.stringify(args));
system.stdout.writeLine('<%== $self->sep %>');
system.stdout.flush();
}
// Setup error handling
var onError = function(msg, trace) {
var msgStack = ['PHANTOM ERROR: ' + msg];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function(t) {
msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function +')' : ''));
});
}
//phantom.exit isn't exitting immediately, so let Perl kill us
perl('CORE::die', msgStack.join('\n'));
//phantom.exit(1);
};
phantom.onError = onError;
// Setup bound functions
% my $bind = $self->bind || {};
% foreach my $func (keys %$bind) {
% my $target = $bind->{$func} || $func;
perl.<%= $func %> = function() {
perl.apply(this, ['<%== $target %>'].concat(Array.prototype.slice.call(arguments)));
};
% }
// Setup Cookies
% foreach my $cookie (@{ $self->cookies }) {
% my $name = $cookie->name;
phantom.addCookie({
name: '<%== $name %>',
value: '<%== $cookie->value %>',
domain: '<%== $cookie->domain || $self->base->host %>',
}) || perl.diag('Failed to import cookie <%== $name %>');
% }
// Requst page and inject user-provided javascript
var page = require('webpage').create();
page.onError = onError;
% if($self->note_console) {
// redirect browser console log to TAP
page.onConsoleMessage = function(msg) {
perl.note('js console: ' + msg);
};
// redirect console log to TAP
(function() {
var old = console.log;
console.log = function(msg) {
perl.note('phantom console: ' + msg);
old.apply(this, Array.prototype.slice.call(arguments));
};
}());
% }
// Additional setup
<%= $self->setup || '' %>;
page.open('<%== $url %>', function(status) {
<%= $js %>;
% unless($self->no_exit) {
phantom.exit();
% }
});
TEMPLATE
sub execute_file {
my ($self, $file, $cb) = @_;
# note that $file might be an object that needs to have a strong reference
my $arguments = $self->arguments // [];
my $proc = Mojo::Phantom::Process->new(arguments => $arguments);
$proc->exe($self->exe) if $self->exe;
my $sep = $self->sep;
my $package = $self->package;
my $buffer = '';
my $error;
$proc->on(read => sub {
my ($proc, $bytes) = @_;
warn "\nPerl <<<< Phantom: $bytes\n" if DEBUG;
$buffer .= $bytes;
while ($buffer =~ s/^(.*)\n$sep\n//) {
my ($function, @args) = @{ Mojo::JSON::decode_json $1 };
local *CORE::die = sub { die @_ } unless CAN_CORE_DIE;
local *CORE::warn = sub { warn @_ } unless CAN_CORE_WARN;
eval "package $package; no strict 'refs'; &{\$function}(\@args)";
if ($@) { $error = $@; return $proc->kill }
}
});
( run in 2.174 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )