File Coverage

blib/lib/Mars/Kind.pm
Criterion Covered Total %
statement 116 118 98.3
branch 18 26 69.2
condition 4 6 66.6
subroutine 29 30 96.6
pod 18 18 100.0
total 185 198 93.4


line stmt bran cond sub pod time code
1             package Mars::Kind;
2              
3 6     6   1501 use 5.018;
  6         17  
4              
5 6     6   55 use strict;
  6         11  
  6         117  
6 6     6   24 use warnings;
  6         10  
  6         778  
7              
8             # VARIABLES
9              
10             state $cache = {};
11              
12             # METHODS
13              
14             sub ARGS {
15 140     140 1 6170 my ($self, @args) = @_;
16              
17             return (!@args)
18             ? ($self->DATA)
19             : ((@args == 1 && ref($args[0]) eq 'HASH')
20 140 100 66     668 ? (!%{$args[0]} ? $self->DATA : {%{$args[0]}})
  8 50       23  
  7 100       30  
    100          
21             : (@args % 2 ? {@args, undef} : {@args}));
22             }
23              
24             sub ATTR {
25 29     29 1 7985 my ($self, $attr, @args) = @_;
26              
27 6     6   36 no strict 'refs';
  6         8  
  6         205  
28 6     6   26 no warnings 'redefine';
  6         12  
  6         1478  
29              
30 29         37 *{"@{[$self->NAME]}::$attr"}
  29         75  
31 29     23   98 = sub { @_ = ($_[0], $attr, @_[1 .. $#_]); goto \&attr };
  23         12574  
  23         63  
32              
33 29         46 my $index = int(keys(%{$${"@{[$self->NAME]}::META"}{ATTR}})) + 1;
  29         26  
  29         30  
  29         42  
34              
35 29         56 $${"@{[$self->NAME]}::META"}{ATTR}{$attr} = [$index, [$attr, @args]];
  29         29  
  29         39  
36              
37 29         113 return $self;
38             }
39              
40             sub AUDIT {
41 11     11 1 16 my ($self) = @_;
42              
43 11         13 return $self;
44             }
45              
46             sub BASE {
47 12     12 1 3367 my ($self, $base, @args) = @_;
48              
49 6     6   46 no strict 'refs';
  6         9  
  6         2776  
50              
51 12 50       558 eval "require $base" if !$$cache{$base};
52              
53 12         20 @{"@{[$self->NAME]}::ISA"} = (
  12         18  
54 12         53 $base, (grep +($_ ne $base), @{"@{[$self->NAME]}::ISA"})
  12         14  
  12         43  
55             );
56              
57 12         51 my $index = int(keys(%{$${"@{[$self->NAME]}::META"}{BASE}})) + 1;
  12         14  
  12         12  
  12         37  
58              
59 12         37 $${"@{[$self->NAME]}::META"}{BASE}{$base} = [$index, [$base, @args]];
  12         14  
  12         23  
60              
61 12         62 return $self;
62             }
63              
64             sub BLESS {
65 137     137 1 17350 my ($self, @args) = @_;
66              
67 137         307 my $data = $self->ARGS($self->BUILDARGS(@args));
68 137 50       538 my $anew = bless(
    100          
69             (
70             ref $data eq 'HASH' ? {%$data} : (ref $data eq 'ARRAY' ? [@$data] : $data)
71             ),
72             $self->NAME
73             );
74              
75 137         389 $anew->BUILD($data);
76              
77 137         872 return $anew;
78             }
79              
80             sub BUILD {
81 94     94 1 119 my ($self, $data) = @_;
82              
83 94         100 return $self;
84             }
85              
86             sub BUILDARGS {
87 129     129 1 200 my ($self, @args) = @_;
88              
89 129         269 return (@args);
90             }
91              
92             sub DATA {
93 20     20 1 29 my ($self) = @_;
94              
95 20         43 return {};
96             }
97              
98             sub DESTROY {
99 130     130   19776 my ($self) = @_;
100              
101 130         568 return $self;
102             }
103              
104             sub DOES {
105 31     31 1 1289 my ($self, $role) = @_;
106              
107 31 50       59 return if !$role;
108              
109 31         60 return $self->META->role($role);
110             }
111              
112             sub EXPORT {
113 0     0 1 0 my ($self, $into) = @_;
114              
115 0         0 return [];
116             }
117              
118             sub FROM {
119 4     4 1 2973 my ($self, $base) = @_;
120              
121 4         14 $self->BASE($base);
122              
123 4 50       32 $base->AUDIT($self->NAME) if $base->can('AUDIT');
124              
125 4         50 return $self;
126             }
127              
128             sub IMPORT {
129 12     12 1 31 my ($self, $into) = @_;
130              
131 12         34 return $self;
132             }
133              
134             sub META {
135 81     81 1 1999 my ($self) = @_;
136              
137 6     6   40 no strict 'refs';
  6         8  
  6         683  
138              
139 81         2622 require Mars::Meta;
140              
141 81         152 return Mars::Meta->new(name => $self->NAME);
142             }
143              
144             sub NAME {
145 511     511 1 2354 my ($self) = @_;
146              
147 511   66     2557 return ref $self || $self;
148             }
149              
150             sub ROLE {
151 35     35 1 19632 my ($self, $role, @args) = @_;
152              
153 35 50       1607 eval "require $role" if !$$cache{$role};
154              
155 6     6   35 no warnings 'redefine';
  6         20  
  6         257  
156              
157 35         214 $role->IMPORT($self->NAME);
158              
159 6     6   30 no strict 'refs';
  6         39  
  6         757  
160              
161 35         46 my $index = int(keys(%{$${"@{[$self->NAME]}::META"}{ROLE}})) + 1;
  35         37  
  35         39  
  35         57  
162              
163 35         77 $${"@{[$self->NAME]}::META"}{ROLE}{$role} = [$index, [$role, @args]];
  35         43  
  35         44  
164              
165 35         174 return $self;
166             }
167              
168             sub SUBS {
169 1     1 1 1716 my ($self) = @_;
170              
171 6     6   36 no strict 'refs';
  6         7  
  6         1823  
172              
173             return [
174 10         14 sort grep *{"@{[$self->NAME]}::$_"}{"CODE"},
  10         12  
175 1         1 grep /^[_a-zA-Z]\w*$/, keys %{"@{[$self->NAME]}::"}
  1         2  
  1         2  
176             ];
177             }
178              
179             sub TEST {
180 18     18 1 1788 my ($self, $role) = @_;
181              
182 18         61 $self->ROLE($role);
183              
184 18 50       118 $role->AUDIT($self->NAME) if $role->can('AUDIT');
185              
186 15         45 return $self;
187             }
188              
189             sub attr {
190 23     23 1 50 my ($self, $name, @args) = @_;
191              
192 23 50       45 return undef if !$name;
193 23 100       143 return $self->{$name} if !int@args;
194 2         10 return $self->{$name} = $args[0];
195             }
196              
197             1;
198              
199              
200              
201             =head1 NAME
202              
203             Mars::Kind - Kind Base Class
204              
205             =cut
206              
207             =head1 ABSTRACT
208              
209             Kind Base Class for Perl 5
210              
211             =cut
212              
213             =head1 SYNOPSIS
214              
215             package User;
216              
217             use base 'Mars::Kind';
218              
219             package main;
220              
221             my $user = User->BLESS(
222             fname => 'Elliot',
223             lname => 'Alderson',
224             );
225              
226             # bless({fname => 'Elliot', lname => 'Alderson'}, 'User')
227              
228             # i.e. BLESS is somewhat equivalent to writing
229              
230             # User->BUILD(bless(User->ARGS(User->BUILDARGS(@args) || User->DATA), 'User'))
231              
232             =cut
233              
234             =head1 DESCRIPTION
235              
236             This package provides a base class for L<"class"|Mars::Kind::Class> and
237             L<"role"|Mars::Kind::Role> (kind) derived packages and provides class building,
238             object construction, and object deconstruction lifecycle hooks. The
239             L and L packages provide a simple DSL for automating
240             L derived base classes.
241              
242             =cut
243              
244             =head1 METHODS
245              
246             This package provides the following methods:
247              
248             =cut
249              
250             =head2 args
251              
252             ARGS(Any @args) (HashRef)
253              
254             The ARGS method is a object construction lifecycle hook which accepts a list of
255             arguments and returns a blessable data structure.
256              
257             I>
258              
259             =over 4
260              
261             =item ARGS example 1
262              
263             # given: synopsis
264              
265             package main;
266              
267             my $args = User->ARGS;
268              
269             # {}
270              
271             =back
272              
273             =over 4
274              
275             =item ARGS example 2
276              
277             # given: synopsis
278              
279             package main;
280              
281             my $args = User->ARGS(name => 'Elliot');
282              
283             # {name => 'Elliot'}
284              
285             =back
286              
287             =over 4
288              
289             =item ARGS example 3
290              
291             # given: synopsis
292              
293             package main;
294              
295             my $args = User->ARGS({name => 'Elliot'});
296              
297             # {name => 'Elliot'}
298              
299             =back
300              
301             =cut
302              
303             =head2 attr
304              
305             ATTR(Str $name, Any @args) (Str | Object)
306              
307             The ATTR method is a class building lifecycle hook which installs an attribute
308             accessors in the calling package.
309              
310             I>
311              
312             =over 4
313              
314             =item ATTR example 1
315              
316             package User;
317              
318             use base 'Mars::Kind';
319              
320             User->ATTR('name');
321              
322             package main;
323              
324             my $user = User->BLESS;
325              
326             # bless({}, 'User')
327              
328             # $user->name;
329              
330             # ""
331              
332             # $user->name('Elliot');
333              
334             # "Elliot"
335              
336             =back
337              
338             =over 4
339              
340             =item ATTR example 2
341              
342             package User;
343              
344             use base 'Mars::Kind';
345              
346             User->ATTR('role');
347              
348             package main;
349              
350             my $user = User->BLESS(role => 'Engineer');
351              
352             # bless({role => 'Engineer'}, 'User')
353              
354             # $user->role;
355              
356             # "Engineer"
357              
358             # $user->role('Hacker');
359              
360             # "Hacker"
361              
362             =back
363              
364             =cut
365              
366             =head2 audit
367              
368             AUDIT(Str $role) (Str | Object)
369              
370             The AUDIT method is a class building lifecycle hook which exist in roles and is
371             executed as a callback when the consuming class invokes the L hook.
372              
373             I>
374              
375             =over 4
376              
377             =item AUDIT example 1
378              
379             package HasType;
380              
381             use base 'Mars::Kind';
382              
383             sub AUDIT {
384             die 'Consumer missing "type" attribute' if !$_[1]->can('type');
385             }
386              
387             package User;
388              
389             use base 'Mars::Kind';
390              
391             User->TEST('HasType');
392              
393             package main;
394              
395             my $user = User->BLESS;
396              
397             # Exception! Consumer missing "type" attribute
398              
399             =back
400              
401             =over 4
402              
403             =item AUDIT example 2
404              
405             package HasType;
406              
407             sub AUDIT {
408             die 'Consumer missing "type" attribute' if !$_[1]->can('type');
409             }
410              
411             package User;
412              
413             use base 'Mars::Kind';
414              
415             User->ATTR('type');
416              
417             User->TEST('HasType');
418              
419             package main;
420              
421             my $user = User->BLESS;
422              
423             # bless({}, 'User')
424              
425             =back
426              
427             =cut
428              
429             =head2 base
430              
431             BASE(Str $name) (Str | Object)
432              
433             The BASE method is a class building lifecycle hook which registers a base class
434             for the calling package. B Unlike the L hook, this hook doesn't
435             invoke the L hook.
436              
437             I>
438              
439             =over 4
440              
441             =item BASE example 1
442              
443             package Entity;
444              
445             sub work {
446             return;
447             }
448              
449             package User;
450              
451             use base 'Mars::Kind';
452              
453             User->BASE('Entity');
454              
455             package main;
456              
457             my $user = User->BLESS;
458              
459             # bless({}, 'User')
460              
461             =back
462              
463             =over 4
464              
465             =item BASE example 2
466              
467             package Engineer;
468              
469             sub debug {
470             return;
471             }
472              
473             package Entity;
474              
475             sub work {
476             return;
477             }
478              
479             package User;
480              
481             use base 'Mars::Kind';
482              
483             User->BASE('Entity');
484              
485             User->BASE('Engineer');
486              
487             package main;
488              
489             my $user = User->BLESS;
490              
491             # bless({}, 'User')
492              
493             =back
494              
495             =cut
496              
497             =head2 bless
498              
499             BLESS(Any @args) (Object)
500              
501             The BLESS method is an object construction lifecycle hook which returns an
502             instance of the calling package.
503              
504             I>
505              
506             =over 4
507              
508             =item BLESS example 1
509              
510             package User;
511              
512             use base 'Mars::Kind';
513              
514             package main;
515              
516             my $example = User->BLESS;
517              
518             # bless({}, 'User')
519              
520             =back
521              
522             =over 4
523              
524             =item BLESS example 2
525              
526             package User;
527              
528             use base 'Mars::Kind';
529              
530             package main;
531              
532             my $example = User->BLESS(name => 'Elliot');
533              
534             # bless({name => 'Elliot'}, 'User')
535              
536             =back
537              
538             =over 4
539              
540             =item BLESS example 3
541              
542             package User;
543              
544             use base 'Mars::Kind';
545              
546             package main;
547              
548             my $example = User->BLESS({name => 'Elliot'});
549              
550             # bless({name => 'Elliot'}, 'User')
551              
552             =back
553              
554             =cut
555              
556             =head2 build
557              
558             BUILD(HashRef $data) (Object)
559              
560             The BUILD method is an object construction lifecycle hook which receives an
561             object and the data structure that was blessed, and should return an object
562             although its return value is ignored by the L hook.
563              
564             I>
565              
566             =over 4
567              
568             =item BUILD example 1
569              
570             package User;
571              
572             use base 'Mars::Kind';
573              
574             sub BUILD {
575             my ($self) = @_;
576              
577             $self->{name} = 'Mr. Robot';
578              
579             return $self;
580             }
581              
582             package main;
583              
584             my $example = User->BLESS(name => 'Elliot');
585              
586             # bless({name => 'Mr. Robot'}, 'User')
587              
588             =back
589              
590             =over 4
591              
592             =item BUILD example 2
593              
594             package User;
595              
596             use base 'Mars::Kind';
597              
598             sub BUILD {
599             my ($self) = @_;
600              
601             $self->{name} = 'Mr. Robot';
602              
603             return $self;
604             }
605              
606             package Elliot;
607              
608             use base 'User';
609              
610             sub BUILD {
611             my ($self, $data) = @_;
612              
613             $self->SUPER::BUILD($data);
614              
615             $self->{name} = 'Elliot';
616              
617             return $self;
618             }
619              
620             package main;
621              
622             my $elliot = Elliot->BLESS;
623              
624             # bless({name => 'Elliot'}, 'Elliot')
625              
626             =back
627              
628             =cut
629              
630             =head2 buildargs
631              
632             BUILDARGS(Any @args) (Any @args | HashRef $data)
633              
634             The BUILDARGS method is an object construction lifecycle hook which receives
635             the arguments provided to the constructor (unaltered) and should return a list
636             of arguments, a hashref, or key/value pairs.
637              
638             I>
639              
640             =over 4
641              
642             =item BUILDARGS example 1
643              
644             package User;
645              
646             use base 'Mars::Kind';
647              
648             sub BUILD {
649             my ($self) = @_;
650              
651             return $self;
652             }
653              
654             sub BUILDARGS {
655             my ($self, @args) = @_;
656              
657             my $data = @args == 1 && !ref $args[0] ? {name => $args[0]} : {};
658              
659             return $data;
660             }
661              
662             package main;
663              
664             my $user = User->BLESS('Elliot');
665              
666             # bless({name => 'Elliot'}, 'User')
667              
668             =back
669              
670             =cut
671              
672             =head2 data
673              
674             DATA() (Ref)
675              
676             The DATA method is an object construction lifecycle hook which returns the
677             default data structure reference to be blessed when no arguments are provided
678             to the constructor. The default data structure is an empty hashref.
679              
680             I>
681              
682             =over 4
683              
684             =item DATA example 1
685              
686             package Example;
687              
688             use base 'Mars::Kind';
689              
690             sub DATA {
691             return [];
692             }
693              
694             package main;
695              
696             my $example = Example->BLESS;
697              
698             # bless([], 'Example')
699              
700             =back
701              
702             =over 4
703              
704             =item DATA example 2
705              
706             package Example;
707              
708             use base 'Mars::Kind';
709              
710             sub DATA {
711             return {};
712             }
713              
714             package main;
715              
716             my $example = Example->BLESS;
717              
718             # bless({}, 'Example')
719              
720             =back
721              
722             =cut
723              
724             =head2 destroy
725              
726             DESTROY() (Any)
727              
728             The DESTROY method is an object destruction lifecycle hook which is called when
729             the last reference to the object goes away.
730              
731             I>
732              
733             =over 4
734              
735             =item DESTROY example 1
736              
737             package User;
738              
739             use base 'Mars::Kind';
740              
741             our $USERS = 0;
742              
743             sub BUILD {
744             return $USERS++;
745             }
746              
747             sub DESTROY {
748             return $USERS--;
749             }
750              
751             package main;
752              
753             my $user = User->BLESS(name => 'Elliot');
754              
755             undef $user;
756              
757             # 1
758              
759             =back
760              
761             =cut
762              
763             =head2 does
764              
765             DOES(Str $name) (Bool)
766              
767             The DOES method returns true or false if the invocant consumed the role or
768             interface provided.
769              
770             I>
771              
772             =over 4
773              
774             =item DOES example 1
775              
776             package Admin;
777              
778             use base 'Mars::Kind';
779              
780             package User;
781              
782             use base 'Mars::Kind';
783              
784             User->ROLE('Admin');
785              
786             sub BUILD {
787             return;
788             }
789              
790             sub BUILDARGS {
791             return;
792             }
793              
794             package main;
795              
796             my $admin = User->DOES('Admin');
797              
798             # 1
799              
800             =back
801              
802             =over 4
803              
804             =item DOES example 2
805              
806             package Admin;
807              
808             use base 'Mars::Kind';
809              
810             package User;
811              
812             use base 'Mars::Kind';
813              
814             User->ROLE('Admin');
815              
816             sub BUILD {
817             return;
818             }
819              
820             sub BUILDARGS {
821             return;
822             }
823              
824             package main;
825              
826             my $is_owner = User->DOES('Owner');
827              
828             # 0
829              
830             =back
831              
832             =cut
833              
834             =head2 export
835              
836             EXPORT(Any @args) (ArrayRef)
837              
838             The EXPORT method is a class building lifecycle hook which returns an arrayref
839             of routine names to be automatically imported by the calling package whenever
840             the L or L hooks are used.
841              
842             I>
843              
844             =over 4
845              
846             =item EXPORT example 1
847              
848             package Admin;
849              
850             use base 'Mars::Kind';
851              
852             sub shutdown {
853             return;
854             }
855              
856             sub EXPORT {
857             ['shutdown']
858             }
859              
860             package User;
861              
862             use base 'Mars::Kind';
863              
864             User->ROLE('Admin');
865              
866             package main;
867              
868             my $user = User->BLESS;
869              
870             # bless({}, 'User')
871              
872             =back
873              
874             =cut
875              
876             =head2 from
877              
878             FROM(Str $name) (Str | Object)
879              
880             The FROM method is a class building lifecycle hook which registers a base class
881             for the calling package, automatically invoking the L hook on the base
882             class.
883              
884             I>
885              
886             =over 4
887              
888             =item FROM example 1
889              
890             package Entity;
891              
892             use base 'Mars::Kind';
893              
894             sub AUDIT {
895             my ($self, $from) = @_;
896             die "Missing startup" if !$from->can('startup');
897             die "Missing shutdown" if !$from->can('shutdown');
898             }
899              
900             package User;
901              
902             use base 'Mars::Kind';
903              
904             User->ATTR('startup');
905             User->ATTR('shutdown');
906              
907             User->FROM('Entity');
908              
909             package main;
910              
911             my $user = User->BLESS;
912              
913             # bless({}, 'User')
914              
915             =back
916              
917             =over 4
918              
919             =item FROM example 2
920              
921             package Entity;
922              
923             use base 'Mars::Kind';
924              
925             sub AUDIT {
926             my ($self, $from) = @_;
927             die "Missing startup" if !$from->can('startup');
928             die "Missing shutdown" if !$from->can('shutdown');
929             }
930              
931             package User;
932              
933             use base 'Mars::Kind';
934              
935             User->FROM('Entity');
936              
937             sub startup {
938             return;
939             }
940              
941             sub shutdown {
942             return;
943             }
944              
945             package main;
946              
947             my $user = User->BLESS;
948              
949             # bless({}, 'User')
950              
951             =back
952              
953             =cut
954              
955             =head2 import
956              
957             IMPORT(Str $into, Any @args) (Str | Object)
958              
959             The IMPORT method is a class building lifecycle hook which dispatches the
960             L lifecycle hook whenever the L or L hooks are used.
961              
962             I>
963              
964             =over 4
965              
966             =item IMPORT example 1
967              
968             package Admin;
969              
970             use base 'Mars::Kind';
971              
972             our $USES = 0;
973              
974             sub shutdown {
975             return;
976             }
977              
978             sub EXPORT {
979             ['shutdown']
980             }
981              
982             sub IMPORT {
983             my ($self, $into) = @_;
984              
985             $self->SUPER::IMPORT($into);
986              
987             $USES++;
988              
989             return $self;
990             }
991              
992             package User;
993              
994             use base 'Mars::Kind';
995              
996             User->ROLE('Admin');
997              
998             package main;
999              
1000             my $user = User->BLESS;
1001              
1002             # bless({}, 'User')
1003              
1004             =back
1005              
1006             =cut
1007              
1008             =head2 meta
1009              
1010             META() (Meta)
1011              
1012             The META method return a L object which describes the invocant's
1013             configuration.
1014              
1015             I>
1016              
1017             =over 4
1018              
1019             =item META example 1
1020              
1021             package User;
1022              
1023             use base 'Mars::Kind';
1024              
1025             package main;
1026              
1027             my $meta = User->META;
1028              
1029             # bless({name => 'User'}, 'Mars::Meta')
1030              
1031             =back
1032              
1033             =cut
1034              
1035             =head2 name
1036              
1037             NAME() (Str)
1038              
1039             The NAME method is a class building lifecycle hook which returns the name of
1040             the package.
1041              
1042             I>
1043              
1044             =over 4
1045              
1046             =item NAME example 1
1047              
1048             package User;
1049              
1050             use base 'Mars::Kind';
1051              
1052             package main;
1053              
1054             my $name = User->NAME;
1055              
1056             # "User"
1057              
1058             =back
1059              
1060             =over 4
1061              
1062             =item NAME example 2
1063              
1064             package User;
1065              
1066             use base 'Mars::Kind';
1067              
1068             package main;
1069              
1070             my $name = User->BLESS->NAME;
1071              
1072             # "User"
1073              
1074             =back
1075              
1076             =cut
1077              
1078             =head2 role
1079              
1080             ROLE(Str $name) (Str | Object)
1081              
1082             The ROLE method is a class building lifecycle hook which consumes the role
1083             provided, automatically invoking the role's L hook. B Unlike
1084             the L and L hooks, this hook doesn't invoke the L hook.
1085             The role composition semantics are as follows: Routines to be consumed must be
1086             explicitly declared via the L hook. Routines will be copied to the
1087             consumer unless they already exist (excluding routines from base classes, which
1088             will be overridden). If multiple roles are consumed having routines with the
1089             same name (i.e. naming collisions) the first routine copied wins.
1090              
1091             I>
1092              
1093             =over 4
1094              
1095             =item ROLE example 1
1096              
1097             package Admin;
1098              
1099             use base 'Mars::Kind';
1100              
1101             package User;
1102              
1103             use base 'Mars::Kind';
1104              
1105             User->ROLE('Admin');
1106              
1107             package main;
1108              
1109             my $admin = User->DOES('Admin');
1110              
1111             # 1
1112              
1113             =back
1114              
1115             =over 4
1116              
1117             =item ROLE example 2
1118              
1119             package Create;
1120              
1121             use base 'Mars::Kind';
1122              
1123             package Delete;
1124              
1125             use base 'Mars::Kind';
1126              
1127             package Manage;
1128              
1129             use base 'Mars::Kind';
1130              
1131             Manage->ROLE('Create');
1132             Manage->ROLE('Delete');
1133              
1134             package User;
1135              
1136             use base 'Mars::Kind';
1137              
1138             User->ROLE('Manage');
1139              
1140             package main;
1141              
1142             my $create = User->DOES('Create');
1143              
1144             # 1
1145              
1146             =back
1147              
1148             =cut
1149              
1150             =head2 subs
1151              
1152             SUBS() (ArrayRef)
1153              
1154             The SUBS method returns the routines defined on the package and consumed from
1155             roles, but not inherited by superclasses.
1156              
1157             I>
1158              
1159             =over 4
1160              
1161             =item SUBS example 1
1162              
1163             package Example;
1164              
1165             use base 'Mars::Kind';
1166              
1167             package main;
1168              
1169             my $subs = Example->SUBS;
1170              
1171             # [...]
1172              
1173             =back
1174              
1175             =cut
1176              
1177             =head2 test
1178              
1179             TEST(Str $name) (Str | Object)
1180              
1181             The TEST method is a class building lifecycle hook which consumes the role
1182             provided, automatically invoking the role's L hook as well as the
1183             L hook if defined.
1184              
1185             I>
1186              
1187             =over 4
1188              
1189             =item TEST example 1
1190              
1191             package Admin;
1192              
1193             use base 'Mars::Kind';
1194              
1195             sub AUDIT {
1196             my ($self, $from) = @_;
1197             die "Missing startup" if !$from->can('startup');
1198             die "Missing shutdown" if !$from->can('shutdown');
1199             }
1200              
1201             sub AUDIT_BUILD {
1202             my ($self, $data) = @_;
1203             die "Attribute 'startup' can't be undefined" if !$self->startup;
1204             die "Attribute 'shutdown' can't be undefined" if !$self->shutdown;
1205             }
1206              
1207             package User;
1208              
1209             use base 'Mars::Kind';
1210              
1211             User->ATTR('startup');
1212             User->ATTR('shutdown');
1213              
1214             User->TEST('Admin');
1215              
1216             sub BUILD {
1217             my ($self, $data) = @_;
1218             # Using AUDIT_BUILD as a callback
1219             $self->Admin::AUDIT_BUILD($data);
1220             }
1221              
1222             package main;
1223              
1224             my $user = User->BLESS(startup => 'hello');
1225              
1226             # Exception! Attribute 'shutdown' can't be undefined
1227              
1228             =back
1229              
1230             =cut
1231              
1232             =head1 AUTHORS
1233              
1234             Awncorp, C
1235              
1236             =cut