File Coverage

blib/lib/Dist/Zilla/Role/PPI.pm
Criterion Covered Total %
statement 41 46 89.1
branch 17 20 85.0
condition 5 6 83.3
subroutine 7 8 87.5
pod 3 3 100.0
total 73 83 87.9


line stmt bran cond sub pod time code
1             # ABSTRACT: a role for plugins which use PPI
2              
3             use Moose::Role;
4 16     16   7680  
  16         48  
  16         124  
5             use Dist::Zilla::Pragmas;
6 16     16   83095  
  16         47  
  16         132  
7             use Digest::MD5 qw(md5);
8 16     16   138  
  16         41  
  16         1357  
9             use namespace::autoclean;
10 16     16   308  
  16         52  
  16         124  
11             #pod =head1 DESCRIPTION
12             #pod
13             #pod This role provides some common utilities for plugins which use L<PPI>.
14             #pod
15             #pod =method ppi_document_for_file
16             #pod
17             #pod my $document = $self->ppi_document_for_file($file);
18             #pod
19             #pod Given a dzil file object (anything that does L<Dist::Zilla::Role::File>), this
20             #pod method returns a new L<PPI::Document> for that file's content.
21             #pod
22             #pod Internally, this method caches these documents. If multiple plugins want a
23             #pod document for the same file, this avoids reparsing it.
24             #pod
25             #pod =cut
26              
27             my %CACHE;
28              
29             my ($self, $file) = @_;
30              
31 149     149 1 387 my $encoded_content = $file->encoded_content;
32              
33 149         565 # We cache on the MD5 checksum to detect if the document has been modified
34             # by some other plugin since it was last parsed, making our document invalid.
35             my $md5 = md5($encoded_content);
36             return $CACHE{$md5}->clone if $CACHE{$md5};
37 149         985  
38 149 100       1120 my $content = $file->content;
39              
40 65         252 require PPI::Document;
41             my $document = PPI::Document->new(\$content)
42 65         6165 or Carp::croak(PPI::Document->errstr . ' while processing file ' . $file->name);
43 65 50       966997  
44             return ($CACHE{$md5} = $document)->clone;
45             }
46 65         298085  
47             #pod =method save_ppi_document_to_file
48             #pod
49             #pod my $document = $self->save_ppi_document_to_file($document,$file);
50             #pod
51             #pod Given a L<PPI::Document> and a dzil file object (anything that does
52             #pod L<Dist::Zilla::Role::File>), this method saves the serialized document in the
53             #pod file.
54             #pod
55             #pod It also updates the internal PPI document cache with the new document.
56             #pod
57             #pod =cut
58              
59             my ($self, $document, $file) = @_;
60              
61             my $new_content = $document->serialize;
62 0     0 1 0  
63             $file->content($new_content);
64 0         0  
65             my $encoded = $file->encoded_content;
66 0         0  
67             $CACHE{ md5($encoded) } = $document->clone;
68 0         0 }
69              
70 0         0 #pod =method document_assigns_to_variable
71             #pod
72             #pod if( $self->document_assigns_to_variable($document, '$FOO')) { ... }
73             #pod
74             #pod This method returns true if the document assigns to the given variable (the
75             #pod sigil must be included).
76             #pod
77             #pod =cut
78              
79             my ($self, $document, $variable) = @_;
80              
81             my $package_stmts = $document->find('PPI::Statement::Package');
82             my @namespaces = map { $_->namespace } @{ $package_stmts || []};
83 53     53 1 157  
84             my ($sigil, $varname) = ($variable =~ m'^([$@%*])(.+)$');
85 53         154  
86 53 50       41605 my $package;
  65         591  
  53         274  
87             my $finder = sub {
88 53         1824 my $node = $_[1];
89              
90 53         102 if ($node->isa('PPI::Statement')
91             && !$node->isa('PPI::Statement::End')
92 1248     1248   11703 && !$node->isa('PPI::Statement::Data')) {
93              
94 1248 100 100     4551 if ($node->isa('PPI::Statement::Variable')) {
      66        
95             return (grep { $_ eq $variable } $node->variables) ? 1 : undef;
96             }
97              
98 197 100       635 return 1 if grep {
99 20 100       113 my $child = $_;
  19         1219  
100             $child->isa('PPI::Token::Symbol')
101             and grep {
102             $child->canonical eq "${sigil}${_}::${varname}"
103 177 100       545 and $node->content =~ /\Q${sigil}${_}::${varname}\E.*=/
  677         1984  
104             } @namespaces
105             } $node->children;
106 677 100       2672 }
  14 100       79  
107             return 0; # not found
108             };
109              
110             my $rv = $document->find_any($finder);
111 1225         2154 Carp::croak($document->errstr) unless defined $rv;
112 53         355  
113             return $rv;
114 53         248 }
115 53 50       1108  
116             1;
117 53         580  
118              
119             =pod
120              
121             =encoding UTF-8
122              
123             =head1 NAME
124              
125             Dist::Zilla::Role::PPI - a role for plugins which use PPI
126              
127             =head1 VERSION
128              
129             version 6.028
130              
131             =head1 DESCRIPTION
132              
133             This role provides some common utilities for plugins which use L<PPI>.
134              
135             =head1 PERL VERSION
136              
137             This module should work on any version of perl still receiving updates from
138             the Perl 5 Porters. This means it should work on any version of perl released
139             in the last two to three years. (That is, if the most recently released
140             version is v5.40, then this module should work on both v5.40 and v5.38.)
141              
142             Although it may work on older versions of perl, no guarantee is made that the
143             minimum required version will not be increased. The version may be increased
144             for any reason, and there is no promise that patches will be accepted to lower
145             the minimum required perl.
146              
147             =head1 METHODS
148              
149             =head2 ppi_document_for_file
150              
151             my $document = $self->ppi_document_for_file($file);
152              
153             Given a dzil file object (anything that does L<Dist::Zilla::Role::File>), this
154             method returns a new L<PPI::Document> for that file's content.
155              
156             Internally, this method caches these documents. If multiple plugins want a
157             document for the same file, this avoids reparsing it.
158              
159             =head2 save_ppi_document_to_file
160              
161             my $document = $self->save_ppi_document_to_file($document,$file);
162              
163             Given a L<PPI::Document> and a dzil file object (anything that does
164             L<Dist::Zilla::Role::File>), this method saves the serialized document in the
165             file.
166              
167             It also updates the internal PPI document cache with the new document.
168              
169             =head2 document_assigns_to_variable
170              
171             if( $self->document_assigns_to_variable($document, '$FOO')) { ... }
172              
173             This method returns true if the document assigns to the given variable (the
174             sigil must be included).
175              
176             =head1 AUTHOR
177              
178             Ricardo SIGNES 😏 <cpan@semiotic.systems>
179              
180             =head1 COPYRIGHT AND LICENSE
181              
182             This software is copyright (c) 2022 by Ricardo SIGNES.
183              
184             This is free software; you can redistribute it and/or modify it under
185             the same terms as the Perl 5 programming language system itself.
186              
187             =cut