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   27075 use 5.010001;
  40         162  
4 40     40   234 use strict;
  40         93  
  40         917  
5 40     40   376 use warnings;
  40         97  
  40         1216  
6 40     40   248 use Readonly;
  40         96  
  40         2206  
7              
8 40     40   277 use Perl::Critic::Utils qw{ :booleans :severities hashify };
  40         128  
  40         2118  
9 40     40   7097 use parent 'Perl::Critic::Policy';
  40         130  
  40         234  
10              
11             our $VERSION = '1.148';
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 1848 sub supported_parameters { return () }
25 96     96 1 421 sub default_severity { return $SEVERITY_MEDIUM }
26 74     74 1 353 sub default_themes { return qw( core bugs ) }
27 119     119 1 364 sub applies_to { return 'PPI::Statement::Include' }
28              
29             #-----------------------------------------------------------------------------
30              
31             sub violates {
32 137     137 1 455 my ( $self, $elem, $doc ) = @_;
33 137 100 100     576 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         5966 return;
38             }
39              
40             #-----------------------------------------------------------------------------
41              
42             # is this a non-string eval statement
43              
44             sub _is_eval {
45 33     33   73 my ( $self, $elem ) = @_;
46 33 100       196 $elem->isa('PPI::Statement') or return;
47 6         39 my $first_elem = $elem->first_element();
48 6 100 100     61 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   83 my ( $self, $elem ) = @_;
59 32 100       120 return if !$elem->isa('PPI::Structure::Block');
60 27 100       94 my $prev_sibling = $elem->sprevious_sibling() or return;
61 26 100 100     961 if ($prev_sibling->isa('PPI::Token::Word') && $prev_sibling eq 'do') {
62 11         206 my $next_sibling = $elem->snext_sibling();
63 11 100 66     373 return $TRUE if $next_sibling
64             && $next_sibling->isa('PPI::Token::Word');
65 5 100       19 $prev_sibling = $prev_sibling->sprevious_sibling() or return;
66             return $TRUE if $prev_sibling->isa('PPI::Token::Operator')
67 4 50 33     132 && $OPS{$prev_sibling->content()};
68             }
69 15         203 return;
70             }
71              
72             #-----------------------------------------------------------------------------
73              
74             # is this a compound statement
75              
76             sub _is_compound_statement {
77 44     44   86 my ( $self, $elem ) = @_;
78 44 100       281 return if !$elem->isa('PPI::Statement::Compound');
79 13 100       48 return $TRUE if $elem->type() ne 'continue'; # exclude bare blocks
80 2         171 return;
81             }
82              
83             #-----------------------------------------------------------------------------
84              
85             # is this contained in conditional logic
86              
87             sub _is_in_conditional_logic {
88 29     29   2386 my ( $self, $elem ) = @_;
89 29         106 while ($elem = $elem->parent()) {
90 51 100       526 last if $elem->isa('PPI::Document');
91 44 100 100     112 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         30 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 :