File Coverage

blib/lib/Moxie.pm
Criterion Covered Total %
statement 93 93 100.0
branch 12 16 75.0
condition 5 6 83.3
subroutine 18 18 100.0
pod 0 1 0.0
total 128 134 95.5


line stmt bran cond sub pod time code
1             package Moxie;
2             # ABSTRACT: Not Another Moose Clone
3              
4 49     49   3007239 use v5.22;
  49         582  
5 49     49   223 use warnings;
  49         89  
  49         1431  
6 49         244 use experimental qw[
7             signatures
8             postderef
9 49     49   12294 ];
  49         122526  
10              
11 49     49   8262 use experimental (); # need this later when we load features
  49         90  
  49         640  
12 49     49   10219 use Module::Runtime (); # load things so they DWIM
  49         41878  
  49         909  
13 49     49   13051 use BEGIN::Lift (); # fake some keywords
  49         172706  
  49         1117  
14 49     49   13326 use Method::Traits (); # for accessor/method generators
  49         1191134  
  49         1231  
15              
16 49     49   334 use MOP;
  49         87  
  49         1105  
17 49     49   221 use MOP::Util;
  49         86  
  49         1025  
18              
19 49     49   13405 use Moxie::Object;
  49         113  
  49         1422  
20 49     49   12279 use Moxie::Object::Immutable;
  49         683  
  49         1353  
21 49     49   12035 use Moxie::Traits::Provider;
  49         117  
  49         36668  
22              
23             our $VERSION = '0.07';
24             our $AUTHORITY = 'cpan:STEVAN';
25              
26 138     138   47438 sub import ($class, %opts) {
  138         257  
  138         223  
  138         178  
27             # get the caller ...
28 138         285 my $caller = caller;
29              
30             # make the assumption that if we are
31             # loaded outside of main then we are
32             # likely being loaded in a class, so
33             # turn on all the features
34 138 50       426 if ( $caller ne 'main' ) {
35 138         649 $class->import_into( $caller, \%opts );
36             }
37             }
38              
39 138     138 0 175 sub import_into ($class, $caller, $opts) {
  138         197  
  138         199  
  138         168  
  138         161  
40              
41             # NOTE:
42             # create the meta-object, we start
43             # with this as a role, but it will
44             # get "cast" to a class if there
45             # is a need for it.
46 138         443 my $meta = MOP::Role->new( name => $caller );
47              
48             # turn on strict/warnings
49 138         8580 strict->import;
50 138         1426 warnings->import;
51              
52             # so we can have fun with attributes ...
53 138         1481 warnings->unimport('reserved');
54              
55             # turn on signatures and more
56 138         560 experimental->import($_) foreach qw[
57             signatures
58              
59             postderef
60             postderef_qq
61              
62             current_sub
63             lexical_subs
64              
65             say
66             state
67             ];
68              
69             # turn on refaliasing if we have it ...
70 138 50       22732 experimental->import('refaliasing') if $] >= 5.022;
71              
72             # turn on declared refs if we have it ...
73 138 50       3256 experimental->import('declared_refs') if $] >= 5.026;
74              
75             # import has, extend and with keyword
76              
77 73         112 BEGIN::Lift::install(
78 73     73   91 ($caller, 'has') => sub ($name, @args) {
  73         1202  
  73         114  
79              
80             # NOTE:
81             # Handle the simple case of `has $name => $code`
82             # by converting it into the more complex
83             # `has $name => %opts` version, just easier
84             # to maintain internal consistency.
85             # - SL
86              
87 73 100 66     330 @args = ( default => $args[0] )
88             if scalar @args == 1
89             && ref $args[0] eq 'CODE';
90              
91 73         182 my %args = @args;
92              
93             # NOTE:
94             # handle the simple case of `required => 1`
95             # by providing this default error message
96             # with the name embedded. This has to be done
97             # here because the Initializer object does
98             # not know the name (nor does it need to)
99             # - SL
100              
101             # TODO - i18n the error message
102             $args{required} = 'A value for `'.$name.'` is required'
103             if exists $args{required}
104 73 100 100     244 && $args{required} =~ /^1$/;
105              
106 73         232 my $initializer = MOP::Slot::Initializer->new(
107             within_package => $meta->name,
108             %args
109             );
110              
111 73         11477 $meta->add_slot( $name, $initializer );
112 73         13883 return;
113             }
114 138         3757 );
115              
116 93         182 BEGIN::Lift::install(
117 93     93   241 ($caller, 'extends') => sub (@isa) {
  93         5247  
118 93         337 Module::Runtime::use_package_optimistically( $_ ) foreach @isa;
119             ($meta->isa('MOP::Class')
120             ? $meta
121 93 50       7967 : do {
122             # FIXME:
123             # This is gross ... - SL
124 93         330 Internals::SvREADONLY( $$meta, 0 );
125 93         158 bless $meta => 'MOP::Class'; # cast into class
126 93         397 Internals::SvREADONLY( $$meta, 1 );
127 93         752 $meta;
128             }
129             )->set_superclasses( @isa );
130 93         12792 return;
131             }
132 138         17725 );
133              
134 41         80 BEGIN::Lift::install(
135 41     41   63 ($caller, 'with') => sub (@does) {
  41         1110  
136 41         140 Module::Runtime::use_package_optimistically( $_ ) foreach @does;
137 41         10452 $meta->set_roles( @does );
138 41         9351 return;
139             }
140 138         14159 );
141              
142             # setup the base traits,
143 138         13475 my @traits = Moxie::Traits::Provider::list_providers();
144             # and anything we were asked to load ...
145 138 100       403 if ( exists $opts->{'traits'} ) {
146 36         88 foreach my $trait ( $opts->{'traits'}->@* ) {
147 37 100       116 if ( $trait eq ':experimental' ) {
148 34         94 push @traits => Moxie::Traits::Provider::list_experimental_providers();;
149             }
150             else {
151 3         6 push @traits => $trait;
152             }
153             }
154             }
155              
156             # then schedule the trait collection ...
157 138         427 Method::Traits->import_into( $meta->name, @traits );
158              
159             # install our class finalizer
160             MOP::Util::defer_until_UNITCHECK(sub {
161              
162             # pre-populate the cache for all the slots (if it is a class)
163 138     138   78648 MOP::Util::inherit_slots( $meta );
164              
165             # apply roles ...
166 138         14808 MOP::Util::compose_roles( $meta );
167              
168             # TODO:
169             # Consider locking the %HAS hash now, this will
170             # prevent anyone from adding new fields after
171             # compile time.
172             # - SL
173              
174 138         35983 });
175             }
176              
177             1;
178              
179             __END__