File Coverage

blib/lib/Mars/Role.pm
Criterion Covered Total %
statement 62 88 70.4
branch 16 16 100.0
condition n/a
subroutine 11 33 33.3
pod 5 5 100.0
total 94 142 66.2


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