File Coverage

blib/lib/Perinci/Sub/Wrapper.pm
Criterion Covered Total %
statement 601 671 89.5
branch 198 286 69.2
condition 97 160 60.6
subroutine 63 76 82.8
pod 1 38 2.6
total 960 1231 77.9


line stmt bran cond sub pod time code
1             package Perinci::Sub::Wrapper;
2              
3             our $DATE = '2019-07-04'; # DATE
4             our $VERSION = '0.851'; # VERSION
5              
6 17     17   227 use 5.010001;
  17         64  
7 17     17   83 use strict;
  17         231  
  17         233  
8 17     15   1487 use warnings;
  15         106  
  15         436  
9 15     15   5281 use experimental 'smartmatch';
  15         38345  
  15         69  
10 15     15   19216 use Log::ger;
  15         695  
  15         58  
11              
12 15     15   8401 use Data::Dmp qw(dmp);
  15         19509  
  15         744  
13 15     15   547 use Function::Fallback::CoreOrPP qw(clone);
  15         115  
  15         485  
14 15     15   5626 use Perinci::Sub::Normalize qw(normalize_function_metadata);
  15         13118  
  15         746  
15 15     15   6161 use Perinci::Sub::Util qw(err);
  15         25534  
  15         750  
16              
17 15     15   98 use Exporter qw(import);
  15         136  
  15         79813  
18             our @EXPORT_OK = qw(wrap_sub);
19              
20             our $Log_Wrapper_Code = $ENV{LOG_PERINCI_WRAPPER_CODE} // 0;
21              
22             our %SPEC;
23              
24             $SPEC{':package'} = {
25             v => 1.1,
26             summary => 'A multi-purpose subroutine wrapping framework',
27             };
28              
29             # "protocol version" (v). whenever there's a significant change in the basic
30             # structure of the wrapper, which potentially cause some/a lot of property
31             # handlers to stop working, we increase this. property handler must always state
32             # which version it follows in its meta. if unspecified, it's assumed to be 1.
33             our $protocol_version = 2;
34              
35             sub new {
36 113     113 0 297 my ($class) = @_;
37 113         552 bless {}, $class;
38             }
39              
40             sub _check_module {
41 183     183   497 my ($self, $mod) = @_;
42              
43 183 50       925 if ($self->{_args}{core}) {
44 1 0       7 if ($mod =~ /\A(experimental|Scalar::Numeric::Util|Scalar::Util::Numeric::PP)\z/) {
    0          
45 1         3 die "BUG: Requested non-core module '$mod' while wrap arg core=1";
46             } elsif ($mod =~ /\A(warnings|List::Util)\z/) {
47             # core modules
48             } else {
49 1         5 die "BUG: Haven't noted whether module '$mod' is core/non-core";
50             }
51             }
52              
53 183 50       478 if ($self->{_args}{pp}) {
54 1 0       3 if ($mod =~ /\A(List::Util|Scalar::Numeric::Util)\z/) {
    0          
55 1         320 die "BUG: Requested XS module '$mod' while wrap arg pp=1";
56             } elsif ($mod =~ /\A(experimental|warnings|Scalar::Util::Numeric::PP)\z/) {
57             # pp modules
58             } else {
59 1         7 die "BUG: Haven't noted whether module '$mod' is pure-perl/XS";
60             }
61             }
62              
63 183 50       413 if ($self->{_args}{core_or_pp}) {
64 1 0       7 if ($mod =~ /\A(Scalar::Numeric::Util)\z/) {
    0          
65 1         89 die "BUG: Requested non-core XS module '$mod' while wrap arg core_or_pp=1";
66             } elsif ($mod =~ /\A(experimental|warnings|List::Util|Scalar::Util::Numeric::PP)\z/) {
67             # core or pp modules
68             } else {
69 1         2 die "BUG: Haven't noted whether module '$mod' is non-core xs or not";
70             }
71             }
72             }
73              
74             sub _add_module {
75 231     231   837 my ($self, $mod) = @_;
76 231 100       724 unless ($mod ~~ $self->{_modules}) {
77 183         376 local $self->{_cur_section};
78 183         456 $self->select_section('before_sub_require_modules');
79 183 100       1237 if ($mod =~ /\A(use|no) (\S+)/) {
    50          
80 125         409 $self->_check_module($2);
81 125         754 $self->push_lines("$mod;");
82             } elsif ($mod =~ /\A\w+(::\w+)*\z/) {
83 59         183 $self->_check_module($mod);
84 59         197 $self->push_lines("require $mod;");
85             } else {
86 1         9 die "BUG: Invalid module name/statement: $mod";
87             }
88 183         338 push @{ $self->{_modules} }, $mod;
  183         491  
89             }
90             }
91              
92             sub _add_var {
93 101     101   802 my ($self, $var, $value) = @_;
94 101 50       321 unless (exists $self->{_vars}{$var}) {
95 101         278 local $self->{_cur_section};
96 101         273 $self->select_section('declare_vars');
97 101         504 $self->push_lines("my \$$var = ".dmp($value).";");
98 101         354 $self->{_vars}{$var} = $value;
99             }
100             }
101              
102             sub _known_sections {
103              
104             # order=>N regulates the order of code. embed=>1 means the code is for embed
105             # mode only and should not be included in dynamic wrapper code.
106              
107 2455     2455   3955 state $val = {
108             before_sub_require_modules => {order=>1},
109              
110             # reserved by wrapper for setting Perl package and declaring 'sub {'
111             OPEN_SUB => {order=>4},
112              
113             # reserved to say 'my %args = @_;' or 'my @args = @_;' etc
114             ACCEPT_ARGS => {order=>5},
115              
116             # reserved to get args values if converted from array/arrayref
117             ACCEPT_ARGS2 => {order=>6},
118              
119             declare_vars => {order=>7},
120              
121             # for handlers to put stuffs right before eval. for example, 'timeout'
122             # uses this to set ALRM signal handler.
123             before_eval => {order=>10},
124              
125             # reserved by wrapper for generating 'eval {'
126             OPEN_EVAL => {order=>20},
127              
128             # used e.g. to load modules used by validation
129             before_call_before_arg_validation => {order=>31},
130              
131             before_call_arg_validation => {order=>32},
132              
133             # used e.g. by dependency checking
134             before_call_after_arg_validation => {order=>33},
135              
136             # feed arguments to sub
137             before_call_feed_args => {order=>48},
138              
139             # for handlers that *must* do stuffs right before call
140             before_call_right_before_call => {order=>49},
141              
142             # reserved by the wrapper for calling the sub
143             CALL => {order=>50},
144              
145             # for handlers that *must* do stuffs right after call
146             after_call_right_after_call => {order=>51},
147              
148             # reserved by the wrapper for adding/stripping result envelope, this
149             # happens before result validation
150             AFTER_CALL_ADD_OR_STRIP_RESULT_ENVELOPE => {order=>52},
151              
152             # used e.g. to load modules used by validation
153             after_call_before_res_validation => {order=>61},
154              
155             after_call_res_validation => {order=>62},
156              
157             after_call_after_res_validation => {order=>63},
158              
159             # reserved by wrapper to put eval end '}' and capturing result in
160             # $_w_res and $@ in $eval_err
161             CLOSE_EVAL => {order=>70},
162              
163             # for handlers to put checks against $eval_err
164             after_eval => {order=>80},
165              
166             # reserved for returning final result '$_w_res'
167             BEFORE_CLOSE_SUB => {order=>99},
168              
169             # reserved for sub closing '}' line
170             CLOSE_SUB => {order=>100},
171             };
172 2455         4189 $val;
173             }
174              
175             sub section_empty {
176 4821     4821 0 6256 my ($self, $section) = @_;
177 4821         10344 !$self->{_codes}{$section};
178             }
179              
180             sub _needs_eval {
181 111     111   218 my ($self) = @_;
182 111   33     333 !($self->section_empty('before_eval') &&
183             $self->section_empty('after_eval'));
184             }
185              
186             # whether we need to store call result to a variable ($_w_res)
187             sub _needs_store_res {
188 105     105   237 my ($self) = @_;
189 105 100       412 return 1 if $self->{_args}{validate_result};
190 7 50       20 return 1 if $self->_needs_eval;
191 7         458 my $ks = $self->_known_sections;
192 6         28 for (grep {/^after_call/} keys %$ks) {
  132         221  
193 24 50       49 return 1 unless $self->section_empty($_);
194             }
195 6         16 0;
196             }
197              
198             sub _check_known_section {
199 1338     1339   1963 my ($self, $section) = @_;
200 1338         2201 my $ks = $self->_known_sections;
201 1338 50       3122 $ks->{$section} or die "BUG: Unknown code section '$section'";
202             }
203              
204             sub _err {
205 366     367   654 my ($self, $c_status, $c_msg) = @_;
206 366 100       736 if ($self->{_meta}{result_naked}) {
207 8         31 $self->push_lines(
208             "warn 'ERROR ' . ($c_status) . ': '. ($c_msg);",
209             'return undef;',
210             );
211             } else {
212 358         1024 $self->push_lines("return [$c_status, $c_msg];");
213             }
214             }
215              
216             sub _errif {
217 270     271   6804 my ($self, $c_status, $c_msg, $c_cond) = @_;
218 270         815 $self->push_lines("if ($c_cond) {");
219 270         612 $self->indent;
220 270         672 $self->_err($c_status, $c_msg);
221 270         658 $self->unindent;
222 270         411 $self->push_lines('}');
223             }
224              
225             sub select_section {
226 1338     1339 0 2125 my ($self, $section) = @_;
227 1338         2691 $self->_check_known_section($section);
228 1338         1880 $self->{_cur_section} = $section;
229 1338         1617 $self;
230             }
231              
232             sub indent {
233 646     647 0 973 my ($self) = @_;
234 646         864 my $section = $self->{_cur_section};
235 646   50     1231 $self->{_codes}{$section} //= undef;
236 646         909 $self->{_levels}{$section}++;
237 646         854 $self;
238             }
239              
240             sub unindent {
241 640     641 0 1074 my ($self) = @_;
242 640         847 my $section = $self->{_cur_section};
243 640   100     1356 $self->{_codes}{$section} //= undef;
244 640         866 $self->{_levels}{$section}--;
245 640         755 $self;
246             }
247              
248             sub get_indent_level {
249 86     86 0 178 my ($self) = @_;
250 86         162 my $section = $self->{_cur_section};
251 86   50     377 $self->{_levels}{$section} // 0;
252             }
253              
254             # line can be code or comment. code should not contain string literals that
255             # cross lines (i.e. contain literal newlines) because push_lines() might add
256             # comment at the end of each line.
257              
258             sub push_lines {
259 2606     2606 0 6994 my ($self, @lines) = @_;
260 2606         3264 my $section = $self->{_cur_section};
261              
262 2606 100       4440 unless (exists $self->{_codes}{$section}) {
263 798         1668 unshift @lines, "# * section: $section";
264             # don't give blank line for the top-most section (order=>0)
265 798 50       1308 unshift @lines, "" if $self->_known_sections->{$section}{order};
266 798         1623 $self->{_codes}{$section} = [];
267 798         1224 $self->{_levels}{$section} = 0;
268             }
269              
270 2606         3471 @lines = map {[$self->{_levels}{$section}, $_]} @lines;
  4736         10004  
271 2606 50       4582 if ($self->{_args}{debug}) {
272 0         0 for my $l (@lines) {
273             $l->[2] =
274             $self->{_cur_handler} ?
275             "$self->{_cur_handler} prio=".$self->{_cur_handler_meta}{prio}
276 0 0       0 : "";
277             }
278             }
279 2606         2956 push @{$self->{_codes}{$section}}, @lines;
  2606         4997  
280 2606         5052 $self;
281             }
282              
283             sub _join_codes {
284 208     208   409 my ($self, $crit, $prev_section_level) = @_;
285 208         292 my @lines;
286 208         364 my $ks = $self->_known_sections;
287 208   100     664 $prev_section_level //= 0;
288 208         280 my $i = 0;
289 208         1139 for my $s (sort {$ks->{$a}{order} <=> $ks->{$b}{order}}
  15364         18929  
290             keys %$ks) {
291 4576 100       6308 next if $self->section_empty($s);
292 1772 100       2692 next unless $crit->(section => $s);
293 678         908 $i++;
294 678         784 for my $l (@{ $self->{_codes}{$s} }) {
  678         1193  
295 4015         4524 $l->[0] += $prev_section_level;
296 4015 50       5418 die "BUG: Negative indent level in line $i (section $s): '$l->[1]'"
297             if $l->[0] < 0;
298 4015         7064 my $s = ($self->{_args}{indent} x $l->[0]) . $l->[1];
299 4015 50       5739 if (defined $l->[2]) {
300 0         0 my $num_ws = 80 - length($s);
301 0 0       0 $num_ws = 1 if $num_ws < 1;
302 0         0 $s .= (" " x $num_ws) . "## $l->[2]";
303             }
304 4015         5725 push @lines, $s;
305             }
306 678         1051 $prev_section_level += $self->{_levels}{$s};
307             }
308 208         1580 [join("\n", @lines), $prev_section_level];
309             }
310              
311             sub _format_dyn_wrapper_code {
312 52     52   110 my ($self) = @_;
313 52         131 my $ks = $self->_known_sections;
314             $self->_join_codes(
315             sub {
316 443     443   796 my %args = @_;
317 443         558 my $section = $args{section};
318 443         1001 !$ks->{$section}{embed};
319 52         424 })->[0];
320             }
321              
322             # for embedded, we need to produce three sections which will be inserted in
323             # different places, demonstrated below:
324             #
325             # $SPEC{foo} = {
326             # ...
327             # };
328             # sub foo {
329             # my %args = @_;
330             # # do stuffs
331             # }
332             #
333             # becomes:
334             #
335             # #PRESUB1: require modules (inserted before sub declaration)
336             # require Data::Dumper;
337             # require Scalar::Util;
338             #
339             # $SPEC{foo} = {
340             # ...
341             # };
342             # #PRESUB2: modify metadata piece-by-piece (inserted before sub declaration &
343             # #after $SPEC{foo}). we're avoiding dumping the new modified metadata because
344             # #metadata might contain coderefs which is sometimes problematic when dumping
345             # {
346             # my $meta = $SPEC{foo};
347             # $meta->{v} = 1.1;
348             # $meta->{result_naked} = 0;
349             # }
350             #
351             # sub foo {
352             # my %args = @_;
353             # #PREAMBLE: before call sections (inserted after accept args), e.g.
354             # #validate arguments, convert argument type, setup eval block
355             # #...
356             #
357             # # do stuffs
358             #
359             # #POSTAMBLE: after call sections (inserted before sub end), e.g.
360             # #validate result, close eval block and do retry/etc.
361             # #...
362             # }
363             sub _format_embed_wrapper_code {
364 52     52   118 my ($self) = @_;
365              
366 52         115 my $res = {};
367 52         132 my $ks = $self->_known_sections;
368 52         83 my $j;
369              
370             $j = $self->_join_codes(
371             sub {
372 443     443   750 my %args = @_;
373 443         541 my $section = $args{section};
374 443         1119 $section =~ /\A(before_sub_require_modules)\z/;
375 52         670 });
376 52         273 $res->{presub1} = $j->[0];
377              
378             # no longer needed/produce, code to modify metadata
379 52         441 $res->{presub2} = '';
380              
381             $j = $self->_join_codes(
382             sub {
383 443     443   746 my %args = @_;
384 443         589 my $section = $args{section};
385 443         546 my $order = $ks->{$section}{order};
386             return 1 if $order > $ks->{ACCEPT_ARGS}{order} &&
387 443 100 100     1239 $order < $ks->{CALL}{order};
388 349         718 0;
389 52         276 }, 1);
390 52         253 $res->{preamble} = $j->[0];
391              
392             $j = $self->_join_codes(
393             sub {
394 443     443   694 my %args = @_;
395 443         550 my $section = $args{section};
396 443         555 my $order = $ks->{$section}{order};
397             return 1 if $order > $ks->{CALL}{order} &&
398 443 100 100     1069 $order < $ks->{CLOSE_SUB}{order};
399 337         655 0;
400 52         276 }, $j->[1]);
401 52         221 $res->{postamble} = $j->[0];
402              
403 52         229 $res;
404             }
405              
406 108     108 0 206 sub handlemeta_v { {} }
407 0     0 0 0 sub handlemeta_name { {} }
408 0     0 0 0 sub handlemeta_summary { {} }
409 0     0 0 0 sub handlemeta_description { {} }
410 0     0 0 0 sub handlemeta_tags { {} }
411 0     0 0 0 sub handlemeta_default_lang { {} }
412 0     0 0 0 sub handlemeta_links { {} }
413 0     0 0 0 sub handlemeta_text_markup { {} }
414 0     0 0 0 sub handlemeta_is_func { {} }
415 0     0 0 0 sub handlemeta_is_meth { {} }
416 0     0 0 0 sub handlemeta_is_class_meth { {} }
417 0     0 0 0 sub handlemeta_examples { {} }
418              
419             # after args
420 4     4 0 10 sub handlemeta_features { {v=>2, prio=>15} }
421             sub handle_features {
422 4     4 0 14 my ($self, %args) = @_;
423              
424 4         7 my $meta = $self->{_meta};
425 4   50     9 my $v = $meta->{features} // {};
426              
427 4         11 $self->select_section('before_call_before_arg_validation');
428              
429 4 50 33     24 if ($v->{tx} && $v->{tx}{req}) {
430 4         16 $self->push_lines('', '# check required transaction');
431 4         10 $self->_errif(412, '"Must run with transaction (pass -tx_manager)"',
432             '!$args{-tx_manager}');
433             }
434             }
435              
436             # run before args
437 108     108 0 392 sub handlemeta_args_as { {v=>2, prio=>1, convert=>1} }
438             sub handle_args_as {
439 108     108 0 461 my ($self, %args) = @_;
440              
441 108         270 my $value = $args{value};
442 108         224 my $new = $args{new};
443 108         193 my $meta = $self->{_meta};
444 108   100     359 my $args_p = $meta->{args} // {};
445 108         202 my $opt_va = $self->{_args}{validate_args};
446              
447             # We support conversion of arguments between hash/hashref/array/arrayref. To
448             # make it simple, currently the algorithm is as follow: we first form the
449             # %args hash. If args_as is already 'hash', we just do 'my %args = @_'.
450             # Otherwise, we convert from the other forms.
451             #
452             # We then validate each argument in %args (code generated in 'args'
453             # handler).
454             #
455             # Finally, unless original args_as is 'hash' we convert to the final form
456             # that the wrapped sub expects.
457             #
458             # This setup is optimal when both the sub and generated wrapper accept
459             # 'hash', but suboptimal for other cases (especially positional ones, as
460             # they have to undergo a round-trip to hash even when both accept 'array').
461             # This will be rectified in the future.
462              
463 108   66     425 my $v = $new // $value;
464              
465 108         314 $self->select_section('ACCEPT_ARGS');
466 108 100       325 if ($v eq 'hash') {
    100          
    50          
467 100 100       353 $self->push_lines(q{die 'BUG: Odd number of hash elements supplied' if @_ % 2;})
468             if $opt_va;
469 100         230 $self->push_lines('my %args = @_;');
470             } elsif ($v eq 'hashref') {
471 2 50       8 $self->push_lines(q{die 'BUG: $_[0] needs to be hashref' if @_ && ref($_[0]) ne "HASH";})
472             if $opt_va;
473 2         5 $self->push_lines('my %args = %{$_[0] // {}};');
474             } elsif ($v =~ /\Aarray(ref)?\z/) {
475 6 100       23 my $ref = $1 ? 1:0;
476 6 100       17 if ($ref) {
477 2 50       7 $self->push_lines(q{die 'BUG: $_[0] needs to be arrayref' if @_ && ref($_[0]) ne "ARRAY";})
478             if $opt_va;
479             }
480 6         15 $self->push_lines('my %args;');
481 6         17 $self->select_section('ACCEPT_ARGS2');
482 6         23 for my $a (sort keys %$args_p) {
483 12         20 my $as = $args_p->{$a};
484 12         43 my $line = '$args{'.dmp($a).'} = ';
485 12 50       436 defined($as->{pos}) or die "Error in args property for arg '$a': ".
486             "no pos defined";
487 12         25 my $pos = int($as->{pos} + 0);
488 12 50       31 $pos >= 0 or die "Error in args property for arg '$a': ".
489             "negative value in pos";
490 12 50 33     50 if ($as->{slurpy} // $as->{greedy}) {
491 0 0       0 if ($ref) {
492 0         0 $line .= '[splice @{$_[0]}, '.$pos.'] if @{$_[0]} > '.$pos;
493             } else {
494 0         0 $line .= '[splice @_, '.$pos.'] if @_ > '.$pos;
495             }
496             } else {
497 12 100       31 if ($ref) {
498 4         12 $line .= '$_[0]['.$pos.'] if @{$_[0]} > '.$pos;
499             } else {
500 8         18 $line .= '$_['.$pos.'] if @_ > '.$pos;
501             }
502             }
503 12         36 $self->push_lines("$line;");
504             }
505             } else {
506 0         0 die "Unknown args_as value '$v'";
507             }
508              
509 108         296 $self->select_section('ACCEPT_ARGS');
510 108 100       481 if ($value eq 'hashref') {
    100          
    100          
511 2         5 $self->push_lines('my $args;');
512             } elsif ($value eq 'array') {
513 4         10 $self->push_lines('my @args;');
514             } elsif ($value eq 'arrayref') {
515 2         4 $self->push_lines('my $args;');
516             }
517              
518 108         177 my $tok;
519 108         271 $self->select_section('before_call_feed_args');
520 108         178 $v = $value;
521 108 100       307 if ($v eq 'hash') {
    100          
    50          
522 100         176 $tok = '%args';
523             } elsif ($v eq 'hashref') {
524 2         4 $tok = '$args';
525 2         16 $self->push_lines($tok.' = \%args;'); # XXX should we set each arg instead?
526             } elsif ($v =~ /\Aarray(ref)?\z/) {
527 6 100       24 my $ref = $1 ? 1:0;
528 6 100       18 $tok = ($ref ? '$':'@') . 'args';
529 6         24 for my $a (sort {$args_p->{$a}{pos} <=> $args_p->{$b}{pos}}
  6         28  
530             keys %$args_p) {
531 12         21 my $as = $args_p->{$a};
532 12         38 my $t = '$args{'.dmp($a).'}';
533 12         459 my $line;
534 12 50       30 defined($as->{pos}) or die "Error in args property for arg '$a': ".
535             "no pos defined";
536 12         24 my $pos = int($as->{pos} + 0);
537 12 50       30 $pos >= 0 or die "Error in args property for arg '$a': ".
538             "negative value in pos";
539 12 50 33     45 if ($as->{slurpy} // $as->{greedy}) {
540 0         0 $line = 'splice @args, '.$pos.', scalar(@args)-1, @{'.$t.'}';
541             } else {
542 12 100       51 $line = '$args'.($ref ? '->':'').'['.$pos."] = $t if exists $t";
543             }
544 12         36 $self->push_lines("$line;");
545             }
546             } else {
547 0         0 die "Unknown args_as value '$v'";
548             }
549 108         522 $self->{_args_token} = $tok;
550             }
551              
552             sub _sah {
553 11     11   2854 require Data::Sah;
554              
555 11         18461 my $self = shift;
556 11         47 state $sah = Data::Sah->new;
557 11         309 $sah;
558             }
559              
560             sub _plc {
561 86     86   155 my $self = shift;
562 86         510 state $plc = do {
563 7         26 my $plc = $self->_sah->get_compiler("perl");
564 7         140979 $plc->comment_style('shell2'); # to make all comment uses ## instead of #
565 7         94 $plc;
566             };
567             }
568              
569             sub _handle_args {
570 78     78   274 my ($self, %args) = @_;
571              
572 78   66     402 my $v = $args{v} // $self->{_meta}{args};
573 78 50       186 return unless $v;
574              
575 78         164 my $opt_sin = $self->{_args}{_schema_is_normalized};
576 78         174 my $opt_va = $self->{_args}{validate_args};
577              
578 78   100     292 my $prefix = $args{prefix} // '';
579 78   100     248 my $argsterm = $args{argsterm} // '%args';
580              
581 78 100       172 if ($opt_va) {
582 76         269 $self->_add_module("use experimental 'smartmatch'");
583 76         220 $self->select_section('before_call_arg_validation');
584 76 100       293 $self->push_lines('', '# check args') if $prefix eq '';
585 76         267 $self->push_lines("for (sort keys $argsterm) {");
586 76         235 $self->indent;
587 76         327 $self->_errif(400, q["Invalid argument name (please use letters/numbers/underscores only)'].$prefix.q[$_'"],
588             '!/\A(-?)\w+(\.\w+)*\z/o');
589 76         582 $self->_errif(400, q["Unknown argument '].$prefix.q[$_'"],
590             '!($1 || $_ ~~ '.dmp([sort keys %$v]).')');
591 76         236 $self->unindent;
592 76         137 $self->push_lines('}');
593             }
594              
595 78         309 for my $argname (sort keys %$v) {
596 108         212 my $argspec = $v->{$argname};
597              
598 108         176 my $argterm = $argsterm;
599 108 100       619 if ($argterm =~ /^%\{\s*(.+)\s*\}/) {
    50          
600 8         28 $argterm = $1 . "->{'$argname'}";
601             } elsif ($argterm =~ s/^%/\$/) {
602 100         234 $argterm .= "{'$argname'}";
603             } else {
604 0         0 $argterm .= "->{'$argname'}";
605             }
606              
607 108         237 my $has_default_prop = exists($argspec->{default});
608 108         205 my $sch = $argspec->{schema};
609              
610 108 100       240 if ($sch) {
    100          
611             my $has_sch_default = ref($sch) eq 'ARRAY' &&
612 78 100 100     435 exists($sch->[1]{default}) ? 1:0;
613 78 100       165 if ($opt_va) {
614              
615 74         264 $self->push_lines("if (exists($argterm)) {");
616 74         176 $self->indent;
617              
618 74 100       164 if ($argspec->{stream}) {
619 2 50       12 die "Error in schema for argument '$argname': must be str/buf/array if stream=1"
620             unless $sch->[0] =~ /\A(str|buf|array)\z/; # XXX allow 'any' if all of its 'of' values are str/buf/array
621             die "Error in schema for argument '$argname': must specify 'of' array clause if stream=1"
622 2 50 33     13 if $sch->[0] eq 'array' && !$sch->[1]{of};
623              
624 2         20 $self->_errif(
625             400,
626             qq["Argument '$prefix$argname' (stream) fails validation: must be coderef"],
627             "!(ref($argterm) eq 'CODE')",
628             );
629 2         5 $self->push_lines('{ ## introduce scope because we want to declare a generic variable $i');
630 2         6 $self->indent;
631 2         9 $self->push_lines(
632             'my $i = -1;',
633             "my \$origsub = $argterm;",
634             '# arg coderef wrapper for validation',
635             "$argterm = sub {",
636             );
637 2         8 $self->indent;
638 2         5 $self->push_lines(
639             '$i++;',
640             "my \$rec = \$origsub->();",
641             'return undef unless defined $rec;',
642             );
643             }
644              
645 74         133 my $dn = $argname; $dn =~ s/\W+/_/g;
  74         165  
646             my $cd = $self->_plc->compile(
647             data_name => $dn,
648             data_term => $argspec->{stream} ? '$rec' : $argterm,
649             schema => $argspec->{stream} && $sch->[0] eq 'array' ? $sch->[1]{of} : $sch,
650             schema_is_normalized => $opt_sin,
651             return_type => 'str',
652             indent_level => $self->get_indent_level + 1,
653             core => $self->{_args}{core},
654             core_or_pp => $self->{_args}{core_or_pp},
655             pp => $self->{_args}{pp},
656 74 100 66     188 %{ $self->{_args}{_extra_sah_compiler_args} // {}},
  74 100 50     576  
657             );
658 72 50       409735 die "Incompatible Data::Sah version (cd v=$cd->{v}, expected 2)" unless $cd->{v} == 2;
659 72         164 for my $mod_rec (@{ $cd->{modules} }) {
  72         196  
660 208 100       439 next unless $mod_rec->{phase} eq 'runtime';
661 136   66     538 $self->_add_module($mod_rec->{use_statement} // $mod_rec->{name});
662             }
663             $self->_add_var($_, $cd->{vars}{$_})
664 72         138 for sort keys %{ $cd->{vars} };
  72         255  
665 72         332 $cd->{result} =~ s/\A\s+//;
666 72         343 $self->push_lines(
667             "my \$err_$dn;",
668             "$cd->{result};",
669             );
670 72 100       195 if ($argspec->{stream}) {
671 2         13 $self->push_lines(
672             'if ('."\$err_$dn".') { die "Record #$i of streaming argument '."'$prefix$argname'".' ($rec) fails validation: '."\$err_$dn".'" }',
673             '$rec;',
674             );
675             } else {
676 70         309 $self->_errif(
677             400, qq["Argument '$prefix$argname' fails validation: \$err_$dn"],
678             "\$err_$dn");
679             }
680 72 100       204 if ($argspec->{meta}) {
681 2         10 $self->push_lines("# check subargs of $prefix$argname");
682             $self->_handle_args(
683             %args,
684             v => $argspec->{meta}{args},
685 2 50       28 prefix => ($prefix ? "$prefix/" : "") . "$argname/",
686             argsterm => '%{'.$argterm.'}',
687             );
688             }
689 72 100       212 if ($argspec->{element_meta}) {
690 2         8 $self->push_lines("# check element subargs of $prefix$argname");
691 2         4 my $indexterm = "$prefix$argname";
692 2         7 $indexterm =~ s/\W+/_/g;
693 2         4 $indexterm = '$i_' . $indexterm;
694 2         10 $self->push_lines('for my '.$indexterm.' (0..$#{ '.$argterm.' }) {');
695 2         6 $self->indent;
696 2         15 $self->_errif(
697             400, qq("Argument '$prefix$argname\[).qq($indexterm]' fails validation: must be hash"),
698             "ref($argterm\->[$indexterm]) ne 'HASH'");
699             $self->_handle_args(
700             %args,
701             v => $argspec->{element_meta}{args},
702 2 50       26 prefix => ($prefix ? "$prefix/" : "") . "$argname\[$indexterm]/",
703             argsterm => '%{'.$argterm.'->['.$indexterm.']}',
704             );
705 2         7 $self->unindent;
706 2         4 $self->push_lines('}');
707             }
708 72         192 $self->unindent;
709 72 100       172 if ($argspec->{stream}) {
710 2         6 $self->push_lines('}; ## arg coderef wrapper');
711 2         5 $self->unindent;
712 2         6 $self->push_lines('} ## close scope');
713 2         5 $self->unindent;
714             }
715 72 100       206 if ($has_default_prop) {
    100          
716             $self->push_lines(
717             '} else {',
718 8         35 " $argterm //= ".dmp($argspec->{default}).";");
719             } elsif ($has_sch_default) {
720             $self->push_lines(
721             '} else {',
722 8         39 " $argterm //= ".dmp($sch->[1]{default}).";");
723             }
724 72         225 $self->push_lines("} ## if exists arg $prefix$argname");
725             } # if opt_va
726              
727             } elsif ($has_default_prop) {
728             # doesn't have schema but have 'default' property, we still need to
729             # set default here
730 2         9 $self->push_lines("$argterm = ".dmp($argspec->{default}).
731             " if !exists($argterm);");
732             }
733 106 100 100     629 if ($argspec->{req} && $opt_va) {
734 18         74 $self->_errif(
735             400, qq["Missing required argument: $argname"],
736             "!exists($argterm)");
737             }
738             } # for arg
739             }
740              
741 74     74 0 268 sub handlemeta_args { {v=>2, prio=>10} }
742             sub handle_args {
743 74     74 0 305 my ($self, %args) = @_;
744 74         328 $self->_handle_args(%args);
745             }
746              
747             # after args
748 4     4 0 9 sub handlemeta_args_rels { {v=>2, prio=>11} }
749             sub handle_args_rels {
750 4     4 0 17 my ($self, %args) = @_;
751              
752 4   33     19 my $v = $args{v} // $self->{_meta}{args_rels};
753 4 50       11 return unless $v;
754              
755 4   50     45 my $argsterm = $args{argsterm} // '%args';
756              
757 4         22 $self->select_section('before_call_arg_validation');
758 4         10 $self->push_lines('', '# check args_rels');
759              
760 4         6 my $dn = "args_rels";
761 4         12 my $hc = $self->_sah->get_compiler("human");
762 4         17504 my $cd_h = $hc->init_cd;
763 4   33     1720 $cd_h->{args}{lang} //= $cd_h->{default_lang};
764              
765             my $cd = $self->_plc->compile(
766             data_name => $dn,
767             data_term => "\\$argsterm",
768             schema => ['hash', $v],
769             return_type => 'str',
770             indent_level => $self->get_indent_level + 1,
771             human_hash_values => {
772             field => $hc->_xlt($cd_h, "argument"),
773             fields => $hc->_xlt($cd_h, "arguments"),
774             },
775             core => $self->{_args}{core},
776             core_or_pp => $self->{_args}{core_or_pp},
777             pp => $self->{_args}{pp},
778 4         13 );
779 2 50       17735 die "Incompatible Data::Sah version (cd v=$cd->{v}, expected 2)" unless $cd->{v} == 2;
780 2         5 for my $mod_rec (@{ $cd->{modules} }) {
  2         7  
781 6 100       14 next unless $mod_rec->{phase} eq 'runtime';
782 4   66     18 $self->_add_module($mod_rec->{use_statement} // $mod_rec->{name});
783             }
784 2         16 $self->_add_var($_, $cd->{vars}{$_}) for sort keys %{ $cd->{vars} };
  2         7  
785 2         10 $cd->{result} =~ s/\A\s+//;
786 2         11 $self->push_lines(
787             "my \$err_$dn;",
788             "$cd->{result};",
789             );
790 2         10 $self->_errif(
791             400, qq["\$err_$dn"],
792             "\$err_$dn");
793             }
794              
795 14     14 0 51 sub handlemeta_result { {v=>2, prio=>50} }
796             sub handle_result {
797 14     14 0 604 require Data::Sah;
798              
799 14         3404 my ($self, %args) = @_;
800              
801 14         43 my $meta = $self->{_meta};
802 14         37 my $v = $meta->{result};
803 14 50       37 return unless $v;
804              
805 14         30 my $opt_sin = $self->{_args}{_schema_is_normalized};
806 14         24 my $opt_vr = $self->{_args}{validate_result};
807              
808 14         37 my %schemas_by_status; # key = status, value = schema
809              
810             # collect and check handlers
811             my %handler_args;
812 14         0 my %handler_metas;
813 14         36 for my $k0 (keys %$v) {
814 18         28 my $k = $k0;
815 18         41 $k =~ s/\..+//;
816 18 100       50 next if $k =~ /\A_/;
817              
818             # check builtin result spec key
819 16 50       92 next if $k =~ /\A(
820             summary|description|tags|default_lang|
821             schema|statuses|stream|
822             x
823             )\z/x;
824             # try a property module first
825 0         0 require "Perinci/Sub/Property/result/$k.pm";
826 0         0 my $meth = "handlemeta_result__$k";
827 0 0       0 unless ($self->can($meth)) {
828 0         0 die "No handler for property result/$k0 ($meth)";
829             }
830 0         0 my $hm = $self->$meth;
831 0   0     0 $hm->{v} //= 1;
832 0 0       0 next unless defined $hm->{prio};
833             die "Please update property handler result/$k which is still at v=$hm->{v} ".
834             "(needs v=$protocol_version)"
835 0 0       0 unless $hm->{v} == $protocol_version;
836             my $ha = {
837 0         0 prio=>$hm->{prio}, value=>$v->{$k0}, property=>$k0,
838             meth=>"handle_result__$k",
839             };
840 0         0 $handler_args{$k} = $ha;
841 0         0 $handler_metas{$k} = $hm;
842             }
843              
844             # call all the handlers in order
845 14         60 for my $k (sort {$handler_args{$a}{prio} <=> $handler_args{$b}{prio}}
  0         0  
846             keys %handler_args) {
847 0         0 my $ha = $handler_args{$k};
848 0         0 my $meth = $ha->{meth};
849 0         0 local $self->{_cur_handler} = $meth;
850 0         0 local $self->{_cur_handler_meta} = $handler_metas{$k};
851 0         0 local $self->{_cur_handler_args} = $ha;
852 0         0 $self->$meth(args=>\%args, meta=>$meta, %$ha);
853             }
854              
855             # validate result
856 14         22 my @modules;
857 14 100 100     54 if ($v->{schema} && $opt_vr) {
858 4         18 $schemas_by_status{200} = $v->{schema};
859             }
860 14 50 33     51 if ($v->{statuses} && $opt_vr) {
861 0         0 for my $s (keys %{$v->{statuses}}) {
  0         0  
862 0         0 my $sv = $v->{statuses}{$s};
863 0 0       0 if ($sv->{schema}) {
864 0         0 $schemas_by_status{$s} = $sv->{schema};
865             }
866             }
867             }
868              
869 14         33 my $sub_name = $self->{_args}{sub_name};
870              
871 14 100       39 if ($opt_vr) {
872 12         35 $self->select_section('after_call_res_validation');
873             $self->push_lines(
874             'my $_w_res2 = $_w_res->[2];',
875 12 100       77 'my $_w_res_is_stream = $_w_res->[3]{stream} // ' . ($v->{stream} ? 1:0) . ';',
876             );
877 12         36 $self->_errif(
878             500,
879             q["Stream result must be coderef"],
880             '$_w_res_is_stream && ref($_w_res2) ne "CODE"',
881             );
882 12         61 for my $s (sort keys %schemas_by_status) {
883 4         10 my $sch = $schemas_by_status{$s};
884 4 100       10 if ($v->{stream}) {
885 2 50       14 die "Error in result schema: must be str/buf/array if stream=1"
886             unless $sch->[0] =~ /\A(str|buf|array)\z/; # XXX allow 'any' if all of its 'of' values are str/buf/array
887             die "Error in result schema: must specify 'of' array clause if stream=1"
888 2 50 33     13 if $sch->[0] eq 'array' && !$sch->[1]{of};
889             }
890 4         16 $self->push_lines("if (\$_w_res->[0] == $s) {");
891 4         9 $self->indent;
892 4         10 $self->push_lines('if (!$_w_res_is_stream) {');
893 4         21 $self->indent;
894              
895             # validation for when not a stream
896             my $cd = $self->_plc->compile(
897             data_name => '_w_res2',
898             # err_res can clash on arg named 'res'
899             err_term => '$_w_err2_res',
900             schema => $sch,
901             schema_is_normalized => $opt_sin,
902             return_type => 'str',
903             indent_level => $self->get_indent_level + 1,
904             core => $self->{_args}{core},
905             core_or_pp => $self->{_args}{core_or_pp},
906             pp => $self->{_args}{pp},
907 4   50     13 %{ $self->{_args}{_extra_sah_compiler_args} // {}},
  4         34  
908             );
909 4 50       72519 die "Incompatible Data::Sah version (cd v=$cd->{v}, expected 2)" unless $cd->{v} == 2;
910 4         9 for my $mod_rec (@{ $cd->{modules} }) {
  4         15  
911 16 100       35 next unless $mod_rec->{phase} eq 'runtime';
912 10   66     45 $self->_add_module($mod_rec->{use_statement} // $mod_rec->{name});
913             }
914             $self->_add_var($_, $cd->{vars}{$_})
915 4         7 for sort keys %{ $cd->{vars} };
  4         21  
916 4         13 $self->push_lines("my \$_w_err2_res;");
917 4         23 $cd->{result} =~ s/\A\s+//;
918 4         38 $self->push_lines("$cd->{result};");
919 4         25 $self->_errif(
920             500,
921             qq["BUG: Result from sub $sub_name (\$_w_res2) fails validation: ].
922             qq[\$_w_err2_res"],
923             "\$_w_err2_res");
924 4         8 $self->unindent;
925 4         10 $self->push_lines("} else {"); # stream
926 4         9 $self->indent;
927 4         13 $self->push_lines(
928             'my $i = -1;',
929             '# wrap result coderef for validation',
930             '$_w_res->[2] = sub {',
931             );
932 4         24 $self->indent;
933 4         13 $self->push_lines(
934             '$i++;',
935             'my $rec = $_w_res2->();',
936             'return undef unless defined $rec;',
937             );
938             # generate schema code once again, this time for when stream
939             $cd = $self->_plc->compile(
940             data_name => 'rec',
941             # err_res can clash on arg named 'res'
942             err_term => '$rec_err',
943             schema => $sch->[0] eq 'array' ? $sch->[1]{of} : $sch,
944             schema_is_normalized => $opt_sin,
945             return_type => 'str',
946             indent_level => $self->get_indent_level + 1,
947             core => $self->{_args}{core},
948             core_or_pp => $self->{_args}{core_or_pp},
949             pp => $self->{_args}{pp},
950 4 100 50     13 %{ $self->{_args}{_extra_sah_compiler_args} // {}},
  4         29  
951             );
952 4 50       8332 die "Incompatible Data::Sah version (cd v=$cd->{v}, expected 2)" unless $cd->{v} == 2;
953             # XXX no need to require modules required by validator?
954 4         15 $self->push_lines('my $rec_err;');
955 4         23 $cd->{result} =~ s/\A\s+//;
956 4         17 $self->push_lines("$cd->{result};");
957 4         11 $self->push_lines('if ($rec_err) { die "BUG: Result stream record #$i ($rec) fails validation: $rec_err" }');
958 4         12 $self->push_lines('$rec;');
959 4         10 $self->unindent;
960 4         11 $self->push_lines('}; ## result coderef wrapper');
961 4         10 $self->unindent;
962 4         9 $self->push_lines("} ## if stream");
963 4         9 $self->unindent;
964 4         13 $self->push_lines("} ## if status=$s");
965             } # for schemas_by_status
966             }
967             }
968              
969 6     6 0 25 sub handlemeta_result_naked { {v=>2, prio=>99, convert=>1} }
970             sub handle_result_naked {
971 6     6 0 32 my ($self, %args) = @_;
972              
973 6         14 my $old = $args{value};
974 6   33     18 my $v = $args{new} // $old;
975              
976 6 50       20 return if !!$v == !!$old;
977              
978 6         15 $self->select_section('AFTER_CALL_ADD_OR_STRIP_RESULT_ENVELOPE');
979 6 100       15 if ($v) {
980 2         8 $self->push_lines(
981             '', '# strip result envelope',
982             '$_w_res = $_w_res->[2];',
983             );
984             } else {
985 4         15 $self->push_lines(
986             '', '# add result envelope',
987             '$_w_res = [200, "OK", $_w_res];',
988             );
989             }
990             }
991              
992 4     4 0 14 sub handlemeta_deps { {v=>2, prio=>0.5} }
993             sub handle_deps {
994 4     4 0 16 my ($self, %args) = @_;
995 4         9 my $value = $args{value};
996 4         9 my $meta = $self->{_meta};
997 4         6 my $v = $self->{_args}{meta_name};
998 4         11 $self->select_section('before_call_after_arg_validation');
999 4         10 $self->push_lines('', '# check dependencies');
1000 4         14 $self->_add_module("Perinci::Sub::DepChecker");
1001             #$self->push_lines('use Data::Dump; dd '.$v.';');
1002 4         16 $self->push_lines('my $_w_deps_res = Perinci::Sub::DepChecker::check_deps('.
1003             $v.'->{deps});');
1004 4         16 $self->_errif(412, '"Deps failed: $_w_deps_res"', '$_w_deps_res');
1005              
1006             # we handle some deps our own
1007 4 50       9 if ($value->{tmp_dir}) {
1008 0         0 $self->_errif(412, '"Dep failed: please specify -tmp_dir"',
1009             '!$args{-tmp_dir}');
1010             }
1011 4 50       9 if ($value->{trash_dir}) {
1012 0         0 $self->_errif(412, '"Dep failed: please specify -trash_dir"',
1013             '!$args{-trash_dir}');
1014             }
1015 4 50       18 if ($value->{undo_trash_dir}) {
1016 0         0 $self->_errif(412, '"Dep failed: please specify -undo_trash_dir"',
1017             '!($args{-undo_trash_dir} || $args{-tx_manager} || '.
1018             '$args{-undo_action} && $args{-undo_action}=~/\A(?:undo|redo)\z/)');
1019             }
1020             }
1021              
1022 110     110 0 208 sub handlemeta_x { {} }
1023 0     0 0 0 sub handlemeta_entity_v { {} }
1024 0     0 0 0 sub handlemeta_entity_date { {} }
1025              
1026             sub _reset_work_data {
1027 108     108   435 my ($self, %args) = @_;
1028              
1029             # to make it stand out more, all work/state data is prefixed with
1030             # underscore.
1031              
1032 108         527 $self->{_cur_section} = undef;
1033 108         258 $self->{_cur_handler} = undef;
1034 108         236 $self->{_cur_handler_args} = undef;
1035 108         211 $self->{_cur_handler_meta} = undef;
1036 108         224 $self->{_levels} = {};
1037 108         224 $self->{_codes} = {};
1038 108         249 $self->{_modules} = []; # modules loaded by wrapper sub
1039 108         564 $self->{$_} = $args{$_} for keys %args;
1040             }
1041              
1042             sub wrap {
1043 112     112 0 729 require Scalar::Util;
1044              
1045 112         380 my ($self, %args) = @_;
1046              
1047 112         226 my $wrap_log_prop = "x.perinci.sub.wrapper.logs";
1048              
1049             # required arguments
1050 112         227 my $sub = $args{sub};
1051 112         211 my $sub_name = $args{sub_name};
1052 112 50 66     379 $sub || $sub_name or return [400, "Please specify sub or sub_name"];
1053 112 50       274 $args{meta} or return [400, "Please specify meta"];
1054 112         197 my $meta_name = $args{meta_name};
1055             # we clone the meta because we'll replace stuffs
1056 112         305 my $meta = clone($args{meta});
1057 112   100     1950 my $wrap_logs = $meta->{$wrap_log_prop} // [];
1058              
1059             # currently internal args, not exposed/documented
1060 112   50     575 $args{_compiled_package} //= 'Perinci::Sub::Wrapped';
1061 112         230 my $comppkg = $args{_compiled_package};
1062             $args{_schema_is_normalized} //=
1063 112 100 66     711 $wrap_logs->[-1] && $wrap_logs->[-1]{normalize_schema} ? 1 : 0;
      100        
1064 112   50     464 $args{_embed} //= 0;
1065 112   50     485 $args{_extra_sah_compiler_args} //= undef;
1066              
1067             # defaults for arguments
1068 112   50     601 $args{indent} //= " " x 4;
1069 112   100     436 $args{convert} //= {};
1070 112   50     484 $args{compile} //= 1;
1071 112   100     491 $args{log} //= 1;
1072             $args{validate_args} //= 0
1073             # function states that it can validate args, so by default we don't have
1074             # to do validation for it.
1075 112 50 0     304 if $meta->{features} && $meta->{features}{validate_args};
      66        
1076             $args{validate_args} //= 0
1077             # function might want to disable validate_args by default, e.g. if
1078             # source code has been processed with
1079             # Dist::Zilla::Plugin::Rinci::Validate
1080 112 100 50     298 if $meta->{'x.perinci.sub.wrapper.disable_validate_args'};
1081             $args{validate_args} //= 0
1082             # by default do not validate args again if previous wrapper(s) have
1083             # already done it
1084 112 100 50     346 if (grep {$_->{validate_args}} @$wrap_logs);
  2         11  
1085 112   100     483 $args{validate_args} //= 1;
1086             $args{validate_result} //= 0
1087             # function might want to disable validate_result by default, e.g. if
1088             # source code has been processed with
1089             # Dist::Zilla::Plugin::Rinci::Validate
1090 112 100 50     281 if $meta->{'x.perinci.sub.wrapper.disable_validate_result'};
1091             $args{validate_result} //= 0
1092             # by default do not validate result again if previous wrapper(s) have
1093             # already done it
1094 112 100 50     289 if (grep {$_->{validate_result}} @$wrap_logs);
  2         9  
1095 112   100     486 $args{validate_result} //= 1;
1096 112   33     517 $args{core} //= $ENV{PERINCI_WRAPPER_CORE};
1097 112   33     512 $args{core_or_pp} //= $ENV{PERINCI_WRAPPER_CORE_OR_PP};
1098 112   33     578 $args{pp} //= $ENV{PERINCI_WRAPPER_PP};
1099              
1100 112         185 my $sub_ref_name;
1101             # if sub_name is not provided, create a unique name for it. it is needed by
1102             # the wrapper-generated code (e.g. printing error messages)
1103 112 100 66     341 if (!$sub_name || $sub) {
1104 110         526 my $n = $comppkg . "::sub".Scalar::Util::refaddr($sub);
1105 15     14   581 no strict 'refs'; no warnings; ${$n} = $sub;
  14     14   158  
  14         495  
  14         471  
  14         37  
  14         698  
  110         191  
  110         497  
1106 14     14   111 use experimental 'smartmatch';
  14         116  
  14         154  
1107 110 50       307 if (!$sub_name) {
1108 110         347 $args{sub_name} = $sub_name = '$' . $n;
1109             }
1110 110         263 $sub_ref_name = '$' . $n;
1111             }
1112             # if meta name is not provided, we store the meta somewhere, it is needed by
1113             # the wrapper-generated code (e.g. deps clause).
1114 112 50       244 if (!$meta_name) {
1115 112         328 my $n = $comppkg . "::meta".Scalar::Util::refaddr($meta);
1116 14     14   1530 no strict 'refs'; no warnings; ${$n} = $meta;
  14     14   39  
  14         386  
  14         72  
  14         99  
  14         546  
  112         167  
  112         497  
1117 14     14   378 use experimental 'smartmatch';
  14         36  
  14         55  
1118 112         339 $args{meta_name} = $meta_name = '$' . $n;
1119             }
1120              
1121             # shallow copy
1122 112         198 my $opt_cvt = { %{ $args{convert} } };
  112         315  
1123 112         234 my $opt_sin = $args{_schema_is_normalized};
1124              
1125 112 100       598 $meta = normalize_function_metadata($meta)
1126             unless $opt_sin;
1127              
1128 108         56127 $self->_reset_work_data(_args=>\%args, _meta=>$meta);
1129              
1130             # add properties from convert, if not yet mentioned in meta
1131 108         361 for (keys %$opt_cvt) {
1132 10 100       40 $meta->{$_} = undef unless exists $meta->{$_};
1133             }
1134              
1135             # mark in the metadata that we have done the wrapping, so future wrapping
1136             # can avoid needless duplicated functionality (like validating args twice).
1137             # note that handler can log their mark too.
1138             {
1139 108   100     176 my @wrap_log = @{ $meta->{$wrap_log_prop} // [] };
  108         169  
  108         574  
1140             push @wrap_log, {
1141             validate_args => $args{validate_args},
1142             validate_result => $args{validate_result},
1143 108         587 normalize_schema => !$opt_sin,
1144             };
1145 108 100       360 if ($args{log}) {
1146 106         318 $meta->{$wrap_log_prop} = \@wrap_log;
1147             }
1148             }
1149              
1150             # start iterating over properties
1151              
1152 108         413 $self->select_section('OPEN_SUB');
1153 108         524 $self->push_lines(
1154             "package $comppkg;", 'sub {');
1155 108         339 $self->indent;
1156              
1157 108   100     534 $meta->{args_as} //= "hash";
1158              
1159 108 100       454 if ($meta->{args_as} =~ /hash/) {
1160 102         226 $self->select_section('before_call_after_arg_validation');
1161             # tell function it's being wrapped, currently disabled
1162             #$self->push_lines('$args{-wrapped} = 1;');
1163             }
1164              
1165 108         361 my %props = map {$_=>1} keys %$meta;
  434         815  
1166 108         335 $props{$_} = 1 for keys %$opt_cvt;
1167              
1168             # collect and check handlers
1169 108         214 my %handler_args;
1170             my %handler_metas;
1171 108         298 for my $k0 (keys %props) {
1172 434         551 my $k = $k0;
1173 434         880 $k =~ s/\..+//;
1174 434 100       812 next if $k =~ /\A_/;
1175 432 50       757 next if $handler_args{$k};
1176             #if ($k ~~ $self->{_args}{skip}) {
1177             # $log->tracef("Skipped property %s (mentioned in skip)", $k);
1178             # next;
1179             #}
1180 432 50       1297 return [500, "Invalid property name $k"] unless $k =~ /\A\w+\z/;
1181 432         814 my $meth = "handlemeta_$k";
1182 432 50       1526 unless ($self->can($meth)) {
1183             # try a property module first
1184 0         0 require "Perinci/Sub/Property/$k.pm";
1185 0 0       0 unless ($self->can($meth)) {
1186 0         0 return [500, "No handler for property $k0 ($meth)"];
1187             }
1188             }
1189 432         1234 my $hm = $self->$meth;
1190 432   100     1256 $hm->{v} //= 1;
1191 432 100       1028 next unless defined $hm->{prio};
1192             die "Please update property handler $k which is still at v=$hm->{v} ".
1193             "(needs v=$protocol_version)"
1194 214 50       431 unless $hm->{v} == $protocol_version;
1195             my $ha = {
1196 214         928 prio=>$hm->{prio}, value=>$meta->{$k0}, property=>$k0,
1197             meth=>"handle_$k",
1198             };
1199 214 100       463 if (exists $opt_cvt->{$k0}) {
1200             return [501, "Property '$k0' does not support conversion"]
1201 10 50       34 unless $hm->{convert};
1202 10         25 $ha->{new} = $opt_cvt->{$k0};
1203 10         19 $meta->{$k0} = $opt_cvt->{$k0};
1204             }
1205 214         360 $handler_args{$k} = $ha;
1206 214         425 $handler_metas{$k} = $hm;
1207             }
1208              
1209             # call all the handlers in order
1210 108         585 for my $k (sort {$handler_args{$a}{prio} <=> $handler_args{$b}{prio}}
  113         444  
1211             keys %handler_args) {
1212 214         387 my $ha = $handler_args{$k};
1213 214         377 my $meth = $ha->{meth};
1214 214         472 local $self->{_cur_handler} = $meth;
1215 214         399 local $self->{_cur_handler_meta} = $handler_metas{$k};
1216 214         370 local $self->{_cur_handler_args} = $ha;
1217 214         1038 $self->$meth(args=>\%args, meta=>$meta, %$ha);
1218             }
1219              
1220 104         356 my $needs_store_res = $self->_needs_store_res;
1221 104 100       248 if ($needs_store_res) {
1222 98         334 $self->_add_var('_w_res');
1223             }
1224              
1225 104         281 $self->select_section('CALL');
1226 104   66     272 my $sn = $sub_ref_name // $sub_name;
1227             $self->push_lines(
1228             ($needs_store_res ? '$_w_res = ' : "") .
1229             $sn. ($sn =~ /^\$/ ? "->" : "").
1230 104 100       842 "(".$self->{_args_token}.");");
    100          
1231 104 100       303 if ($args{validate_result}) {
1232 98         259 $self->select_section('after_call_before_res_validation');
1233 98 100       264 unless ($meta->{result_naked}) {
1234 96         300 $self->push_lines(
1235             '',
1236             '# check that sub produces enveloped result',
1237             'unless (ref($_w_res) eq "ARRAY" && $_w_res->[0]) {',
1238             );
1239 96         242 $self->indent;
1240 96 50       396 if (log_is_trace) {
1241 0         0 $self->_add_module('Data::Dumper');
1242 0         0 $self->push_lines(
1243             'local $Data::Dumper::Purity = 1;',
1244             'local $Data::Dumper::Terse = 1;',
1245             'local $Data::Dumper::Indent = 0;',
1246             );
1247 0         0 $self->_err(500,
1248             qq['BUG: Sub $sub_name does not produce envelope: '.].
1249             qq[Data::Dumper::Dumper(\$_w_res)]);
1250             } else {
1251 96         615 $self->_err(500,
1252             qq['BUG: Sub $sub_name does not produce envelope']);
1253             }
1254 96         280 $self->unindent;
1255 96         184 $self->push_lines('}');
1256             }
1257             }
1258              
1259 104         296 my $use_eval = $self->_needs_eval;
1260 104 50       278 if ($use_eval) {
1261 0         0 $self->select_section('CLOSE_EVAL');
1262 0         0 $self->push_lines('return $_w_res;');
1263 0         0 $self->unindent;
1264 0         0 $self->_add_var('_w_eval_err');
1265 0         0 $self->push_lines(
1266             '};',
1267             '$_w_eval_err = $@;');
1268              
1269             # _needs_eval will automatically be enabled here, due after_eval being
1270             # filled
1271 0         0 $self->select_section('after_eval');
1272 0         0 $self->push_lines('warn $_w_eval_err if $_w_eval_err;');
1273 0         0 $self->_errif(500, '"Function died: $_w_eval_err"', '$_w_eval_err');
1274              
1275 0         0 $self->select_section('OPEN_EVAL');
1276 0         0 $self->push_lines('eval {');
1277 0         0 $self->indent;
1278             }
1279              
1280             # return sub result
1281 104         280 $self->select_section('BEFORE_CLOSE_SUB');
1282 104 100       337 $self->push_lines('return $_w_res;') if $needs_store_res;
1283 104         279 $self->select_section('CLOSE_SUB');
1284 104         247 $self->unindent;
1285 104         247 $self->push_lines('}'); # wrapper sub
1286              
1287             # return wrap result
1288 104         562 my $result = {
1289             sub_name => $sub_name,
1290             sub_ref_name => $sub_ref_name,
1291             meta => $meta,
1292             meta_name => $meta_name,
1293             use_eval => $use_eval,
1294             };
1295 104 100       279 if ($args{embed}) {
1296 52         179 $result->{source} = $self->_format_embed_wrapper_code;
1297             } else {
1298 52         182 my $source = $self->_format_dyn_wrapper_code;
1299 52 50 33     330 if ($Log_Wrapper_Code && log_is_trace()) {
1300 0         0 require String::LineNumber;
1301             log_trace("wrapper code:\n%s",
1302 0 0 0     0 $ENV{LINENUM} // 1 ?
1303             String::LineNumber::linenum($source) :
1304             $source);
1305             }
1306 52         124 $result->{source} = $source;
1307 52 50       143 if ($args{compile}) {
1308 52     8   6409 my $wrapped = eval $source;
  8     8   63  
  8         16  
  8         62  
  8         553  
  8         17  
  8         2412  
1309 52 50 33     376 die "BUG: Wrapper code can't be compiled: $@" if $@ || !$wrapped;
1310 52         191 $result->{sub} = $wrapped;
1311             }
1312             }
1313              
1314 104         1083 [200, "OK", $result];
1315             }
1316              
1317             $SPEC{wrap_sub} = {
1318             v => 1.1,
1319             summary => 'Wrap subroutine to do various things, '.
1320             'like enforcing Rinci properties',
1321             result => {
1322             summary => 'The wrapped subroutine along with its new metadata',
1323             description => <<'_',
1324              
1325             Aside from wrapping the subroutine, the wrapper will also create a new metadata
1326             for the subroutine. The new metadata is a clone of the original, with some
1327             properties changed, e.g. schema in `args` and `result` normalized, some values
1328             changed according to the `convert` argument, some defaults set, etc.
1329              
1330             The new metadata will also contain (or append) the wrapping log located in the
1331             `x.perinci.sub.wrapper.logs` attribute. The wrapping log marks that the wrapper
1332             has added some functionality (like validating arguments or result) so that
1333             future nested wrapper can choose to avoid duplicating the same functionality.
1334              
1335             _
1336             schema=>['hash*'=>{keys=>{
1337             sub=>'code*',
1338             source=>['any*' => of => ['str*', ['hash*' => each_value=>'str*']]],
1339             meta=>'hash*',
1340             }}],
1341             },
1342             args => {
1343             sub => {
1344             schema => 'str*',
1345             summary => 'The code to be wrapped',
1346             description => <<'_',
1347              
1348             At least one of `sub` or `sub_name` must be specified.
1349              
1350             _
1351             },
1352             sub_name => {
1353             schema => 'str*',
1354             summary => 'The name of the subroutine, '.
1355             'e.g. func or Foo::func (qualified)',
1356             description => <<'_',
1357              
1358             At least one of `sub` or `sub_name` must be specified.
1359              
1360             _
1361             },
1362             meta => {
1363             schema => 'hash*',
1364             summary => 'The function metadata',
1365             req => 1,
1366             },
1367             meta_name => {
1368             schema => 'str*',
1369             summary => 'Where to find the metadata, e.g. "$SPEC{foo}"',
1370             description => <<'_',
1371              
1372             Some wrapper code (e.g. handler for `dep` property) needs to refer to the
1373             function metadata. If not provided, the wrapper will store the function metadata
1374             in a unique variable (e.g. `$Perinci::Sub::Wrapped::meta34127816`).
1375              
1376             _
1377             },
1378             convert => {
1379             schema => 'hash*',
1380             summary => 'Properties to convert to new value',
1381             description => <<'_',
1382              
1383             Not all properties can be converted, but these are a partial list of those that
1384             can: v (usually do not need to be specified when converting from 1.0 to 1.1,
1385             will be done automatically), args_as, result_naked, default_lang.
1386              
1387             _
1388             },
1389             compile => {
1390             schema => ['bool' => {default=>1}],
1391             summary => 'Whether to compile the generated wrapper',
1392             description => <<'_',
1393              
1394             Can be set to 0 to not actually wrap but just return the generated wrapper
1395             source code.
1396              
1397             _
1398             },
1399             compile => {
1400             schema => ['bool' => {default=>1}],
1401             summary => 'Whether to compile the generated wrapper',
1402             description => <<'_',
1403              
1404             Can be set to 0 to not actually wrap but just return the generated wrapper
1405             source code.
1406              
1407             _
1408             },
1409             debug => {
1410             schema => [bool => {default=>0}],
1411             summary => 'Generate code with debugging',
1412             description => <<'_',
1413              
1414             If turned on, will produce various debugging in the generated code. Currently
1415             what this does:
1416              
1417             * add more comments (e.g. for each property handler)
1418              
1419             _
1420             },
1421             validate_args => {
1422             schema => ['bool'],
1423             summary => 'Whether wrapper should validate arguments',
1424             description => <<'_',
1425              
1426             If set to true, will validate arguments. Validation error will cause status 400
1427             to be returned. The default is to enable this unless previous wrapper(s) have
1428             already done this.
1429              
1430             _
1431             },
1432             validate_result => {
1433             schema => ['bool'],
1434             summary => 'Whether wrapper should validate arguments',
1435             description => <<'_',
1436              
1437             If set to true, will validate sub's result. Validation error will cause wrapper
1438             to return status 500 instead of sub's result. The default is to enable this
1439             unless previous wrapper(s) have already done this.
1440              
1441             _
1442             },
1443             core => {
1444             summary => 'If set to true, will avoid the use of non-core modules',
1445             schema => 'bool',
1446             },
1447             core_or_pp => {
1448             summary => 'If set to true, will avoid the use of non-core XS modules',
1449             schema => 'bool',
1450             description => <<'_',
1451              
1452             In other words, will stick to core or pure-perl modules only.
1453              
1454             _
1455             },
1456             pp => {
1457             summary => 'If set to true, will avoid the use of XS modules',
1458             schema => 'bool',
1459             },
1460             },
1461             };
1462             sub wrap_sub {
1463 112     112 1 567 __PACKAGE__->new->wrap(@_);
1464             }
1465              
1466             1;
1467             # ABSTRACT: A multi-purpose subroutine wrapping framework
1468              
1469             __END__
1470              
1471             =pod
1472              
1473             =encoding UTF-8
1474              
1475             =head1 NAME
1476              
1477             Perinci::Sub::Wrapper - A multi-purpose subroutine wrapping framework
1478              
1479             =head1 VERSION
1480              
1481             This document describes version 0.851 of Perinci::Sub::Wrapper (from Perl distribution Perinci-Sub-Wrapper), released on 2019-07-04.
1482              
1483             =head1 SYNOPSIS
1484              
1485             For dynamic usage:
1486              
1487             use Perinci::Sub::Wrapper qw(wrap_sub);
1488             my $res = wrap_sub(sub_name => "mysub", meta=>{...});
1489             my ($wrapped_sub, $meta) = ($res->[2]{sub}, $res->[2]{meta});
1490             $wrapped_sub->(); # call the wrapped function
1491              
1492             =head1 DESCRIPTION
1493              
1494             Perinci::Sub::Wrapper (PSW for short) is an extensible subroutine wrapping
1495             framework. It generates code to do stuffs before calling your subroutine, like
1496             validate arguments, convert arguments from positional/array to named/hash or
1497             vice versa, etc; as well as generate code to do stuffs after calling your
1498             subroutine, like retry calling for a number of times if subroutine returns a
1499             non-success status, check subroutine result against a schema, etc). Some other
1500             things it can do: apply a timeout, currying, and so on.
1501              
1502             PSW differs from other function composition or decoration system like Python
1503             decorators (or its Perl equivalent L<Python::Decorator>) in a couple of ways:
1504              
1505             =over
1506              
1507             =item * Single wrapper
1508              
1509             Instead of multiple/nested wrapping for implementing different features, PSW
1510             is designed to generate a single large wrapper around your code, i.e.:
1511              
1512             sub _wrapper_for_your_sub {
1513             ...
1514             # do various stuffs before calling:
1515              
1516             # e.g. start timer
1517             # e.g. convert, prefill, validate arguments
1518             my @args = ...;
1519             ...
1520             your_sub(@args);
1521             ...
1522             # do various stuffs after calling
1523             ...
1524             # e.g. report times
1525             # e.g. perform retry
1526             # e.g. convert or envelope results
1527              
1528             # return result
1529             }
1530              
1531             Multiple functionalities will be added and combined in this single wrapper
1532             subroutine in the appropriate location. This is done to reduce function call
1533             overhead or depth of nested call levels. And also to make it easier to embed the
1534             wrapping code to your source code (see L<Dist::Zilla::Plugin::Rinci::Wrap>).
1535              
1536             Of course, you can still wrap multiple times if wanted.
1537              
1538             =item * Rinci
1539              
1540             The wrapper code is built according to the L<Rinci> metadata you provide. Rinci
1541             allows you to specify various things for your function, e.g. list of arguments
1542             including the expected data type of each argument and whether an argument is
1543             required or optional. PSW can then be used to generate the necessary code to
1544             enforce this specification, e.g. generate validator for the function arguments.
1545              
1546             Since Rinci specification is extensible, you can describe additional stuffs for
1547             your function and write a PSW plugin to generate the necessary code to implement
1548             your specification. An example is C<timeout> to specify execution time limit,
1549             implemented by L<Perinci::Sub::Property::timeout> which generates code to call
1550             function inside an C<eval()> block and use C<alarm()> to limit the execution.
1551             Another example is C<retry> property, implemented by
1552             L<Perinci::Sub::Property::retry> which generates code to call function inside a
1553             simple retry loop.
1554              
1555             =back
1556              
1557             Normally you do not use PSW directly in your applications. You might want to
1558             check out L<Perinci::Access::Perl> and L<Perinci::Exporter> on examples of
1559             wrapping function dynamically (during runtime), or
1560             L<Dist::Zilla::Plugin::Rinci::Wrap> on an example of embedding the generated
1561             wrapping code to source code during build.
1562              
1563             =head1 EXTENDING
1564              
1565             The framework is simple and extensible. Please delve directly into the source
1566             code for now. Some notes:
1567              
1568             The internal uses OO.
1569              
1570             The main wrapper building mechanism is in the C<wrap()> method.
1571              
1572             For each Rinci property, it will call C<handle_NAME()> wrapper handler method.
1573             The C<handlemeta_NAME()> methods are called first, to determine order of
1574             processing. You can supply these methods either by subclassing the class or,
1575             more simply, monkeypatching the method in the C<Perinci::Sub::Wrapper> package.
1576              
1577             The wrapper handler method will be called with a hash argument, containing these
1578             keys: B<value> (property value), B<new> (this key will exist if C<convert>
1579             argument of C<wrap()> exists, to convert a property to a new value).
1580              
1581             For properties that have name in the form of C<NAME1.NAME2.NAME3> (i.e., dotted)
1582             only the first part of the name will be used (i.e., C<handle_NAME1()>).
1583              
1584             =head1 VARIABLES
1585              
1586             =head2 $Log_Wrapper_Code (BOOL)
1587              
1588             Whether to log wrapper result. Default is from environment variable
1589             LOG_PERINCI_WRAPPER_CODE, or false. Logging is done with L<Log::ger> at trace
1590             level.
1591              
1592             =head1 RINCI FUNCTION METADATA
1593              
1594             =head2 x.perinci.sub.wrapper.disable_validate_args => bool
1595              
1596             Can be set to 1 to set C<validate_args> to 0 by default. This is used e.g. if
1597             you already embed/insert code to validate arguments by other means and do not
1598             want to repeat validating arguments. E.g. used if you use
1599             L<Dist::Zilla::Plugin::Rinci::Validate>.
1600              
1601             =head2 x.perinci.sub.wrapper.disable_validate_result => bool
1602              
1603             Can be set to 1 to set C<validate_result> to 0 by default. This is used e.g. if
1604             you already embed/insert code to validate result by other means and do not want
1605             to repeat validating result. E.g. used if you use
1606             L<Dist::Zilla::Plugin::Rinci::Validate>.
1607              
1608             =head2 x.perinci.sub.wrapper.logs => array
1609              
1610             Generated/added by this module to the function metadata for every wrapping done.
1611             Used to avoid adding repeated code, e.g. to validate result or arguments.
1612              
1613             =head1 PERFORMANCE NOTES
1614              
1615             The following numbers are produced on an Intel Core i5-2400 3.1GHz desktop using
1616             PSW v0.51 and Perl v5.18.2. Operating system is Debian sid (64bit).
1617              
1618             For perspective, empty subroutine (C<< sub {} >>) as well as C<< sub { [200,
1619             "OK"] } >> can be called around 5.3 mil/sec.
1620              
1621             Wrapping this subroutine C<< sub { [200, "OK"] } >> and this simple metadata C<<
1622             {v=>1.1} >> using default options yields call performance for C<< $sub->() >> of
1623             about 0.9 mil/sec. With C<< validate_args=>0 >> and C<< validate_result=>0 >>,
1624             it's 1.5 mil/sec.
1625              
1626             As more (and more complex) arguments are introduced and validated, overhead will
1627             increase. The significant portion of the overhead is in argument validation. For
1628             example, this metadata C<< {v=>1.1, args=>{a=>{schema=>"int"}}} >> yields 0.5
1629             mil/sec.
1630              
1631             =head1 FUNCTIONS
1632              
1633              
1634             =head2 wrap_sub
1635              
1636             Usage:
1637              
1638             wrap_sub(%args) -> [status, msg, payload, meta]
1639              
1640             Wrap subroutine to do various things, like enforcing Rinci properties.
1641              
1642             This function is not exported by default, but exportable.
1643              
1644             Arguments ('*' denotes required arguments):
1645              
1646             =over 4
1647              
1648             =item * B<compile> => I<bool> (default: 1)
1649              
1650             Whether to compile the generated wrapper.
1651              
1652             Can be set to 0 to not actually wrap but just return the generated wrapper
1653             source code.
1654              
1655             =item * B<convert> => I<hash>
1656              
1657             Properties to convert to new value.
1658              
1659             Not all properties can be converted, but these are a partial list of those that
1660             can: v (usually do not need to be specified when converting from 1.0 to 1.1,
1661             will be done automatically), args_as, result_naked, default_lang.
1662              
1663             =item * B<core> => I<bool>
1664              
1665             If set to true, will avoid the use of non-core modules.
1666              
1667             =item * B<core_or_pp> => I<bool>
1668              
1669             If set to true, will avoid the use of non-core XS modules.
1670              
1671             In other words, will stick to core or pure-perl modules only.
1672              
1673             =item * B<debug> => I<bool> (default: 0)
1674              
1675             Generate code with debugging.
1676              
1677             If turned on, will produce various debugging in the generated code. Currently
1678             what this does:
1679              
1680             =over
1681              
1682             =item * add more comments (e.g. for each property handler)
1683              
1684             =back
1685              
1686             =item * B<meta>* => I<hash>
1687              
1688             The function metadata.
1689              
1690             =item * B<meta_name> => I<str>
1691              
1692             Where to find the metadata, e.g. "$SPEC{foo}".
1693              
1694             Some wrapper code (e.g. handler for C<dep> property) needs to refer to the
1695             function metadata. If not provided, the wrapper will store the function metadata
1696             in a unique variable (e.g. C<$Perinci::Sub::Wrapped::meta34127816>).
1697              
1698             =item * B<pp> => I<bool>
1699              
1700             If set to true, will avoid the use of XS modules.
1701              
1702             =item * B<sub> => I<str>
1703              
1704             The code to be wrapped.
1705              
1706             At least one of C<sub> or C<sub_name> must be specified.
1707              
1708             =item * B<sub_name> => I<str>
1709              
1710             The name of the subroutine, e.g. func or Foo::func (qualified).
1711              
1712             At least one of C<sub> or C<sub_name> must be specified.
1713              
1714             =item * B<validate_args> => I<bool>
1715              
1716             Whether wrapper should validate arguments.
1717              
1718             If set to true, will validate arguments. Validation error will cause status 400
1719             to be returned. The default is to enable this unless previous wrapper(s) have
1720             already done this.
1721              
1722             =item * B<validate_result> => I<bool>
1723              
1724             Whether wrapper should validate arguments.
1725              
1726             If set to true, will validate sub's result. Validation error will cause wrapper
1727             to return status 500 instead of sub's result. The default is to enable this
1728             unless previous wrapper(s) have already done this.
1729              
1730             =back
1731              
1732             Returns an enveloped result (an array).
1733              
1734             First element (status) is an integer containing HTTP status code
1735             (200 means OK, 4xx caller error, 5xx function error). Second element
1736             (msg) is a string containing error message, or 'OK' if status is
1737             200. Third element (payload) is optional, the actual result. Fourth
1738             element (meta) is called result metadata and is optional, a hash
1739             that contains extra information.
1740              
1741             Return value: The wrapped subroutine along with its new metadata (hash)
1742              
1743              
1744             Aside from wrapping the subroutine, the wrapper will also create a new metadata
1745             for the subroutine. The new metadata is a clone of the original, with some
1746             properties changed, e.g. schema in C<args> and C<result> normalized, some values
1747             changed according to the C<convert> argument, some defaults set, etc.
1748              
1749             The new metadata will also contain (or append) the wrapping log located in the
1750             C<x.perinci.sub.wrapper.logs> attribute. The wrapping log marks that the wrapper
1751             has added some functionality (like validating arguments or result) so that
1752             future nested wrapper can choose to avoid duplicating the same functionality.
1753              
1754             =for Pod::Coverage ^(new|handle(meta)?_.+|wrap|add_.+|section_empty|indent|unindent|get_indent_level|select_section|push_lines)$
1755              
1756             =head1 METHODS
1757              
1758             The OO interface is only used internally or when you want to extend the wrapper.
1759              
1760             =head1 FAQ
1761              
1762             =head2 General
1763              
1764             =over
1765              
1766             =item * What is a function wrapper?
1767              
1768             A wrapper function calls the target function but with additional behaviors. The
1769             goal is similar to function composition or decorator system like in Python (or
1770             its Perl equivalent L<Python::Decorator>) where you use a higher-order function
1771             which accepts another function and modifies it.
1772              
1773             It is used to add various functionalities, e.g.: cache/memoization, singleton,
1774             adding benchmarking/timing around function call, logging, argument validation
1775             (parameter checking), checking pre/post-condition, authentication/authorization
1776             checking, etc. The Python folks use decorators quite a bit; see discussions on
1777             the Internet on those.
1778              
1779             =item * How is PSW different from Python::Decorator?
1780              
1781             PSW uses dynamic code generation (it generates Perl code on the fly). It also
1782             creates a single large wrapper instead of nested wrappers. It builds wrapper
1783             code according to L<Rinci> specification.
1784              
1785             =item * Why use code generation?
1786              
1787             Mainly because L<Data::Sah>, which is the module used to do argument validation,
1788             also uses code generation. Data::Sah allows us to do data validation at full
1789             Perl speed, which can be one or two orders of magnitude faster than
1790             "interpreter" modules like L<Data::FormValidator>.
1791              
1792             =item * Why use a single large wrapper?
1793              
1794             This is just a design approach. It can impose some restriction for wrapper code
1795             authors, since everything needs to be put in a single subroutine, but has nice
1796             properties like less stack trace depth and less function call overhead.
1797              
1798             =back
1799              
1800             =head2 Debugging
1801              
1802             =over
1803              
1804             =item * How to display the wrapper code being generated?
1805              
1806             If environment variable L<LOG_PERINCI_WRAPPER_CODE> or package variable
1807             $Log_Perinci_Wrapper_Code is set to true, generated wrapper source code is
1808             logged at trace level using L<Log::ger>. It can be displayed, for example:
1809              
1810             % LOG_PERINCI_WRAPPER_CODE=1 TRACE=1 \
1811             perl -MLog::ger::LevelFromEnv -MLog::ger::Output=Screen \
1812             -MPerinci::Sub::Wrapper=wrap_sub \
1813             -e 'wrap_sub(sub=>sub{}, meta=>{v=>1.1, args=>{a=>{schema=>"int"}}});'
1814              
1815             Note that L<Data::Sah> (the module used to generate validator code) observes
1816             C<LOG_SAH_VALIDATOR_CODE>, but during wrapping this environment flag is
1817             currently disabled by this module, so you need to set
1818             L<LOG_PERINCI_WRAPPER_CODE> instead.
1819              
1820             =back
1821              
1822             =head2 caller() doesn't work from inside my wrapped code!
1823              
1824             Wrapping adds at least one or two levels of calls: one for the wrapper
1825             subroutine itself, the other is for the eval trap when necessary.
1826              
1827             This poses a problem if you need to call caller() from within your wrapped code;
1828             it will also be off by at least one or two.
1829              
1830             The solution is for your function to use the caller() replacement, provided by
1831             L<Perinci::Sub::Util>. Or use embedded mode, where the wrapper code won't add
1832             extra subroutine calls.
1833              
1834             =head1 ENVIRONMENT
1835              
1836             =head2 LOG_PERINCI_WRAPPER_CODE (bool)
1837              
1838             If set to 1, will log the generated wrapper code. This value is used to set
1839             C<$Log_Wrapper_Code> if it is not already set.
1840              
1841             =head2 PERINCI_WRAPPER_CORE => bool
1842              
1843             Set default for wrap argument C<core>.
1844              
1845             =head2 PERINCI_WRAPPER_CORE_OR_PP => bool
1846              
1847             Set default for wrap argument C<core_or_pp>.
1848              
1849             =head2 PERINCI_WRAPPER_PP => bool
1850              
1851             Set default for wrap argument C<pp>.
1852              
1853             =head1 HOMEPAGE
1854              
1855             Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Wrapper>.
1856              
1857             =head1 SOURCE
1858              
1859             Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Wrapper>.
1860              
1861             =head1 BUGS
1862              
1863             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Wrapper>
1864              
1865             When submitting a bug or request, please include a test-file or a
1866             patch to an existing test-file that illustrates the bug or desired
1867             feature.
1868              
1869             =head1 SEE ALSO
1870              
1871             L<Perinci>, L<Rinci>
1872              
1873             L<Python::Decorator>
1874              
1875             L<Dist::Zilla::Plugin::Rinci::Wrap>
1876              
1877             L<Dist::Zilla::Plugin::Rinci::Validate>
1878              
1879             =head1 AUTHOR
1880              
1881             perlancar <perlancar@cpan.org>
1882              
1883             =head1 COPYRIGHT AND LICENSE
1884              
1885             This software is copyright (c) 2019, 2017, 2016, 2015, 2014, 2013, 2012, 2011 by perlancar@cpan.org.
1886              
1887             This is free software; you can redistribute it and/or modify it under
1888             the same terms as the Perl 5 programming language system itself.
1889              
1890             =cut