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   1218 use strict;
  3         8  
  3         99  
3 3     3   16 use warnings;
  3         7  
  3         98  
4              
5 3     3   18 use Readonly;
  3         6  
  3         2341  
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 48 my $class = shift;
60             my @logic_keywords
61 19 50       146 = @LOGIC_KEYWORDS ? @LOGIC_KEYWORDS : @DEFAULT_LOGIC_KEYWORDS;
62 19         1253 %LOGIC_KEYWORDS = hashify(@logic_keywords);
63 19         71 $_LOGIC_OPERATORS{$class} = \%LOGIC_KEYWORDS;
64              
65             my @logic_operators
66 19 50       81 = @LOGIC_OPERATORS ? @LOGIC_OPERATORS : @DEFAULT_LOGIC_OPERATORS;
67 19         1887 %LOGIC_OPERATORS = hashify(@logic_operators);
68 19         99 $_LOGIC_OPERATORS{$class} = \%LOGIC_OPERATORS;
69             }
70              
71             sub measure {
72 19     19 0 57 my ( $class, $context, $elem ) = @_;
73              
74 19         44 my $complexity_count = 0;
75 19 50       55 if ( Perl::Metrics::Lite::Analysis::Util::get_node_length($elem) == 0 ) {
76 0         0 return $complexity_count;
77             }
78              
79 19 50       76 if ($elem) {
80 19         44 $complexity_count++;
81             }
82 19         65 $complexity_count += _countup_logic_keywords($elem);
83 19         70 $complexity_count += _counup_logic_operators($elem);
84              
85 19         70 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     76 my $keywords_ref = $elem->find('PPI::Token::Word') || [];
92 19         25734 my @filtered = grep { !is_hash_key($_) } @{$keywords_ref};
  112         240  
  19         56  
93 19         55 my $complexity_count = grep { exists $LOGIC_KEYWORDS{$_} } @filtered;
  103         402  
94 19         112 return $complexity_count;
95             }
96              
97             sub _counup_logic_operators {
98 19     19   41 my $elem = shift;
99 19         39 my $complexity_count = 0;
100 19         64 my $operators_ref = $elem->find('PPI::Token::Operator');
101 19 100       25983 if ($operators_ref) {
102             $complexity_count
103 11         28 += grep { exists $LOGIC_OPERATORS{$_} } @{$operators_ref};
  50         214  
  11         39  
104             }
105 19         88 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 154 my @hash_keys = @_;
113 38         81 return map { $_ => 1 } @hash_keys;
  722         1590  
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 179 my $ppi_elem = shift;
121              
122 112         178 my $is_hash_key = eval {
123 112         293 my $parent = $ppi_elem->parent();
124 112         635 my $grandparent = $parent->parent();
125 112 100       641 if ( $grandparent->isa('PPI::Structure::Subscript') ) {
126 6         13 return 1;
127             }
128 106         248 my $sib = $ppi_elem->snext_sibling();
129 106 100 66     2492 if ( $sib->isa('PPI::Token::Operator') && $sib eq '=>' ) {
130 3         66 return 1;
131             }
132 103         276 return;
133             };
134              
135 112         631 return $is_hash_key;
136             }
137              
138             1;
139