Max Maischein > MozRepl-RemoteObject-0.37 > MozRepl::RemoteObject

Download:
MozRepl-RemoteObject-0.37.tar.gz

Dependencies

Annotate this POD

CPAN RT

Open  1
View/Report Bugs
Module Version: 0.37   Source   Latest Release: MozRepl-RemoteObject-0.38

NAME ^

MozRepl::RemoteObject - treat Javascript objects as Perl objects

SYNOPSIS ^

    #!perl -w
    use strict;
    use MozRepl::RemoteObject;
    
    # use $ENV{MOZREPL} or localhost:4242
    my $repl = MozRepl::RemoteObject->install_bridge();
    
    # get our root object:
    my $tab = $repl->expr(<<JS);
        window.getBrowser().addTab()
    JS

    # Now use the object:
    my $body = $tab->{linkedBrowser}
                ->{contentWindow}
                ->{document}
                ->{body}
                ;
    $body->{innerHTML} = "<h1>Hello from MozRepl::RemoteObject</h1>";

    $body->{innerHTML} =~ '/Hello from/'
        and print "We stored the HTML";

    $tab->{linkedBrowser}->loadURI('http://corion.net/');

BRIDGE SETUP ^

MozRepl::RemoteObject->install_bridge %options

Installs the Javascript <-> Perl bridge. If you pass in an existing MozRepl instance, it must have MozRepl::Plugin::JSON2 loaded if you're running on a browser without native JSON support.

If repl is not passed in, $ENV{MOZREPL} will be used to find the ip address and portnumber to connect to. If $ENV{MOZREPL} is not set, the default of localhost:4242 will be used.

If repl is not a reference, it will be used instead of $ENV{MOZREPL}.

To replace the default JSON parser, you can pass it in using the json option.

Connect to a different machine

If you want to connect to a Firefox instance on a different machine, call ->install_bridge as follows:

    MozRepl::RemoteObject->install_bridge(
        repl => "$remote_machine:4242"
    );

Using an existing MozRepl

If you want to pass in a preconfigured MozRepl object, call ->install_bridge as follows:

    my $repl = MozRepl->new;
    $repl->setup({
        log => [qw/ error info /],
        plugins => { plugins => [qw[ JSON2 ]] },
    });
    my $bridge = MozRepl::RemoteObject->install_bridge(repl => $repl);

Launch a mozrepl program if it's not found running

If you want to launch Firefox if it's not already running, call ->install_bridge as follows:

    MozRepl::RemoteObject->install_bridge(
        launch => 'iceweasel' # that program must be in the path
    );

Using a custom command line

By default the launched program will be launched with the -repl command line switch to start up mozrepl. If you need to provide the full command line, pass an array reference to the launch option:

    MozRepl::RemoteObject->install_bridge(
        launch => ['iceweasel','-repl','666']
    );

Using a custom Mozrepl class

By default, any class named in $ENV{MOZREPL} will get loaded and used as the MozRepl backend. That value will get untainted! If you want to prevent $ENV{MOZREPL} from getting used, pass an explicit class name using the repl_class option.

    MozRepl::RemoteObject->install_bridge(
        repl_class => 'MozRepl::AnyEvent',
    );

Preventing/forcing native JSON

The Javascript part of MozRepl::RemoteObject will try to detect whether to use the native Mozilla JSON object or whether to supply its own JSON encoder from MozRepl::Plugin::JSON2. To prevent the autodetection, pass the js_JSON option:

  js_JSON => 'native', # force to use the native JSON object

  js_JSON => '', # force the json2.js encoder

The autodetection detects whether the connection has a native JSON encoder and whether it properly transports UTF-8.

$bridge->expr( $js, $context )

Runs the Javascript passed in through $js and links the returned result to a Perl object or a plain value, depending on the type of the Javascript result.

This is how you get at the initial Javascript object in the object forest.

  my $window = $bridge->expr('window');
  print $window->{title};

You can also create Javascript functions and use them from Perl:

  my $add = $bridge->expr(<<JS);
      function (a,b) { return a+b }
  JS
  print $add->(2,3);
  # prints 5

The context parameter allows you to specify that you expect a Javascript array and want it to be returned as list. To do that, specify 'list' as the $context parameter:

  for ($bridge->expr(<<JS,'list')) { print $_ };
      [1,2,3,4]
  JS

This is slightly more efficient than passing back an array reference and then fetching all elements.

as_list( $array )

    for $_ in (as_list $array) {
        print $_->{innerHTML},"\n";
    };

Efficiently fetches all elements from @$array . This is functionally equivalent to writing

    @$array

except that it involves much less roundtrips between Javascript and Perl. If you find yourself using this, consider declaring a Javascript function with list context by using ->declare instead.

$bridge->declare( $js, $context )

Shortcut to declare anonymous JS functions that will be cached in the bridge. This allows you to use anonymous functions in an efficient manner from your modules while keeping the serialization features of MozRepl::RemoteObject:

  my $js = <<'JS';
    function(a,b) {
        return a+b
    }
  JS
  my $fn = $self->bridge->declare($js);
  $fn->($a,$b);

The function $fn will remain declared on the Javascript side until the bridge is torn down.

If you expect an array to be returned and want the array to be fetched as list, pass 'list' as the $context. This is slightly more efficient than passing an array reference to Perl and fetching the single elements from Perl.

$bridge->constant( $NAME )

    my $i = $bridge->constant( 'Components.interfaces.nsIWebProgressListener.STATE_STOP' );

Fetches and caches a Javascript constant. If you use this to fetch and cache Javascript objects, this will create memory leaks, as these objects will not get released.

$bridge->appinfo()

Returns the nsIXULAppInfo object so you can inspect what application the bridge is connected to:

    my $info = $bridge->appinfo();
    print $info->{name}, "\n";
    print $info->{version}, "\n";
    print $info->{ID}, "\n";

$bridge->js_call_to_perl_struct( $js, $context )

Takes a scalar with JS code, executes it, and returns the result as a Perl structure.

This will not (yet?) cope with objects on the remote side, so you will need to make sure to call $rn.link() on all objects that are to persist across the bridge.

This is a very low level method. You are better advised to use $bridge->expr() as that will know to properly wrap objects but leave other values alone.

$context is passed through and tells the Javascript side whether to return arrays as objects or as lists. Pass list if you want a list of results instead of a reference to a Javascript array object.

$bridge->remove_callback( $callback )

    my $onload = sub {
        ...
    };
    $js_object->{ onload } = $onload;
    $bridge->remove_callback( $onload )

If you want to remove a callback that you instated, this is the way.

This will release the resources associated with the callback on both sides of the bridge.

$bridge->poll

A crude no-op that can be used to just look if new events have arrived.

HASH access ^

All MozRepl::RemoteObject objects implement transparent hash access through overloading, which means that accessing $document->{body} will return the wrapped document.body object.

This is usually what you want when working with Javascript objects from Perl.

Setting hash keys will try to set the respective property in the Javascript object, but always as a string value, numerical values are not supported.

ARRAY access ^

Accessing an object as an array will mainly work. For determining the length, it is assumed that the object has a .length method. If the method has a different name, you will have to access the object as a hash with the index as the key.

Note that push expects the underlying object to have a .push() Javascript method, and pop gets mapped to the .pop() Javascript method.

OBJECT IDENTITY ^

Object identity is currently implemented by overloading the == operator. Two objects are considered identical if the javascript === operator returns true.

  my $obj_a = MozRepl::RemoteObject->expr('window.document');
  print $obj_a->__id(),"\n"; # 42
  my $obj_b = MozRepl::RemoteObject->expr('window.document');
  print $obj_b->__id(), "\n"; #43
  print $obj_a == $obj_b; # true

CALLING METHODS ^

Calling methods on a Javascript object is supported.

All arguments will be autoquoted if they contain anything other than ASCII digits ([0-9]). There currently is no way to specify that you want an all-digit parameter to be put in between double quotes.

Passing MozRepl::RemoteObject objects as parameters in Perl passes the proxied Javascript object as parameter to the Javascript method.

As in Javascript, functions are first class objects, the following two methods of calling a function are equivalent:

  $window->loadURI('http://search.cpan.org/');
  
  $window->{loadURI}->('http://search.cpan.org/');

EVENTS / CALLBACKS ^

This module also implements a rudimentary asynchronous event dispatch mechanism. Basically, it allows you to write code like this and it will work:

  $window->addEventListener('load', sub { 
       my ($event) = @_; 
       print "I got a " . $event->{type} . " event\n";
       print "on " . $event->{originalTarget};
  });
  # do other things...

Note that you cannot block the execution of Javascript that way. The Javascript code has long continued running when you receive the event.

Currently, only busy-waiting is implemented and there is no way yet for Javascript to tell Perl it has something to say. So in absence of a real mainloop, you have to call

  $repl->poll;

from time to time to look for new events. Note that any call to Javascript will carry all events back to Perl and trigger the handlers there, so you only need to use poll if no other activity happens.

In the long run, a move to AnyEvent would make more sense, but currently, MozRepl::RemoteObject is still under heavy development on many fronts so that has been postponed.

OBJECT METHODS ^

These methods are considered to be internal. You usually do not want to call them from your code. They are documented here for the rare case you might need to use them directly instead of treating the objects as Perl structures. The official way to access these functions is by using MozRepl::RemoteObject::Methods instead.

$obj->__invoke(METHOD, ARGS)

The ->__invoke() object method is an alternate way to invoke Javascript methods. It is normally equivalent to $obj->$method(@ARGS). This function must be used if the METHOD name contains characters not valid in a Perl variable name (like foreign language characters). To invoke a Javascript objects native __invoke method (if such a thing exists), please use:

    $object->MozRepl::RemoteObject::Methods::invoke::invoke('__invoke', @args);

The same method can be used to call the Javascript functions with the same name as other convenience methods implemented by this package:

    __attr
    __setAttr
    __xpath
    __click
    ...

$obj->__transform_arguments(@args)

This method transforms the passed in arguments to their JSON string representations.

Things that match /^(?:[1-9][0-9]*|0+)$/ get passed through.

MozRepl::RemoteObject::Instance instances are transformed into strings that resolve to their Javascript global variables. Use the ->expr method to get an object representing these.

It's also impossible to pass a negative or fractional number as a number through to Javascript, or to pass digits as a Javascript string.

$obj->__id

Readonly accessor for the internal object id that connects the Javascript object to the Perl object.

$obj->__on_destroy

Accessor for the callback that gets invoked from DESTROY.

$obj->bridge

Readonly accessor for the bridge that connects the Javascript object to the Perl object.

$obj->__release_action

Accessor for Javascript code that gets executed when the Perl object gets released.

$obj->__attr( $attribute )

Read-only accessor to read the property of a Javascript object.

    $obj->__attr('foo')

is identical to

    $obj->{foo}

$obj->__setAttr( $attribute, $value )

Write accessor to set a property of a Javascript object.

    $obj->__setAttr('foo', 'bar')

is identical to

    $obj->{foo} = 'bar'

$obj->__dive( @PATH )

DEPRECATED - this method will vanish somewhere after 0.23. Use MozRepl::RemoteObject::Methods::dive instead.

Convenience method to quickly dive down a property chain.

If any element on the path is missing, the method dies with the error message which element was not found.

This method is faster than descending through the object forest with Perl, but otherwise identical.

  my $obj = $tab->{linkedBrowser}
                ->{contentWindow}
                ->{document}
                ->{body}

  my $obj = $tab->__dive(qw(linkedBrowser contentWindow document body));

$obj->__keys()

Please use instead:

    keys %$obj

The function returns the names of all properties of the javascript object as a list, just like the keys Perl function.

  $obj->__keys()

is identical to

  keys %$obj

$obj->__values()

Please use instead:

    values %$obj

Returns the values of all properties as a list.

  $obj->values()

is identical to

  values %$obj

$obj->__xpath( $query [, $ref ] )

DEPRECATED - this method will vanish somewhere after 0.23. Use MozRepl::RemoteObject::Methods::xpath instead:

  $obj->MozRepl::RemoteObject::Methods::xpath( $query )

Executes an XPath query and returns the node snapshot result as a list.

This is a convenience method that should only be called on HTMLdocument nodes.

The optional $ref parameter can be a DOM node relative to which a relative XPath expression will be evaluated. It defaults to undef.

The optional $cont parameter can be a Javascript function that will get applied to every result. This can be used to directly map each DOM node in the XPath result to an attribute. For example for efficiently fetching the text value of an XPath query resulting in textnodes, the two snippets are equivalent, but the latter executes less roundtrips between Perl and Javascript:

    my @text = map { $_->{nodeValue} }
        $obj->MozRepl::RemoteObject::Methods::xpath( '//p/text()' )


    my $fetch_nodeValue = $bridge->declare(<<JS);
        function (e){ return e.nodeValue }
    JS
    my @text = map { $_->{nodeValue} }
        $obj->MozRepl::RemoteObject::Methods::xpath( '//p/text()', undef, $fetch_nodeValue )

$obj->__click

Sends a Javascript click event to the object.

This is a convenience method that should only be called on HTMLdocument nodes or their children.

$obj->__change

Sends a Javascript change event to the object.

This is a convenience method that should only be called on HTMLdocument nodes or their children.

$obj->__event TYPE

Sends a Javascript event of type TYPE to the object.

This is a convenience method that should only be called on HTMLdocument nodes or their children.

Send a focus, change and blur event to an element

The following code simulates the events sent by the user entering a value into a field:

  $elt->__event('focus');
  $elt->{value} = 'Hello';
  $elt->__event('change');
  $elt->__event('blur');

MozRepl::RemoteObject::Instance->new( $bridge, $ID, $onDestroy )

This creates a new Perl object that's linked to the Javascript object ID. You usually do not call this directly but use $bridge->link_ids @IDs to wrap a list of Javascript ids with Perl objects.

The $onDestroy parameter should contain a Javascript string that will be executed when the Perl object is released. The Javascript string is executed in its own scope container with the following variables defined:

This method is useful if you want to automatically close tabs or release other resources when your Perl program exits.

ENCODING ^

The communication with the MozRepl plugin is done through 7bit safe ASCII. The received bytes are supposed to be UTF-8, but this seems not always to be the case, so the JSON encoder on the Javascript side also uses a 7bit safe encoding.

Currently there is no way to specify a different encoding on the fly. You have to replace or reconfigure the JSON object in the constructor.

TODO ^

SEE ALSO ^

Win32::OLE for another implementation of proxy objects

http://wiki.github.com/bard/mozrepl - the MozRepl FireFox plugin homepage

REPOSITORY ^

The public repository of this module is http://github.com/Corion/mozrepl-remoteobject.

AUTHOR ^

Max Maischein corion@cpan.org

COPYRIGHT (c) ^

Copyright 2009-2012 by Max Maischein corion@cpan.org.

LICENSE ^

This module is released under the same terms as Perl itself.

syntax highlighting: