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 19 89.4
pod 0 4 0.0
total 109 125 87.2


line stmt bran cond sub pod time code
1 108     108   2234 use 5.010001;
  108         378  
2 108     108   551 use strict;
  108         233  
  108         2600  
3 108     108   513 use warnings;
  108         244  
  108         5706  
4              
5             use Mite::Miteception -role, -all;
6 108     108   676  
  108         282  
  108         884  
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.010008';
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 189     189   494  
20             return if !$self->name; # called from constructor
21 189 50       1271  
22             # Set up our @ISA so we can use mro to calculate the class hierarchy
23             $self->_set_isa;
24 189         764  
25             # Allow $self->parents to recalculate itself
26             $self->_clear_parents;
27 189         936 };
28              
29             has superclass_args =>
30             is => rw,
31             isa => Map[ NonEmptyStr, HashRef|Undef ],
32             builder => sub { {} };
33 150     150   455  
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 189     189   378 my $name = $self->name;
46              
47 189         549 mro::set_mro($name, "c3");
48             no strict 'refs';
49 189         1210 @{$name.'::ISA'} = @{$self->superclasses};
50 108     108   849  
  108         233  
  108         8471  
51 189         305 return;
  189         3613  
  189         807  
52             }
53 189         756  
54             my $self = shift;
55              
56             my $name = $self->name;
57 4     4 0 8  
58             no strict 'refs';
59 4         12 return @{$name.'::ISA'};
60             }
61 108     108   705  
  108         271  
  108         52599  
62 4         6 my $self = shift;
  4         22  
63              
64             return @{mro::get_linear_isa($self->name)};
65             }
66 666     666 0 1060  
67             my $self = shift;
68 666         839  
  666         4067  
69             my $project = $self->project;
70              
71             return grep defined, map { $project->class($_) } $self->linear_isa;
72 81     81 0 140 }
73              
74 81         229 my $self = shift;
75              
76 81         220 my ( @extends, %extends_args );
  194         461  
77             while ( @_ ) {
78             my $class = shift;
79             my $args = Str->check( $_[0] ) ? undef : shift;
80 23     23 0 68 push @extends, $class;
81             $extends_args{$class} = $args;
82 23         45 }
83 23         102 $self->superclasses( \@extends );
84 25         52 $self->superclass_args( \%extends_args );
85 25 100       122  
86 25         413 return;
87 25         95 }
88              
89 23         117 my $self = shift;
90 23         159  
91             my $extends = $self->superclasses;
92 23         52 return [] if !@$extends;
93              
94             # Load each parent and store its Mite::Class
95             my @parents;
96 112     112   306 for my $parent_name (@$extends) {
97             push @parents, $self->_get_parent($parent_name);
98 112         385 }
99 112 100       547  
100             return \@parents;
101             }
102 21         71  
103 21         79 my ( $self, $parent_name ) = ( shift, @_ );
104 26         85  
105             my $project = $self->project;
106              
107 21         67 # See if it's already loaded
108             my $parent = $project->class($parent_name);
109             return $parent if $parent;
110              
111 118     118   262 # If not, try to load it
112             eval "require $parent_name;";
113 118         276 $parent = $project->class($parent_name);
114             return $parent if $parent;
115              
116 118         361 return;
117 118 100       529 }
118              
119             before inject_mite_functions => sub {
120 10         559 my ( $self, $file, $arg ) = ( shift, @_ );
121 10         277  
122 10 50       26 my $requested = sub { $arg->{$_[0]} ? 1 : $arg->{'!'.$_[0]} ? 0 : $arg->{'-all'} ? 1 : $_[1]; };
123             my $defaults = ! $arg->{'!-defaults'};
124 10         46 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 108     108   840 : @_
  108         348  
  108         61434  
137             );
138             };
139              
140             $self->imported_keywords->{'extends'} = 'sub {}';
141 0 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 121     121   323 # Don't require a class from the same source
180             grep { !$source || !$source->has_class($_) }
181 121         419 @$extends;
182 121 100       765  
183             my $version_tests = join "\n\t",
184 30         88 map { sprintf '%s->VERSION( %s );',
185             B::perlstring( $_ ),
186             B::perlstring( $self->superclass_args->{$_}{'-version'} )
187 13         71 }
188             grep {
189 30   66     80 $self->superclass_args->{$_}
  33         187  
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 30         84 $require_list
199 33 50       100 $version_tests
200             use mro 'c3';
201             our \@ISA;
202             push \@ISA, $isa_list;
203 30         170 }
204             END
205 30         190 }
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;