File Coverage

blib/lib/PPI/Statement/Include.pm
Criterion Covered Total %
statement 85 87 97.7
branch 60 76 78.9
condition 20 25 80.0
subroutine 18 18 100.0
pod 8 8 100.0
total 191 214 89.2


line stmt bran cond sub pod time code
1             package PPI::Statement::Include;
2              
3             =pod
4              
5             =head1 NAME
6              
7             PPI::Statement::Include - Statements that include other code
8              
9             =head1 SYNOPSIS
10              
11             # The following are all includes
12             use 5.006;
13             use strict;
14             use My::Module;
15             use constant FOO => 'Foo';
16             require Foo::Bar;
17             require "Foo/Bar.pm";
18             require $foo if 1;
19             no strict 'refs';
20              
21             =head1 INHERITANCE
22              
23             PPI::Statement::Include
24             isa PPI::Statement
25             isa PPI::Node
26             isa PPI::Element
27              
28             =head1 DESCRIPTION
29              
30             Despite its name, the C<PPI::Statement::Include> class covers a number
31             of different types of statement that cover all statements starting with
32             C<use>, C<no> and C<require>.
33              
34             But basically, they cover three situations.
35              
36             Firstly, a dependency on a particular version of perl (for which the
37             C<version> method returns true), a pragma (for which the C<pragma> method
38             returns true), or the loading (and unloading via no) of modules.
39              
40             =head1 METHODS
41              
42             C<PPI::Statement::Include> has a number of methods in addition to the standard
43             L<PPI::Statement>, L<PPI::Node> and L<PPI::Element> methods.
44              
45             =cut
46              
47 66     66   359 use strict;
  66         112  
  66         2451  
48              
49 66     66   22010 use version 0.77 ();
  66         105478  
  66         2175  
50 66     66   27133 use Safe::Isa '$_call_if_object';
  66         32248  
  66         6823  
51              
52 66     66   401 use PPI::Statement ();
  66         94  
  66         911  
53 66     66   25183 use PPI::Statement::Include::Perl6 ();
  66         165  
  66         67945  
54              
55             our $VERSION = '1.284';
56              
57             our @ISA = "PPI::Statement";
58              
59             =pod
60              
61             =head2 type
62              
63             The C<type> method returns the general type of statement (C<'use'>, C<'no'>
64             or C<'require'>).
65              
66             Returns the type as a string, or C<undef> if the type cannot be detected.
67              
68             =cut
69              
70             sub type {
71 426724     426724 1 470361 my $self = shift;
72 426724 50       596329 my $keyword = $self->schild(0) or return undef;
73 426724 50       1071505 $keyword->isa('PPI::Token::Word') and $keyword->content;
74             }
75              
76             =pod
77              
78             =head2 module
79              
80             The C<module> method returns the module name specified in any include
81             statement. This C<includes> pragma names, because pragma are implemented
82             as modules. (And lets face it, the definition of a pragma can be fuzzy
83             at the best of times in any case)
84              
85             This covers all of these...
86              
87             use strict;
88             use My::Module;
89             no strict;
90             require My::Module;
91              
92             ...but does not cover any of these...
93              
94             use 5.006;
95             require 5.005;
96             require "explicit/file/name.pl";
97              
98             Returns the module name as a string, or C<undef> if the include does
99             not specify a module name.
100              
101             =cut
102              
103             sub module {
104 1278517     1278517 1 1418726 my $self = shift;
105 1278517 50       1608429 my $module = $self->schild(1) or return undef;
106 1278517 100       2755303 $module->isa('PPI::Token::Word') and $module->content;
107             }
108              
109             =pod
110              
111             =head2 module_version
112              
113             The C<module_version> method returns the minimum version of the module
114             required by the statement, if there is one.
115              
116             =cut
117              
118             sub module_version {
119 13     13 1 662 my $self = shift;
120 13         33 my $argument = $self->schild(3);
121 13 100 100     84 if ( $argument and $argument->isa('PPI::Token::Operator') ) {
122 1         4 return undef;
123             }
124              
125 12 50       38 my $version = $self->schild(2) or return undef;
126 12 100       53 return undef unless $version->isa('PPI::Token::Number');
127              
128 9         34 return $version;
129             }
130              
131             =pod
132              
133             =head2 pragma
134              
135             The C<pragma> method checks for an include statement's use as a
136             pragma, and returns it if so.
137              
138             Or at least, it claims to. In practice it's a lot harder to say exactly
139             what is or isn't a pragma, because the definition is fuzzy.
140              
141             The C<intent> of a pragma is to modify the way in which the parser works.
142             This is done though the use of modules that do various types of internals
143             magic.
144              
145             For now, PPI assumes that any "module name" that is only a set of
146             lowercase letters (and perhaps numbers, like C<use utf8;>). This
147             behaviour is expected to change, most likely to something that knows
148             the specific names of the various "pragmas".
149              
150             Returns the name of the pragma, or false ('') if the include is not a
151             pragma.
152              
153             =cut
154              
155             sub pragma {
156 2     2 1 240 my $self = shift;
157 2 50       8 my $module = $self->module or return '';
158 2 50       19 $module =~ /^[a-z][a-z\d]*$/ ? $module : '';
159             }
160              
161             =pod
162              
163             =head2 version
164              
165             The C<version> method checks for an include statement that introduces a
166             dependency on the version of C<perl> the code is compatible with.
167              
168             This covers two specific statements.
169              
170             use 5.006;
171             require 5.006;
172              
173             Currently the version is returned as a string, although in future the version
174             may be returned as a L<version> object. If you want a numeric representation,
175             use C<version_literal()>. Returns false if the statement is not a version
176             dependency.
177              
178             =cut
179              
180             sub version {
181 213321     213321 1 233526 my $self = shift;
182 213321 50       308689 my $version = $self->schild(1) or return undef;
183 213321 100       770936 $version->isa('PPI::Token::Number') ? $version->content : '';
184             }
185              
186             =pod
187              
188             =head2 version_literal
189              
190             The C<version_literal> method has the same behavior as C<version()>, but the
191             version is returned as a numeric literal. Returns false if the statement is
192             not a version dependency.
193              
194             =cut
195              
196             sub version_literal {
197 11     11 1 556 my $self = shift;
198 11 50       32 my $version = $self->schild(1) or return undef;
199 11 100       54 $version->isa('PPI::Token::Number') ? $version->literal : '';
200             }
201              
202             =pod
203              
204             =head2 arguments
205              
206             The C<arguments> method gives you the rest of the statement after the
207             module/pragma and module version, i.e. the stuff that will be used to
208             construct what gets passed to the module's C<import()> subroutine. This does
209             include the comma, etc. operators, but doesn't include non-significant direct
210             children or any final semicolon.
211              
212             =cut
213              
214             sub arguments {
215 60     60 1 642 my $self = shift;
216 60         134 my @args = $self->schildren;
217              
218             # Remove the "use", "no" or "require"
219 60         73 shift @args;
220              
221             # Remove the statement terminator
222 60 100 66     178 if (
223             $args[-1]->isa('PPI::Token::Structure')
224             and
225             $args[-1]->content eq ';'
226             ) {
227 58         80 pop @args;
228             }
229              
230             # Remove the module or perl version.
231 60         67 shift @args;
232              
233 60 100       113 return unless @args;
234              
235 58 100       176 if ( $args[0]->isa('PPI::Token::Number') ) {
236 2 100       8 my $after = $args[1] or return;
237 1 50       6 $after->isa('PPI::Token::Operator') or shift @args;
238             }
239              
240 57         85 return @args;
241             }
242              
243             =head2 feature_mods
244              
245             # `use feature 'signatures';`
246             my %mods = $include->feature_mods;
247             # { signatures => "perl" }
248              
249             # `use 5.036;`
250             my %mods = $include->feature_mods;
251             # { signatures => "perl" }
252              
253             Returns a hashref of features identified as enabled by the include, or undef if
254             the include does not enable features. The value for each feature indicates the
255             provider of the feature.
256              
257             =cut
258              
259             sub feature_mods {
260 213413     213413 1 284382 my ($self) = @_;
261 213413 100       315500 return if $self->type eq "require";
262              
263 213317 100       369459 if ( my $cb_features = $self->_custom_feature_include_cb->($self) ) #
264 7         33 { return $cb_features; }
265              
266 213310 100       491320 if ( my $perl_version = $self->version ) {
267             ## tried using feature.pm, but it is impossible to install future
268             ## versions of it, so e.g. a 5.20 install cannot know about
269             ## 5.36 features
270              
271             # crude proof of concept hack due to above
272 220 100       2804 return { signatures => "perl" }
273             if version::->parse($perl_version) >= 5.035;
274             }
275              
276 213304         442983 my %known = ( signatures => 1, try => 1 );
277 213304         295154 my $on_or_off = $self->type eq "use";
278              
279 213304 100 100     437054 if ( $on_or_off
280             and my $custom = $self->_custom_feature_includes->{ $self->module } ) #
281 14         42 { return $custom; }
282              
283 213290 100       362215 if ( $self->module eq "feature" ) {
    100          
    100          
    100          
    100          
284 38         77 my @features = grep $known{$_}, $self->_decompose_arguments;
285 38 100       194 return { map +( $_ => $on_or_off ? "perl" : 0 ), @features };
286             }
287             elsif ( $self->module eq "Mojolicious::Lite" ) {
288 4         8 my $wants_signatures = grep /-signatures/, $self->_decompose_arguments;
289 4 50       19 return { signatures => $wants_signatures ? "perl" : 0 };
290             }
291             elsif ( $self->module eq "Modern::Perl" ) {
292 4   50     7 my $v = $self->module_version->$_call_if_object("literal") || 0;
293 4 50       20 return { signatures => $v >= 2023 ? "perl" : 0 };
294             }
295             elsif ( $self->module eq "experimental" ) {
296 4         22 my $wants_signatures = grep /signatures/, $self->_decompose_arguments;
297 4 50       32 return { signatures => $wants_signatures ? "perl" : 0 };
298             }
299             elsif ( $self->module eq "Syntax::Keyword::Try" ) {
300 7 50       28 return { try => $on_or_off ? "Syntax::Keyword::Try" : 0 };
301             }
302              
303 213233         579893 return;
304             }
305              
306             sub _decompose_arguments {
307 46     46   62 my ($self) = @_;
308 46         121 my @args = $self->arguments;
309 46         103 while ( grep ref, @args ) {
310 50         81 @args = map $self->_decompose_argument($_), @args;
311             }
312 46         118 return @args;
313             }
314              
315             sub _decompose_argument {
316 52     52   71 my ( $self, $arg ) = @_;
317 52 100 100     215 return $arg->children
318             if $arg->isa("PPI::Structure::List")
319             or $arg->isa("PPI::Statement::Expression");
320 47   100     154 my $as_text = $arg->can("literal") || $arg->can("string");
321 47 100       127 return $as_text->($arg) if $as_text;
322 1 50 33     5 return if $arg->isa("PPI::Token::Operator")
323             or $arg->content eq ",";
324 0         0 warn "possibly unrecognized feature because of unknown arg decompose"
325             . " type: '$arg' : " . ref $arg;
326 0         0 return;
327             }
328              
329             sub _custom_feature_includes {
330 212234     212234   251211 my ($self) = @_;
331             return unless #
332 212234 50       320759 my $document = $self->document;
333 212234   100     398064 return $document->custom_feature_includes || {};
334             }
335              
336             sub _custom_feature_include_cb {
337 213317     213317   246427 my ($self) = @_;
338             return unless #
339 213317 50       331101 my $document = $self->document;
340 213317   66 213310   425253 return $document->custom_feature_include_cb || sub { };
341             }
342              
343             1;
344              
345             =pod
346              
347             =head1 TO DO
348              
349             - Write specific unit tests for this package
350              
351             =head1 SUPPORT
352              
353             See the L<support section|PPI/SUPPORT> in the main module.
354              
355             =head1 AUTHOR
356              
357             Adam Kennedy E<lt>adamk@cpan.orgE<gt>
358              
359             =head1 COPYRIGHT
360              
361             Copyright 2001 - 2011 Adam Kennedy.
362              
363             This program is free software; you can redistribute
364             it and/or modify it under the same terms as Perl itself.
365              
366             The full text of the license can be found in the
367             LICENSE file included with this module.
368              
369             =cut