Steven Haryanto > Perinci-Sub-Wrapper > Perinci::Sub::Wrapper

Download:
Perinci-Sub-Wrapper-0.61.tar.gz

Dependencies

Annotate this POD

Website

CPAN RT

Open  0
View/Report Bugs
Module Version: 0.61   Source  

NAME ^

Perinci::Sub::Wrapper - A multi-purpose subroutine wrapping framework

VERSION ^

This document describes version 0.61 of Perinci::Sub::Wrapper (from Perl distribution Perinci-Sub-Wrapper), released on 2014-05-01.

SYNOPSIS ^

For dynamic usage:

 use Perinci::Sub::Wrapper qw(wrap_sub);
 my $res = wrap_sub(sub_name => "mysub", meta=>{...});
 my ($wrapped_sub, $meta) = ($res->[2]{sub}, $res->[2]{meta});
 $wrapped_sub->(); # call the wrapped function

DESCRIPTION ^

Perinci::Sub::Wrapper (PSW for short) is an extensible subroutine wrapping framework. It generates code to do stuffs before calling your subroutine, like validate arguments, convert arguments from positional/array to named/hash or vice versa, etc; as well as generate code to do stuffs after calling your subroutine, like retry calling for a number of times if subroutine returns a non-success status, check subroutine result against a schema, etc). Some other things it can do: apply a timeout, currying, and so on.

PSW differs from other function composition or decoration system like Python decorators (or its Perl equivalent Python::Decorator) in a couple of ways:

Normally you do not use PSW directly in your applications. You might want to check out Perinci::Access::Perl and Perinci::Exporter on examples of wrapping function dynamically (during runtime), or Dist::Zilla::Plugin::Rinci::Wrap on an example of embedding the generated wrapping code to source code during build.

FUNCTIONS ^

wrap_sub(%args) -> [status, msg, result, meta]

Wrap subroutine to do various things, like enforcing Rinci properties.

Arguments ('*' denotes required arguments):

Return value:

Returns an enveloped result (an array).

First element (status) is an integer containing HTTP status code (200 means OK, 4xx caller error, 5xx function error). Second element (msg) is a string containing error message, or 'OK' if status is 200. Third element (result) is optional, the actual result. Fourth element (meta) is called result metadata and is optional, a hash that contains extra information.

The wrapped subroutine along with its new metadata (hash)

EXTENDING ^

The framework is simple and extensible. Please delve directly into the source code for now. Some notes:

The internal uses OO.

The main wrapper building mechanism is in the wrap() method.

For each Rinci property, it will call handle_NAME() wrapper handler method. The handlemeta_NAME() methods are called first, to determine order of processing. You can supply these methods either by subclassing the class or, more simply, monkeypatching the method in the Perinci::Sub::Wrapper package.

The wrapper handler method will be called with a hash argument, containing these keys: value (property value), new (this key will exist if convert argument of wrap() exists, to convert a property to a new value).

For properties that have name in the form of NAME1.NAME2.NAME3 (i.e., dotted) only the first part of the name will be used (i.e., handle_NAME1()).

VARIABLES ^

$Log_Wrapper_Code (BOOL)

Whether to log wrapper result. Default is from environment variable LOG_PERINCI_WRAPPER_CODE, or false. Logging is done with Log::Any at trace level.

METHODS ^

The OO interface is only used internally or when you want to extend the wrapper.

ENVIRONMENT ^

LOG_PERINCI_WRAPPER_CODE (bool)

If set to 1, will log the generated wrapper code. This value is used to set $Log_Wrapper_Code if it is not already set.

PERFORMANCE NOTES ^

The following numbers are produced on an Intel Core i5-2400 3.1GHz desktop using PSW v0.51 and Perl v5.18.2. Operating system is Debian sid (64bit).

For perspective, empty subroutine (sub {}) as well as sub { [200, "OK"] } can be called around 5.3 mil/sec.

Wrapping this subroutine sub { [200, "OK"] } and this simple metadata {v=>1.1} using default options yields call performance for $sub->() of about 0.9 mil/sec. With validate_args=>0 and validate_result=>0, it's 1.5 mil/sec.

As more (and more complex) arguments are introduced and validated, overhead will increase. The significant portion of the overhead is in argument validation. For example, this metadata {v=>1.1, args=>{a=>{schema=>"int"}}} yields 0.5 mil/sec.

FAQ ^

General

Debugging

caller() doesn't work from inside my wrapped code!

Wrapping adds at least one or two levels of calls: one for the wrapper subroutine itself, the other is for the eval trap when necessary.

This poses a problem if you need to call caller() from within your wrapped code; it will also be off by at least one or two.

The solution is for your function to use the caller() replacement, provided by Perinci::Sub::Util. Or use embedded mode, where the wrapper code won't add extra subroutine calls.

SEE ALSO ^

Perinci, Rinci

Python::Decorator

Dist::Zilla::Plugin::Rinci::Wrap

Dist::Zilla::Plugin::Rinci::Validate

HOMEPAGE ^

Please visit the project's homepage at https://metacpan.org/release/Perinci-Sub-Wrapper.

SOURCE ^

Source repository is at https://github.com/sharyanto/perl-Perinci-Sub-Wrapper.

BUGS ^

Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Wrapper

When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.

AUTHOR ^

Steven Haryanto <stevenharyanto@gmail.com>

COPYRIGHT AND LICENSE ^

This software is copyright (c) 2014 by Steven Haryanto.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

syntax highlighting: