File Coverage

blib/lib/PPI/Statement/Include.pm
Criterion Covered Total %
statement 87 89 97.7
branch 64 78 82.0
condition 20 25 80.0
subroutine 18 18 100.0
pod 8 8 100.0
total 197 218 90.3


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 class covers a number
31             of different types of statement that cover all statements starting with
32             C, C and C.
33              
34             But basically, they cover three situations.
35              
36             Firstly, a dependency on a particular version of perl (for which the
37             C method returns true), a pragma (for which the C method
38             returns true), or the loading (and unloading via no) of modules.
39              
40             =head1 METHODS
41              
42             C has a number of methods in addition to the standard
43             L, L and L methods.
44              
45             =cut
46              
47 67     67   335 use strict;
  67         98  
  67         2210  
48              
49 67     67   20829 use version 0.77 ();
  67         102413  
  67         2230  
50 67     67   28008 use Safe::Isa '$_call_if_object';
  67         30803  
  67         6609  
51              
52 67     67   363 use PPI::Statement ();
  67         90  
  67         802  
53 67     67   25380 use PPI::Statement::Include::Perl6 ();
  67         156  
  67         65578  
54              
55             our $VERSION = '1.287';
56              
57             our @ISA = "PPI::Statement";
58              
59             =pod
60              
61             =head2 type
62              
63             The C 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 if the type cannot be detected.
67              
68             =cut
69              
70             sub type {
71 3329     3329 1 8166 my $self = shift;
72 3329 50       9212 my $keyword = $self->schild(0) or return undef;
73 3329 50       11543 $keyword->isa('PPI::Token::Word') and $keyword->content;
74             }
75              
76             =pod
77              
78             =head2 module
79              
80             The C method returns the module name specified in any include
81             statement. This C 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 if the include does
99             not specify a module name.
100              
101             =cut
102              
103             sub module {
104 3294     3294 1 4179 my $self = shift;
105 3294 100       5533 my $module = $self->schild(1) or return undef;
106 3292 100       11099 $module->isa('PPI::Token::Word') and $module->content;
107             }
108              
109             =pod
110              
111             =head2 module_version
112              
113             The C 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 10     10 1 605 my $self = shift;
120 10         26 my $argument = $self->schild(3);
121 10 100 100     56 if ( $argument and $argument->isa('PPI::Token::Operator') ) {
122 1         4 return undef;
123             }
124              
125 9 50       16 my $version = $self->schild(2) or return undef;
126 9 100       39 return undef unless $version->isa('PPI::Token::Number');
127              
128 6         21 return $version;
129             }
130              
131             =pod
132              
133             =head2 pragma
134              
135             The C 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 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). 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 373 my $self = shift;
157 2 50       5 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 method checks for an include statement that introduces a
166             dependency on the version of C 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 object. If you want a numeric representation,
175             use C. Returns false if the statement is not a version
176             dependency.
177              
178             =cut
179              
180             sub version {
181 3310     3310 1 4778 my $self = shift;
182 3310 100       6575 my $version = $self->schild(1) or return undef;
183 3308 100       15615 $version->isa('PPI::Token::Number') ? $version->content : '';
184             }
185              
186             =pod
187              
188             =head2 version_literal
189              
190             The C method has the same behavior as C, 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 670 my $self = shift;
198 11 50       39 my $version = $self->schild(1) or return undef;
199 11 100       56 $version->isa('PPI::Token::Number') ? $version->literal : '';
200             }
201              
202             =pod
203              
204             =head2 arguments
205              
206             The C 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 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 22     22 1 696 my $self = shift;
216 22         62 my @args = $self->schildren;
217              
218             # Remove the "use", "no" or "require"
219 22         33 shift @args;
220              
221             # Remove the statement terminator
222 22 100 66     126 if (
223             $args[-1]->isa('PPI::Token::Structure')
224             and
225             $args[-1]->content eq ';'
226             ) {
227 21         32 pop @args;
228             }
229              
230             # Remove the module or perl version.
231 22         33 shift @args;
232              
233 22 100       45 return unless @args;
234              
235 20 100       62 if ( $args[0]->isa('PPI::Token::Number') ) {
236 2 100       11 my $after = $args[1] or return;
237 1 50       6 $after->isa('PPI::Token::Operator') or shift @args;
238             }
239              
240 19         35 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 3322     3322 1 5034 my ($self) = @_;
261 3322         7691 my $type = $self->type;
262 3322 100       6264 return if $type eq "require";
263              
264 3300 100       8048 if ( my $cb_features = $self->_custom_feature_include_cb->($self) ) #
265 1         6 { return $cb_features; }
266              
267 3299 100       12812 if ( my $perl_version = $self->version ) {
268             ## tried using feature.pm, but it is impossible to install future
269             ## versions of it, so e.g. a 5.20 install cannot know about
270             ## 5.36 features
271              
272             # crude proof of concept hack due to above
273 32 100       536 return { signatures => "perl" }
274             if version::->parse($perl_version) >= 5.035;
275             }
276              
277 3291 100       7820 my $module = $self->module or return;
278              
279 3262         10715 my %known = ( signatures => 1, try => 1 );
280 3262         6047 my $on_or_off = $type eq "use";
281              
282 3262 100 100     9217 if ( $on_or_off
283             and my $custom = $self->_custom_feature_includes->{ $module } ) #
284 2         7 { return $custom; }
285              
286 3260 100       14813 if ( $module eq "feature" ) {
    100          
    100          
    100          
    100          
287 12         22 my @features = grep $known{$_}, $self->_decompose_arguments;
288 12 100       78 return { map +( $_ => $on_or_off ? "perl" : 0 ), @features };
289             }
290             elsif ( $module eq "Mojolicious::Lite" ) {
291 1         3 my $wants_signatures = grep /-signatures/, $self->_decompose_arguments;
292 1 50       6 return { signatures => $wants_signatures ? "perl" : 0 };
293             }
294             elsif ( $module eq "Modern::Perl" ) {
295 1   50     4 my $v = $self->module_version->$_call_if_object("literal") || 0;
296 1 50       9 return { signatures => $v >= 2023 ? "perl" : 0 };
297             }
298             elsif ( $module eq "experimental" ) {
299 1         16 my $wants_signatures = grep /signatures/, $self->_decompose_arguments;
300 1 50       18 return { signatures => $wants_signatures ? "perl" : 0 };
301             }
302             elsif ( $module eq "Syntax::Keyword::Try" ) {
303 7 50       25 return { try => $on_or_off ? "Syntax::Keyword::Try" : 0 };
304             }
305              
306 3238         11753 return;
307             }
308              
309             sub _decompose_arguments {
310 14     14   19 my ($self) = @_;
311 14         25 my @args = $self->arguments;
312 14         34 while ( grep ref, @args ) {
313 16         29 @args = map $self->_decompose_argument($_), @args;
314             }
315 14         51 return @args;
316             }
317              
318             sub _decompose_argument {
319 18     18   28 my ( $self, $arg ) = @_;
320 18 100 100     81 return $arg->children
321             if $arg->isa("PPI::Structure::List")
322             or $arg->isa("PPI::Statement::Expression");
323 16   100     79 my $as_text = $arg->can("literal") || $arg->can("string");
324 16 100       43 return $as_text->($arg) if $as_text;
325 1 50 33     17 return if $arg->isa("PPI::Token::Operator")
326             or $arg->content eq ",";
327 0         0 warn "possibly unrecognized feature because of unknown arg decompose"
328             . " type: '$arg' : " . ref $arg;
329 0         0 return;
330             }
331              
332             sub _custom_feature_includes {
333 2249     2249   3413 my ($self) = @_;
334             return unless #
335 2249 50       4662 my $document = $self->document;
336 2249   100     5222 return $document->custom_feature_includes || {};
337             }
338              
339             sub _custom_feature_include_cb {
340 3300     3300   5267 my ($self) = @_;
341             return unless #
342 3300 50       7703 my $document = $self->document;
343 3300   66 3299   10462 return $document->custom_feature_include_cb || sub { };
344             }
345              
346             1;
347              
348             =pod
349              
350             =head1 TO DO
351              
352             - Write specific unit tests for this package
353              
354             =head1 SUPPORT
355              
356             See the L in the main module.
357              
358             =head1 AUTHOR
359              
360             Adam Kennedy Eadamk@cpan.orgE
361              
362             =head1 COPYRIGHT
363              
364             Copyright 2001 - 2011 Adam Kennedy.
365              
366             This program is free software; you can redistribute
367             it and/or modify it under the same terms as Perl itself.
368              
369             The full text of the license can be found in the
370             LICENSE file included with this module.
371              
372             =cut