NAME
Dist::Zilla::Plugin::Rinci::Wrap - Insert wrapper-generated code
VERSION
This document describes version 0.13 of Dist::Zilla::Plugin::Rinci::Wrap (from Perl distribution Dist-Zilla-Plugin-Rinci-Wrap), released on 2016-06-02.
SYNOPSIS
In dist.ini:
[Rinci::Wrap]
; optional, will be eval'ed as Perl code and passed to wrap_sub()
wrap_args = { validate_result => 0, convert => {retry=>2} }
; optional, will not squish code and add marker comment
debug=1
; optional, exclude some functions
;exclude_func=func1
;exclude_func=func2
; optional, only include specified functions
;include_func=func3
;include_func=func4
In your module:
$SPEC{foo} = {
v => 1.1,
args => {
arg1 => { schema => ['int*', default=>3] },
arg2 => { },
},
};
sub foo {
my %args = @_;
... your code
return [200, "OK", "some result"];
}
output will be something like:
$SPEC{foo} = {
v => 1.1,
args => {
arg1 => { schema => ['int*', default=>3] },
arg2 => { },
},
};
require Scalar::Util; require Data::Dumper; { my $meta = $SPEC{foo}; $meta->{args}{arg1}{schema} = ["int", {req=>1, default=>3}, {}]; } # WRAP_PRESUB
sub foo {
my %args = @_;
... generated preamble code
... your code
return [200, "OK", "some result"];
... generated postamble code
}
DESCRIPTION
This plugin inserts code generated by Perinci::Sub::Wrapper to your source code during building. This lets you add functionalities like argument validation, result validation, automatic retries, conversion of argument passing style, currying, and so on.
Code is inserted in three places (see the above example in Synopsis):
The first part (which is the part to load required modules and to modify function metadata, e.g. normalize Sah schemas, etc) will be inserted right before the opening of the subroutine (
sub NAME {
).The second part (which is the part to validate arguments and do stuffs before performing the function) will be inserted at the start of subroutine body after the
my %args = @_;
(ormy $args = $_[0] // {};
if you accept arguments from a hashref, ormy @args = @_;
if you accept arguments from an array, ormy $args = $_[0] // [];
if you accept arguments from an arrayref) statement. This should be one of the first things you write after your sub declaration before you do anything else.The third part (which is the part to validate function result and do stuffs after performing the function) will be inserted right before the closing of the subroutine.
Currently regexes are used to parse the code so things might be rather fragile.
RESTRICTIONS
There are some restrictions (hopefully not actually restricting) when writing your code if you want to use this plugin.
Clash of variables
The generated wrapper code will declare some variables. You need to make sure that the variables do not clash. This is rather simple: the variables used by the wrapper code will all be prefixed with
_w_
(e.g.$_w_res
) or_sahv_
for variables generated by the Sah schema compiler (e.g.$_sahv_dpath
).Variable used to accept arguments
Currently the wrapper internally will perform argument validation on
$args{ARGNAME}
variables, even if you accept arguments from a hashref/array/arrayref. Thus:If you accept arguments from a hash (the default), you need to put the arguments to
%args
, i.e.:my %args = @_;
You can then get the validated arguments e.g.:
my $name = $args{name}; my $addr = $args{address}; ...
If you accept arguments from a hashref (i.e.
func({ arg1=>1, arg2=>2 })
):my $args = $_[0] // {};
If you accept arguments from an array (e.g.
func(1, 2)
:my @args = @_;
If you accept arguments from an arrayref
func([1, 2])
:my $args = $_[0] // [];
FAQ
Rationale for this plugin?
This plugin is an alternative to using Perinci::Sub::Wrapper (PSW) dynamically. During build, you generate the wrapper code and insert it to the target code. The result is lower startup overhead (no need to generate the wrapper code during runtime) and better guarantee that your wrapping code (argument validation, etc) is always called when your subroutines are called, even if your users do not use PSW and call your subroutines directly.
Another advantage/characteristic using this plugin is that, the wrapper code does not introduce extra call level.
But why use PSW at all?
In short, adding Rinci metadata to your subroutines allows various tools to do useful stuffs, relieving you from coding those stuffs manually. Using Sah schema allows you to write validation code succintly, and gives you the ability to automatically generate Perl/JavaScript/error messages from the schema.
PSW is one of the ways (currently the only way) to implement those behaviours/functionalities.
But the generated code looks ugly!
Admittedly, yes. Wrapper-generated code is formatted as a single long line to avoid modifying line numbers, which is desirable when debugging your modules. If you don't want to compress everything as a single line, add debug=1
in your dist.ini
.
How do I customize wrapping for my function
Two ways. You can either use wrap_args
in dist.ini
(see Synopsis) or add an attribute in your function metadata:
"x.dist.zilla.plugin.rinci.wrap.wrap_args" => { validate_args => 0 },
which will be merged and will override wrap_args
keys specified in dist.ini
.
HOMEPAGE
Please visit the project's homepage at https://metacpan.org/release/Dist-Zilla-Plugin-Rinci-Wrap.
SOURCE
Source repository is at https://github.com/sharyanto/perl-Dist-Zilla-Plugin-Rinci-Wrap.
BUGS
Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Dist-Zilla-Plugin-Rinci-Wrap
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.
SEE ALSO
If you are only concerned with argument validation, you can take a look at: Dist::Zilla::Plugin::Rinci::Validate, Data::Sah::Manual::ParamsValidating.
If you are only concerned with function return validation, you can take a look at: Dist::Zilla::Plugin::Rinci::Validate, Data::Sah::Manual::ResultValidating.
AUTHOR
perlancar <perlancar@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2016 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.