File Coverage

blib/lib/Mars/Kind.pm
Criterion Covered Total %
statement 104 106 98.1
branch 15 22 68.1
condition 4 6 66.6
subroutine 29 30 96.6
pod 18 18 100.0
total 170 182 93.4


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