File Coverage

blib/lib/Perl/Critic/Policy/Modules/ProhibitConditionalUseStatements.pm
Criterion Covered Total %
statement 47 47 100.0
branch 25 26 96.1
condition 23 27 85.1
subroutine 15 15 100.0
pod 4 5 80.0
total 114 120 95.0


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Modules::ProhibitConditionalUseStatements;
2              
3 40     40   27148 use 5.010001;
  40         164  
4 40     40   253 use strict;
  40         90  
  40         1065  
5 40     40   228 use warnings;
  40         102  
  40         1018  
6 40     40   411 use Readonly;
  40         107  
  40         2410  
7              
8 40     40   283 use Perl::Critic::Utils qw{ :booleans :severities hashify };
  40         102  
  40         2205  
9 40     40   6986 use parent 'Perl::Critic::Policy';
  40         128  
  40         260  
10              
11             our $VERSION = '1.146';
12              
13             #-----------------------------------------------------------------------------
14              
15             Readonly::Scalar my $DESC => q{Conditional "use" statement};
16             Readonly::Scalar my $EXPL => q{Use "require" to conditionally include a module.};
17              
18             # operators
19              
20             Readonly::Hash my %OPS => hashify( qw( || && or and ) );
21              
22             #-----------------------------------------------------------------------------
23              
24 178     178 0 1895 sub supported_parameters { return () }
25 96     96 1 451 sub default_severity { return $SEVERITY_MEDIUM }
26 74     74 1 349 sub default_themes { return qw( core bugs ) }
27 119     119 1 372 sub applies_to { return 'PPI::Statement::Include' }
28              
29             #-----------------------------------------------------------------------------
30              
31             sub violates {
32 137     137 1 358 my ( $self, $elem, $doc ) = @_;
33 137 100 100     489 return $self->violation( $DESC, $EXPL, $elem ) if $elem->type() eq 'use'
      66        
      100        
34             && !$elem->pragma()
35             && $elem->module()
36             && $self->_is_in_conditional_logic($elem);
37 115         5821 return;
38             }
39              
40             #-----------------------------------------------------------------------------
41              
42             # is this a non-string eval statement
43              
44             sub _is_eval {
45 33     33   84 my ( $self, $elem ) = @_;
46 33 100       195 $elem->isa('PPI::Statement') or return;
47 6         57 my $first_elem = $elem->first_element();
48 6 100 100     48 return $TRUE if $first_elem->isa('PPI::Token::Word')
49             && $first_elem eq 'eval';
50 5         59 return;
51             }
52              
53             #-----------------------------------------------------------------------------
54              
55             # is this in a conditional do block
56              
57             sub _is_in_do_conditional_block {
58 32     32   65 my ( $self, $elem ) = @_;
59 32 100       122 return if !$elem->isa('PPI::Structure::Block');
60 27 100       103 my $prev_sibling = $elem->sprevious_sibling() or return;
61 26 100 100     972 if ($prev_sibling->isa('PPI::Token::Word') && $prev_sibling eq 'do') {
62 11         208 my $next_sibling = $elem->snext_sibling();
63 11 100 66     404 return $TRUE if $next_sibling
64             && $next_sibling->isa('PPI::Token::Word');
65 5 100       16 $prev_sibling = $prev_sibling->sprevious_sibling() or return;
66             return $TRUE if $prev_sibling->isa('PPI::Token::Operator')
67 4 50 33     154 && $OPS{$prev_sibling->content()};
68             }
69 15         206 return;
70             }
71              
72             #-----------------------------------------------------------------------------
73              
74             # is this a compound statement
75              
76             sub _is_compound_statement {
77 44     44   98 my ( $self, $elem ) = @_;
78 44 100       238 return if !$elem->isa('PPI::Statement::Compound');
79 13 100       45 return $TRUE if $elem->type() ne 'continue'; # exclude bare blocks
80 2         195 return;
81             }
82              
83             #-----------------------------------------------------------------------------
84              
85             # is this contained in conditional logic
86              
87             sub _is_in_conditional_logic {
88 29     29   2371 my ( $self, $elem ) = @_;
89 29         110 while ($elem = $elem->parent()) {
90 51 100       523 last if $elem->isa('PPI::Document');
91 44 100 100     123 return $TRUE if $self->_is_compound_statement($elem)
      100        
92             || $self->_is_eval($elem)
93             || $self->_is_in_do_conditional_block($elem);
94             }
95 7         27 return;
96             }
97              
98             1;
99              
100             __END__
101              
102             #-----------------------------------------------------------------------------
103              
104             =pod
105              
106             =for stopwords evals
107              
108             =head1 NAME
109              
110             Perl::Critic::Policy::Modules::ProhibitConditionalUseStatements - Avoid putting conditional logic around compile-time includes.
111              
112              
113             =head1 AFFILIATION
114              
115             This Policy is part of the core L<Perl::Critic|Perl::Critic>
116             distribution.
117              
118              
119             =head1 DESCRIPTION
120              
121             Modules included via "use" are loaded at compile-time. Placing conditional
122             logic around the "use" statement has no effect on whether the module will be
123             loaded. Doing so can also serve to confuse the reader as to the author's
124             original intent.
125              
126             If you need to conditionally load a module you should be using "require"
127             instead.
128              
129             This policy will catch the following forms of conditional "use" statements:
130              
131             # if-elsif-else
132             if ($a == 1) { use Module; }
133             if ($a == 1) { } elsif ($a == 2) { use Module; }
134             if ($a == 1) { } else { use Module; }
135              
136             # for/foreach
137             for (1..$a) { use Module; }
138             foreach (@a) { use Module; }
139              
140             # while
141             while ($a == 1) { use Module; }
142              
143             # unless
144             unless ($a == 1) { use Module; }
145              
146             # until
147             until ($a == 1) { use Module; }
148              
149             # do-condition
150             do { use Module; } if $a == 1;
151             do { use Module; } while $a == 1;
152             do { use Module; } unless $a == 1;
153             do { use Module; } until $a == 1;
154              
155             # operator-do
156             $a == 1 || do { use Module; };
157             $a == 1 && do { use Module; };
158             $a == 1 or do { use Module; };
159             $a == 1 and do { use Module; };
160              
161             # non-string eval
162             eval { use Module; };
163              
164             Including a module via "use" in bare blocks, standalone do blocks, or
165             string evals is allowed.
166              
167             # bare block
168             { use Module; }
169              
170             # do
171             do { use Module; }
172              
173             # string eval
174             eval "use Module";
175              
176             =head1 CONFIGURATION
177              
178             This Policy is not configurable except for the standard options.
179              
180              
181             =head1 AUTHOR
182              
183             Peter Guzis <pguzis@cpan.org>
184              
185              
186             =head1 COPYRIGHT
187              
188             Copyright (c) 2010-2011 Peter Guzis. All rights reserved.
189              
190             This program is free software; you can redistribute it and/or modify
191             it under the same terms as Perl itself. The full text of this license
192             can be found in the LICENSE file included with this module.
193              
194             =cut
195              
196             # Local Variables:
197             # mode: cperl
198             # cperl-indent-level: 4
199             # fill-column: 78
200             # indent-tabs-mode: nil
201             # c-indentation-style: bsd
202             # End:
203             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :