The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

JSPL::Controller - Control which Perl namespaces can be used from JavaScript.

SYNOPSIS

    use JSPL;
    use Gtk2 -init;     # Load your perl modules as usual

    my $ctx = JSPL->stock_context;
    my $ctl = $ctx->get_controller;
    $ctl->install(
        'Gtk2' => 'Gtk2',
        'Gtk2.Window' => 'Gtk2::Window',
        'Gtk2.Button' => 'Gtk2::Button',
        # Any more needed
    );

    $ctx->eval(q|
        var window = new Gtk2.Window('toplevel');
        var button = new Gtk2.Button('Quit');
        button.signal_connect('clicked', function() { Gtk2.main_quit() });
        window.add(button);
        window.show_all();
        Gtk2.main();
        say('Thats all folks!');
    |);

DESCRIPTION

Every context has a controller object. Context's controller object allows you to reflect entire perl namespaces to JavaScript side and control how they can be used.

In the following discussion, we use the words "perl package" or simply "package" to refer to a perl namespace, declared in perl with the keyword "package" in perlfunc.

The controller object holds a list of every perl package exposed in some form to JavaScript land. When JavaScript is made aware of a perl package an instance of the special Stash native class is created in the context. How you can use that particular namespace from JavaScript depends on how the Stash instance or its properties are bound in JavaScript.

See JSPL::Stash for details on Stash instances.

This perl class allows you to make JavaScript land aware of perl packages and provides some utilities methods.

INTERFACE

You obtain the instance of a context's controller calling "get_controller" in JSPL::Context.

    my $ctl = $context->get_controller;

With this you can use any of the following:

Instance methods

add( $package_name )
    my $stash = $ctl->add('Foo::Bar');

Adds the package named $package_name to the list of namespaces visible in JavaScript, if not in there already. Returns the JSPL::Stash object that encapsulates the associated Stash.

added ( $package_name )
    $ctl->added('Foo::Bar');

Check if the package with the given $package_name is in the list of perl namespaces visible from JavaScript land. Returns a TRUE value (the JSPL::Stash object) if $package_name is in the list, otherwise returns a FALSE value.

Normal operation is to automatically add namespaces as needed. Packages are added when a perl object enters javacript or you use "bind_class" in JSPL::Context and the package isn't already known.

list ( )
    @exported = $ctl->list();

Returns a list with the names of packages available in JavaScript land.

install ( BIND_OPERATION, ... )

Performs a series of BIND_OPERATIONs in JavaScript land.

Every BIND_OPERATION is an expression of the form:

    bind => [ $package, $mode ]

Where bind is the property name to attach the package named $package and $mode is the form to perform the binding.

There are three ways to bind a package: binding as a constructor, as a static class or in indirect form. You choose which way to use depending on the value you give to the $mode argument:

  • STRING

    When a STRING is used as $mode, you want to bind a constructor. The property bind in JavaScript will be bound to a PerlSub that references the function named STRING in the perl class associated with $package. bind will then be used as a constructor.

    For example

        $ctl->install(Img => [ 'GD::Simple', 'new' ]);

    Binds to Img a JavaScript constructor for objects of the perl class GD::Simple, so in JavaScript you can write:

        myimg = new Img(400, 250);

    In perl the most common name for a constructor is new, as long as you known that your perl class has a constructor named new, you can use a simplified form of the BIND_OPERATION:

        $ctl->install(Img => 'GD::Simple');
  • undef

    When $mode is undef, you want to bind the perl package as a static class. The property bind in JavaScript will be bound to the Stash itself associated with the $package. See JSPL::Stash for all the implications.

    You should bind in this form any perl package for which you need to make static calls to multiple functions (class methods).

    For example:

        $ctl->install(DBI => [ 'DBI', undef ]);

    Binds to DBI the Stash instance associated to the DBI perl package, allowing you to write in JavaScript:

        drivers = DBI->available_drivers();
        handle = DBI->connect(...);

    In perl many packages work this way and/or provide constructors for other packages as static functions, but don't have a constructor for themselves.

    If you know the perl class doesn't has a constructor named new you can use the same simplified form of the BIND_OPERATION above, and install will do the right thing.

        $ctl->install(DBI => 'DBI');
  • -1

    When $mode is -1, you want to bind the perl package in indirect mode. This mode allows JavaScript to resolve method calls on bind to subroutines defined in $package.

    Using the indirect form will make plain function calls to those subroutines instead of static method calls.

    For example:

        $ctl->install(Tests => [ 'Test::More', -1 ]);

    Bind to Tests an object allowing JavaScript to find all subroutines defined in Test::More. In JavaScript you'll write:

        Test.ok(...);
        Test.is(...);

    A simple way to export to JavaScript a lot of new functions is to bind this way a carefully crafted namespace.

        #!/usr/bin/perl
        # We are in 'main'
        use JSPL;
    
        package forjsuse;
        sub foo {...};
        sub bar {...};
        sub baz {...};
    
        my $ctx = JSPL->stock_context;
        $ctx->get_controller->install(Utils => ['forjsuse', -1]);
        
        $ctx->eval(q|
            Utils.bar(...);
        |);

    An advantage of this method over using "bind_function" in JSPL::Context is that the PerlSub objects associated to your perl subroutines won't get created in JavaScript until needed.

Every BIND_OPERATION, search for a "Tweaks file" associated to the $package added and if found loads it, see JSPL::Tweaks for details.

To create a hierarchy of related properties you can pass to install many BIND_OPERATIONs as follows:

    $ctl->install(
        'Gtk2' => 'Gtk2',                # Gtk lacks a 'new'. Binds a static class
        'Gtk2.Window' => 'Gtk2::Window', # Bind Gtk2::Window constructor
        'Gtk2.Button' => 'Gtk2::Button', # Bind Grk2::Button constructor
    );
secure ( )
    $ctl->secure();

Prevent further modifications to the controller's list. As a result no more perl namespaces can be installed nor exported to the context.