File Coverage

blib/lib/Perl/Critic/Policy/RegularExpressions/ProhibitSingleCharAlternation.pm
Criterion Covered Total %
statement 51 51 100.0
branch 16 18 88.8
condition 10 12 83.3
subroutine 15 15 100.0
pod 4 5 80.0
total 96 101 95.0


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::RegularExpressions::ProhibitSingleCharAlternation;
2              
3 40     40   27387 use 5.010001;
  40         206  
4 40     40   288 use strict;
  40         120  
  40         837  
5 40     40   273 use warnings;
  40         135  
  40         1069  
6              
7 40     40   249 use Carp;
  40         128  
  40         2599  
8 40     40   370 use English qw(-no_match_vars);
  40         134  
  40         276  
9 40     40   15287 use List::SomeUtils qw(all);
  40         116  
  40         2121  
10 40     40   312 use Readonly;
  40         133  
  40         2226  
11              
12 40     40   358 use Perl::Critic::Utils qw{ :booleans :characters :severities };
  40         166  
  40         2205  
13 40     40   13482 use parent 'Perl::Critic::Policy';
  40         166  
  40         291  
14              
15             our $VERSION = '1.146';
16              
17             #-----------------------------------------------------------------------------
18              
19             Readonly::Scalar my $EXPL => [265];
20              
21             #-----------------------------------------------------------------------------
22              
23 95     95 0 1682 sub supported_parameters { return qw() }
24 77     77 1 329 sub default_severity { return $SEVERITY_LOWEST }
25 86     86 1 420 sub default_themes { return qw( core pbp performance ) }
26 36     36 1 142 sub applies_to { return qw(PPI::Token::Regexp::Match
27             PPI::Token::Regexp::Substitute
28             PPI::Token::QuoteLike::Regexp) }
29              
30             #-----------------------------------------------------------------------------
31              
32             sub violates {
33 12     12 1 34 my ( $self, $elem, $document ) = @_;
34              
35             # optimization: don't bother parsing the regexp if there are no pipes
36 12 100       43 return if $elem !~ m/[|]/xms;
37              
38 9 50       81 my $re = $document->ppix_regexp_from_element( $elem ) or return;
39 9 100       120865 $re->failures() and return;
40              
41 8         59 my @violations;
42 8         16 foreach my $node ( @{ $re->find_parents( sub {
43 304   66 304   4549 return $_[1]->isa( 'PPIx::Regexp::Token::Operator' )
44             && $_[1]->content() eq q<|>;
45 8 50       68 } ) || [] } ) {
46              
47 9         522 my @singles;
48             my @alternative;
49 9         25 foreach my $kid ( $node->children() ) {
50 172 100 66     686 if ( $kid->isa( 'PPIx::Regexp::Token::Operator' )
    100          
51             && $kid->content() eq q<|>
52             ) {
53             @alternative == 1
54             and $alternative[0]->isa( 'PPIx::Regexp::Token::Literal' )
55 33 100 100     236 and push @singles, map { $_->content() } @alternative;
  13         26  
56 33         116 @alternative = ();
57             } elsif ( $kid->significant() ) {
58 70         221 push @alternative, $kid;
59             }
60             }
61             @alternative == 1
62             and $alternative[0]->isa( 'PPIx::Regexp::Token::Literal' )
63 9 100 100     65 and push @singles, map { $_->content() } @alternative;
  3         8  
64              
65 9 100       43 if ( 1 < @singles ) {
66 3         15 my $description =
67             'Use ['
68             . join( $EMPTY, @singles )
69             . '] instead of '
70             . join q<|>, @singles;
71 3         17 push @violations, $self->violation( $description, $EXPL, $elem );
72             }
73             }
74              
75 8         54 return @violations;
76             }
77              
78             1;
79              
80             __END__
81              
82             #-----------------------------------------------------------------------------
83              
84             =pod
85              
86             =head1 NAME
87              
88             Perl::Critic::Policy::RegularExpressions::ProhibitSingleCharAlternation - Use C<[abc]> instead of C<a|b|c>.
89              
90              
91             =head1 AFFILIATION
92              
93             This Policy is part of the core L<Perl::Critic|Perl::Critic>
94             distribution.
95              
96              
97             =head1 DESCRIPTION
98              
99             Character classes (like C<[abc]>) are significantly faster than single
100             character alternations (like C<(?:a|b|c)>). This policy complains if
101             you have more than one instance of a single character in an
102             alternation. So C<(?:a|the)> is allowed, but C<(?:a|e|i|o|u)> is not.
103              
104             NOTE: Perl 5.10 (not released as of this writing) has major regexp
105             optimizations which may mitigate the performance penalty of
106             alternations, which will be rewritten behind the scenes as something
107             like character classes. Consequently, if you are deploying
108             exclusively on 5.10, yo might consider ignoring this policy.
109              
110              
111             =head1 CONFIGURATION
112              
113             This Policy is not configurable except for the standard options.
114              
115              
116             =head1 CREDITS
117              
118             Initial development of this policy was supported by a grant from the
119             Perl Foundation.
120              
121              
122             =head1 AUTHOR
123              
124             Chris Dolan <cdolan@cpan.org>
125              
126              
127             =head1 COPYRIGHT
128              
129             Copyright (c) 2007-2021 Chris Dolan. Many rights reserved.
130              
131             This program is free software; you can redistribute it and/or modify
132             it under the same terms as Perl itself. The full text of this license
133             can be found in the LICENSE file included with this module
134              
135             =cut
136              
137             # Local Variables:
138             # mode: cperl
139             # cperl-indent-level: 4
140             # fill-column: 78
141             # indent-tabs-mode: nil
142             # c-indentation-style: bsd
143             # End:
144             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :