File Coverage

blib/lib/Class/Superclasses.pm
Criterion Covered Total %
statement 107 107 100.0
branch 40 40 100.0
condition 5 5 100.0
subroutine 16 16 100.0
pod 3 3 100.0
total 171 171 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 16     16   560993 use strict;
  16         90  
  16         421  
6 16     16   84 use warnings;
  16         46  
  16         545  
7              
8 16     16   76 use List::Util qw(first);
  16         28  
  16         1587  
9 16     16   7172 use PPI;
  16         1645851  
  16         16193  
10              
11             our $VERSION = '0.09';
12              
13             sub new{
14 16     16 1 14768 my ($class,$doc) = @_,
15             my $self = {};
16              
17 16         42 bless $self,$class;
18            
19 16         67 $self->document($doc);
20            
21 16         35 return $self;
22             }
23              
24             sub superclasses{
25 14     14 1 91 my ($self) = @_;
26 14 100       40 return wantarray ? @{$self->{super}} : $self->{super};
  13         125  
27             }
28              
29             sub document{
30 28     28 1 5551 my ($self,$doc) = @_;
31              
32 28 100       94 if(defined $doc){
33 13         51 $self->{document} = $doc;
34 13         44 $self->{super} = $self->_find_super($doc);
35             }
36              
37 28         1828 return $self;
38             }
39              
40             sub _find_super{
41 18     18   2556 my ($self,$doc) = @_;
42              
43 18 100       130 my $ppi = PPI::Document->new($doc) or die $!;
44 17         49830 my $varref = $ppi->find('PPI::Statement::Variable');
45 17         10912 my @vars = ();
46              
47 17 100       58 if($varref){
48 4         17 @vars = $self->_get_isa_values($varref);
49             }
50            
51 17   100     54 my $baseref = $ppi->find('PPI::Statement::Include') || [];
52 17         9051 my @includes = qw(base parent);
53 17         58 my @base = $self->_get_include_values([grep{my $i = $_->module; grep{ $_ eq $i }@includes }@$baseref]);
  13         62  
  13         641  
  26         93  
54              
55 17         28 my @moose;
56 17         52 my @moose_like_modules = qw(Moose Moo Mouse Mo);
57 17         28 my $is_moose;
58              
59 17         24 for my $base_class ( @{$baseref} ) {
  17         35  
60 13 100   35   88 if ( first{ $base_class->module eq $_ }@moose_like_modules ) {
  35         419  
61              
62 7         133 for my $stmt ( @{ $ppi->find('PPI::Statement') } ) {
  7         16  
63 24         4141 push @moose, $self->_get_moose_values( $stmt );
64             }
65             }
66             }
67              
68 17         351 return [@vars, @base, @moose];
69             }
70              
71             sub _get_moose_values{
72 34     34   30240 my ($self,$elem) = @_;
73              
74 34         47 my @parents;
75              
76 34 100       78 return if $elem->schild(0)->content ne 'extends';
77              
78 12 100       172 if ( $elem->find_any('PPI::Statement::Expression') ) {
    100          
    100          
79 5         1215 push @parents, $self->_parse_expression( $elem );
80             }
81             elsif ( $elem->find_any('PPI::Token::QuoteLike::Words') ) {
82 2         715 push @parents, $self->_parse_quotelike( $elem );
83             }
84             elsif( $elem->find( \&_any_quotes ) ){
85 4         249 push @parents, $self->_parse_quotes( $elem );
86             }
87              
88 12         110 return @parents;
89             }
90              
91             sub _get_include_values{
92 24     24   19746 my ($self, $baseref) = @_;
93 24         112 my @parents;
94              
95             BASE:
96 24         38 for my $base( @{$baseref} ){
  24         89  
97 13         24 my @tmp_array;
98              
99 13 100       52 if( $base->find_any('PPI::Statement::Expression') ){
    100          
    100          
100 8         2290 push @tmp_array, $self->_parse_expression( $base );
101             }
102             elsif( $base->find_any('PPI::Token::QuoteLike::Words') ){
103 1         859 push @tmp_array, $self->_parse_quotelike( $base );
104             }
105             elsif( $base->find( \&_any_quotes ) ){
106 3         226 push @tmp_array, $self->_parse_quotes( $base );
107             }
108              
109 13 100       158 if ( $base->module eq 'parent' ) {
110 6         144 @tmp_array = grep{ $_ ne '-norequire' }@tmp_array;
  13         31  
111             }
112              
113 13         191 push @parents, @tmp_array;
114             }
115              
116 24         64 return @parents;
117             }
118              
119             sub _any_quotes{
120 79     79   11579 my ($parent,$elem) = @_;
121              
122 79 100 100     265 $parent eq $elem->parent and (
123             $elem->isa( 'PPI::Token::Quote::Double' ) or
124             $elem->isa( 'PPI::Token::Quote::Single' )
125             );
126             }
127              
128             sub _get_isa_values{
129 10     10   21587 my ($self,$varref) = @_;
130 10         16 my @parents;
131              
132 10 100       18 for my $variable ( @{ $varref || [] } ) {
  10         39  
133 8         40 my @children = $variable->children();
134            
135 8 100       55 if( grep{$_->content eq '@ISA'}@children ) {
  56         264  
136 7 100       120 if( $variable->find_any('PPI::Token::QuoteLike::Words') ) {
    100          
137 2         565 push @parents, $self->_parse_quotelike($variable);
138             }
139             elsif( $variable->find_any('PPI::Statement::Expression') ) {
140 4         3305 push @parents, $self->_parse_expression($variable);
141             }
142             }
143             }
144              
145 10         437 return @parents;
146             }
147              
148             sub _parse_expression {
149 20     20   6626 my ($self, $variable) = @_;
150              
151 20         88 my $ref = $variable->find( 'PPI::Statement::Expression' );
152 20         7799 my @parents;
153              
154 20         40 for my $expression ( @{$ref} ) {
  20         51  
155 21         106 for my $element( $expression->children ){
156 74 100       475 if( $element->class =~ /^PPI::Token::Quote::/ ) {
157 37         291 push @parents, $element->string;
158             }
159             }
160             }
161              
162 20         149 return @parents;
163             }
164              
165             sub _parse_quotes{
166 7     7   17 my ($self,$variable,$type) = @_;
167            
168 7         11 my @parents;
169            
170 7         37 for my $element( $variable->children ){
171 52         165 my ($type) = $element->class =~ /PPI::Token::Quote::([^:]+)$/;
172              
173 52 100       225 next unless $type;
174              
175 12         41 my $value = $element->string;
176 12         176 push @parents, $value;
177             }
178              
179 7         22 return @parents;
180             }
181              
182             sub _parse_quotelike{
183 11     11   6682 my ($self,$variable) = @_;
184              
185 11         42 my $words = ($variable->find('PPI::Token::QuoteLike::Words'))[0]->[0];
186 11         2318 my $operator = $words->{operator};
187 11         29 my $section_type = $words->{sections}->[0]->{type};
188 11         49 my ($left,$right) = split //, $section_type;
189 11         36 (my $value = $words->content) =~ s~$operator\Q$left\E(.*)\Q$right\E~$1~;
190 11         265 my @parents = split /\s+/, $value;
191              
192 11         47 return @parents;
193             }
194              
195              
196             1;
197              
198             __END__