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