File Coverage

blib/lib/Mars/Role.pm
Criterion Covered Total %
statement 63 89 70.7
branch 18 18 100.0
condition 17 18 94.4
subroutine 11 37 29.7
pod 5 5 100.0
total 114 167 68.2


line stmt bran cond sub pod time code
1             package Mars::Role;
2              
3 3     6   1168 use 5.018;
  3         8  
4              
5 3     3   12 use strict;
  3         5  
  3         45  
6 3     3   9 use warnings;
  3         5  
  3         169  
7              
8             # IMPORT
9              
10             sub import {
11 19     19   25179 my ($self, @args) = @_;
12              
13 19         36 my $from = caller;
14              
15 19         1114 require Mars::Kind::Role;
16              
17 3     3   15 no strict 'refs';
  3         5  
  3         86  
18 3     3   13 no warnings 'redefine';
  3         3  
  3         104  
19 3     3   23 no warnings 'once';
  3         6  
  3         2108  
20              
21 19 100       153 my %exports = map +($_,$_), @args ? @args : qw(
22             attr
23             base
24             false
25             from
26             role
27             test
28             true
29             with
30             );
31              
32 19         37 @{"${from}::ISA"} = 'Mars::Kind::Role';
  19         286  
33              
34 19 100 66     85 if ($exports{"attr"} && !*{"${from}::attr"}{"CODE"}) {
  19         95  
35 12     9   52 *{"${from}::attr"} = sub {@_ = ($from, @_); goto \&attr};
  12     9   31  
  9     6   34  
  9         18  
36             }
37 19 100 100     41 if ($exports{"base"} && !*{"${from}::base"}{"CODE"}) {
  17         77  
38 10     0   32 *{"${from}::base"} = sub {@_ = ($from, @_); goto \&base};
  10     0   21  
  0     0   0  
  0         0  
39             }
40 19 100       22 if (!*{"${from}::false"}{"CODE"}) {
  19         73  
41 12     0   39 *{"${from}::false"} = sub {require Mars; Mars::false()};
  12     0   26  
  0     0   0  
  0     0   0  
42             }
43 19 100 100     40 if ($exports{"from"} && !*{"${from}::from"}{"CODE"}) {
  17         68  
44 10     0   42 *{"${from}::from"} = sub {@_ = ($from, @_); goto \&from};
  10     0   21  
  0     0   0  
  0         0  
45             }
46 19 100 100     40 if ($exports{"role"} && !*{"${from}::role"}{"CODE"}) {
  17         62  
47 10     0   32 *{"${from}::role"} = sub {@_ = ($from, @_); goto \&role};
  10     0   72  
  0     0   0  
  0         0  
48             }
49 19 100 100     39 if ($exports{"test"} && !*{"${from}::test"}{"CODE"}) {
  17         70  
50 10     0   25 *{"${from}::test"} = sub {@_ = ($from, @_); goto \&test};
  10     0   21  
  0     0   0  
  0         0  
51             }
52 19 100       27 if (!*{"${from}::true"}{"CODE"}) {
  19         50  
53 12     0   34 *{"${from}::true"} = sub {require Mars; Mars::true()};
  12     0   25  
  0     0   0  
  0     0   0  
54             }
55 19 100 100     39 if ($exports{"with"} && !*{"${from}::with"}{"CODE"}) {
  17         61  
56 10     0   37 *{"${from}::with"} = sub {@_ = ($from, @_); goto \&test};
  10     0   23  
  0         0  
  0         0  
57             }
58              
59 19         28 ${"${from}::META"} = {};
  19         53  
60              
61 19         1515 return $self;
62             }
63              
64             sub attr {
65 9     9 1 15 my ($from, @args) = @_;
66              
67 9         30 $from->ATTR(@args);
68              
69 9         107 return $from;
70             }
71              
72             sub base {
73 0     0 1   my ($from, @args) = @_;
74              
75 0           $from->BASE(@args);
76              
77 0           return $from;
78             }
79              
80             sub from {
81 0     0 1   my ($from, @args) = @_;
82              
83 0           $from->FROM(@args);
84              
85 0           return $from;
86             }
87              
88             sub role {
89 0     0 1   my ($from, @args) = @_;
90              
91 0           $from->ROLE(@args);
92              
93 0           return $from;
94             }
95              
96             sub test {
97 0     0 1   my ($from, @args) = @_;
98              
99 0           $from->TEST(@args);
100              
101 0           return $from;
102             }
103              
104             1;
105              
106              
107              
108             =head1 NAME
109              
110             Mars::Role - Role Declaration
111              
112             =cut
113              
114             =head1 ABSTRACT
115              
116             Role Declaration for Perl 5
117              
118             =cut
119              
120             =head1 SYNOPSIS
121              
122             package Person;
123              
124             use Mars::Class 'attr';
125              
126             attr 'fname';
127             attr 'lname';
128              
129             package Identity;
130              
131             use Mars::Role 'attr';
132              
133             attr 'id';
134             attr 'login';
135             attr 'password';
136              
137             sub EXPORT {
138             # explicitly declare routines to be consumed
139             ['id', 'login', 'password']
140             }
141              
142             package Authenticable;
143              
144             use Mars::Role;
145              
146             sub authenticate {
147             return true;
148             }
149              
150             sub AUDIT {
151             my ($self, $from) = @_;
152             # ensure the caller has a login and password when consumed
153             die "${from} missing the login attribute" if !$from->can('login');
154             die "${from} missing the password attribute" if !$from->can('password');
155             }
156              
157             sub BUILD {
158             my ($self, $data) = @_;
159             $self->{auth} = undef;
160             return $self;
161             }
162              
163             sub EXPORT {
164             # explicitly declare routines to be consumed
165             ['authenticate']
166             }
167              
168             package User;
169              
170             use Mars::Class;
171              
172             base 'Person';
173              
174             with 'Identity';
175              
176             attr 'email';
177              
178             test 'Authenticable';
179              
180             sub valid {
181             my ($self) = @_;
182             return $self->login && $self->password ? true : false;
183             }
184              
185             package main;
186              
187             my $user = User->new(
188             fname => 'Elliot',
189             lname => 'Alderson',
190             );
191              
192             # bless({fname => 'Elliot', lname => 'Alderson'}, 'User')
193              
194             =cut
195              
196             =head1 DESCRIPTION
197              
198             This package provides a role builder which when used causes the consumer to
199             inherit from L which provides role construction and lifecycle
200             L. A role differs from a L<"class"|Mars::Class> in that it
201             can't be instantiated using the C method. A role can act as an interface
202             by defining an L<"audit"|Mars::Kind/AUDIT> hook, which is invoked automatically
203             by the L<"test"|Mars::Class/test> function.
204              
205             =cut
206              
207             =head1 FUNCTIONS
208              
209             This package provides the following functions:
210              
211             =cut
212              
213             =head2 attr
214              
215             attr(Str $name) (Str)
216              
217             The attr function creates attribute accessors for the calling package. This
218             function is always exported unless a routine of the same name already exists.
219              
220             I>
221              
222             =over 4
223              
224             =item attr example 1
225              
226             package Example;
227              
228             use Mars::Class;
229              
230             attr 'name';
231              
232             # "Example"
233              
234             =back
235              
236             =cut
237              
238             =head2 base
239              
240             base(Str $name) (Str)
241              
242             The base function registers one or more base classes for the calling package.
243             This function is always exported unless a routine of the same name already
244             exists.
245              
246             I>
247              
248             =over 4
249              
250             =item base example 1
251              
252             package Entity;
253              
254             use Mars::Class;
255              
256             sub output {
257             return;
258             }
259              
260             package Example;
261              
262             use Mars::Class;
263              
264             base 'Entity';
265              
266             # "Example"
267              
268             =back
269              
270             =cut
271              
272             =head2 false
273              
274             false() (Bool)
275              
276             The false function returns a falsy boolean value which is designed to be
277             practically indistinguishable from the conventional numerical C<0> value. This
278             function is always exported unless a routine of the same name already exists.
279              
280             I>
281              
282             =over 4
283              
284             =item false example 1
285              
286             package Example;
287              
288             use Mars::Class;
289              
290             my $false = false;
291              
292             # 0
293              
294             =back
295              
296             =over 4
297              
298             =item false example 2
299              
300             package Example;
301              
302             use Mars::Class;
303              
304             my $true = !false;
305              
306             # 1
307              
308             =back
309              
310             =cut
311              
312             =head2 from
313              
314             from(Str $name) (Str)
315              
316             The from function registers one or more base classes for the calling package
317             and performs an L<"audit"|Mars::Kind/AUDIT>. This function is always exported
318             unless a routine of the same name already exists.
319              
320             I>
321              
322             =over 4
323              
324             =item from example 1
325              
326             package Entity;
327              
328             use Mars::Role;
329              
330             attr 'startup';
331             attr 'shutdown';
332              
333             sub EXPORT {
334             ['startup', 'shutdown']
335             }
336              
337             package Record;
338              
339             use Mars::Class;
340              
341             sub AUDIT {
342             my ($self, $from) = @_;
343             die "Missing startup" if !$from->can('startup');
344             die "Missing shutdown" if !$from->can('shutdown');
345             }
346              
347             package Example;
348              
349             use Mars::Class;
350              
351             with 'Entity';
352              
353             from 'Record';
354              
355             # "Example"
356              
357             =back
358              
359             =cut
360              
361             =head2 role
362              
363             role(Str $name) (Str)
364              
365             The role function registers and consumes roles for the calling package. This
366             function is always exported unless a routine of the same name already exists.
367              
368             I>
369              
370             =over 4
371              
372             =item role example 1
373              
374             package Ability;
375              
376             use Mars::Role;
377              
378             sub action {
379             return;
380             }
381              
382             package Example;
383              
384             use Mars::Class;
385              
386             role 'Ability';
387              
388             # "Example"
389              
390             =back
391              
392             =over 4
393              
394             =item role example 2
395              
396             package Ability;
397              
398             use Mars::Role;
399              
400             sub action {
401             return;
402             }
403              
404             sub EXPORT {
405             return ['action'];
406             }
407              
408             package Example;
409              
410             use Mars::Class;
411              
412             role 'Ability';
413              
414             # "Example"
415              
416             =back
417              
418             =cut
419              
420             =head2 test
421              
422             test(Str $name) (Str)
423              
424             The test function registers and consumes roles for the calling package and
425             performs an L<"audit"|Mars::Kind/AUDIT>, effectively allowing a role to act as
426             an interface. This function is always exported unless a routine of the same
427             name already exists.
428              
429             I>
430              
431             =over 4
432              
433             =item test example 1
434              
435             package Actual;
436              
437             use Mars::Role;
438              
439             package Example;
440              
441             use Mars::Class;
442              
443             test 'Actual';
444              
445             # "Example"
446              
447             =back
448              
449             =over 4
450              
451             =item test example 2
452              
453             package Actual;
454              
455             use Mars::Role;
456              
457             sub AUDIT {
458             die "Example is not an 'actual' thing" if $_[1]->isa('Example');
459             }
460              
461             package Example;
462              
463             use Mars::Class;
464              
465             test 'Actual';
466              
467             # "Example"
468              
469             =back
470              
471             =cut
472              
473             =head2 true
474              
475             true() (Bool)
476              
477             The true function returns a truthy boolean value which is designed to be
478             practically indistinguishable from the conventional numerical C<1> value. This
479             function is always exported unless a routine of the same name already exists.
480              
481             I>
482              
483             =over 4
484              
485             =item true example 1
486              
487             package Example;
488              
489             use Mars::Class;
490              
491             my $true = true;
492              
493             # 1
494              
495             =back
496              
497             =over 4
498              
499             =item true example 2
500              
501             package Example;
502              
503             use Mars::Class;
504              
505             my $false = !true;
506              
507             # 0
508              
509             =back
510              
511             =cut
512              
513             =head2 with
514              
515             with(Str $name) (Str)
516              
517             The with function registers and consumes roles for the calling package. This
518             function is an alias of the L function and will perform an
519             L<"audit"|Mars::Kind/AUDIT> if present. This function is always exported unless
520             a routine of the same name already exists.
521              
522             I>
523              
524             =over 4
525              
526             =item with example 1
527              
528             package Understanding;
529              
530             use Mars::Role;
531              
532             sub knowledge {
533             return;
534             }
535              
536             package Example;
537              
538             use Mars::Class;
539              
540             with 'Understanding';
541              
542             # "Example"
543              
544             =back
545              
546             =over 4
547              
548             =item with example 2
549              
550             package Understanding;
551              
552             use Mars::Role;
553              
554             sub knowledge {
555             return;
556             }
557              
558             sub EXPORT {
559             return ['knowledge'];
560             }
561              
562             package Example;
563              
564             use Mars::Class;
565              
566             with 'Understanding';
567              
568             # "Example"
569              
570             =back
571              
572             =cut
573              
574             =head1 AUTHORS
575              
576             Awncorp, C
577              
578             =cut