Sub-QuoteX-Utils

Sugar for Sub::Quote


License
GPL-3.0

Documentation

NAME

Sub::QuoteX::Utils - Sugar for Sub::Quote

VERSION

version 0.01

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 separate 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.

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 chunks of inlined code defined by the specifications, returning an inlineable code reference.

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.

A specification may have the following form:

  • $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.

Options which may be passed as the last parameter include all of the options accepted by Sub::Quote::quote_sub, as well as:

  • name

    An optional name for the compiled subroutine.

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

    @_ = ...;
    
  • 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, so
      • changes 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

    @_ = ...;
    
  • 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, so
      • changes 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_method( \%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

    @_ = ...;
    
  • 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, so
      • changes 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

Sub::Quote

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