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   908340  
  8         61  
  8         54  
4             use 5.010;
5 8     8   302  
  8         28  
6             use strict;
7 8     8   31 use warnings;
  8         15  
  8         171  
8 8     8   34  
  8         15  
  8         361  
9             our $VERSION = '0.03';
10              
11             use Readonly;
12 8     8   45  
  8         14  
  8         363  
13             use Perl::Critic::Utils qw{ :severities :data_conversion :classification };
14 8     8   44 use Perl::Critic::Utils::McCabe qw{ calculate_mccabe_of_main };
  8         14  
  8         454  
15 8     8   5906  
  8         8920  
  8         127  
16             use Perl::Critic::Mardem::Util qw( search_for_block_keyword);
17 8     8   2450  
  8         23  
  8         394  
18             use base 'Perl::Critic::Policy';
19 8     8   47  
  8         16  
  8         3806  
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 97  
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 164276 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 74847 },
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 300  
59             my $block_keyword = search_for_block_keyword( $elem );
60 16         42 if ( !$block_keyword ) {
61 16 100       5889 $block_keyword = 'no-keyword-found';
62 6         17 }
63             else {
64             my @found = grep { $block_keyword eq $_ } @BLOCK_SEARCH_KEYWORD;
65 10         31 if ( !@found ) {
66 10 50       21 return; # if a keyword is found, but not for an conditional block - than ignore
67 0         0 }
68             }
69              
70 10         25 my $desc = qq<"${block_keyword}" condition has a high complexity score ($score)>;
  70         355  
71 10 50       74 return $self->violation( $desc, $EXPL, $elem );
72 0         0 }
73              
74             1;
75              
76 10         28  
77 10         33 #-----------------------------------------------------------------------------
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<Perl::Critic::Mardem>.
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