File Coverage

blib/lib/MooX/Purple/G.pm
Criterion Covered Total %
statement 276 284 97.1
branch 79 88 89.7
condition 6 8 75.0
subroutine 35 35 100.0
pod 0 23 0.0
total 396 438 90.4


line stmt bran cond sub pod time code
1             use strict;
2 9     9   5442 use warnings;
  9         18  
  9         286  
3 9     9   41 use 5.006;
  9         16  
  9         258  
4 9     9   179 our $VERSION = '0.19';
  9         26  
5             use PPR;
6 9     9   44 use Perl::Tidy;
  9         14  
  9         156  
7 9     9   7602 use Cwd qw/abs_path/;
  9         2624375  
  9         996  
8 9     9   84 our %POD;
  9         23  
  9         1753  
9              
10             our (%HAS, $GATTRS, $SATTRS, $PATTRS, $PREFIX, %MACROS, $DIST_VERSION, $AUTHOR, $AUTHOR_EMAIL);
11             BEGIN {
12             $DIST_VERSION = '-version';
13 9     9   30 $AUTHOR = '-author';
14 9         20 $AUTHOR_EMAIL = '-author';
15 9         17 $GATTRS = '(
16 9         15 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         21 allow (?&PerlNWS)
36             (?:(?!qw)(?&PerlQualifiedIdentifier)|
37             (?&PerlList))
38             |
39             (?:(?&PerlNWS)*)
40             )';
41             $PATTRS = '(
42 9         16 describe (?&PerlNWS)
43             (?:(?&PerlString))
44             |
45             (?:(?&PerlNWS)*)
46             )';
47             %HAS = (
48 9         126 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         85 $HAS{compile_value_regex} = sprintf q|[\[\s]+(%s)[\s,]+|, join '|', map { quotemeta($_) }
70 9         29 qw/default lazy required trigger clearer coerce handles builder predicate reader writer weak_ref init_arg moosify/;
  126         33565  
71             };
72              
73             my ($source, $keyword, $callback, $lib, $pod) = @_;
74             while ($$source =~ m/
75 245     245 0 994 $keyword
76 245         5434891 $PPR::GRAMMAR
77             /xms) {
78             my %hack = %+;
79             $hack{generate_pod} = $pod;
80 105         114804 my ($make, %makes) = $callback->(%hack);
81 105         627 $hack{match} = quotemeta($hack{match});
82 105         629 if ($lib) {
83 105         814 $make =~ s/(^\{\s*)|(\}\s*$)//g;
84 105 100       316 $make =~ s/^\t//gm;
85 26         1495 $make .= render_pod($makes{class});
86 26         375 write_file(sprintf("%s/%s.pmc", $lib, $makes{class}), $make)
87 26         165 if $makes{class};
88             $$source =~ s/$hack{match}//;
89 26 50       305 } else {
90 26         588115 $$source =~ s/$hack{match}/$make/e;
91             }
92 79         1691 }
  79         1952942  
93             $source;
94             }
95 245         29283  
96             g(
97             g(
98             g(
99 26     26 0 186 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 127 (?<hash>\s*(?&PerlAnonymousHash))|
155 49         105 (?<array>\s*(?&PerlAnonymousArray))|
156 49         1115061 (?<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         1480775  
169             my $i = shift;
170 49         5932 while ($i =~ m/$_[0]/xms) {
171             my $m = $1;
172             $i =~ s/$m/$_[1]->{$m}/;
173             }
174 24     24 0 68 $i;
175 24         466 }
176 13         38  
177 13         204 my ($i, %a) = @_;
178             while (
179 24         130 $i =~ s/
180             \s*(?<key> (?&PerlTerm))\s*
181             (?&PerlComma)
182             \s*(?<value> (?&PerlTerm))\s*
183 4     4 0 35 $PPR::GRAMMAR
184 4         127450 //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         1132  
193 6         72 my ($class, %args) = @_;
194 6         187645 $PREFIX = $args{-prefix} unless $PREFIX;
195             if ($args{-author}) {
196 4         650 $args{-author} =~ m/(.*)\s*\<(.*)\>/;
197             $AUTHOR_EMAIL = $2;
198             ($AUTHOR = $1) =~ s/\s$//;
199             $AUTHOR_EMAIL =~ s/\@/ at /;
200 11     11   287 }
201 11 100       97 $DIST_VERSION = $args{-version} if $args{-version};
202 11 100       45 my $lib = $args{-lib};
203 1         12 my $file = $args{-module} ? [caller(1)]->[1] : $0;
204 1         5 open FH, "<$file";
205 1         8 my $source = \join '', <FH>;
206 1         5 close FH;
207             g(
208 11 100       47 g(
209 11         24 g(
210 11 100       81 $source,
211 11         477 qq/(?<match>(?&PerlPod))/,
212 11         485 \&parse_pod
213 11         133 ),
214 11         65 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       1062 }
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 499 }
246 26         212 }
247 77         192  
248 77 100       1394 my $f = $_[0];
249 5 50       470 $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 62 $args{block} =~ s/^\n*\{\n*\s*|;\n*\t*\}\n*$//g;
258 26         88 $MACROS{$args{macro}} = $args{block};
259 26         160 return '';
260 26 50       6620 }
261 26         185  
262 26         2299 push @_, pre => '-';
263             when(@_);
264             }
265              
266 2     2 0 12 push @_, pre => '+';
267 2         23 when(@_);
268 2         11 }
269 2         9  
270             push @_, pre => '~';
271             when(@_);
272             }
273 1     1 0 5  
274 1         54 push @_, pre => '=';
275             when(@_);
276             }
277              
278 1     1 0 4 my %args = @_;
279 1         4 my %map = (
280             '-' => 'before',
281             '+' => 'after',
282             '~' => 'around',
283 1     1 0 4 '=' => 'around'
284 1         5 );
285              
286             $args{block} =~ s/(^{)|(}$)//g;
287             if ($args{pre} eq '~') {
288 1     1 0 4 $args{block} = "{
289 1         6 my (\$orig, \$self) = (shift, shift);
290             $args{block};
291             }";
292             } elsif ($args{pre} eq '=') {
293 4     4 0 21 $args{block} = "{
294 4         24 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         40 $args{block};
302 4 100       24 }";
    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         7 \\s*(?<value> (?&PerlTerm))\\s*
315             )/,
316             sub {
317             my %hack = _construct_attribute(@_);
318             $hack{key} =~ m/\s*(?<array> (?&PerlAnonymousArray)) $PPR::GRAMMAR/xms;
319 4         33 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 106 %s
324 4         116 );/,
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   111 }
334 24         523805 }
335 24 100       2701 );
  3         523  
336 29         312 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         148 my @spec = i($attr{value});
343 36         157 my $oc = scalar @spec;
344 174         329 unshift @spec, { string => '"ro"' } if (!$spec[0]->{string});
345 25         104 $attr{is} = $spec[0]->{string} =~ m/[\'\"\s]+(ro|rw)[\'\"\s]+/
346 25 100       177 ? shift(@spec)->{string}
347 25         1050 : '"ro"';
348 29         121 ($spec[0]->{ident} eq 'undef')
  29         244  
349             ? shift(@spec)
350             : do {
351 4         54 $attr{isa} = shift(@spec)->{ident};
352 4         187 } 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   103 %attr = kv($spec[0]->{match}, %attr) if ($spec[0]);
357 24         153 }
358 24         233 delete $attr{value};
359 24         86 return %attr;
360 24         81 }
361 24 100       150  
362             my %args = @_;
363             my @hack = grep {$_ && $_ !~ m/^\s*$/} $args{attrs} =~ m/(?:$GATTRS) $PPR::GRAMMAR/gx;
364 24 100       332 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         5  
369 24 100       126 my $pod = prepare_pod($args{class});
    100          
370 24 100       385  
371 24 100 66     118 my $r = \qq|{
  24         126  
372 22 100 66     188 package $args{class};
    100          
373 22 100       92 use Moo::Role;
374             use MooX::LazierAttributes;
375 24         93 use MooX::ValidateSubs;
376 24         195 use Data::LnArray qw/arr/;
377             $attrs{with}$attrs{use}$body
378             1;
379             }|;
380 12     12 0 107 p($r, !$pod);
381 12 100       267919 return ($$r, %args);
  3780         4928  
382 12         1530 }
383 12         155  
384             my %h = @_;
385 12         86 if ($h{match} =~ m/=head1 NAME\n*([^\s]+)/) {
386             $POD{$1} = $POD{CURRENT} = { PARSED => 1, DATA => [] };
387 12         51 }
388             push @{$POD{CURRENT}{DATA}}, $h{match};
389 12         103 }
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         56 =cut";
399 12         566 push @{$POD{$class}{DATA}}, " =head1 Version
400              
401             Version $DIST_VERSION
402              
403 24     24 0 90 =cut";
404 24 100       122 push @{$POD{$class}{DATA}}, " =head1 SYNOPSIS
405 8         60  
406             use $class;
407 24         43  
  24         129  
408             $class\-\>new(\\%args)
409              
410             =cut";
411 26     26 0 67 push @{$POD{$class}{DATA}}, " =head1 SUBROUTINES/METHODS
412 26 100       109  
413 18         106 =cut";
414 18         41 return 0;
  18         103  
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         36  
  18         67  
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         74  
432             automatically be notified of progress on your bug as I make changes.
433              
434 18         54 =cut";
435             push @{$POD{$class}{DATA}}, " =head1 SUPPORT
436 8         17  
437             You can find documentation for this module with the perldoc command.
438              
439             perldoc $class
440 26     26 0 76  
441 26 50       138  
442 26 100       114 You can also look for information at:
443 18         64  
444 18         36 =over 4
  18         136  
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         41  
  18         125  
450             =item * AnnoCPAN: Annotated CPAN documentation
451              
452             L<http://annocpan.org/dist/$url_class>
453              
454             =item * CPAN Ratings
455              
456 18         42 L<http://cpanratings.perl.org/d/$url_class>
  18         118  
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         57 your Modified Version complies with the requirements of this license.
  18         54  
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         129  
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", map { my $v = $_; $v =~ s/^\t//gm; $v; } @{$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         63 p($r, !$pod);
  197         241  
  197         907  
  197         515  
  26         121  
534             return ($$r, %args);
535 0         0 }
536              
537             my $block = shift;
538             my $mac = join '|', keys %MACROS;
539 14     14 0 71 $block =~ s/&($mac)/$MACROS{$1}/g;
540 14 100       313489 return $block;
  6210         8063  
541 14         1623 }
542 14         334  
543 14         162 my %args = @_;
544             my @hack = grep {$_ && $_ !~ m/^\s*$/} $args{attrs} =~ m/(?:$SATTRS) $PPR::GRAMMAR/gx;
545 14         71 my %attrs = _parse_role_attrs(@hack);
546 14         83 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         90 die \"cannot call private method $args{method} from \$caller\";
556 14         736 }
557             $args{block}
558             }";
559             }
560 21     21 0 52  
561 21         88 my %args = @_;
562 21         190 if ($args{pod}) {
563 21         64 $args{pod} =~ m/describe\s*(.*)/i;
564             $args{pod} = eval $1;
565             }
566             $args{pod} //= '';
567 2     2 0 9 push @{ $POD{CURRENT}{DATA} }, " =head2 $args{method}
568 2 100       43335  
  810         1011  
569 2         141 $args{pod}
570 2 50       9  
  2         11  
571 2         8 \$class->$args{method}
572 2         14  
573 2         8 =cut" if $args{generate_pod};
574 2         20 $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             my @roles = @_;
583             my %attrs;
584             my $i = 0;
585             for (@roles) {
586 19     19 0 100 if ($_ =~ m/\s*use\s*((?!qw)(?&PerlQualifiedIdentifier))\s*((?&PerlList)) $PPR::GRAMMAR/xms) {
587 19 50       142 $attrs{use}{sprintf "%s %s", $1, $2}++;
588 19         61 next;
589 19         2743 }
590             $_ =~ m/(with|allow|is|use)(.*)/i;
591 19   100     169 my @list = eval($2); # || $2
592 11         90 push @list, do { (my $g = $2) =~ s/^\s*//; $g; } unless @list;
593             for (@list) {
594             $attrs{$1}{$_} = $i++;
595             }
596             }
597             for my $o (qw/with allow is use/) {
598 19 100       61 $attrs{$o} = [sort { $attrs{$o}{$a} <=> $attrs{$o}{$b} } keys %{$attrs{$o}}] if $attrs{$o};
599 19         83 }
600 19         163 return %attrs;
601 19         120 }
602              
603             my ($body, %attrs) = @_;
604             if ($attrs{allow}) {
605             my $allow = join ' ', @{$attrs{allow}};
606             $body =~ s{private\s*(\p{XIDS}\p{XIDC}*)}{private $1 allow qw/$allow/}g;
607             }
608 28     28   135 $attrs{is} = $attrs{is} ? sprintf "extends qw/%s/;\n", join(' ', map { my $l = $_; $l =~ s/^\s*\+/$PREFIX\:\:/; $l; } @{$attrs{is}}) : '';
609 28         93 my $last;
610 28         87 $attrs{with} = $attrs{with}
611 28         98 ? sprintf "with qw/%s/;\n", join(' ', map {
612 17 100       370922 my $l = $_;
613 1         11 $l =~ s/^\s*\+/$PREFIX\:\:/;
614 1         90 unless($l =~ s/^\s*\-/$last\:\:/) {
615             $last = $l;
616 16         1888 }
617 16         1988 if ($l =~ s/^\s*\~//) {
618 16 100       102 $last = $PREFIX ? ($PREFIX . '::' . $l) : $l;
  8         56  
  8         32  
619 16         47 $l = '';
620 24         152 }
621             $l;
622             } @{$attrs{with}})
623 28         94 : '';
624 112 100       250 $attrs{use} = $attrs{use} ? join('', map { sprintf("\tuse %s;\n", $_) } @{$attrs{use}}) : '';
  17         38  
  16         102  
625             $body =~ s/(^{)|(}$)//g;
626 28         154 return $body, %attrs;
627             }
628              
629             my $source = shift;
630 26     26   101
631 26 100       93 my $dest_string;
632 2         5 my $stderr_string;
  2         8  
633 2         23 my $errorfile_string;
634             my $argv = "-npro"; # Ignore any .perltidyrc at this site
635 26 100       126 $argv .= " -pbp"; # Format according to perl best practices
  5         13  
  5         32  
  5         37  
  5         18  
636 26         58 $argv .= " -nst"; # Must turn off -st in case -pbp is specified
637             $argv .= " -se"; # -se appends the errorfile to stderr
638             $argv .= " -nola"; # Disable label indent
639 14         23 $argv .= " -t"; # Use tab instead of 4 spaces
640 14         31
641 14 100       58 my $error = Perl::Tidy::perltidy(
642 6         11 argv => $argv,
643             source => \$source,
644 14 100       43 destination => \$dest_string,
645 2 50       9 stderr => \$stderr_string,
646 2         7 errorfile => \$errorfile_string, # ignored when -se flag is set
647             ##phasers => 'stun', # uncomment to trigger an error
648 14         52 );
649 26 100       96
  6         21  
650             if ($error) {
651 26 100       90 # serious error in input parameters, no tidied output
  2         6  
  1         4  
652 26         716 print "<<STDERR>>\n$stderr_string\n";
653 26         168 die "Exiting because of serious errors\n";
654             }
655              
656             return $dest_string;
657 26     26 0 67 }
658              
659 26         101 1;
660              
661 26         0  
662 26         59 =head1 NAME
663 26         76  
664 26         53 MooX::Purple - MooX::Purple::G
665 26         52  
666 26         59 =head1 VERSION
667 26         45  
668             Version 0.19
669 26         208  
670             =cut
671              
672             =head1 SYNOPSIS
673              
674             use MooX::Purple;
675             use MooX::Purple::G;
676              
677             role Before {
678 26 50       3770547 public seven { return '7' }
679             };
680 0         0  
681 0         0 role World allow Hello with Before {
682             private six { 'six' }
683             };
684 26         938  
685             class Hello with qw/World/ allow qw/main/ use Scalar::Util qw/reftype/ use qw/JSON/ {
686             use Types::Standard qw/Str HashRef ArrayRef Object/;
687              
688             attributes
689             one => [{ okay => 'one'}],
690             [qw/two three/] => [rw, Str, { default => 'the world is flat' }];
691              
692             validate_subs
693             four => {
694             params => {
695             message => [Str, sub {'four'}]
696             }
697             };
698              
699             public four { return $_[1]->{message} }
700             private five { return $_[0]->six }
701             public ten { reftype bless {}, 'Flat::World' }
702             public eleven { encode_json { flat => "world" } }
703             };
704              
705             class Night is qw/Hello/ {
706             public nine { return 'nine' }
707             };
708              
709             Night->new()->five();
710              
711             ... writes to same/path/yourfile.pmc
712              
713             {
714             package Before;
715             use Moo::Role;
716              
717             sub seven { return '7' }
718             };
719              
720             {
721             package World;
722             use Moo::Role;
723             with qw/Before/;
724              
725             sub six {
726             my $caller = caller();
727             my @allowed = qw(Hello);
728             unless ($caller eq __PACKAGE__ || grep { $_ eq $caller } @allowed) {
729             die "cannot call private method six from $caller";
730             }
731             'six'
732             }
733             };
734              
735             {
736             package Hello;
737             use Moo;
738             use MooX::LazierAttributes;
739             use MooX::ValidateSubs;
740             with qw/World/;
741             use Scalar::Util qw/reftype/ ;
742             use JSON;
743              
744             use Types::Standard qw/Str HashRef ArrayRef Object/;
745              
746             attributes
747             one => [{ okay => 'one'}],
748             [qw/two three/] => [rw, Str, { default => 'the world is flat' }];
749              
750             validate_subs
751             four => {
752             params => {
753             message => [Str, sub {'four'}]
754             }
755             };
756              
757             sub four { return $_[1]->{message} }
758             sub five {
759             my $caller = caller();
760             my @allowed = qw(main);
761             unless ($caller eq __PACKAGE__ || grep { $_ eq $caller } @allowed) {
762             die "cannot call private method five from $caller";
763             }
764             return $_[0]->six
765             }
766             sub ten { reftype bless {}, 'Flat::World' }
767             sub eleven { encode_json { flat => "world" } }
768             1;
769             };
770              
771             {
772             package Night;
773             use Moo;
774             use MooX::LazierAttributes;
775             use MooX::ValidateSubs;
776             extends qw/Hello/;
777              
778             sub nine { return 'nine' }
779             1;
780             };
781              
782              
783             =head1 AUTHOR
784              
785             lnation, C<< <thisusedtobeanemail at gmail.com> >>
786              
787             =head1 BUGS
788              
789             Please report any bugs or feature requests to C<bug-moox-purple at rt.cpan.org>, or through
790             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooX-Purple>. I will be notified, and then you'll
791             automatically be notified of progress on your bug as I make changes.
792              
793             =head1 SUPPORT
794              
795             You can find documentation for this module with the perldoc command.
796              
797             perldoc MooX::Purple
798              
799              
800             You can also look for information at:
801              
802             =over 4
803              
804             =item * RT: CPAN's request tracker (report bugs here)
805              
806             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Purple>
807              
808             =item * AnnoCPAN: Annotated CPAN documentation
809              
810             L<http://annocpan.org/dist/MooX-Purple>
811              
812             =item * CPAN Ratings
813              
814             L<http://cpanratings.perl.org/d/MooX-Purple>
815              
816             =item * Search CPAN
817              
818             L<http://search.cpan.org/dist/MooX-Purple/>
819              
820             =back
821              
822              
823             =head1 ACKNOWLEDGEMENTS
824              
825              
826             =head1 LICENSE AND COPYRIGHT
827              
828             Copyright 2019 lnation.
829              
830             This program is free software; you can redistribute it and/or modify it
831             under the terms of the the Artistic License (2.0). You may obtain a
832             copy of the full license at:
833              
834             L<http://www.perlfoundation.org/artistic_license_2_0>
835              
836             Any use, modification, and distribution of the Standard or Modified
837             Versions is governed by this Artistic License. By using, modifying or
838             distributing the Package, you accept this license. Do not use, modify,
839             or distribute the Package, if you do not accept this license.
840              
841             If your Modified Version has been derived from a Modified Version made
842             by someone other than you, you are nevertheless required to ensure that
843             your Modified Version complies with the requirements of this license.
844              
845             This license does not grant you the right to use any trademark, service
846             mark, tradename, or logo of the Copyright Holder.
847              
848             This license includes the non-exclusive, worldwide, free-of-charge
849             patent license to make, have made, use, offer to sell, sell, import and
850             otherwise transfer the Package with respect to any patent claims
851             licensable by the Copyright Holder that are necessarily infringed by the
852             Package. If you institute patent litigation (including a cross-claim or
853             counterclaim) against any party alleging that the Package constitutes
854             direct or contributory patent infringement, then this Artistic License
855             to you shall terminate on the date that such litigation is filed.
856              
857             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
858             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
859             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
860             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
861             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
862             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
863             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
864             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
865              
866              
867              
868             1; # End of MooX::Purple