File Coverage

blib/lib/Perl/Critic/Policy/BuiltinFunctions/ProhibitComplexMappings.pm
Criterion Covered Total %
statement 23 36 63.8
branch 1 16 6.2
condition 0 6 0.0
subroutine 11 11 100.0
pod 4 5 80.0
total 39 74 52.7


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::BuiltinFunctions::ProhibitComplexMappings;
2              
3 40     40   26350 use 5.010001;
  40         190  
4 40     40   320 use strict;
  40         117  
  40         859  
5 40     40   281 use warnings;
  40         120  
  40         1032  
6 40     40   270 use Readonly;
  40         136  
  40         2215  
7              
8 40     40   350 use Perl::Critic::Utils qw{ :severities :classification };
  40         201  
  40         2104  
9 40     40   13985 use parent 'Perl::Critic::Policy';
  40         159  
  40         252  
10              
11             our $VERSION = '1.150';
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 90     90 0 2208 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 74     74 1 320 sub default_severity { return $SEVERITY_MEDIUM }
34 86     86 1 390 sub default_themes { return qw( core pbp maintenance complexity) }
35 30     30 1 89 sub applies_to { return 'PPI::Token::Word' }
36              
37             #-----------------------------------------------------------------------------
38              
39             sub violates {
40 329     329 1 487 my ( $self, $elem, undef ) = @_;
41              
42 329 50       567 return if $elem->content() ne 'map';
43 0 0         return if ! is_function_call($elem);
44              
45 0           my $sib = $elem->snext_sibling();
46 0 0         return if !$sib;
47              
48 0           my $arg = $sib;
49 0 0         if ( $arg->isa('PPI::Structure::List') ) {
50 0           $arg = $arg->schild(0);
51             # Forward looking: PPI might change in v1.200 so schild(0) is a PPI::Statement::Expression
52 0 0 0       if ( $arg && $arg->isa('PPI::Statement::Expression') ) {
53 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 0 0         return if !$arg;
58 0 0         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 0 0 0       && 0 == grep {$_->isa('PPI::Statement::Compound')} $arg->schildren();
  0            
63              
64             # more than one child statements
65 0           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 :