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   637915 use strict;
  12         128  
4 12     12   47 use warnings;
  12         17  
  12         224  
5 12     12   51 our $VERSION = '0.17';
  12         24  
  12         458  
6             use Keyword::Declare;
7 12     12   8603 our ($PREFIX, %MACROS);
  12         1110438  
  12         109  
8              
9             my ($class, %args) = @_;
10 0         0 $PREFIX = $args{-prefix} unless $PREFIX;
11 14     14   1185 keytype GATTRS is m{
12 14 100       136 (?:
  14         27  
13 12     12   288371 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         19 (?:
32 12     12   276733 allow (?&PerlNWS)
33             (?:(?!qw)(?&PerlQualifiedIdentifier)|
34             (?&PerlList))
35             |
36             )?+
37             }xms;
38             keytype PATTRS is m{
39 14         22 (?:
40 12     12   267173 describe (?&PerlNWS)
41             (?:(?&PerlString))
42             )?+
43             }xms;
44             keyword role (QualIdent $class, GATTRS @roles, Block $block) {
45 14         22 _handle_role($class, $block, @roles)
46 0 50 50 7   0 }
  0         0  
  0         0  
  14         232  
  7         513586  
  7         15  
  7         17  
47 0         0 keyword role (PrefixUnaryOperator $pre, QualIdent $class, GATTRS @roles, Block $block) {
  14         71  
  7         17  
48 0         0 $class = $PREFIX . '::' . $class if $pre;
  7         123  
  14         322  
49 0 50 50 9   0 _handle_role($class, $block, @roles)
  0         0  
  0         0  
  14         130  
  9         704523  
  9         23  
  9         25  
50 0         0 }
  0         0  
  0         0  
  7         196  
  7         13  
  14         48  
  9         20  
51 0         0 keyword class (QualIdent $class, GATTRS @roles, Block $block) {
  0         0  
  7         17  
  9         182  
52 0   0     0 _handle_class($class, $block, @roles);
  7   100     79448  
  14         281  
53 0 50 50 12   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  9         332  
  9         21  
  14         135  
  12         1577643  
  12         32  
  12         36  
54 0         0 keyword class (PrefixUnaryOperator $pre, QualIdent $class, GATTRS @roles, Block $block) {
  0         0  
  9         28  
  14         52  
  12         36  
55 0         0 $class = $PREFIX . '::' . $class if $pre;
  0         0  
  9         180  
  12         235  
  14         238  
56 0 50 50 6   0 _handle_class($class, $block, @roles);
  0         0  
  0         0  
  14         145  
  6         580024  
  6         18  
  6         20  
57 0         0 }
  0         0  
  0         0  
  0         0  
  0         0  
  9         161  
  9         19  
  12         390  
  12         27  
  14         236  
  6         12  
58 0         0 keyword class (PrefixUnaryOperator $pre, QualIdent $class, Block $block) {
  0         0  
  0         0  
  9         20  
  12         26  
  6         130  
59 0   0     0 $class = $PREFIX . '::' . $class if $pre;
  0   0     0  
  9   33     71  
  12   100     179644  
  14         234  
60 0 50 50 0   0 _handle_class($class, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  6         202  
  6         14  
  14         124  
  0         0  
  0         0  
  0         0  
61 0         0 }
  0         0  
  6         15  
  14         48  
  0         0  
62 0         0 keyword macro (Ident $macro, Block $block) {
  0         0  
  6         92  
  0         0  
63 14         231 return _handle_macro($macro, $block);
64 0 50 50 2   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  6         101  
  6         13  
  0         0  
  0         0  
  14         112  
  2         220283  
  2         4  
  2         4  
65 0         0 keyword private (Ident $method, SATTRS @roles, Block $block) {
  0         0  
  0         0  
  6         13  
  0         0  
  14         60  
  2         6  
66 0   0     0 return _handle_private($method, $block, @roles);
  0   100     0  
  0         0  
  6         107362  
  0         0  
  2         29  
  14         230  
67 0 50 50 6   0 }
  0         0  
  0         0  
  14         140  
  6         279785  
  6         18  
  6         18  
68 0         0 keyword public (Ident $method, Block $block, PATTRS @pod) {
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         54  
  2         5  
  14         62  
  6         16  
69 0         0 return _handle_public($method, $block, @pod);
  0         0  
  0         0  
  0         0  
  2         4  
  6         175  
  14         234  
70 0 50 50 29   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         21  
  14         111  
  29         2137774  
  29         175  
  29         137  
71 0         0 keyword start (Ident $method, Block $block) {
  0         0  
  0         0  
  0         0  
  12         160773  
  6         408  
  6         16  
  14         46  
  29         76  
72 0         0 return _handle_when('-', $method, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  2         68  
  6         13  
  29         609  
  14         244  
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         116911  
  14         111  
  1         48598  
  1         2  
  1         2  
74 0         0 keyword during (Ident $method, Block $block) {
  0         0  
  12         115  
  0         0  
  0         0  
  0         0  
  7         79421  
  0         0  
  14         74  
  29         960  
  29         69  
  14         50  
  1         19  
75 12         83 return _handle_when('~', $method, $block);
  0         0  
  0         0  
  14         73  
  14         356  
  29         551  
  1         20  
  14         245  
76 0 50 50 12   0 }
  0     1   0  
  12         333744  
  0         0  
  0         0  
  0         0  
  0         0  
  7         17  
  7         15  
  14         396  
  29         402  
  14         132  
  1         46262  
  1         2  
  1         2  
77 0     12   0 keyword trigger (Ident $method, Block $block) {
  12         338955  
  0         0  
  0         0  
  0         0  
  7         336  
  1         28  
  1         2  
  14         49  
  1         3  
78 0         0 return _handle_when('=', $method, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  7         159  
  0         0  
  25         344154  
  29         507  
  29         56  
  1         3  
  1         16  
  14         251  
79 0 50 50 1   0 }
  0         0  
  0         0  
  0         0  
  0         0  
  29         62  
  1         11  
  14         107  
  1         48337  
  1         3  
  1         3  
80 0   0     0 keyword end (Ident $method, Block $block) {
  0   100     0  
  0         0  
  0         0  
  0         0  
  7         107  
  29         40220  
  1         27  
  1         2  
  14         46  
  1         3  
81 0         0 return _handle_when('+', $method, $block);
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  7         33  
  9         24  
  12         184030  
  12         119525  
  1         16  
  1         2  
  1         17  
  14         249  
82 12 50 50 1   120 }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  14         112  
  1         4  
  1         12  
  14         104  
  1         45855  
  1         2  
  1         2  
83 0         0 }
  0         0  
  0         0  
  0         0  
  12         255  
  0         0  
  0         0  
  0         0  
  14         591  
  9         18  
  9         23  
  12         34  
  12         49  
  14         86  
  1         29  
  1         2  
  14         41  
  1         3  
84 12     12   335720  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  9         548  
  12         706  
  6         118729  
  14         448  
  1         15  
  1         3  
  1         16  
85 0     12   0 my ($macro, $block) = @_;
  0         0  
  0         0  
  12         330542  
  0         0  
  0         0  
  9         165  
  12         348  
  10         109467  
  1         4  
  1         11  
86 0         0 $block =~ s/^\n*\{\n*\s*|;\n*\t*\}\n*$//g;
  0         0  
  0         0  
  12         74  
  0         0  
  0         0  
  6         18  
  6         19  
  4         41640  
  14         71  
  1         28  
  1         2  
87 0         0 $MACROS{$macro} = $block;
  0         0  
  0         0  
  0         0  
  0         0  
  9         108  
  12         215  
  6         23  
  14         359  
  1         15  
  1         2  
88 0 0   12   0 return '';
  0 50   2   0  
  0         0  
  0         0  
  12         328948  
  0         0  
  0         0  
  9         120  
  12         66  
  6         106952  
  6         293  
  1         4  
  1         12  
  2         6  
89 0         0 }
  12         88  
  0         0  
  12         127  
  9         175  
  14         81  
  29         41786  
  14         72  
  2         8  
90 12         75  
  0         0  
  0         0  
  0         0  
  0         0  
  14         96  
  14         415  
  6         21  
  6         21  
  6         234  
  14         367  
  1         15  
  2         31  
91 12     12   340124 my ($method, $block) = @_;
  0     12   0  
  0         0  
  0         0  
  12         325065  
  0         0  
  14         533  
  6         241  
  6         37  
  29         56  
  1         5  
  2         13  
92 12     12   327858 my $mac = join '|', keys %MACROS;
  0         0  
  12         79  
  0         0  
  12         94  
  6         274  
  14         79  
  29         187  
  14         66  
93 12         90 $block =~ s/&($mac)/$MACROS{$1}/g;
  14         393  
  14         76  
  14         357  
94 0     12   0 $block =~ s/(^{)|(}$)//g;
  12     12   342561  
  12         327835  
  6         144  
  14         388  
95 0 0   12   0 return "sub $method {
  12 50   29   333353  
  6         72  
  29         90  
96 0         0 my (\$self) = shift;
  6         203  
  29         128  
97 12         89 $block
  14         149  
  29         334  
98 14         439 }";
  29         240  
99 12     12   367848 }
  29         342  
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         33 return "sub $method {
108 6 50       33 my (\$self) = shift;
  6         39  
109 6         28 my \$caller = caller();
110 6         87 my \@allowed = $allowed;
111 6         47 unless (\$caller eq __PACKAGE__ || grep { \$_ eq \$caller } \@allowed) {
112 6         81 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   13 );
125 4         29 $block =~ s/(^{)|(}$)//g;
126             if ($pre eq '~') {
127             $block = "{
128             my (\$orig, \$self) = (shift, shift);
129             $block;
130             }";
131 4         17 } elsif ($pre eq '=') {
132 4 100       63 $block = "{
    100          
133 1         4 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         16 package $class;
150             use Moo;
151             use MooX::LazierAttributes;
152             use MooX::ValidateSubs;
153 18     18   75 use Data::LnArray qw/arr/;
154 18         91 $attrs{is}
155 18         236 $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         310 use Moo::Role;
168             use MooX::LazierAttributes;
169             use MooX::ValidateSubs;
170             use Data::LnArray qw/arr/;
171 16     16   68 $attrs{with}
172 16         78 $attrs{use}
173 16         226 $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   126 my @list = eval($2); # || $2
188 40         100 push @list, $2 unless @list;
189 40         96 for (@list) {
190 40         130 $attrs{$1}{$_} = $i++;
191 59 100       1170987 }
192 2         38 }
193 2         714 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         13308 }
196 57         8566 return %attrs;
197 57 100       391 }
198 57         187  
199 73         558 =pod todo uncomment and remove above hack
200             sub _parse_role_attrs {
201             my @roles = @_;
202 40         190 my %attrs;
203 160 100       402 for (@roles) {
  19         50  
  32         197  
204             if ($_ =~ m/\s*use\s*((?!qw)(?&PerlQualifiedIdentifier))\s*((?&PerlList)) $PPR::GRAMMAR/xms) {
205 40         311 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   137 $l =~ s/^\s*\+/$PREFIX\:\:/;
226 34 100       140 unless($l =~ s/^\s*\-/$last\:\:/) {
227 6         15 $last = $l;
  6         27  
228 6         76 }
229             if ($l =~ s/^\s*\~//) {
230 34 100       175 $last = $PREFIX ? ($PREFIX . '::' . $l) : $l;
  7         17  
  7         37  
  7         51  
  7         24  
231 34         74 $l = '';
232             }
233             $l;
234 20         34 } @{$attrs{with}})
235 20         53 : '';
236 20 100       81 $attrs{use} = $attrs{use} ? join('', map { sprintf("use %s;\n", $_) } @{$attrs{use}}) : '';
237 12         23 $body =~ s/(^{)|(}$)//g;
238             return $body, %attrs;
239 20 100       70 }
240 2 50       11  
241 2         5 1;
242              
243 20         83  
244 34 100       155 =head1 NAME
  11         40  
245              
246 34 100       146 MooX::Purple - MooX::Purple
  4         14  
  2         7  
247 34         808  
248 34         231 =head1 VERSION
249              
250             Version 0.17
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