File Coverage

blib/lib/CPANfile/Parse/PPI.pm
Criterion Covered Total %
statement 63 63 100.0
branch 35 38 92.1
condition 6 6 100.0
subroutine 10 10 100.0
pod 1 1 100.0
total 115 118 97.4


line stmt bran cond sub pod time code
1             package CPANfile::Parse::PPI;
2              
3             # ABSTRACT: Parse Is with PPI
4              
5 8     8   3502 use strict;
  8         62  
  8         236  
6 8     8   41 use warnings;
  8         15  
  8         188  
7              
8 8     8   4813 use PPI;
  8         941005  
  8         327  
9 8     8   4601 use Moo;
  8         106204  
  8         42  
10 8     8   12178 use Carp qw(carp croak);
  8         20  
  8         5693  
11              
12             our $VERSION = '0.04';
13              
14             my $strict;
15              
16             has modules => (
17             is => 'ro',
18             isa => sub {
19             die if 'ARRAY' ne ref $_[0];
20             }
21             );
22              
23              
24             sub BUILDARGS {
25 27     27 1 259829 my ($class, $file_or_code) = @_;
26              
27 27         93 my @modules = _parse( $file_or_code );
28              
29             return {
30 24         19514 modules => \@modules,
31             };
32             }
33              
34             sub import {
35 8 100   8   69 $strict = 1 if grep{ $_ eq '-strict' }@_;
  11         293  
36             }
37              
38             sub _parse {
39 27     27   65 my ($file_or_code) = @_;
40              
41 27         174 my $doc = PPI::Document->new( $file_or_code );
42             my $requires = $doc->find(
43             sub {
44 3309 100 100 3309   37688 $_[1]->isa('PPI::Token::Word') and (
45             $_[1]->content eq 'requires' ||
46             $_[1]->content eq 'recommends'
47             )
48             }
49 27         374066 );
50              
51 27 50       485 return if !$requires;
52              
53 27         58 my @modules;
54              
55             REQUIRED:
56 27 50       50 for my $required ( @{ $requires || [] } ) {
  27         105  
57 276         669 my $value = $required->snext_sibling;
58              
59 276         5802 my $type = $required->content;
60              
61 276 100       1314 my $can_string = $value->can('string') ? 1 : 0;
62 276 100       782 my $prereq = $can_string ?
63             $value->string :
64             $value->content;
65              
66 276 100       1669 next REQUIRED if $prereq eq 'perl';
67              
68 260 100 100     1555 if (
69             $value->isa('PPI::Token::Symbol') ||
70             $prereq =~ m{\A[^A-Za-z]}
71             ) {
72 6 100       146 carp 'Cannot handle dynamic code' if !$strict;
73 6 100       2461 croak 'Cannot handle dynamic code' if $strict;
74              
75 3         14 next REQUIRED;
76             }
77              
78 254         435 my $stage = '';
79              
80 254         341 my $parent_node = $value;
81              
82             PARENT:
83 254         336 while ( 1 ) {
84 509         1002 $parent_node = $parent_node->parent;
85 509 50       2173 last PARENT if !$parent_node;
86 509 100       1341 last PARENT if $parent_node->isa('PPI::Document');
87              
88 380 100       873 if ( $parent_node->isa('PPI::Structure::Block') ) {
89 126         234 $parent_node = $parent_node->parent;
90              
91 126 100   148   704 my ($on) = $parent_node->find_first( sub { $_[1]->isa('PPI::Token::Word') && $_[1]->content eq 'on' } );
  148         2847  
92              
93 126 100       1962 next PARENT if !$on;
94              
95 125         255 my $word = $on->snext_sibling;
96 125 100       2653 $stage = $word->can('string') ? $word->string : $word->content;
97            
98 125         681 last PARENT;
99             }
100             }
101              
102 254         392 my $version = '';
103 254         472 my $sibling = $value->snext_sibling;
104             SIBLING:
105 254         5050 while ( 1 ) {
106 318 100       1409 last SIBLING if !$sibling;
107              
108 254 100       682 do { $sibling = $sibling->snext_sibling; next SIBLING } if !$sibling->isa('PPI::Token::Operator');
  64         153  
  64         1362  
109              
110 190         395 my $value = $sibling->snext_sibling;
111 190 100       4552 $version = $value->can('string') ? $value->string : $value->content;
112              
113 190         1117 last SIBLING;
114             }
115              
116 254         1142 push @modules, {
117             name => $prereq,
118             version => $version,
119             type => $type,
120             stage => $stage,
121             };
122             }
123              
124 24         161 return @modules;
125             }
126              
127             1;
128              
129             __END__