File Coverage

blib/lib/Class/Superclasses.pm
Criterion Covered Total %
statement 111 111 100.0
branch 42 42 100.0
condition 8 8 100.0
subroutine 17 17 100.0
pod 3 3 100.0
total 181 181 100.0


line stmt bran cond sub pod time code
1             package Class::Superclasses;
2              
3             # ABSTRACT: Find all (direct) superclasses of a class
4              
5 18     18   874761 use strict;
  18         140  
  18         520  
6 18     18   96 use warnings;
  18         58  
  18         549  
7              
8 18     18   95 use List::Util qw(first);
  18         42  
  18         1952  
9 18     18   8686 use PPI;
  18         2087374  
  18         793  
10 18     18   161 use Scalar::Util qw(blessed);
  18         42  
  18         22904  
11              
12             our $VERSION = '1.00';
13              
14             sub new{
15 18     18 1 10340 my ($class,$doc) = @_,
16             my $self = {};
17              
18 18         54 bless $self,$class;
19            
20 18         88 $self->document($doc);
21            
22 18         51 return $self;
23             }
24              
25             sub superclasses{
26 16     16 1 117 my ($self) = @_;
27 16 100       49 return wantarray ? @{$self->{super}} : $self->{super};
  14         62  
28             }
29              
30             sub document{
31 31     31 1 5229 my ($self,$doc) = @_;
32              
33 31 100       148 $self->{super} = $self->_find_super($doc) if defined $doc;
34              
35 30         2335 return $self;
36             }
37              
38             sub _find_super{
39 20     20   2892 my ($self,$doc) = @_;
40              
41 20         38 my $ppi;
42 20 100 100     153 if ( blessed $doc && $doc->isa('PPI::Document') ) {
43 1         2 $ppi = $doc;
44             }
45             else {
46 19 100       137 $ppi = PPI::Document->new($doc) or die $!;
47             }
48              
49 18         56253 my $varref = $ppi->find('PPI::Statement::Variable');
50 18         12870 my @vars = ();
51              
52 18 100       70 if($varref){
53 5         22 @vars = $self->_get_isa_values($varref);
54             }
55            
56 18   100     62 my $baseref = $ppi->find('PPI::Statement::Include') || [];
57 18         11634 my @includes = qw(base parent);
58 18         66 my @base = $self->_get_include_values([grep{my $i = $_->module; grep{ $_ eq $i }@includes }@$baseref]);
  13         64  
  13         476  
  26         99  
59              
60 18         38 my @moose;
61 18         75 my @moose_like_modules = qw(Moose Moo Mouse Mo);
62 18         42 my $is_moose;
63              
64 18         35 for my $base_class ( @{$baseref} ) {
  18         41  
65 13 100   35   88 if ( first{ $base_class->module eq $_ }@moose_like_modules ) {
  35         525  
66              
67 7         171 for my $stmt ( @{ $ppi->find('PPI::Statement') } ) {
  7         18  
68 24         4836 push @moose, $self->_get_moose_values( $stmt );
69             }
70             }
71             }
72              
73 18         408 return [@vars, @base, @moose];
74             }
75              
76             sub _get_moose_values{
77 34     34   25202 my ($self,$elem) = @_;
78              
79 34         52 my @parents;
80              
81 34 100       116 return if $elem->schild(0)->content ne 'extends';
82              
83 12 100       202 if ( $elem->find_any('PPI::Statement::Expression') ) {
    100          
    100          
84 5         1481 push @parents, $self->_parse_expression( $elem );
85             }
86             elsif ( $elem->find_any('PPI::Token::QuoteLike::Words') ) {
87 2         878 push @parents, $self->_parse_quotelike( $elem );
88             }
89             elsif( $elem->find( \&_any_quotes ) ){
90 4         286 push @parents, $self->_parse_quotes( $elem );
91             }
92              
93 12         120 return @parents;
94             }
95              
96             sub _get_include_values{
97 25     25   23984 my ($self, $baseref) = @_;
98 25         50 my @parents;
99              
100             BASE:
101 25         41 for my $base( @{$baseref} ){
  25         65  
102 13         20 my @tmp_array;
103              
104 13 100       80 if( $base->find_any('PPI::Statement::Expression') ){
    100          
    100          
105 8         2852 push @tmp_array, $self->_parse_expression( $base );
106             }
107             elsif( $base->find_any('PPI::Token::QuoteLike::Words') ){
108 1         598 push @tmp_array, $self->_parse_quotelike( $base );
109             }
110             elsif( $base->find( \&_any_quotes ) ){
111 3         272 push @tmp_array, $self->_parse_quotes( $base );
112             }
113              
114 13 100       179 if ( $base->module eq 'parent' ) {
115 6         173 @tmp_array = grep{ $_ ne '-norequire' }@tmp_array;
  13         37  
116             }
117              
118 13         228 push @parents, @tmp_array;
119             }
120              
121 25         68 return @parents;
122             }
123              
124             sub _any_quotes{
125 79     79   13668 my ($parent,$elem) = @_;
126              
127 79 100 100     270 $parent eq $elem->parent and (
128             $elem->isa( 'PPI::Token::Quote::Double' ) or
129             $elem->isa( 'PPI::Token::Quote::Single' )
130             );
131             }
132              
133             sub _get_isa_values{
134 11     11   15294 my ($self,$varref) = @_;
135 11         23 my @parents;
136              
137 11 100       18 for my $variable ( @{ $varref || [] } ) {
  11         87  
138 9         52 my @children = $variable->children();
139            
140 9 100       102 if( grep{$_->content eq '@ISA'}@children ) {
  64         372  
141 8 100       155 if( $variable->find_any('PPI::Token::QuoteLike::Words') ) {
    100          
142 2         661 push @parents, $self->_parse_quotelike($variable);
143             }
144             elsif( $variable->find_any('PPI::Statement::Expression') ) {
145 5         4852 push @parents, $self->_parse_expression($variable);
146             }
147             }
148             }
149              
150 11         506 return @parents;
151             }
152              
153             sub _parse_expression {
154 21     21   7692 my ($self, $variable) = @_;
155              
156 21         115 my $ref = $variable->find( 'PPI::Statement::Expression' );
157 21         9908 my @parents;
158              
159 21         47 for my $expression ( @{$ref} ) {
  21         75  
160 22         142 for my $element( $expression->children ){
161 78 100       625 if( $element->class =~ /^PPI::Token::Quote::/ ) {
162 39         323 push @parents, $element->string;
163             }
164             }
165             }
166              
167 21         201 return @parents;
168             }
169              
170             sub _parse_quotes{
171 7     7   20 my ($self,$variable,$type) = @_;
172            
173 7         12 my @parents;
174            
175 7         37 for my $element( $variable->children ){
176 52         195 my ($type) = $element->class =~ /PPI::Token::Quote::([^:]+)$/;
177              
178 52 100       266 next unless $type;
179              
180 12         42 my $value = $element->string;
181 12         83 push @parents, $value;
182             }
183              
184 7         23 return @parents;
185             }
186              
187             sub _parse_quotelike{
188 11     11   8305 my ($self,$variable) = @_;
189              
190 11         47 my $words = ($variable->find('PPI::Token::QuoteLike::Words'))[0]->[0];
191 11         2866 my $operator = $words->{operator};
192 11         32 my $section_type = $words->{sections}->[0]->{type};
193 11         42 my ($left,$right) = split //, $section_type;
194 11         47 (my $value = $words->content) =~ s~$operator\Q$left\E(.*)\Q$right\E~$1~;
195 11         296 my @parents = split /\s+/, $value;
196              
197 11         50 return @parents;
198             }
199              
200              
201             1;
202              
203             __END__