File Coverage

blib/lib/Perl/Critic/Policy/Mardem/ProhibitConditionComplexity.pm
Criterion Covered Total %
statement 40 43 93.0
branch 4 6 66.6
condition n/a
subroutine 13 14 92.8
pod 4 5 80.0
total 61 68 89.7


line stmt bran cond sub pod time code
1              
2             use utf8;
3 8     8   936214  
  8         65  
  8         49  
4             use 5.010;
5 8     8   366  
  8         27  
6             use strict;
7 8     8   41 use warnings;
  8         15  
  8         150  
8 8     8   33  
  8         16  
  8         369  
9             our $VERSION = '0.01';
10              
11             use Readonly;
12 8     8   45  
  8         24  
  8         425  
13             use Perl::Critic::Utils qw{ :severities :data_conversion :classification };
14 8     8   50 use Perl::Critic::Utils::McCabe qw{ calculate_mccabe_of_main };
  8         15  
  8         430  
15 8     8   5887  
  8         9098  
  8         128  
16             use Mardem::RefactoringPerlCriticPolicies::Util qw( search_for_block_keyword);
17 8     8   2615  
  8         25  
  8         360  
18             use base 'Perl::Critic::Policy';
19 8     8   44  
  8         16  
  8         3884  
20             Readonly::Scalar my $EXPL => q{Consider refactoring};
21              
22             # see lib\PPI\Lexer.pm
23             Readonly::Array my @BLOCK_SEARCH_KEYWORD => qw(
24             IF ELSIF UNLESS
25             WHILE UNTIL
26             FOR FOREACH );
27              
28             {
29             return $SEVERITY_MEDIUM;
30             }
31 10     10 1 148  
32             {
33             return qw(complexity maintenance);
34             }
35              
36 0     0 1 0 {
37             return ( 'PPI::Structure::Condition', 'PPI::Structure::For' );
38             }
39              
40             {
41 18     18 1 185723 return (
42             { 'name' => 'max_mccabe',
43             'description' => 'The maximum complexity score allowed.',
44             'default_string' => '2',
45             'behavior' => 'integer',
46             'integer_minimum' => 1,
47 18     18 0 93407 },
48             );
49             }
50              
51             {
52             my ( $self, $elem, undef ) = @_;
53              
54             my $score = calculate_mccabe_of_main( $elem );
55             if ( $score <= $self->{ '_max_mccabe' } ) {
56             return;
57             }
58 16     16 1 385  
59             my $block_keyword = search_for_block_keyword( $elem );
60 16         85 if ( !$block_keyword ) {
61 16 100       6871 $block_keyword = 'no-keyword-found';
62 6         18 }
63             else {
64             my @found = grep { $block_keyword eq $_ } @BLOCK_SEARCH_KEYWORD;
65 10         55 if ( !@found ) {
66 10 50       34 return; # if a keyword is found, but not for an conditional block - than ignore
67 0         0 }
68             }
69              
70 10         35 my $desc = qq<"${block_keyword}" condition has a high complexity score ($score)>;
  70         400  
71 10 50       99 return $self->violation( $desc, $EXPL, $elem );
72 0         0 }
73              
74             1;
75              
76 10         48  
77 10         47 #-----------------------------------------------------------------------------
78              
79             =pod
80              
81             =encoding utf8
82              
83             =head1 NAME
84              
85             Perl::Critic::Policy::Mardem::ProhibitConditionComplexity
86              
87             =head1 DESCRIPTION
88              
89             This Policy approximates the McCabe score within a coditional block "eg if(...)".
90              
91             See L<http://en.wikipedia.org/wiki/Cyclomatic_complexity>
92              
93             It should help to find complex conditions, which should be extracted
94             into subs, to be more testable.
95              
96             eg. from
97              
98             if( $a && $b || $c > 20 ) { ... }
99              
100             to
101              
102             if( _some_test ($a, $b, $c) ) { .. }
103              
104             sub _some_test {
105             my ($a, $b, $c ) = @_;
106              
107             return $a && $b || $c > 20;
108             }
109              
110             =head1 CONFIGURATION
111              
112             The maximum acceptable McCabe can be set with the C<max_mccabe>
113             configuration item. Any block with a McCabe score higher than
114             this number will generate a policy violation. The default is 2.
115              
116             An example section for a F<.perlcriticrc>:
117              
118             [Mardem::ProhibitConditionComplexity]
119             max_mccabe = 1
120              
121             =head1 AFFILIATION
122              
123             This policy is part of L<Mardem::RefactoringPerlCriticPolicies>.
124              
125             =head1 AUTHOR
126              
127             Markus Demml, mardem@cpan.com
128              
129             =head1 LICENSE AND COPYRIGHT
130              
131             Copyright (c) 2022, Markus Demml
132              
133             This library is free software; you can redistribute it and/or modify it
134             under the same terms as the Perl 5 programming language system itself.
135             The full text of this license can be found in the LICENSE file included
136             with this module.
137              
138             =cut