File Coverage

blib/lib/Perl/Critic/Policy/BuiltinFunctions/ProhibitComplexMappings.pm
Criterion Covered Total %
statement 35 36 97.2
branch 15 16 93.7
condition 4 6 66.6
subroutine 11 11 100.0
pod 4 5 80.0
total 69 74 93.2


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::BuiltinFunctions::ProhibitComplexMappings;
2              
3 40     40   26688 use 5.010001;
  40         182  
4 40     40   299 use strict;
  40         124  
  40         845  
5 40     40   250 use warnings;
  40         136  
  40         1053  
6 40     40   251 use Readonly;
  40         121  
  40         2313  
7              
8 40     40   351 use Perl::Critic::Utils qw{ :severities :classification };
  40         145  
  40         2235  
9 40     40   14117 use parent 'Perl::Critic::Policy';
  40         154  
  40         268  
10              
11             our $VERSION = '1.146';
12              
13             #-----------------------------------------------------------------------------
14              
15             Readonly::Scalar my $DESC => q{Map blocks should have a single statement};
16             Readonly::Scalar my $EXPL => [ 113 ];
17              
18             #-----------------------------------------------------------------------------
19              
20             sub supported_parameters {
21             return (
22             {
23 95     95 0 2237 name => 'max_statements',
24             description =>
25             'The maximum number of statements to allow within a map block.',
26             default_string => '1',
27             behavior => 'integer',
28             integer_minimum => 1,
29             },
30             );
31             }
32              
33 77     77 1 361 sub default_severity { return $SEVERITY_MEDIUM }
34 86     86 1 386 sub default_themes { return qw( core pbp maintenance complexity) }
35 35     35 1 139 sub applies_to { return 'PPI::Token::Word' }
36              
37             #-----------------------------------------------------------------------------
38              
39             sub violates {
40 357     357 1 682 my ( $self, $elem, undef ) = @_;
41              
42 357 100       690 return if $elem->content() ne 'map';
43 17 100       101 return if ! is_function_call($elem);
44              
45 16         38 my $sib = $elem->snext_sibling();
46 16 100       309 return if !$sib;
47              
48 15         28 my $arg = $sib;
49 15 100       51 if ( $arg->isa('PPI::Structure::List') ) {
50 1         14 $arg = $arg->schild(0);
51             # Forward looking: PPI might change in v1.200 so schild(0) is a PPI::Statement::Expression
52 1 50 33     27 if ( $arg && $arg->isa('PPI::Statement::Expression') ) {
53 0         0 $arg = $arg->schild(0);
54             }
55             }
56             # If it's not a block, it's an expression-style map, which is only one statement by definition
57 15 100       39 return if !$arg;
58 14 100       52 return if !$arg->isa('PPI::Structure::Block');
59              
60             # If we get here, we found a sort with a block as the first arg
61             return if $self->{_max_statements} >= $arg->schildren()
62 10 100 100     36 && 0 == grep {$_->isa('PPI::Statement::Compound')} $arg->schildren();
  9         215  
63              
64             # more than one child statements
65 3         51 return $self->violation( $DESC, $EXPL, $elem );
66             }
67              
68             1;
69              
70             #-----------------------------------------------------------------------------
71              
72             __END__
73              
74             =pod
75              
76             =head1 NAME
77              
78             Perl::Critic::Policy::BuiltinFunctions::ProhibitComplexMappings - Map blocks should have a single statement.
79              
80              
81             =head1 AFFILIATION
82              
83             This Policy is part of the core L<Perl::Critic|Perl::Critic>
84             distribution.
85              
86              
87             =head1 DESCRIPTION
88              
89             The map function can be confusing to novices in the best of
90             circumstances. Mappings with multiple statements are even worse.
91             They're also a maintainer's nightmare because any added complexity
92             decreases readability precipitously. Why? Because map is
93             traditionally a one-liner converting one array to another. Trying to
94             cram lots of functionality into a one-liner is a bad idea in general.
95              
96             The best solutions to a complex mapping are: 1) write a subroutine
97             that performs the manipulation and call that from map; 2) rewrite the
98             map as a for loop.
99              
100              
101             =head1 CAVEATS
102              
103             This policy currently misses some compound statements inside of the
104             map. For example, the following code incorrectly does not trigger a
105             violation:
106              
107             map { do { foo(); bar() } } @list
108              
109              
110             =head1 CONFIGURATION
111              
112             By default this policy flags any mappings with more than one
113             statement. While we do not recommend it, you can increase this limit
114             as follows in a F<.perlcriticrc> file:
115              
116             [BuiltinFunctions::ProhibitComplexMappings]
117             max_statements = 2
118              
119              
120             =head1 AUTHOR
121              
122             Chris Dolan <cdolan@cpan.org>
123              
124              
125             =head1 CREDITS
126              
127             Initial development of this policy was supported by a grant from the
128             Perl Foundation.
129              
130              
131             =head1 COPYRIGHT
132              
133             Copyright (c) 2007-2011 Chris Dolan.
134              
135             This program is free software; you can redistribute it and/or modify
136             it under the same terms as Perl itself.
137              
138             =cut
139              
140             # Local Variables:
141             # mode: cperl
142             # cperl-indent-level: 4
143             # fill-column: 78
144             # indent-tabs-mode: nil
145             # c-indentation-style: bsd
146             # End:
147             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :