File Coverage

blib/lib/Perl/Metrics/Lite/Analysis/Sub/Plugin/MccabeComplexity.pm
Criterion Covered Total %
statement 54 55 98.1
branch 10 14 71.4
condition 3 5 60.0
subroutine 9 9 100.0
pod 0 4 0.0
total 76 87 87.3


line stmt bran cond sub pod time code
1             package Perl::Metrics::Lite::Analysis::Sub::Plugin::MccabeComplexity;
2 3     3   3807 use strict;
  3         8  
  3         97  
3 3     3   17 use warnings;
  3         7  
  3         122  
4              
5 3     3   24 use Readonly;
  3         6  
  3         2547  
6             Readonly::Array our @DEFAULT_LOGIC_OPERATORS => qw(
7             !
8             !~
9             &&
10             &&=
11             //
12             <
13             <<=
14             <=>
15             ==
16             =~
17             >
18             >>=
19             ?
20             and
21             cmp
22             eq
23             gt
24             lt
25             ne
26             not
27             or
28             xor
29             ||
30             ||=
31             ~~
32             );
33              
34             Readonly::Array our @DEFAULT_LOGIC_KEYWORDS => qw(
35             else
36             elsif
37             for
38             foreach
39             goto
40             grep
41             if
42             last
43             map
44             next
45             unless
46             until
47             while
48             );
49             Readonly::Scalar my $LAST_CHARACTER => -1;
50              
51             our ( @LOGIC_KEYWORDS, @LOGIC_OPERATORS ); # For user-supplied values;
52              
53             our ( %LOGIC_KEYWORDS, %LOGIC_OPERATORS ); # Populated in _init()
54              
55             my %_LOGIC_KEYWORDS = ();
56             my %_LOGIC_OPERATORS = ();
57              
58             sub init {
59 19     19 0 44 my $class = shift;
60             my @logic_keywords
61 19 50       135 = @LOGIC_KEYWORDS ? @LOGIC_KEYWORDS : @DEFAULT_LOGIC_KEYWORDS;
62 19         1260 %LOGIC_KEYWORDS = hashify(@logic_keywords);
63 19         69 $_LOGIC_OPERATORS{$class} = \%LOGIC_KEYWORDS;
64              
65             my @logic_operators
66 19 50       95 = @LOGIC_OPERATORS ? @LOGIC_OPERATORS : @DEFAULT_LOGIC_OPERATORS;
67 19         1969 %LOGIC_OPERATORS = hashify(@logic_operators);
68 19         100 $_LOGIC_OPERATORS{$class} = \%LOGIC_OPERATORS;
69             }
70              
71             sub measure {
72 19     19 0 60 my ( $class, $context, $elem ) = @_;
73              
74 19         38 my $complexity_count = 0;
75 19 50       54 if ( Perl::Metrics::Lite::Analysis::Util::get_node_length($elem) == 0 ) {
76 0         0 return $complexity_count;
77             }
78              
79 19 50       90 if ($elem) {
80 19         32 $complexity_count++;
81             }
82 19         65 $complexity_count += _countup_logic_keywords($elem);
83 19         58 $complexity_count += _counup_logic_operators($elem);
84              
85 19         63 return $complexity_count;
86             }
87              
88             # Count up all the logic keywords, weed out hash keys
89             sub _countup_logic_keywords {
90 19     19   42 my $elem = shift;
91 19   50     75 my $keywords_ref = $elem->find('PPI::Token::Word') || [];
92 19         26145 my @filtered = grep { !is_hash_key($_) } @{$keywords_ref};
  112         239  
  19         54  
93 19         49 my $complexity_count = grep { exists $LOGIC_KEYWORDS{$_} } @filtered;
  103         407  
94 19         104 return $complexity_count;
95             }
96              
97             sub _counup_logic_operators {
98 19     19   37 my $elem = shift;
99 19         41 my $complexity_count = 0;
100 19         63 my $operators_ref = $elem->find('PPI::Token::Operator');
101 19 100       25879 if ($operators_ref) {
102             $complexity_count
103 11         26 += grep { exists $LOGIC_OPERATORS{$_} } @{$operators_ref};
  50         200  
  11         36  
104             }
105 19         91 return $complexity_count;
106             }
107              
108             #-------------------------------------------------------------------------
109             # Copied from
110             # http://search.cpan.org/src/THALJEF/Perl-Critic-0.19/lib/Perl/Critic/Utils.pm
111             sub hashify {
112 38     38 0 163 my @hash_keys = @_;
113 38         79 return map { $_ => 1 } @hash_keys;
  722         1634  
114             }
115              
116             #-------------------------------------------------------------------------
117             # Copied and somehwat simplified from
118             # http://search.cpan.org/src/THALJEF/Perl-Critic-0.19/lib/Perl/Critic/Utils.pm
119             sub is_hash_key {
120 112     112 0 188 my $ppi_elem = shift;
121              
122 112         180 my $is_hash_key = eval {
123 112         277 my $parent = $ppi_elem->parent();
124 112         581 my $grandparent = $parent->parent();
125 112 100       590 if ( $grandparent->isa('PPI::Structure::Subscript') ) {
126 6         14 return 1;
127             }
128 106         247 my $sib = $ppi_elem->snext_sibling();
129 106 100 66     2464 if ( $sib->isa('PPI::Token::Operator') && $sib eq '=>' ) {
130 3         69 return 1;
131             }
132 103         296 return;
133             };
134              
135 112         291 return $is_hash_key;
136             }
137              
138             1;
139