File Coverage

blib/lib/MooX/Purple/G.pm
Criterion Covered Total %
statement 273 281 97.1
branch 79 88 89.7
condition 6 8 75.0
subroutine 35 35 100.0
pod 0 23 0.0
total 393 435 90.3


line stmt bran cond sub pod time code
1             use strict;
2 9     9   5387 use warnings;
  9         16  
  9         271  
3 9     9   39 use 5.006;
  9         14  
  9         253  
4 9     9   184 our $VERSION = '0.16';
  9         21  
5             use PPR;
6 9     9   57 use Perl::Tidy;
  9         15  
  9         193  
7 9     9   7224 use Cwd qw/abs_path/;
  9         2621506  
  9         1166  
8 9     9   90 our %POD;
  9         18  
  9         1650  
9              
10             our (%HAS, $GATTRS, $SATTRS, $PATTRS, $PREFIX, %MACROS, $DIST_VERSION, $AUTHOR, $AUTHOR_EMAIL);
11             BEGIN {
12             $DIST_VERSION = '-version';
13 9     9   33 $AUTHOR = '-author';
14 9         16 $AUTHOR_EMAIL = '-author';
15 9         17 $GATTRS = '(
16 9         14 allow (?&PerlNWS)
17             (?:(?!qw)(?&PerlQualifiedIdentifier)|
18             (?&PerlList))
19             |
20             with (?&PerlNWS)
21             (?:(?!qw)(?&PerlPrefixUnaryOperator)*(?&PerlQualifiedIdentifier)|
22             (?&PerlList))
23             |
24             is (?&PerlNWS)
25             (?:(?!qw)(?&PerlPrefixUnaryOperator)*(?&PerlQualifiedIdentifier)|
26             (?&PerlList))
27             |
28             use (?&PerlNWS)
29             (?:(?&PerlQualifiedIdentifier)\s*(?&PerlList)|(?:(?!qw)(?&PerlQualifiedIdentifier)|
30             (?&PerlList)))
31             |
32             (?:(?&PerlNWS)*)
33             )';
34             $SATTRS = '(
35 9         15 allow (?&PerlNWS)
36             (?:(?!qw)(?&PerlQualifiedIdentifier)|
37             (?&PerlList))
38             |
39             (?:(?&PerlNWS)*)
40             )';
41             $PATTRS = '(
42 9         17 describe (?&PerlNWS)
43             (?:(?&PerlString))
44             |
45             (?:(?&PerlNWS)*)
46             )';
47             %HAS = (
48 9         128 ro => '"ro"',
49             ro => '"ro"',
50             is_ro => 'is => "ro"',
51             rw => '"rw"',
52             is_rw => 'is => "rw"',
53             nan => 'undef',
54             lzy => 'lazy => 1',
55             bld => 'builder => 1',
56             lzy_bld => 'lazy_build => 1',
57             trg => 'trigger => 1',
58             clr => 'clearer => 1',
59             req => 'required => 1',
60             coe => 'coerce => 1',
61             lzy_hash => 'lazy => 1, default => sub { {} }',
62             lzy_array => 'lazy => 1, default => sub { [] }',
63             lzy_str => 'lazy => 1, default => sub { "" }',
64             dhash => 'default => sub { {} }',
65             darray => 'default => sub { [] }',
66             dstr => 'default => sub { "" }',
67             );
68             $HAS{compile_regex} = sprintf q|[\[\s]+(%s)[\s,]+|, join '|', keys %HAS;
69 9         80 $HAS{compile_value_regex} = sprintf q|[\[\s]+(%s)[\s,]+|, join '|', map { quotemeta($_) }
70 9         31 qw/default lazy required trigger clearer coerce handles builder predicate reader writer weak_ref init_arg moosify/;
  126         31300  
71             };
72              
73             my ($source, $keyword, $callback, $lib, $pod) = @_;
74             while ($$source =~ m/
75 245     245 0 1212 $keyword
76 245         5006472 $PPR::GRAMMAR
77             /xms) {
78             my %hack = %+;
79             $hack{generate_pod} = $pod;
80 105         121353 my ($make, %makes) = $callback->(%hack);
81 105         638 $hack{match} = quotemeta($hack{match});
82 105         691 if ($lib) {
83 105         908 $make =~ s/(^\{\s*)|(\}\s*$)//g;
84 105 100       357 $make =~ s/^\t//gm;
85 26         1343 $make .= render_pod($makes{class});
86 26         363 write_file(sprintf("%s/%s.pmc", $lib, $makes{class}), $make)
87 26         163 if $makes{class};
88             $$source =~ s/$hack{match}//;
89 26 50       297 } else {
90 26         561197 $$source =~ s/$hack{match}/$make/e;
91             }
92 79         1754 }
  79         1765527  
93             $source;
94             }
95 245         50600  
96             g(
97             g(
98             g(
99 26     26 0 212 g(
100             g(
101             g(
102             g(
103             g(
104             $_[0],
105             qq|(?<match>start\\s*
106             (?<method>(?&PerlIdentifier))\\s*
107             (?<block>(?&PerlBlock)))|,
108             \&start
109             ),
110             qq|(?<match>end\\s*
111             (?<method>(?&PerlIdentifier))\\s*
112             (?<block>(?&PerlBlock)))|,
113             \&end
114             ),
115             qq|(?<match>during\\s*
116             (?<method>(?&PerlIdentifier))\\s*
117             (?<block>(?&PerlBlock)))|,
118             \&during
119             ),
120             qq|(?<match>trigger\\s*
121             (?<method>(?&PerlIdentifier))\\s*
122             (?<block>(?&PerlBlock)))|,
123             \&trigger
124             ),
125             qq|(?<match>macro\\s*
126             (?<macro> (?&PerlIdentifier))\\s*
127             (?<block> (?&PerlBlock));\n*)|,
128             \&macro
129             ),
130             qq|(?<match> private\\s*
131             (?<method> (?&PerlIdentifier))
132             (?<attrs> (?: $SATTRS*))
133             (?<block> (?&PerlBlock)))|,
134             \&private,
135             ),
136             qq|(?<match> public\\s*
137             (?<method> (?&PerlIdentifier))
138             (?:(?&PerlNWS))*
139             (?<block> (?&PerlBlock))
140             (?<pod> (?: $PATTRS*)))|,
141             \&public,
142             undef,
143             $_[1]
144             ),
145             qq|(?<match> attributes\\s* (?<list> (?&PerlList))\\s*\;)|,
146             \&attributes
147             );
148             }
149              
150             my $i = shift;
151             my @s;
152             while ( $i =~ s/
153             (?<match>\s*(?:
154 49     49 0 114 (?<hash>\s*(?&PerlAnonymousHash))|
155 49         82 (?<array>\s*(?&PerlAnonymousArray))|
156 49         1012551 (?<sub>\s*(?&PerlAnonymousSubroutine))|
157             (?<bless>\s*(bless\s*(?&PerlExpression)))|
158             (?<ident>\s*(?&PerlIdentifier))|
159             (?<string>\s*(?&PerlString))|
160             (?<num>\s*(?&PerlNumber))
161             )+)\s*(?&PerlComma)*
162             $PPR::GRAMMAR
163             //xms ) {
164             push @s, {%+}
165             }
166             return @s;
167             }
168 66         1346212  
169             my $i = shift;
170 49         9806 while ($i =~ m/$_[0]/xms) {
171             my $m = $1;
172             $i =~ s/$m/$_[1]->{$m}/;
173             }
174 24     24 0 64 $i;
175 24         401 }
176 13         30  
177 13         187 my ($i, %a) = @_;
178             while (
179 24         85 $i =~ s/
180             \s*(?<key> (?&PerlTerm))\s*
181             (?&PerlComma)
182             \s*(?<value> (?&PerlTerm))\s*
183 4     4 0 30 $PPR::GRAMMAR
184 4         115033 //xms
185             ) {
186             my %h = %+;
187             $h{key} =~ s/(^\s*)|(\s*$)//g;
188             $a{$h{key}} = $h{value};
189             }
190             return %a;
191             }
192 6         1371  
193 6         64 my ($class, %args) = @_;
194 6         171303 $PREFIX = $args{-prefix} unless $PREFIX;
195             if ($args{-author}) {
196 4         935 $args{-author} =~ m/(.*)\s*\<(.*)\>/;
197             $AUTHOR_EMAIL = $2;
198             ($AUTHOR = $1) =~ s/\s$//;
199             $AUTHOR_EMAIL =~ s/\@/ at /;
200 11     11   272 }
201 11 100       94 $DIST_VERSION = $args{-version} if $args{-version};
202 11 100       40 my $lib = $args{-lib};
203 1         6 my $file = $args{-module} ? [caller(1)]->[1] : $0;
204 1         4 open FH, "<$file";
205 1         5 my $source = \join '', <FH>;
206 1         4 close FH;
207             g(
208 11 100       34 g(
209 11         25 g(
210 11 100       86 $source,
211 11         430 qq/(?<match>(?&PerlPod))/,
212 11         445 \&parse_pod
213 11         142 ),
214 11         63 qq/(?<match> role\\s*
215             (?<class>(?&PerlPrefixUnaryOperator)*(?&PerlQualifiedIdentifier))
216             (?<attrs> (?: $GATTRS*))
217             (?<block> (?&PerlBlock)))/,
218             \&roles,
219             $lib
220             ),
221             qq/(?<match> class\\s*
222             (?<class>(?&PerlPrefixUnaryOperator)*(?&PerlQualifiedIdentifier))
223             (?<attrs> (?: $GATTRS*))
224             (?<block> (?&PerlBlock)))/,
225             \&classes,
226             $lib
227             );
228             unless ($lib) {
229             $source =~ s/use MooX\:\:Purple;\n*//;
230             $source =~ s/use MooX\:\:Purple\:\:G;\n*//;
231             my $current = [caller()]->[1];
232             $current =~ s/\.(.*)/\.pmc/;
233             write_file($current, $$source);
234             }
235 11 50       1103 }
236 0         0  
237 0         0 my $path = abs_path();;
238 0         0 for (split '/', $_[0]) {
239 0         0 $path .= "/$_";
240 0         0 if (! -d $path) {
241             mkdir $path or Carp::croak(qq/
242             Cannot open file for writing $!
243             /);
244             }
245 26     26 0 472 }
246 26         243 }
247 77         183  
248 77 100       1302 my $f = $_[0];
249 5 50       506 $f =~ s/\:\:/\//g;
250             make_path(substr($f, 0, rindex($f, '/')));
251             open FH, '>', $f or die "$f cannot open file to write $!";
252             print FH perl_tidy($_[1]);
253             close FH;
254             }
255              
256             my %args = @_;
257 26     26 0 58 $args{block} =~ s/^\n*\{\n*\s*|;\n*\t*\}\n*$//g;
258 26         93 $MACROS{$args{macro}} = $args{block};
259 26         161 return '';
260 26 50       83848 }
261 26         179  
262 26         3214 push @_, pre => '-';
263             when(@_);
264             }
265              
266 2     2 0 9 push @_, pre => '+';
267 2         23 when(@_);
268 2         10 }
269 2         15  
270             push @_, pre => '~';
271             when(@_);
272             }
273 1     1 0 4  
274 1         67 push @_, pre => '=';
275             when(@_);
276             }
277              
278 1     1 0 5 my %args = @_;
279 1         4 my %map = (
280             '-' => 'before',
281             '+' => 'after',
282             '~' => 'around',
283 1     1 0 4 '=' => 'around'
284 1         6 );
285              
286             $args{block} =~ s/(^{)|(}$)//g;
287             if ($args{pre} eq '~') {
288 1     1 0 4 $args{block} = "{
289 1         7 my (\$orig, \$self) = (shift, shift);
290             $args{block};
291             }";
292             } elsif ($args{pre} eq '=') {
293 4     4 0 23 $args{block} = "{
294 4         26 my (\$orig, \$self) = (shift, shift);
295             my \$out = \$self->\$orig(\@_);
296             $args{block};
297             }";
298             } else {
299             $args{block} = "{
300             my (\$self) = (shift);
301 4         51 $args{block};
302 4 100       26 }";
    100          
303 1         4 }
304             return "$map{$args{pre}} $args{method} => sub $args{block};";
305             }
306              
307             my %args = @_;
308 1         4 my @attr;
309             g(
310             \$args{list},
311             qq/(?<match>
312             \\s*(?<key> (?&PerlTerm))\\s*
313             (?&PerlComma)
314 2         9 \\s*(?<value> (?&PerlTerm))\\s*
315             )/,
316             sub {
317             my %hack = _construct_attribute(@_);
318             $hack{key} =~ m/\s*(?<array> (?&PerlAnonymousArray)) $PPR::GRAMMAR/xms;
319 4         35 for my $key ( ($+{array} ? @{ eval $+{array} } : $hack{key}) ) {
320             $key =~ s/(^\s*)|(\s*$)//g;
321             push @attr, sprintf(
322             q/has %s => (
323 4     4 0 16 %s
324 4         115 );/,
325             $key, join( ",\n\t", (map {
326             $hack{$_} =~ s/(["']+)/"/g;
327             qq/\t$_ => $hack{$_}/
328             } grep { defined $hack{$_} } qw/is isa trigger builder lazy clearer/), (map {
329             my $hak = [i($hack{$_})]->[0];
330             $hack{$_} = defined $hak->{sub} ? $hak->{sub} : qq/sub { $hack{$_} }/;
331             qq/\t$_ => $hack{$_}/;
332             } grep { $hack{$_} } qw/default/)));
333 24     24   209 }
334 24         474420 }
335 24 100       4493 );
  3         416  
336 29         314 return join "\n\n", @attr;
337             }
338              
339             my (%attr) = @_;
340             $attr{value} = r($attr{value}, $HAS{compile_regex}, \%HAS);
341             $attr{value} =~ s/(^\s*\[)|(\s*\]$)//g;
342 36         146 my @spec = i($attr{value});
343 36         120 my $oc = scalar @spec;
344 174         300 unshift @spec, { string => '"ro"' } if (!$spec[0]->{string});
345 25         132 $attr{is} = $spec[0]->{string} =~ m/[\'\"\s]+(ro|rw)[\'\"\s]+/
346 25 100       190 ? shift(@spec)->{string}
347 25         1126 : '"ro"';
348 29         100 ($spec[0]->{ident} eq 'undef')
  29         303  
349             ? shift(@spec)
350             : do {
351 4         49 $attr{isa} = shift(@spec)->{ident};
352 4         156 } if $spec[0]->{ident};
353             my $attrHash = $spec[0]->{hash} ? $spec[0]->{match} =~ m/$HAS{compile_value_regex}/g : 0;
354             if ($spec[0] && keys %{$spec[0]}) {
355             $attr{default} = !$attrHash && $oc <= 3 ? $spec[0]->{sub} ? shift(@spec)->{sub} : qq/sub { / . shift(@spec)->{match} . qq/ }/ : '';
356 24     24   97 %attr = kv($spec[0]->{match}, %attr) if ($spec[0]);
357 24         151 }
358 24         248 delete $attr{value};
359 24         95 return %attr;
360 24         68 }
361 24 100       134  
362             my %args = @_;
363             my @hack = grep {$_ && $_ !~ m/^\s*$/} $args{attrs} =~ m/(?:$GATTRS) $PPR::GRAMMAR/gx;
364 24 100       284 my ($body, %attrs) = _set_class_role_attrs($args{block}, _parse_role_attrs(@hack));
365             $body =~ s/\s*$//;
366            
367             $args{class} =~ s/^\+/$PREFIX\:\:/;
368 1         4  
369 24 100       125 my $pod = prepare_pod($args{class});
    100          
370 24 100       426  
371 24 100 66     100 my $r = \qq|{
  24         135  
372 22 100 66     174 package $args{class};
    100          
373 22 100       87 use Moo::Role;
374             use MooX::LazierAttributes;
375 24         82 use MooX::ValidateSubs;
376 24         207 use Data::LnArray qw/arr/;
377             $attrs{with}$attrs{use}$body
378             1;
379             }|;
380 12     12 0 57 p($r, !$pod);
381 12 100       242142 return ($$r, %args);
  3780         4363  
382 12         2645 }
383 12         196  
384             my %h = @_;
385 12         106 if ($h{match} =~ m/=head1 NAME\n*([^\s]+)/) {
386             $POD{$1} = $POD{CURRENT} = { PARSED => 1, DATA => [] };
387 12         56 }
388             push @{$POD{CURRENT}{DATA}}, $h{match};
389 12         88 }
390              
391             my $class = shift;
392             if (!$POD{$class}) {
393             $POD{$class} = $POD{CURRENT} = { PARSED => 0, DATA => [] };
394             push @{$POD{$class}{DATA}}, "=head1 NAME
395              
396             $class - The great new $class!
397              
398 12         73 =cut";
399 12         920 push @{$POD{$class}{DATA}}, "=head1 Version
400              
401             Version $DIST_VERSION
402              
403 24     24 0 99 =cut";
404 24 100       171 push @{$POD{$class}{DATA}}, "=head1 SYNOPSIS
405 8         69  
406             use $class;
407 24         55  
  24         153  
408             $class\-\>new(\\%args)
409              
410             =cut";
411 26     26 0 72 push @{$POD{$class}{DATA}}, "=head1 SUBROUTINES/METHODS
412 26 100       122  
413 18         103 =cut";
414 18         38 return 0;
  18         92  
415             }
416             return 1;
417             }
418              
419 18         37 my $class = shift;
  18         82  
420             if ($POD{$class}) {
421             if (!$POD{$class}{PARSED}) {
422             (my $url_class = $class) =~ s/\:\:/-/g;
423             push @{$POD{$class}{DATA}}, "=head1 AUTHOR
424 18         33  
  18         73  
425             $AUTHOR, C<< <$AUTHOR_EMAIL> >>
426              
427             =cut";
428             push @{$POD{$class}{DATA}}, "=head1 BUGS
429              
430             Please report any bugs or feature requests to C<bug-moox-purple at rt.cpan.org>, or through
431 18         34 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=$url_class>. I will be notified, and then you'll
  18         52  
432             automatically be notified of progress on your bug as I make changes.
433              
434 18         44 =cut";
435             push @{$POD{$class}{DATA}}, "=head1 SUPPORT
436 8         24  
437             You can find documentation for this module with the perldoc command.
438              
439             perldoc $class
440 26     26 0 79  
441 26 50       206  
442 26 100       121 You can also look for information at:
443 18         70  
444 18         36 =over 4
  18         144  
445              
446             =item * RT: CPAN's request tracker (report bugs here)
447              
448             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=$url_class>
449 18         38  
  18         103  
450             =item * AnnoCPAN: Annotated CPAN documentation
451              
452             L<http://annocpan.org/dist/$url_class>
453              
454             =item * CPAN Ratings
455              
456 18         36 L<http://cpanratings.perl.org/d/$url_class>
  18         190  
457              
458             =item * Search CPAN
459              
460             L<http://search.cpan.org/dist/$url_class/>
461              
462             =back
463              
464             =cut";
465             push @{$POD{$class}{DATA}}, "=head1 ACKNOWLEDGEMENTS
466              
467             =cut";
468              
469             push @{$POD{$class}{DATA}}, "=head1 LICENSE AND COPYRIGHT
470              
471             Copyright 2019 $AUTHOR.
472              
473             This program is free software; you can redistribute it and/or modify it
474             under the terms of the the Artistic License (2.0). You may obtain a
475             copy of the full license at:
476              
477             L<http://www.perlfoundation.org/artistic_license_2_0>
478              
479             Any use, modification, and distribution of the Standard or Modified
480             Versions is governed by this Artistic License. By using, modifying or
481             distributing the Package, you accept this license. Do not use, modify,
482             or distribute the Package, if you do not accept this license.
483              
484             If your Modified Version has been derived from a Modified Version made
485             by someone other than you, you are nevertheless required to ensure that
486 18         39 your Modified Version complies with the requirements of this license.
  18         52  
487              
488             This license does not grant you the right to use any trademark, service
489             mark, tradename, or logo of the Copyright Holder.
490 18         35  
  18         142  
491             This license includes the non-exclusive, worldwide, free-of-charge
492             patent license to make, have made, use, offer to sell, sell, import and
493             otherwise transfer the Package with respect to any patent claims
494             licensable by the Copyright Holder that are necessarily infringed by the
495             Package. If you institute patent litigation (including a cross-claim or
496             counterclaim) against any party alleging that the Package constitutes
497             direct or contributory patent infringement, then this Artistic License
498             to you shall terminate on the date that such litigation is filed.
499              
500             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
501             AND CONTRIBUTORS 'AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
502             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
503             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
504             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
505             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
506             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
507             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
508              
509             =cut";
510              
511             }
512             return join "\n", @{$POD{$class}{DATA}};
513             }
514             return '';
515             }
516              
517             my %args = @_;
518             my @hack = grep {$_ && $_ !~ m/^\s*$/} $args{attrs} =~ m/(?:$GATTRS) $PPR::GRAMMAR/gx;
519             my ($body, %attrs) = _set_class_role_attrs($args{block}, _parse_role_attrs(@hack));
520             $body =~ s/\s*$//;
521             $args{class} =~ s/^\+/$PREFIX\:\:/;
522              
523             my $pod = prepare_pod($args{class});
524             my $r = \qq|{
525             package $args{class};
526             use Moo;
527             use MooX::LazierAttributes;
528             use MooX::ValidateSubs;
529             use Data::LnArray qw/arr/;
530             $attrs{is}$attrs{with}$attrs{use}$body
531             1;
532             }|;
533 26         88 p($r, !$pod);
  26         197  
534             return ($$r, %args);
535 0         0 }
536              
537             my $block = shift;
538             my $mac = join '|', keys %MACROS;
539 14     14 0 70 $block =~ s/&($mac)/$MACROS{$1}/g;
540 14 100       282240 return $block;
  6210         7279  
541 14         2530 }
542 14         314  
543 14         128 my %args = @_;
544             my @hack = grep {$_ && $_ !~ m/^\s*$/} $args{attrs} =~ m/(?:$SATTRS) $PPR::GRAMMAR/gx;
545 14         66 my %attrs = _parse_role_attrs(@hack);
546 14         113 my $allowed = $attrs{allow} ? sprintf 'qw(%s)', join ' ', @{$attrs{allow}} : 'qw//';
547             $args{block} = macro_replacement($args{block});
548             $args{block} =~ s/(^{)|(}$)//g;
549             $args{block} =~ s/^\s*//;
550             return "sub $args{method} {
551             my (\$self) = shift;
552             my \$caller = caller();
553             my \@allowed = $allowed;
554             unless (\$caller eq __PACKAGE__ || grep { \$_ eq \$caller } \@allowed) {
555 14         78 die \"cannot call private method $args{method} from \$caller\";
556 14         855 }
557             $args{block}
558             }";
559             }
560 21     21 0 51  
561 21         180 my %args = @_;
562 21         167 if ($args{pod}) {
563 21         78 $args{pod} =~ m/describe\s*(.*)/i;
564             $args{pod} = eval $1;
565             }
566             $args{pod} //= '';
567 2     2 0 11 push @{ $POD{CURRENT}{DATA} }, "=head2 $args{method}
568 2 100       40097  
  810         918  
569 2         533 $args{pod}
570 2 50       13  
  2         12  
571 2         15 \$class->$args{method}
572 2         15  
573 2         9 =cut" if $args{generate_pod};
574 2         31 $args{block} = macro_replacement($args{block});
575             $args{block} =~ s/(^{)|(}$)//g;
576             return "sub $args{method} {
577             my (\$self) = shift;
578             $args{block}
579             }";
580             }
581              
582             =pod
583             sub _parse_role_attrs {
584             my @roles = @_;
585             my %attrs;
586 19     19 0 100 for (@roles) {
587 19 50       134 if ($_ =~ m/\s*use\s*((?!qw)(?&PerlQualifiedIdentifier))\s*((?&PerlList)) $PPR::GRAMMAR/xms) {
588 19         59 push @{$attrs{use}}, sprintf "%s %s", $1, $2;
589 19         2823 next;
590             }
591 19   100     174 $_ =~ m/(with|allow|is|use)(.*)/i;
592 11         93 push @{$attrs{$1}}, eval $2 || do { (my $g = $2) =~ s/^\s*//; $g; };
593             }
594             return %attrs;
595             }
596             =cut
597              
598 19 100       71 my @roles = @_;
599 19         109 my %attrs;
600 19         166 my $i = 0;
601 19         122 for (@roles) {
602             if ($_ =~ m/\s*use\s*((?!qw)(?&PerlQualifiedIdentifier))\s*((?&PerlList)) $PPR::GRAMMAR/xms) {
603             $attrs{use}{sprintf "%s %s", $1, $2}++;
604             next;
605             }
606             $_ =~ m/(with|allow|is|use)(.*)/i;
607             my @list = eval($2); # || $2
608             push @list, do { (my $g = $2) =~ s/^\s*//; $g; } unless @list;
609             for (@list) {
610             $attrs{$1}{$_} = $i++;
611             }
612             }
613             for my $o (qw/with allow is use/) {
614             $attrs{$o} = [sort { $attrs{$o}{$a} <=> $attrs{$o}{$b} } keys %{$attrs{$o}}] if $attrs{$o};
615             }
616             return %attrs;
617             }
618              
619             my ($body, %attrs) = @_;
620             if ($attrs{allow}) {
621             my $allow = join ' ', @{$attrs{allow}};
622             $body =~ s{private\s*(\p{XIDS}\p{XIDC}*)}{private $1 allow qw/$allow/}g;
623             }
624 28     28   109 $attrs{is} = $attrs{is} ? sprintf "extends qw/%s/;\n", join(' ', map { my $l = $_; $l =~ s/^\s*\+/$PREFIX\:\:/; $l; } @{$attrs{is}}) : '';
625 28         102 my $last;
626 28         92 $attrs{with} = $attrs{with}
627 28         89 ? sprintf "with qw/%s/;\n", join(' ', map {
628 17 100       338654 my $l = $_;
629 1         49 $l =~ s/^\s*\+/$PREFIX\:\:/;
630 1         280 unless($l =~ s/^\s*\-/$last\:\:/) {
631             $last = $l;
632 16         3724 }
633 16         2104 if ($l =~ s/^\s*\~//) {
634 16 100       117 $last = $PREFIX ? ($PREFIX . '::' . $l) : $l;
  8         57  
  8         28  
635 16         54 $l = '';
636 24         177 }
637             $l;
638             } @{$attrs{with}})
639 28         86 : '';
640 112 100       258 $attrs{use} = $attrs{use} ? join('', map { sprintf("\tuse %s;\n", $_) } @{$attrs{use}}) : '';
  14         35  
  16         122  
641             $body =~ s/(^{)|(}$)//g;
642 28         170 return $body, %attrs;
643             }
644              
645             my $source = shift;
646 26     26   100
647 26 100       102 my $dest_string;
648 2         5 my $stderr_string;
  2         7  
649 2         25 my $errorfile_string;
650             my $argv = "-npro"; # Ignore any .perltidyrc at this site
651 26 100       163 $argv .= " -pbp"; # Format according to perl best practices
  5         11  
  5         31  
  5         35  
  5         17  
652 26         57 $argv .= " -nst"; # Must turn off -st in case -pbp is specified
653             $argv .= " -se"; # -se appends the errorfile to stderr
654             $argv .= " -nola"; # Disable label indent
655 14         24 $argv .= " -t"; # Use tab instead of 4 spaces
656 14         29
657 14 100       53 my $error = Perl::Tidy::perltidy(
658 6         14 argv => $argv,
659             source => \$source,
660 14 100       43 destination => \$dest_string,
661 2 50       11 stderr => \$stderr_string,
662 2         3 errorfile => \$errorfile_string, # ignored when -se flag is set
663             ##phasers => 'stun', # uncomment to trigger an error
664 14         51 );
665 26 100       100
  6         22  
666             if ($error) {
667 26 100       103 # serious error in input parameters, no tidied output
  2         6  
  1         3  
668 26         645 print "<<STDERR>>\n$stderr_string\n";
669 26         167 die "Exiting because of serious errors\n";
670             }
671              
672             return $dest_string;
673 26     26 0 70 }
674              
675 26         103 1;
676              
677 26         0  
678 26         88 =head1 NAME
679 26         70  
680 26         57 MooX::Purple - MooX::Purple::G
681 26         52  
682 26         68 =head1 VERSION
683 26         54  
684             Version 0.16
685 26         234  
686             =cut
687              
688             =head1 SYNOPSIS
689              
690             use MooX::Purple;
691             use MooX::Purple::G;
692              
693             role Before {
694 26 50       3620766 public seven { return '7' }
695             };
696 0         0  
697 0         0 role World allow Hello with Before {
698             private six { 'six' }
699             };
700 26         1228  
701             class Hello with qw/World/ allow qw/main/ use Scalar::Util qw/reftype/ use qw/JSON/ {
702             use Types::Standard qw/Str HashRef ArrayRef Object/;
703              
704             attributes
705             one => [{ okay => 'one'}],
706             [qw/two three/] => [rw, Str, { default => 'the world is flat' }];
707              
708             validate_subs
709             four => {
710             params => {
711             message => [Str, sub {'four'}]
712             }
713             };
714              
715             public four { return $_[1]->{message} }
716             private five { return $_[0]->six }
717             public ten { reftype bless {}, 'Flat::World' }
718             public eleven { encode_json { flat => "world" } }
719             };
720              
721             class Night is qw/Hello/ {
722             public nine { return 'nine' }
723             };
724              
725             Night->new()->five();
726              
727             ... writes to same/path/yourfile.pmc
728              
729             {
730             package Before;
731             use Moo::Role;
732              
733             sub seven { return '7' }
734             };
735              
736             {
737             package World;
738             use Moo::Role;
739             with qw/Before/;
740              
741             sub six {
742             my $caller = caller();
743             my @allowed = qw(Hello);
744             unless ($caller eq __PACKAGE__ || grep { $_ eq $caller } @allowed) {
745             die "cannot call private method six from $caller";
746             }
747             'six'
748             }
749             };
750              
751             {
752             package Hello;
753             use Moo;
754             use MooX::LazierAttributes;
755             use MooX::ValidateSubs;
756             with qw/World/;
757             use Scalar::Util qw/reftype/ ;
758             use JSON;
759              
760             use Types::Standard qw/Str HashRef ArrayRef Object/;
761              
762             attributes
763             one => [{ okay => 'one'}],
764             [qw/two three/] => [rw, Str, { default => 'the world is flat' }];
765              
766             validate_subs
767             four => {
768             params => {
769             message => [Str, sub {'four'}]
770             }
771             };
772              
773             sub four { return $_[1]->{message} }
774             sub five {
775             my $caller = caller();
776             my @allowed = qw(main);
777             unless ($caller eq __PACKAGE__ || grep { $_ eq $caller } @allowed) {
778             die "cannot call private method five from $caller";
779             }
780             return $_[0]->six
781             }
782             sub ten { reftype bless {}, 'Flat::World' }
783             sub eleven { encode_json { flat => "world" } }
784             1;
785             };
786              
787             {
788             package Night;
789             use Moo;
790             use MooX::LazierAttributes;
791             use MooX::ValidateSubs;
792             extends qw/Hello/;
793              
794             sub nine { return 'nine' }
795             1;
796             };
797              
798              
799             =head1 AUTHOR
800              
801             lnation, C<< <thisusedtobeanemail at gmail.com> >>
802              
803             =head1 BUGS
804              
805             Please report any bugs or feature requests to C<bug-moox-purple at rt.cpan.org>, or through
806             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooX-Purple>. I will be notified, and then you'll
807             automatically be notified of progress on your bug as I make changes.
808              
809             =head1 SUPPORT
810              
811             You can find documentation for this module with the perldoc command.
812              
813             perldoc MooX::Purple
814              
815              
816             You can also look for information at:
817              
818             =over 4
819              
820             =item * RT: CPAN's request tracker (report bugs here)
821              
822             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Purple>
823              
824             =item * AnnoCPAN: Annotated CPAN documentation
825              
826             L<http://annocpan.org/dist/MooX-Purple>
827              
828             =item * CPAN Ratings
829              
830             L<http://cpanratings.perl.org/d/MooX-Purple>
831              
832             =item * Search CPAN
833              
834             L<http://search.cpan.org/dist/MooX-Purple/>
835              
836             =back
837              
838              
839             =head1 ACKNOWLEDGEMENTS
840              
841              
842             =head1 LICENSE AND COPYRIGHT
843              
844             Copyright 2019 lnation.
845              
846             This program is free software; you can redistribute it and/or modify it
847             under the terms of the the Artistic License (2.0). You may obtain a
848             copy of the full license at:
849              
850             L<http://www.perlfoundation.org/artistic_license_2_0>
851              
852             Any use, modification, and distribution of the Standard or Modified
853             Versions is governed by this Artistic License. By using, modifying or
854             distributing the Package, you accept this license. Do not use, modify,
855             or distribute the Package, if you do not accept this license.
856              
857             If your Modified Version has been derived from a Modified Version made
858             by someone other than you, you are nevertheless required to ensure that
859             your Modified Version complies with the requirements of this license.
860              
861             This license does not grant you the right to use any trademark, service
862             mark, tradename, or logo of the Copyright Holder.
863              
864             This license includes the non-exclusive, worldwide, free-of-charge
865             patent license to make, have made, use, offer to sell, sell, import and
866             otherwise transfer the Package with respect to any patent claims
867             licensable by the Copyright Holder that are necessarily infringed by the
868             Package. If you institute patent litigation (including a cross-claim or
869             counterclaim) against any party alleging that the Package constitutes
870             direct or contributory patent infringement, then this Artistic License
871             to you shall terminate on the date that such litigation is filed.
872              
873             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
874             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
875             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
876             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
877             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
878             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
879             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
880             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
881              
882              
883              
884             1; # End of MooX::Purple