File Coverage

blib/lib/Perl/Critic/Policy/Modules/RequireNoMatchVarsWithUseEnglish.pm
Criterion Covered Total %
statement 58 68 85.2
branch 25 32 78.1
condition 7 15 46.6
subroutine 13 13 100.0
pod 4 5 80.0
total 107 133 80.4


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish;
2              
3 40     40   27391 use 5.010001;
  40         169  
4 40     40   322 use strict;
  40         139  
  40         801  
5 40     40   200 use warnings;
  40         106  
  40         967  
6              
7 40     40   211 use Readonly;
  40         103  
  40         1937  
8              
9 40     40   282 use Perl::Critic::Utils qw< :characters :severities >;
  40         93  
  40         2020  
10 40     40   11580 use parent 'Perl::Critic::Policy';
  40         115  
  40         249  
11              
12             our $VERSION = '1.148';
13              
14             #-----------------------------------------------------------------------------
15              
16             Readonly::Scalar my $EXPL =>
17             q{"use English" without the '-no_match_vars' argument degrades performance.'};
18             Readonly::Scalar my $DESC => q{"use English" without '-no_match_vars' argument};
19              
20             #-----------------------------------------------------------------------------
21              
22 110     110 0 1667 sub supported_parameters { return () }
23 80     80 1 352 sub default_severity { return $SEVERITY_LOW }
24 74     74 1 340 sub default_themes { return qw( core performance ) }
25 51     51 1 169 sub applies_to { return 'PPI::Statement::Include' }
26              
27             #-----------------------------------------------------------------------------
28              
29             sub violates {
30 125     125 1 288 my ( $self, $elem, $doc ) = @_;
31              
32             # "require"ing English is kind of useless.
33 125 100       352 return if $elem->type() ne 'use';
34 123 100       2920 return if $elem->module() ne 'English';
35              
36 66         1508 my @elements = $elem->schildren();
37 66         881 shift @elements; # dump "use"
38 66         113 shift @elements; # dump "English"
39              
40 66 50       159 if (not @elements) {
41 0         0 return $self->violation($DESC, $EXPL, $elem);
42             }
43              
44 66         192 _skip_version_number( \@elements );
45              
46 66         147 @elements = _descend_into_parenthesized_list_if_present(@elements);
47              
48 66 50       158 if (not @elements) {
49 0         0 return $self->violation($DESC, $EXPL, $elem);
50             }
51              
52 66         103 my $current_element = $elements[0];
53              
54 66         187 while ( $current_element ) {
55 73 100 33     287 if ( $current_element->isa('PPI::Token::Quote') ) {
    100 66        
    100          
56 45 100       162 return if $current_element->string() eq '-no_match_vars';
57             }
58             elsif ( $current_element->isa('PPI::Token::QuoteLike::Words') ) {
59 20 100       57 return if $current_element->content() =~ m/-no_match_vars \b/xms;
60             }
61             elsif (
62             not $current_element->isa('PPI::Token::Operator')
63             or $current_element->content() ne $COMMA
64             and $current_element->content() ne $FATCOMMA
65             ) {
66 6         29 return $self->violation($DESC, $EXPL, $elem);
67             }
68              
69 7         57 shift @elements;
70 7         25 $current_element = $elements[0];
71             }
72              
73 0         0 return $self->violation($DESC, $EXPL, $elem);
74             }
75              
76              
77             sub _skip_version_number {
78 66     66   125 my ($elements_ref) = @_;
79              
80 66         121 my $current_element = $elements_ref->[0];
81              
82 66 100 66     228 if ( $current_element->isa('PPI::Token::Number') ) {
    50 33        
      33        
83 5         11 shift @{$elements_ref};
  5         12  
84             }
85             elsif (
86 61         357 @{$elements_ref} >= 2
87             and $current_element->isa('PPI::Token::Word')
88             and $current_element->content() =~ m/\A v \d+ \z/xms
89             and $elements_ref->[1]->isa('PPI::Token::Number')
90             ) {
91             # The above messy conditional necessary due to PPI not handling
92             # v-strings.
93 0         0 shift @{$elements_ref};
  0         0  
94 0         0 shift @{$elements_ref};
  0         0  
95             }
96              
97 66         148 return;
98             }
99              
100             sub _descend_into_parenthesized_list_if_present {
101 66     66   133 my @elements = @_;
102              
103 66 50       153 return if not @elements;
104              
105 66         108 my $current_element = $elements[0];
106              
107 66 100       220 if ( $current_element->isa('PPI::Structure::List') ) {
108 3         50 my @grand_children = $current_element->schildren();
109 3 50       33 if (not @grand_children) {
110 0         0 return;
111             }
112              
113 3         8 my $grand_child = $grand_children[0];
114              
115 3 50       14 if ( $grand_child->isa('PPI::Statement::Expression') ) {
116 3         15 my @great_grand_children = $grand_child->schildren();
117              
118 3 50       34 if (not @great_grand_children) {
119 0         0 return;
120             }
121              
122 3         13 return @great_grand_children;
123             }
124             else {
125 0         0 return @grand_children;
126             }
127             }
128              
129 63         134 return @elements;
130             }
131              
132             1;
133              
134             __END__
135              
136             #-----------------------------------------------------------------------------
137              
138             =pod
139              
140             =head1 NAME
141              
142             Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish - C<use English> must be passed a C<-no_match_vars> argument.
143              
144              
145             =head1 AFFILIATION
146              
147             This Policy is part of the core L<Perl::Critic|Perl::Critic>
148             distribution.
149              
150              
151             =head1 DESCRIPTION
152              
153             Due to unfortunate history, if you use the L<English|English> module
154             but don't pass in a C<-no_match_vars> argument, all regular
155             expressions in the entire program, not merely the module in question,
156             suffer a significant performance penalty, even if you only import a
157             subset of the variables.
158              
159             use English; # not ok
160             use English '-no_match_vars'; # ok
161             use English qw< $ERRNO -no_match_vars >; # ok
162             use English qw($OS_ERROR); # not ok
163              
164             In the last example above, while the match variables aren't loaded
165             into your namespace, they are still created in the C<English>
166             namespace and you still pay the cost.
167              
168              
169             =head1 CONFIGURATION
170              
171             This Policy is not configurable except for the standard options.
172              
173              
174             =head1 AUTHOR
175              
176             Elliot Shank C<< <perl@galumph.com> >>
177              
178              
179             =head1 COPYRIGHT
180              
181             Copyright (c) 2008-2011 Elliot Shank.
182              
183             This program is free software; you can redistribute it and/or modify
184             it under the same terms as Perl itself. The full text of this license
185             can be found in the LICENSE file included with this module.
186              
187              
188             =cut
189              
190             # Local Variables:
191             # mode: cperl
192             # cperl-indent-level: 4
193             # fill-column: 78
194             # indent-tabs-mode: nil
195             # c-indentation-style: bsd
196             # End:
197             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :