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   26601 use 5.010001;
  40         191  
4 40     40   291 use strict;
  40         111  
  40         844  
5 40     40   258 use warnings;
  40         134  
  40         1119  
6 40     40   279 use Readonly;
  40         139  
  40         2323  
7              
8 40     40   339 use Perl::Critic::Utils qw{ :severities :classification };
  40         155  
  40         2115  
9 40     40   14551 use parent 'Perl::Critic::Policy';
  40         129  
  40         271  
10              
11             our $VERSION = '1.148';
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 2210 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 338 sub default_severity { return $SEVERITY_MEDIUM }
34 86     86 1 437 sub default_themes { return qw( core pbp maintenance complexity) }
35 35     35 1 112 sub applies_to { return 'PPI::Token::Word' }
36              
37             #-----------------------------------------------------------------------------
38              
39             sub violates {
40 357     357 1 738 my ( $self, $elem, undef ) = @_;
41              
42 357 100       717 return if $elem->content() ne 'map';
43 17 100       101 return if ! is_function_call($elem);
44              
45 16         39 my $sib = $elem->snext_sibling();
46 16 100       355 return if !$sib;
47              
48 15         28 my $arg = $sib;
49 15 100       55 if ( $arg->isa('PPI::Structure::List') ) {
50 1         25 $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     18 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       41 return if !$arg;
58 14 100       54 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     37 && 0 == grep {$_->isa('PPI::Statement::Compound')} $arg->schildren();
  9         194  
63              
64             # more than one child statements
65 3         72 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 :