File Coverage

blib/lib/Venus/Mixin.pm
Criterion Covered Total %
statement 121 126 96.0
branch 27 28 96.4
condition 29 36 80.5
subroutine 34 34 100.0
pod 6 6 100.0
total 217 230 94.3


line stmt bran cond sub pod time code
1             package Venus::Mixin;
2              
3 4     9   81 use 5.018;
  4         17  
4              
5 4     9   27 use strict;
  4         10  
  4         93  
6 4     5   19 use warnings;
  4         9  
  4         327  
7              
8             # IMPORT
9              
10             sub import {
11 48     48   158 my ($self, @args) = @_;
12              
13 48         138 my $from = caller;
14              
15 48         2194 require Venus::Core::Mixin;
16              
17 4     4   27 no strict 'refs';
  4         10  
  4         166  
18 4     4   26 no warnings 'redefine';
  4         9  
  4         173  
19 4     4   26 no warnings 'once';
  4         5  
  4         5430  
20              
21 48   33     184 @args = grep defined && !ref && /^[A-Za-z]/, @args;
22              
23 48 100       528 my %exports = map +($_,$_), @args ? @args : qw(
24             attr
25             base
26             false
27             from
28             mixin
29             role
30             test
31             true
32             with
33             );
34              
35 48         121 @{"${from}::ISA"} = 'Venus::Core::Mixin';
  48         1067  
36              
37 48 100 100     346 if ($exports{"attr"} && !*{"${from}::attr"}{"CODE"}) {
  45         305  
38 7     4   37 *{"${from}::attr"} = sub {@_ = ($from, @_); goto \&attr};
  7     4   26  
  4         12  
  4         13  
39             }
40 48 100 100     176 if ($exports{"base"} && !*{"${from}::base"}{"CODE"}) {
  44         207  
41 6     1   25 *{"${from}::base"} = sub {@_ = ($from, @_); goto \&base};
  6         21  
  1         5  
  1         5  
42             }
43 48 100 66     168 if ($exports{"catch"} && !*{"${from}::catch"}{"CODE"}) {
  1         7  
44 1     1   17 *{"${from}::catch"} = sub (&) {require Venus; goto \&Venus::catch};
  1         6  
  1         5  
  1         6  
45             }
46 48 100 66     158 if ($exports{"error"} && !*{"${from}::error"}{"CODE"}) {
  1         14  
47 1     2   6 *{"${from}::error"} = sub (;$) {require Venus; goto \&Venus::error};
  1         3  
  1         5  
  1         6  
48             }
49 48 100       85 if (!*{"${from}::false"}{"CODE"}) {
  48         195  
50 8     2   28 *{"${from}::false"} = sub {require Venus; Venus::false()};
  8     2   21  
  2         10  
  2         10  
51             }
52 48 50 33     164 if ($exports{"fault"} && !*{"${from}::fault"}{"CODE"}) {
  0         0  
53 0     2   0 *{"${from}::fault"} = sub (;$) {require Venus; goto \&Venus::fault};
  0         0  
  0         0  
  0         0  
54             }
55 48 100 100     179 if ($exports{"from"} && !*{"${from}::from"}{"CODE"}) {
  44         201  
56 6     3   24 *{"${from}::from"} = sub {@_ = ($from, @_); goto \&from};
  6     3   19  
  1         6  
  1         14  
57             }
58 48 100 66     146 if ($exports{"raise"} && !*{"${from}::raise"}{"CODE"}) {
  1         9  
59 1     4   5 *{"${from}::raise"} = sub ($;$) {require Venus; goto \&Venus::raise};
  1         6  
  1         6  
  1         7  
60             }
61 48 100 100     133 if ($exports{"mixin"} && !*{"${from}::mixin"}{"CODE"}) {
  44         223  
62 6     4   21 *{"${from}::mixin"} = sub {@_ = ($from, @_); goto \&mixin};
  6     3   18  
  3         17  
  3         15  
63             }
64 48 100 100     149 if ($exports{"role"} && !*{"${from}::role"}{"CODE"}) {
  44         208  
65 6     5   24 *{"${from}::role"} = sub {@_ = ($from, @_); goto \&role};
  6     2   26  
  2         7  
  2         9  
66             }
67 48 100 100     144 if ($exports{"test"} && !*{"${from}::test"}{"CODE"}) {
  44         182  
68 6     4   22 *{"${from}::test"} = sub {@_ = ($from, @_); goto \&test};
  6     4   19  
  2         9  
  2         10  
69             }
70 48 100       87 if (!*{"${from}::true"}{"CODE"}) {
  48         184  
71 8     2   27 *{"${from}::true"} = sub {require Venus; Venus::true()};
  8     2   19  
  2         11  
  2         7  
72             }
73 48 100 100     158 if ($exports{"with"} && !*{"${from}::with"}{"CODE"}) {
  44         173  
74 6     7   33 *{"${from}::with"} = sub {@_ = ($from, @_); goto \&test};
  6     5   17  
  5         23  
  5         23  
75             }
76              
77 48         122 ${"${from}::META"} = {};
  48         163  
78              
79 48         87 ${"${from}::@{[$from->METACACHE]}"} = undef;
  48         104  
  48         296  
80              
81 48         3783 return $self;
82             }
83              
84             sub attr {
85 4     9 1 10 my ($from, @args) = @_;
86              
87 4         37 $from->ATTR(@args);
88              
89 4         70 return $from;
90             }
91              
92             sub base {
93 1     6 1 7 my ($from, @args) = @_;
94              
95 1         9 $from->BASE(@args);
96              
97 1         9 return $from;
98             }
99              
100             sub from {
101 1     1 1 3 my ($from, @args) = @_;
102              
103 1         8 $from->FROM(@args);
104              
105 1         10 return $from;
106             }
107              
108             sub mixin {
109 3     3 1 9 my ($from, @args) = @_;
110              
111 3         21 $from->MIXIN(@args);
112              
113 3         51 return $from;
114             }
115              
116             sub role {
117 2     2 1 7 my ($from, @args) = @_;
118              
119 2         11 $from->ROLE(@args);
120              
121 2         16 return $from;
122             }
123              
124             sub test {
125 7     7 1 19 my ($from, @args) = @_;
126              
127 7         43 $from->TEST(@args);
128              
129 6         87 return $from;
130             }
131              
132             1;
133              
134              
135              
136             =head1 NAME
137              
138             Venus::Mixin - Mixin Builder
139              
140             =cut
141              
142             =head1 ABSTRACT
143              
144             Mixin Builder for Perl 5
145              
146             =cut
147              
148             =head1 SYNOPSIS
149              
150             package Person;
151              
152             use Venus::Class 'attr';
153              
154             attr 'fname';
155             attr 'lname';
156              
157             package Identity;
158              
159             use Venus::Mixin 'attr';
160              
161             attr 'id';
162             attr 'login';
163             attr 'password';
164              
165             sub EXPORT {
166             # explicitly declare routines to be consumed
167             ['id', 'login', 'password']
168             }
169              
170             package Authenticable;
171              
172             use Venus::Role;
173              
174             sub authenticate {
175             return true;
176             }
177              
178             sub AUDIT {
179             my ($self, $from) = @_;
180             # ensure the caller has a login and password when consumed
181             die "${from} missing the login attribute" if !$from->can('login');
182             die "${from} missing the password attribute" if !$from->can('password');
183             }
184              
185             sub BUILD {
186             my ($self, $data) = @_;
187             $self->{auth} = undef;
188             return $self;
189             }
190              
191             sub EXPORT {
192             # explicitly declare routines to be consumed
193             ['authenticate']
194             }
195              
196             package User;
197              
198             use Venus::Class;
199              
200             base 'Person';
201              
202             mixin 'Identity';
203              
204             attr 'email';
205              
206             test 'Authenticable';
207              
208             sub valid {
209             my ($self) = @_;
210             return $self->login && $self->password ? true : false;
211             }
212              
213             package main;
214              
215             my $user = User->new(
216             fname => 'Elliot',
217             lname => 'Alderson',
218             );
219              
220             # bless({fname => 'Elliot', lname => 'Alderson'}, 'User')
221              
222             =cut
223              
224             =head1 DESCRIPTION
225              
226             This package provides a mixin builder which when used causes the consumer to
227             inherit from L which provides mixin building and lifecycle
228             L. A mixin can do almost everything that a role can do but
229             differs from a L<"role"|Venus::Role> in that whatever routines are declared
230             using L<"export"|Venus::Core/EXPORT> will be exported and will overwrite
231             routines of the same name in the consumer.
232              
233             =cut
234              
235             =head1 FUNCTIONS
236              
237             This package provides the following functions:
238              
239             =cut
240              
241             =head2 attr
242              
243             attr(Str $name) (Str)
244              
245             The attr function creates attribute accessors for the calling package. This
246             function is always exported unless a routine of the same name already exists.
247              
248             I>
249              
250             =over 4
251              
252             =item attr example 1
253              
254             package Example;
255              
256             use Venus::Mixin;
257              
258             attr 'name';
259              
260             # "Example"
261              
262             =back
263              
264             =cut
265              
266             =head2 base
267              
268             base(Str $name) (Str)
269              
270             The base function registers one or more base classes for the calling package.
271             This function is always exported unless a routine of the same name already
272             exists.
273              
274             I>
275              
276             =over 4
277              
278             =item base example 1
279              
280             package Entity;
281              
282             use Venus::Class;
283              
284             sub output {
285             return;
286             }
287              
288             package Example;
289              
290             use Venus::Mixin;
291              
292             base 'Entity';
293              
294             # "Example"
295              
296             =back
297              
298             =cut
299              
300             =head2 catch
301              
302             catch(CodeRef $block) (Error, Any)
303              
304             The catch function executes the code block trapping errors and returning the
305             caught exception in scalar context, and also returning the result as a second
306             argument in list context. This function isn't export unless requested.
307              
308             I>
309              
310             =over 4
311              
312             =item catch example 1
313              
314             package Ability;
315              
316             use Venus::Mixin 'catch';
317              
318             sub attempt_catch {
319             catch {die};
320             }
321              
322             sub EXPORT {
323             ['attempt_catch']
324             }
325              
326             package Example;
327              
328             use Venus::Class 'with';
329              
330             mixin 'Ability';
331              
332             package main;
333              
334             my $example = Example->new;
335              
336             my $error = $example->attempt_catch;
337              
338             $error;
339              
340             # "Died at ..."
341              
342             =back
343              
344             =cut
345              
346             =head2 error
347              
348             error(Maybe[HashRef] $args) (Error)
349              
350             The error function throws a L exception object using the
351             exception object arguments provided. This function isn't export unless requested.
352              
353             I>
354              
355             =over 4
356              
357             =item error example 1
358              
359             package Ability;
360              
361             use Venus::Mixin 'error';
362              
363             sub attempt_error {
364             error;
365             }
366              
367             sub EXPORT {
368             ['attempt_error']
369             }
370              
371             package Example;
372              
373             use Venus::Class 'with';
374              
375             with 'Ability';
376              
377             package main;
378              
379             my $example = Example->new;
380              
381             my $error = $example->attempt_error;
382              
383             # bless({...}, 'Venus::Error')
384              
385             =back
386              
387             =cut
388              
389             =head2 false
390              
391             false() (Bool)
392              
393             The false function returns a falsy boolean value which is designed to be
394             practically indistinguishable from the conventional numerical C<0> value. This
395             function is always exported unless a routine of the same name already exists.
396              
397             I>
398              
399             =over 4
400              
401             =item false example 1
402              
403             package Example;
404              
405             use Venus::Mixin;
406              
407             my $false = false;
408              
409             # 0
410              
411             =back
412              
413             =over 4
414              
415             =item false example 2
416              
417             package Example;
418              
419             use Venus::Mixin;
420              
421             my $true = !false;
422              
423             # 1
424              
425             =back
426              
427             =cut
428              
429             =head2 from
430              
431             from(Str $name) (Str)
432              
433             The from function registers one or more base classes for the calling package
434             and performs an L<"audit"|Venus::Core/AUDIT>. This function is always exported
435             unless a routine of the same name already exists.
436              
437             I>
438              
439             =over 4
440              
441             =item from example 1
442              
443             package Entity;
444              
445             use Venus::Role;
446              
447             attr 'startup';
448             attr 'shutdown';
449              
450             sub EXPORT {
451             ['startup', 'shutdown']
452             }
453              
454             package Record;
455              
456             use Venus::Class;
457              
458             sub AUDIT {
459             my ($self, $from) = @_;
460             die "Missing startup" if !$from->can('startup');
461             die "Missing shutdown" if !$from->can('shutdown');
462             }
463              
464             package Example;
465              
466             use Venus::Class;
467              
468             with 'Entity';
469              
470             from 'Record';
471              
472             # "Example"
473              
474             =back
475              
476             =cut
477              
478             =head2 mixin
479              
480             mixin(Str $name) (Str)
481              
482             The mixin function registers and consumes mixins for the calling package. This
483             function is always exported unless a routine of the same name already exists.
484              
485             I>
486              
487             =over 4
488              
489             =item mixin example 1
490              
491             package YesNo;
492              
493             use Venus::Mixin;
494              
495             sub no {
496             return 0;
497             }
498              
499             sub yes {
500             return 1;
501             }
502              
503             sub EXPORT {
504             ['no', 'yes']
505             }
506              
507             package Answer;
508              
509             use Venus::Mixin;
510              
511             mixin 'YesNo';
512              
513             # "Answer"
514              
515             =back
516              
517             =over 4
518              
519             =item mixin example 2
520              
521             package YesNo;
522              
523             use Venus::Mixin;
524              
525             sub no {
526             return 0;
527             }
528              
529             sub yes {
530             return 1;
531             }
532              
533             sub EXPORT {
534             ['no', 'yes']
535             }
536              
537             package Answer;
538              
539             use Venus::Mixin;
540              
541             mixin 'YesNo';
542              
543             sub no {
544             return [0];
545             }
546              
547             sub yes {
548             return [1];
549             }
550              
551             my $package = "Answer";
552              
553             # "Answer"
554              
555             =back
556              
557             =cut
558              
559             =head2 raise
560              
561             raise(Str $class | Tuple[Str, Str] $class, Maybe[HashRef] $args) (Error)
562              
563             The raise function generates and throws a named exception object derived from
564             L, or provided base class, using the exception object arguments
565             provided. This function isn't export unless requested.
566              
567             I>
568              
569             =over 4
570              
571             =item raise example 1
572              
573             package Ability;
574              
575             use Venus::Mixin 'raise';
576              
577             sub attempt_raise {
578             raise 'Example::Error';
579             }
580              
581             sub EXPORT {
582             ['attempt_raise']
583             }
584              
585             package Example;
586              
587             use Venus::Class 'with';
588              
589             with 'Ability';
590              
591             package main;
592              
593             my $example = Example->new;
594              
595             my $error = $example->attempt_raise;
596              
597             # bless({...}, 'Example::Error')
598              
599             =back
600              
601             =cut
602              
603             =head2 role
604              
605             role(Str $name) (Str)
606              
607             The role function registers and consumes roles for the calling package. This
608             function is always exported unless a routine of the same name already exists.
609              
610             I>
611              
612             =over 4
613              
614             =item role example 1
615              
616             package Ability;
617              
618             use Venus::Role;
619              
620             sub action {
621             return;
622             }
623              
624             package Example;
625              
626             use Venus::Class;
627              
628             role 'Ability';
629              
630             # "Example"
631              
632             =back
633              
634             =over 4
635              
636             =item role example 2
637              
638             package Ability;
639              
640             use Venus::Role;
641              
642             sub action {
643             return;
644             }
645              
646             sub EXPORT {
647             return ['action'];
648             }
649              
650             package Example;
651              
652             use Venus::Class;
653              
654             role 'Ability';
655              
656             # "Example"
657              
658             =back
659              
660             =cut
661              
662             =head2 test
663              
664             test(Str $name) (Str)
665              
666             The test function registers and consumes roles for the calling package and
667             performs an L<"audit"|Venus::Core/AUDIT>, effectively allowing a role to act as
668             an interface. This function is always exported unless a routine of the same
669             name already exists.
670              
671             I>
672              
673             =over 4
674              
675             =item test example 1
676              
677             package Actual;
678              
679             use Venus::Role;
680              
681             package Example;
682              
683             use Venus::Class;
684              
685             test 'Actual';
686              
687             # "Example"
688              
689             =back
690              
691             =over 4
692              
693             =item test example 2
694              
695             package Actual;
696              
697             use Venus::Role;
698              
699             sub AUDIT {
700             die "Example is not an 'actual' thing" if $_[1]->isa('Example');
701             }
702              
703             package Example;
704              
705             use Venus::Class;
706              
707             test 'Actual';
708              
709             # "Example"
710              
711             =back
712              
713             =cut
714              
715             =head2 true
716              
717             true() (Bool)
718              
719             The true function returns a truthy boolean value which is designed to be
720             practically indistinguishable from the conventional numerical C<1> value. This
721             function is always exported unless a routine of the same name already exists.
722              
723             I>
724              
725             =over 4
726              
727             =item true example 1
728              
729             package Example;
730              
731             use Venus::Class;
732              
733             my $true = true;
734              
735             # 1
736              
737             =back
738              
739             =over 4
740              
741             =item true example 2
742              
743             package Example;
744              
745             use Venus::Class;
746              
747             my $false = !true;
748              
749             # 0
750              
751             =back
752              
753             =cut
754              
755             =head2 with
756              
757             with(Str $name) (Str)
758              
759             The with function registers and consumes roles for the calling package. This
760             function is an alias of the L function and will perform an
761             L<"audit"|Venus::Core/AUDIT> if present. This function is always exported
762             unless a routine of the same name already exists.
763              
764             I>
765              
766             =over 4
767              
768             =item with example 1
769              
770             package Understanding;
771              
772             use Venus::Role;
773              
774             sub knowledge {
775             return;
776             }
777              
778             package Example;
779              
780             use Venus::Class;
781              
782             with 'Understanding';
783              
784             # "Example"
785              
786             =back
787              
788             =over 4
789              
790             =item with example 2
791              
792             package Understanding;
793              
794             use Venus::Role;
795              
796             sub knowledge {
797             return;
798             }
799              
800             sub EXPORT {
801             return ['knowledge'];
802             }
803              
804             package Example;
805              
806             use Venus::Class;
807              
808             with 'Understanding';
809              
810             # "Example"
811              
812             =back
813              
814             =cut
815              
816             =head1 AUTHORS
817              
818             Awncorp, C
819              
820             =cut
821              
822             =head1 LICENSE
823              
824             Copyright (C) 2000, Al Newkirk.
825              
826             This program is free software, you can redistribute it and/or modify it under
827             the terms of the Apache license version 2.0.
828              
829             =cut