NAME
Sub::QuoteX::Utils - Sugar for Sub::Quote
VERSION
version 0.08
SYNOPSIS
use Sub::Quote;
use Sub::QuoteX::Utils qw[ quote_subs ];
my $sub;
# class with method
{
package Yipee;
use Moo;
sub halloo { shift; print "Yipee, @_\n" }
}
# and the object
my $object = Yipee->new;
# quoted sub
my $foo = quote_sub(
q[ print "$foo: @_\n"],
{ '$foo' => \"Foo" }
);
# bare sub
sub bar { print "Bar: @_\n" }
# create single subroutine. each invoked piece of code will have a
# localized view of @_
$sub = quote_subs(
\&bar, # bare sub
$foo, # quoted sub
[ q[ print "$goo: @_\n"], # code in string with capture
capture => { '$goo' => \"Goo" },
],
[ $object, 'halloo' ], # method call
);
# and run it
$sub->( "Common" );
# Bar: Common
# Goo: Common
# Foo: Common
# Yipee: Common
# now, give each a personalized @_
$sub = quote_subs(
[ \&bar, # bare sub
args => [qw( Bar )]
],
[ $foo, # quoted sub
args => [qw( Foo )]
],
[ q[ print "$goo, @_\n"], # code in string with capture
capture => { '$goo' => \"Goo" },
args => [qw( Goo )],
],
[ $object, 'halloo', # method call
args => [qw( Yipee )]
],
);
$sub->( "Common" );
# Bar: Bar
# Foo: Foo
# Goo: Goo
# Yipee: Yipee
# now, explicitly empty @_
$sub = quote_subs(
[ \&bar, # bare sub
args => undef
],
[ $foo, # quoted sub
args => undef
],
[ q[ print "$goo, @_\n"], # code in string with capture
capture => { '$goo' => \"Goo" },
args => undef,
],
[ $object, 'halloo', #method call
args => undef
],
);
$sub->( "Common" );
# Bar:
# Foo:
# Goo:
# Yipee:
DESCRIPTION
Sub::QuoteX::Utils provides a simplified interface to the process of combining Sub::Quote compatible code references with new code.
Sub::Quote provides a number of routines to make code more performant by inlining syntactically complete chunks of code into a single compiled subroutine.
When a chunk of code is compiled into a subroutine by Sub::Quote::quote_sub()
, Sub::Quote keeps track of the code and any captured variables used to construct that subroutine, so that new code can be added to the original code and the results compiled into a new subroutine.
Sub::QuoteX::Utils makes that latter process a little easier.
Usage
Typically, "quote_subs" is used rather than the lower level inlinify_*
routines. quote_subs
is passed a list of chunk specifications or snippets of code, and generates code which is isolated in a Perl block. Each code chunk is additionally isolated in its own block, while code snippets are in the main block. This permits manipulation of the code chunk values. This is schematically equivalent to
{
<snippet>
do { <chunk> };
<snippet>
do { <chunk> };
do { <chunk> };
}
The values of each chunk may be stored (see "Storing Chunk Values") and manipulated by the code snippets.
Storing Chunk Values
A code chunk may have it's value stored in a lexical variable by adding the store
option to the chunk's options. For example,
quote_subs( [ q{ sqrt(2); }, { store => '$x' } ],
[ q{ log(2); }, { store => '$y' } ],
[ q{ ( 0..10 ); }, { store => '@z' } ],
\q{print $x + $y, "\n";},
);
would result in code equivalent to:
{
my ( $x, $y, @z );
$x = do { sqrt(2) };
$y = do { log(2) };
@z = do { ( 0.. 10 ) };
print $x + $y, "\n";
}
If the variable passed to store
has no sigil, e.g. x
, then the calling context is taken into account. In list context, the value is stored in @x
, in scalar context it is stored in $x
and in void context it is not stored at all.
Automatic declaration of the variables occurs only when quote_subs
is used to generate the code.
Captures
Sub::Quote keeps track of captured variables in hashes, copying the values. For example,
use Sub::Quote;
my $sound = 'woof';
my $emit = quote_sub( q{ print "$sound\n" }, { '$sound' => \$sound } );
&$emit; # woof
$sound = 'meow';
&$emit; # woof
When combining chunks of inlined code, each chunk has it's own set of captured values which must be kept distinct.
"quote_subs" manages this for the caller, but when using the low level routines ( "inlinify_coderef", "inlinify_method", "inlinify_code" ) the caller must manage the captures. These routines store per-chunk captures in their \%global_capture
argument. The calling routine optionally may provide a mnemonic (but unique!) string which will be part of the key for the chunk.
The %global_capture
hash should be passed to "quote_sub" in Sub::Quote, when the final subroutine is compiled. For example,
my %global_capture;
my $code = inlinify_coderef( \%global_capture, $coderef, %options );
# add more code to $code [...]
$new_coderef = Sub::Quote::quote_sub( $code, \%global_capture );
FUNCTIONS
quote_subs
my $coderef = quote_subs( $spec, ?$spec, ... , ?\%options );
Creates a compiled subroutine from syntactically complete chunks of code or from snippets of code.
Chunks may be extracted from code previously inlined by Sub::Quote, specified as strings containing code, or generated to accomodate invoking object methods or calling non-inlineable code.
By default each chunk will localize @_
to avoid changing @_
for the other chunks. This can be changed on a per-chunk basis by specifying the local
option in each specification.
Specifications may take one of the following forms:
$coderef
-
If
$coderef
is inlineable (i.e, generated by "quote_sub" in Sub::Quote) it will be directly inlined, else code to invoke it will be generated. [ $coderef, %option ]
-
This is another way of specifying a code reference, allowing more manipulation; see "inlinify_coderef" for available options.
[ $object, $method, %option ]
-
Inline a method call. A weakened reference to
$object
is kept to avoid leaks. Method lookup is performed at runtime. See "inlinify_method" for available options. [ $string, %option ]
-
Inline a chunk of code in a string. See "inlinify_code" for available options.
$scalarref
-
Inline a snippet of code stored in the referenced scalar. Snippets need not be syntactically complete, and thus may be used to enclose chunks in blocks. For example, to catch exceptions thrown by a chunk:
$coderef = quote_subs( \'eval {', \&chunk_as_func, \'};' );
Specify any required captured values in the
capture
option toquote_subs
.
If the store
option is passed in a specification, a lexical variable with the specified name will automatically be created. See "Storing Chunk Values".
Options which may be passed as the last parameter include all of the options accepted by Sub::Quote::quote_sub
, as well as:
name
=> string-
An optional name for the compiled subroutine.
capture
=> hashref-
A hash containing captured variable names and values. See the documentation of the
\%captures
argument to "quote_sub" in Sub::Quote for more information. lexicals
=> scalar | arrayref-
One or more lexical variables to declare. If specified, quote_subs will enclose the generated code in a block and will declare these variables at the start of the block. For example,
quote_subs( \'@x = 33;', \'@y = 22;', lexicals => [ '@x', '@y' ] );
will result in code equivalent to:
{ my ( @x, @y ); @x = 33; @y = 22; }
inlinify_coderef
my $code = inlinify_coderef( \%global_capture, $coderef, %options );
Generate code which will execute $coderef
. If $coderef
is inlineable, it is inlined, else code which will invoke it is generated.
See "Captures" for more information on %global_capture
.
Available options are:
name
=> string-
An optional string used as part of the hash key for this chunk's captures.
local
=> boolean-
If true (the default) changes to
@_
will be local, e.g.local @_ = ...;
rather than
@_ = ...;
store
=> variable-
If specified, the result of the generated code will be stored in the variable of the given name. For example
store => '@x'
would result in code equivalent to:
@x = &$coderef;
The variable is not declared. See "Storing Chunk Values".
args
=> arrayref | hashref | string |undef
-
This specified the values of
@_
.if not specified, the value of
@_
is unchanged.if the value is
undef
,@_
will be empty.if the value is a reference to an array or hash,
@_
will be set equal to its contents. Note that the reference is cached, sochanges to its contents will be reflected in calls to the code.
there is the danger of memory leaks, as any non-weakened references in the structure will be destroyed only when both
%global_capture
and any subroutines based on this are destroyed.
if a string, this is inlined directly, e.g.
args => q[( 'FRANK' )]
results in
@_ = ( 'FRANK' )
inlinify_method
my $code = inlinify_method( \%global_capture, $object, $method, %options );
Generate code which will invoke the method named by $method
on $object
. While method resolution is performed at runtime, inlinify_method
checks that $method
is available for $object
and will croak
if not.
See "Captures" for more information on %global_capture
.
Available options are:
name
=> string-
An optional string used as part of the hash key for this chunk's captures.
local
=> boolean-
If true (the default) changes to
@_
will be local, e.g.local @_ = ...;
rather than
@_ = ...;
store
=> variable-
If specified, the result of the generated code will be stored in the variable of the given name. For example
store => '@x'
would result in code equivalent to:
@x = $object->$method( @_ );
The variable is not declared. See "Storing Chunk Values".
args
=> arrayref | hashref | string |undef
-
This specified the values of
@_
.if not specified, the value of
@_
is unchanged.if the value is
undef
,@_
will be empty.if the value is a reference to an array or hash,
@_
will be set equal to its contents. Note that the reference is cached, sochanges to its contents will be reflected in calls to the code.
there is the danger of memory leaks, as any non-weakened references in the structure will be destroyed only when both
%global_capture
and any subroutines based on this are destroyed.
if a string, this is inlined directly, e.g.
args => q[( 'FRANK' )]
results in
@_ = ( 'FRANK' )
inlinify_code
my $code = inlinify_code( \%global_capture, $code, %options );
Generate code which inlines $code
handling captures specified in %options
.
Available options are:
capture
=> hashref-
A hash containing captured variable names and values. See the documentation of the
\%captures
argument to "quote_sub" in Sub::Quote for more information. name
=> string-
An optional string used as part of the hash key for this chunk's captures.
local
=> boolean-
If true (the default) changes to
@_
will be local, e.g.local @_ = ...;
rather than
@_ = ...;
store
=> variable-
If specified, the result of the generated code will be stored in the variable of the given name. For example
store => '@x'
would result in code equivalent to:
@x = ... code ...;
The variable is not declared. See "Storing Chunk Values".
args
=> arrayref | hashref | string |undef
-
This specified the values of
@_
.if not specified, the value of
@_
is unchanged.if the value is
undef
,@_
will be empty.if the value is a reference to an array or hash,
@_
will be set equal to its contents. Note that the reference is cached, sochanges to its contents will be reflected in calls to the code.
there is the danger of memory leaks, as any non-weakened references in the structure will be destroyed only when both
%global_capture
and any subroutines based on this are destroyed.
if a string, this is inlined directly, e.g.
args => q[( 'FRANK' )]
results in
@_ = ( 'FRANK' )
SEE ALSO
AUTHOR
Diab Jerius <djerius@cpan.org>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2016 by Smithsonian Astrophysical Observatory.
This is free software, licensed under:
The GNU General Public License, Version 3, June 2007