File Coverage

blib/lib/MooX/Purple.pm
Criterion Covered Total %
statement 344 545 63.1
branch 40 64 62.5
condition 27 60 45.0
subroutine 39 40 97.5
pod n/a
total 450 709 63.4


line stmt bran cond sub pod time code
1              
2             use 5.006;
3 12     12   692228 use strict;
  12         132  
4 12     12   58 use warnings;
  12         19  
  12         262  
5 12     12   82 our $VERSION = '0.19';
  12         39  
  12         514  
6             use Keyword::Declare;
7 12     12   9290 our ($PREFIX, %MACROS);
  12         1150735  
  12         114  
8              
9             my ($class, %args) = @_;
10 0         0 $PREFIX = $args{-prefix} unless $PREFIX;
11 14     14   975 keytype GATTRS is m{
12 14 100       65 (?:
  14         24  
13 12     12   299766 allow (?&PerlNWS)
14             (?:(?!qw)(?&PerlQualifiedIdentifier)|
15             (?&PerlList))
16             |
17             with (?&PerlNWS)
18             (?:(?!qw)(?&PerlPrefixUnaryOperator)*(?&PerlQualifiedIdentifier)|
19             (?&PerlList))
20             |
21             is (?&PerlNWS)
22             (?:(?!qw)(?&PerlPrefixUnaryOperator)*(?&PerlQualifiedIdentifier)|
23             (?&PerlList))
24             |
25             use (?&PerlNWS)
26             (?:(?&PerlQualifiedIdentifier)\s*(?&PerlList)|(?:(?!qw)(?&PerlQualifiedIdentifier)|
27             (?&PerlList)))
28             )?+
29             }xms;
30             keytype SATTRS is m{
31 14         25 (?:
32 12     12   295163 allow (?&PerlNWS)
33             (?:(?!qw)(?&PerlQualifiedIdentifier)|
34             (?&PerlList))
35             |
36             )?+
37             }xms;
38             keytype PATTRS is m{
39 14         22 (?:
40 12     12   286187 describe (?&PerlNWS)
41             (?:(?&PerlString))
42             )?+
43             }xms;
44             keyword role (QualIdent $class, GATTRS @roles, Block $block) {
45 14         18 _handle_role($class, $block, @roles)
46 0 50 50 7   0 }
  0         0  
  0         0  
  14         209  
  7         579200  
  7         17  
  7         20  
47 0         0 keyword role (PrefixUnaryOperator $pre, QualIdent $class, GATTRS @roles, Block $block) {
  14         115  
  7         19  
48 0         0 $class = $PREFIX . '::' . $class if $pre;
  7         138  
  14         297  
49 0 50 50 9   0 _handle_role($class, $block, @roles)
  0         0  
  0         0  
  14         180  
  9         689038  
  9         21  
  9         25  
50 0         0 }
  0         0  
  0         0  
  7         288  
  7         13  
  14         55  
  9         20  
51 0         0 keyword class (QualIdent $class, GATTRS @roles, Block $block) {
  0         0  
  7         18  
  9         193  
52 0   0     0 _handle_class($class, $block, @roles);
  7   100     89436  
  14         297  
53 0 50 50 12   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  9         316  
  9         21  
  14         125  
  12         1676399  
  12         35  
  12         31  
54 0         0 keyword class (PrefixUnaryOperator $pre, QualIdent $class, GATTRS @roles, Block $block) {
  0         0  
  9         22  
  14         50  
  12         35  
55 0         0 $class = $PREFIX . '::' . $class if $pre;
  0         0  
  9         152  
  12         238  
  14         265  
56 0 50 50 6   0 _handle_class($class, $block, @roles);
  0         0  
  0         0  
  14         118  
  6         618742  
  6         17  
  6         16  
57 0         0 }
  0         0  
  0         0  
  0         0  
  0         0  
  9         169  
  9         15  
  12         496  
  12         27  
  14         228  
  6         13  
58 0         0 keyword class (PrefixUnaryOperator $pre, QualIdent $class, Block $block) {
  0         0  
  0         0  
  9         22  
  12         27  
  6         137  
59 0   0     0 $class = $PREFIX . '::' . $class if $pre;
  0   0     0  
  9   33     58  
  12   100     198242  
  14         263  
60 0 50 50 0   0 _handle_class($class, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  6         213  
  6         15  
  14         131  
  0         0  
  0         0  
  0         0  
61 0         0 }
  0         0  
  6         15  
  14         49  
  0         0  
62 0         0 keyword macro (Ident $macro, Block $block) {
  0         0  
  6         102  
  0         0  
63 14         253 return _handle_macro($macro, $block);
64 0 50 50 2   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  6         119  
  6         15  
  0         0  
  0         0  
  14         114  
  2         228260  
  2         6  
  2         6  
65 0         0 keyword private (Ident $method, SATTRS @roles, Block $block) {
  0         0  
  0         0  
  6         13  
  0         0  
  14         47  
  2         5  
66 0   0     0 return _handle_private($method, $block, @roles);
  0   100     0  
  0         0  
  6         108925  
  0         0  
  2         35  
  14         254  
67 0 50 50 6   0 }
  0         0  
  0         0  
  14         106  
  6         305625  
  6         17  
  6         123  
68 0         0 keyword public (Ident $method, Block $block, PATTRS @pod) {
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         67  
  2         4  
  14         56  
  6         17  
69 0         0 return _handle_public($method, $block, @pod);
  0         0  
  0         0  
  0         0  
  2         6  
  6         210  
  14         262  
70 0 50 50 29   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         26  
  14         110  
  29         2236518  
  29         71  
  29         73  
71 0         0 keyword start (Ident $method, Block $block) {
  0         0  
  0         0  
  0         0  
  12         182548  
  6         259  
  6         13  
  14         61  
  29         81  
72 0         0 return _handle_when('-', $method, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  2         33  
  6         13  
  29         560  
  14         265  
73 0 0 0 1   0 }
  0 0 66     0  
  0 50 50     0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         11  
  6         133285  
  14         112  
  1         51006  
  1         2  
  1         3  
74 0         0 keyword during (Ident $method, Block $block) {
  0         0  
  12         83  
  0         0  
  0         0  
  0         0  
  7         90094  
  0         0  
  14         70  
  29         911  
  29         73  
  14         46  
  1         3  
75 12         95 return _handle_when('~', $method, $block);
  0         0  
  0         0  
  14         78  
  14         358  
  29         475  
  1         22  
  14         264  
76 0 50 50 12   0 }
  0     1   0  
  12         342755  
  0         0  
  0         0  
  0         0  
  0         0  
  7         19  
  7         21  
  14         398  
  29         749  
  14         109  
  1         50025  
  1         2  
  1         4  
77 0     12   0 keyword trigger (Ident $method, Block $block) {
  12         351610  
  0         0  
  0         0  
  0         0  
  7         361  
  1         32  
  1         3  
  14         44  
  1         2  
78 0         0 return _handle_when('=', $method, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  7         182  
  0         0  
  25         356899  
  29         504  
  29         57  
  1         2  
  1         19  
  14         282  
79 0 50 50 1   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  29         69  
  1         14  
  14         108  
  1         52318  
  1         3  
  1         2  
80 0   0     0 keyword end (Ident $method, Block $block) {
  0   100     0  
  0         0  
  0         0  
  0         0  
  7         121  
  29         44517  
  1         35  
  1         3  
  14         49  
  1         3  
81 0         0 return _handle_when('+', $method, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  7         39  
  9         25  
  12         197798  
  12         134528  
  1         18  
  1         3  
  1         21  
  14         276  
82 12 50 50 1   94 }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  14         107  
  1         5  
  1         12  
  14         105  
  1         49835  
  1         3  
  1         3  
83 0         0 }
  0         0  
  0         0  
  0         0  
  12         78  
  0         0  
  0         0  
  0         0  
  14         586  
  9         17  
  9         17  
  12         33  
  12         35  
  14         90  
  1         31  
  1         2  
  14         73  
  1         2  
84 12     12   334909  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  9         481  
  12         666  
  6         134624  
  14         371  
  1         18  
  1         3  
  1         19  
85 0     12   0 my ($macro, $block) = @_;
  0         0  
  0         0  
  12         351623  
  0         0  
  0         0  
  9         105  
  12         292  
  10         114199  
  1         4  
  1         14  
86 0         0 $block =~ s/^\n*\{\n*\s*|;\n*\t*\}\n*$//g;
  0         0  
  0         0  
  12         75  
  0         0  
  0         0  
  6         16  
  6         24  
  4         44180  
  14         72  
  1         33  
  1         3  
87 0         0 $MACROS{$macro} = $block;
  0         0  
  0         0  
  0         0  
  0         0  
  9         116  
  12         216  
  6         24  
  14         380  
  1         18  
  1         3  
88 0 0   12   0 return '';
  0 50   2   0  
  0         0  
  0         0  
  12         345317  
  0         0  
  0         0  
  9         110  
  12         70  
  6         111991  
  6         256  
  1         5  
  1         14  
  2         8  
89 0         0 }
  12         83  
  0         0  
  12         78  
  9         194  
  14         84  
  29         46404  
  14         73  
  2         10  
90 12         85  
  0         0  
  0         0  
  0         0  
  0         0  
  14         87  
  14         420  
  6         20  
  6         24  
  6         236  
  14         370  
  1         17  
  2         33  
91 12     12   348246 my ($method, $block) = @_;
  0     12   0  
  0         0  
  0         0  
  12         352236  
  0         0  
  14         480  
  6         224  
  6         36  
  29         54  
  1         5  
  2         16  
92 12     12   352960 my $mac = join '|', keys %MACROS;
  0         0  
  12         92  
  0         0  
  12         96  
  6         252  
  14         78  
  29         174  
  14         69  
93 12         128 $block =~ s/&($mac)/$MACROS{$1}/g;
  14         404  
  14         72  
  14         387  
94 0     12   0 $block =~ s/(^{)|(}$)//g;
  12     12   350372  
  12         349562  
  6         142  
  14         467  
95 0 0   12   0 return "sub $method {
  12 50   29   355375  
  6         63  
  29         98  
96 0         0 my (\$self) = shift;
  6         129  
  29         124  
97 12         88 $block
  14         137  
  29         325  
98 14         461 }";
  29         233  
99 12     12   360235 }
  29         340  
100              
101             my ($method, $block, @roles) = @_;
102             my %attrs = _parse_role_attrs(@roles);
103             my $allowed = $attrs{allow} ? sprintf 'qw(%s)', join ' ', @{$attrs{allow}} : 'qw//';
104             my $mac = join '|', keys %MACROS;
105             $block =~ s/&($mac)/$MACROS{$1}/g;
106 6     6   26 $block =~ s/(^{)|(}$)//g;
107 6         31 return "sub $method {
108 6 50       35 my (\$self) = shift;
  6         45  
109 6         28 my \$caller = caller();
110 6         91 my \@allowed = $allowed;
111 6         45 unless (\$caller eq __PACKAGE__ || grep { \$_ eq \$caller } \@allowed) {
112 6         89 die \"cannot call private method $method from \$caller\";
113             }
114             $block
115             }";
116             }
117              
118             my ($pre, $method, $block) = @_;
119             my %map = (
120             '-' => 'before',
121             '+' => 'after',
122             '~' => 'around',
123             '=' => 'around'
124 4     4   18 );
125 4         32 $block =~ s/(^{)|(}$)//g;
126             if ($pre eq '~') {
127             $block = "{
128             my (\$orig, \$self) = (shift, shift);
129             $block;
130             }";
131 4         22 } elsif ($pre eq '=') {
132 4 100       76 $block = "{
    100          
133 1         5 my (\$orig, \$self) = (shift, shift);
134             my \$out = \$self->\$orig(\@_);
135             $block;
136             }";
137             } else {
138 1         4 $block = "{
139             my (\$self) = (shift);
140             $block;
141             }"
142             }
143             return "$map{$pre} $method => sub $block;";
144 2         7 }
145              
146             my ($class, $block, @roles) = @_;
147             my ($body, %attrs) = _set_class_role_attrs($block, _parse_role_attrs(@roles));
148             my $out = qq|{
149 4         18 package $class;
150             use Moo;
151             use MooX::LazierAttributes;
152             use MooX::ValidateSubs;
153 18     18   71 use Data::LnArray qw/arr/;
154 18         94 $attrs{is}
155 18         232 $attrs{with}
156             $attrs{use}
157             $body
158             1;
159             }|;
160             return $out;
161             }
162              
163             my ($class, $block, @roles) = @_;
164             my ($body, %attrs) = _set_class_role_attrs($block, _parse_role_attrs(@roles));
165             return qq|{
166             package $class;
167 18         285 use Moo::Role;
168             use MooX::LazierAttributes;
169             use MooX::ValidateSubs;
170             use Data::LnArray qw/arr/;
171 16     16   64 $attrs{with}
172 16         77 $attrs{use}
173 16         252 $body
174             1;
175             }|;
176             }
177              
178             my @roles = @_;
179             my %attrs;
180             my $i = 0;
181             for (@roles) {
182             if ($_ =~ m/\s*use\s*((?!qw)(?&PerlQualifiedIdentifier))\s*((?&PerlList)) $PPR::GRAMMAR/xms) {
183             $attrs{use}{sprintf "%s %s", $1, $2}++;
184             next;
185             }
186             $_ =~ m/(with|allow|is|use)(.*)/i;
187 40     40   115 my @list = eval($2); # || $2
188 40         86 push @list, $2 unless @list;
189 40         132 for (@list) {
190 40         193 $attrs{$1}{$_} = $i++;
191 59 100       1285013 }
192 2         26 }
193 2         264 for my $o (qw/with allow is use/) {
194             $attrs{$o} = [sort { $attrs{$o}{$a} <=> $attrs{$o}{$b} } keys %{$attrs{$o}}] if $attrs{$o};
195 57         7667 }
196 57         8050 return %attrs;
197 57 100       431 }
198 57         165  
199 73         525 =pod todo uncomment and remove above hack
200             sub _parse_role_attrs {
201             my @roles = @_;
202 40         128 my %attrs;
203 160 100       450 for (@roles) {
  15         46  
  32         215  
204             if ($_ =~ m/\s*use\s*((?!qw)(?&PerlQualifiedIdentifier))\s*((?&PerlList)) $PPR::GRAMMAR/xms) {
205 40         254 push @{$attrs{use}}, sprintf "%s %s", $1, $2;
206             next;
207             }
208             $_ =~ m/(with|allow|is|use)(.*)/i;
209             push @{$attrs{$1}}, eval($2) || $2;
210             }
211             return %attrs;
212             }
213             =cut
214              
215             my ($body, %attrs, %args) = @_;
216             if ($attrs{allow}) {
217             my $allow = join ' ', @{$attrs{allow}};
218             $body =~ s{private\s*(\p{XIDS}\p{XIDC}*)}{private $1 allow qw/$allow/}g;
219             }
220             $attrs{is} = $attrs{is} ? sprintf "extends qw/%s/;\n", join(' ', map { my $l = $_; $l =~ s/^\s*\+/$PREFIX\:\:/; $l; } @{$attrs{is}}) : '';
221             my $last;
222             $attrs{with} = $attrs{with}
223             ? sprintf "with qw/%s/;\n", join(' ', map {
224             my $l = $_;
225 34     34   143 $l =~ s/^\s*\+/$PREFIX\:\:/;
226 34 100       136 unless($l =~ s/^\s*\-/$last\:\:/) {
227 6         13 $last = $l;
  6         27  
228 6         86 }
229             if ($l =~ s/^\s*\~//) {
230 34 100       195 $last = $PREFIX ? ($PREFIX . '::' . $l) : $l;
  7         18  
  7         40  
  7         53  
  7         30  
231 34         77 $l = '';
232             }
233             $l;
234 20         36 } @{$attrs{with}})
235 20         66 : '';
236 20 100       83 $attrs{use} = $attrs{use} ? join('', map { sprintf("use %s;\n", $_) } @{$attrs{use}}) : '';
237 12         25 $body =~ s/(^{)|(}$)//g;
238             return $body, %attrs;
239 20 100       75 }
240 2 50       11  
241 2         5 1;
242              
243 20         95  
244 34 100       140 =head1 NAME
  11         31  
245              
246 34 100       144 MooX::Purple - MooX::Purple
  4         15  
  2         5  
247 34         902  
248 34         238 =head1 VERSION
249              
250             Version 0.19
251              
252             =cut
253              
254             =head1 SYNOPSIS
255              
256             use MooX::Purple;
257              
258             role Before {
259             public seven { return '7' }
260             };
261              
262             role World allow Hello with Before {
263             private six { 'six' }
264             };
265              
266             class Hello with qw/World/ allow qw/main/ use Scalar::Util qw/reftype/ use qw/JSON/ {
267             use Types::Standard qw/Str HashRef ArrayRef Object/;
268              
269             attributes
270             one => [{ okay => 'one'}],
271             [qw/two three/] => [rw, Str, { default => 'the world is flat' }];
272              
273             validate_subs
274             four => {
275             params => {
276             message => [Str, sub {'four'}]
277             }
278             };
279              
280             public four { return $_[1]->{message} }
281             private five { return $_[0]->six }
282             public ten { reftype bless {}, 'Flat::World' }
283             public eleven { encode_json { flat => "world" } }
284             };
285              
286             class Night is qw/Hello/ {
287             public nine { return 'nine' }
288             };
289              
290             Night->new()->five();
291              
292             ...
293              
294             # ../Foo.pm
295             package Foo;
296             use MooX::Purple -prefix => 'Foo';
297             use Foo::Roles;
298             class +Class with qw/~Role -One -Two -Three -Four/ {
299             public print {
300             return $_[1];
301             }
302             }
303            
304             # ../Foo/Roles.pm
305             package Foo::Roles;
306             use MooX::Purple;
307             role +Role::One {
308             public one {
309             $_[0]->print(1);
310             }
311             }
312             role +Role::Two {
313             public two {
314             $_[0]->print(2);
315             }
316             }
317             role +Role::Three {
318             public three {
319             $_[0]->print(3);
320             }
321             }
322             role +Role::Four {
323             public four {
324             $_[0]->print(4);
325             }
326             }
327              
328             ...
329              
330             use MooX::Purple -prefix => 'Macro';
331              
332             class +Simple {
333             macro generic {
334             'crazy';
335             };
336             macro second {
337             my $x = 0;
338             $x++ for (0..100);
339             return $x;
340             };
341             public one { &generic; }
342            
343             start one {
344             print "before\n";
345             }
346            
347             during one {
348             print "around\n";
349             $self->$orig();
350             };
351              
352             trigger one {
353             print "trigger\n";
354             return 'insane';
355             }
356              
357             end one {
358             print "after\n";
359             }
360              
361             public two {
362             print &generic
363             &second;
364             } describe "Add Documentation for method 'two'"
365             };
366              
367             class +Inherit is +Simple {};
368              
369              
370              
371             =head1 AUTHOR
372              
373             lnation, C<< <thisusedtobeanemail at gmail.com> >>
374              
375             =head1 BUGS
376              
377             Please report any bugs or feature requests to C<bug-moox-purple at rt.cpan.org>, or through
378             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooX-Purple>. I will be notified, and then you'll
379             automatically be notified of progress on your bug as I make changes.
380              
381             =head1 SUPPORT
382              
383             You can find documentation for this module with the perldoc command.
384              
385             perldoc MooX::Purple
386              
387              
388             You can also look for information at:
389              
390             =over 4
391              
392             =item * RT: CPAN's request tracker (report bugs here)
393              
394             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooX-Purple>
395              
396             =item * AnnoCPAN: Annotated CPAN documentation
397              
398             L<http://annocpan.org/dist/MooX-Purple>
399              
400             =item * CPAN Ratings
401              
402             L<http://cpanratings.perl.org/d/MooX-Purple>
403              
404             =item * Search CPAN
405              
406             L<http://search.cpan.org/dist/MooX-Purple/>
407              
408             =back
409              
410              
411             =head1 ACKNOWLEDGEMENTS
412              
413              
414             =head1 LICENSE AND COPYRIGHT
415              
416             Copyright 2019 lnation.
417              
418             This program is free software; you can redistribute it and/or modify it
419             under the terms of the the Artistic License (2.0). You may obtain a
420             copy of the full license at:
421              
422             L<http://www.perlfoundation.org/artistic_license_2_0>
423              
424             Any use, modification, and distribution of the Standard or Modified
425             Versions is governed by this Artistic License. By using, modifying or
426             distributing the Package, you accept this license. Do not use, modify,
427             or distribute the Package, if you do not accept this license.
428              
429             If your Modified Version has been derived from a Modified Version made
430             by someone other than you, you are nevertheless required to ensure that
431             your Modified Version complies with the requirements of this license.
432              
433             This license does not grant you the right to use any trademark, service
434             mark, tradename, or logo of the Copyright Holder.
435              
436             This license includes the non-exclusive, worldwide, free-of-charge
437             patent license to make, have made, use, offer to sell, sell, import and
438             otherwise transfer the Package with respect to any patent claims
439             licensable by the Copyright Holder that are necessarily infringed by the
440             Package. If you institute patent litigation (including a cross-claim or
441             counterclaim) against any party alleging that the Package constitutes
442             direct or contributory patent infringement, then this Artistic License
443             to you shall terminate on the date that such litigation is filed.
444              
445             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
446             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
447             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
448             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
449             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
450             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
451             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
452             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
453              
454              
455             =cut
456              
457             1; # End of MooX::Purple