File Coverage

blib/lib/Mite/Trait/HasSuperclasses.pm
Criterion Covered Total %
statement 79 81 97.5
branch 11 18 61.1
condition 2 3 66.6
subroutine 17 18 94.4
pod 0 4 0.0
total 109 124 87.9


line stmt bran cond sub pod time code
1 109     109   2717 use 5.010001;
  109         418  
2 109     109   685 use strict;
  109         368  
  109         2824  
3 109     109   606 use warnings;
  109         255  
  109         6459  
4              
5             use Mite::Miteception -role, -all;
6 109     109   754  
  109         398  
  109         1152  
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.011000';
9              
10             # Super classes as class names
11             has extends =>
12             is => bare,
13             accessor => 'superclasses',
14             isa => ArrayRef[ValidClassName],
15             default => sub { [] },
16             default_does_trigger => true,
17             trigger => sub {
18             my $self = shift;
19 175     175   576  
20             return if !$self->name; # called from constructor
21 175 50       1373  
22             # Set up our @ISA so we can use mro to calculate the class hierarchy
23             $self->_set_isa;
24 175         913  
25             # Allow $self->parents to recalculate itself
26             $self->_clear_parents;
27 175         1080 };
28              
29             has superclass_args =>
30             is => rw,
31             isa => Map[ NonEmptyStr, HashRef|Undef ],
32             builder => sub { {} };
33 142     142   562  
34             # Super classes as Mite::Classes populated from $self->superclasses
35             has parents =>
36             is => ro,
37             isa => ArrayRef[MiteClass],
38             # Build on demand to allow the project to load all the classes first
39             lazy => true,
40             builder => '_build_parents',
41             clearer => '_clear_parents';
42              
43             my $self = shift;
44              
45 175     175   438 my $name = $self->name;
46              
47 175         617 mro::set_mro($name, "c3");
48             no strict 'refs';
49 175         1301 @{$name.'::ISA'} = @{$self->superclasses};
50 109     109   898  
  109         268  
  109         9717  
51 175         346 return;
  175         3693  
  175         1010  
52             }
53 175         776  
54             my $self = shift;
55              
56             my $name = $self->name;
57 2     2 0 5  
58             no strict 'refs';
59 2         9 return @{$name.'::ISA'};
60             }
61 109     109   835  
  109         295  
  109         60867  
62 2         4 my $self = shift;
  2         13  
63              
64             return @{mro::get_linear_isa($self->name)};
65             }
66 621     621 0 1104  
67             my $self = shift;
68 621         919  
  621         4291  
69             my $project = $self->project;
70              
71             return grep defined, map { $project->class($_) } $self->linear_isa;
72 71     71 0 141 }
73              
74 71         248 my $self = shift;
75              
76 71         231 my ( @extends, %extends_args );
  166         451  
77             while ( @_ ) {
78             my $class = shift;
79             my $args = Str->check( $_[0] ) ? undef : shift;
80 23     23 0 57 push @extends, $class;
81             $extends_args{$class} = $args;
82 23         60 }
83 23         87 $self->superclasses( \@extends );
84 25         60 $self->superclass_args( \%extends_args );
85 25 100       111  
86 25         426 return;
87 25         101 }
88              
89 23         127 my $self = shift;
90 23         136  
91             my $extends = $self->superclasses;
92 23         68 return [] if !@$extends;
93              
94             # Load each parent and store its Mite::Class
95             my @parents;
96 106     106   285 for my $parent_name (@$extends) {
97             push @parents, $self->_get_parent($parent_name);
98 106         446 }
99 106 100       690  
100             return \@parents;
101             }
102 18         37  
103 18         55 my ( $self, $parent_name ) = ( shift, @_ );
104 21         74  
105             my $project = $self->project;
106              
107 18         54 # See if it's already loaded
108             my $parent = $project->class($parent_name);
109             return $parent if $parent;
110              
111 98     98   234 # If not, try to load it
112             eval "require $parent_name;";
113 98         278 $parent = $project->class($parent_name);
114             return $parent if $parent;
115              
116 98         329 return;
117 98 100       494 }
118              
119             before inject_mite_functions => sub {
120 10         703 my ( $self, $file, $arg ) = ( shift, @_ );
121 10         364  
122 10 50       25 my $requested = sub { $arg->{$_[0]} ? 1 : $arg->{'!'.$_[0]} ? 0 : $arg->{'-all'} ? 1 : $_[1]; };
123             my $defaults = ! $arg->{'!-defaults'};
124 10         49 my $shim = $self->shim_name;
125             my $package = $self->name;
126             my $fake_ns = $self->project->can('_module_fakeout_namespace') && $self->project->_module_fakeout_namespace;
127              
128             no strict 'refs';
129              
130             if ( $requested->( 'extends', $defaults ) ) {
131              
132             *{ $package .'::extends' } = sub {
133             return $self->handle_extends_keyword(
134             defined( $fake_ns )
135             ? map Str->check($_) ? "$fake_ns\::$_" : $_, @_
136 109     109   895 : @_
  109         265  
  109         73065  
137             );
138             };
139              
140             $self->imported_keywords->{'extends'} = 'sub {}';
141 0 0   0     }
    0          
142             };
143              
144             around compilation_stages => sub {
145             my ( $next, $self ) = ( shift, shift );
146             my @stages = $self->$next( @_ );
147             push @stages, qw( _compile_extends );
148             return @stages;
149             };
150              
151             around _compile_meta_method => sub {
152             my ( $next, $self ) = ( shift, shift );
153              
154             # Check if we are inheriting from a Mite class in this project
155             my $inherit_from_mite = do {
156             # First parent
157             my $first_isa = do {
158             my @isa = $self->linear_isa;
159             shift @isa;
160             shift @isa;
161             };
162             !! ( $first_isa and $self->_get_parent( $first_isa ) );
163             };
164              
165             return '' if $inherit_from_mite;
166              
167             return $self->$next( @_ );
168             };
169              
170             my $self = shift;
171              
172             my $extends = $self->superclasses;
173             return '' unless @$extends;
174              
175             my $source = $self->source;
176              
177             my $require_list = join "\n\t",
178             map { "require $_;" }
179 113     113   299 # Don't require a class from the same source
180             grep { !$source || !$source->has_class($_) }
181 113         452 @$extends;
182 113 100       886  
183             my $version_tests = join "\n\t",
184 25         89 map { sprintf '%s->VERSION( %s );',
185             B::perlstring( $_ ),
186             B::perlstring( $self->superclass_args->{$_}{'-version'} )
187 7         42 }
188             grep {
189 25   66     79 $self->superclass_args->{$_}
  27         201  
190             and $self->superclass_args->{$_}{'-version'}
191             }
192             @$extends;
193              
194             my $isa_list = join ", ", map B::perlstring($_), @$extends;
195 0         0  
196             return <<"END";
197             BEGIN {
198 25         93 $require_list
199 27 50       130 $version_tests
200             use mro 'c3';
201             our \@ISA;
202             push \@ISA, $isa_list;
203 25         203 }
204             END
205 25         191 }
206              
207             around _compile_mop_postamble => sub {
208             my ( $next, $self ) = ( shift, shift );
209             my $code = $self->$next( @_ );
210              
211             my @superclasses = @{ $self->superclasses || [] }
212             or return $code;
213             $code .= sprintf "Moose::Util::find_meta( %s )->superclasses( %s );\n",
214             B::perlstring( $self->name ),
215             join q{, }, map B::perlstring( $_ ), @superclasses;
216              
217             return $code;
218             };
219              
220             1;