NAME

Scope::With - A JavaScript-style with statement for lexically-scoped method delegation

SYNOPSIS

use Builder;
use Scope::With;

my $builder = Builder->new();
my $xml = $builder->block('Builder::XML');

with ($xml) {
    body(
        div(
            span({ id => 1 }, 'one'),
            span({ id => 2 }, 'two'),
        )
    );
}

say $builder->render();

DESCRIPTION

Scope::With provides an implementation of the JavaScript with statement. Subroutines inside the with block that correspond to methods on the value passed into the with statement (the invocant) invoke the corresponding method on that value with the supplied arguments. The subroutines are lexically-scoped, and are not defined outside of the block.

The with keyword can be replaced by another keyword by supplying it as an argument to the use Scope::With statement e.g.

use Scope::With qw(using);

using ($xml) {
    div(
        span( ... ),
        span( ... ),
    );
}

The with statement takes two forms.

STATIC

with can be passed a class name/invocant pair separated by one or more spaces e.g.:

with (Dog $spot) {
    bark ...;
    wag_tail;
}

The class name must be a bareword i.e. an expression evaluating to a class name is not allowed. The invocant can be an arbitrary expression.

In this form, the class's methods are determined at compile-time and used to install the appropriate subroutines. The benefit of this usage is that the delegating subroutines are installed, with suitable prototypes, before the rest of the block is compiled, and therefore do not need to be invoked with parentheses.

By default, these subs have a prototype of @, which works for zero or more arguments, though it doesn't cater for subs that take blocks.

Note that when using the static form, the installed subroutines correspond to the methods available on the specified class at the time the with statement is compiled. This will install an AUTOLOAD subroutine, if the class defines or inherits an AUTOLOAD method, but won't pick up methods added after the with statement has been compiled, and, likewise, won't detect methods that are subsequently removed from the class.

DYNAMIC

The second form takes only an invocant (which can be an arbitrary expression), and defers the method lookup to runtime. This is done by means of a (lexically-scoped) AUTOLOAD sub. This requires each delegating sub to be called with parentheses.

This is useful in situations where parentheses are either a) not burdensome or b) required:

with ($xml) {
    div( 
        span( ... ),
        span( ... ),
    );
}

CAVEATS

  • lvalue subs/methods are not currently supported

  • method prototypes are not currently honoured i.e. the default prototype, @, is used in all cases

VERSION

0.01

SEE ALSO

AUTHOR

chocolateboy <chocolate@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2010 by chocolateboy

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.