simplabs-excellent 1.0.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +19 -0
- data/README.rdoc +34 -0
- data/VERSION.yml +1 -1
- data/bin/excellent +21 -6
- data/lib/simplabs/excellent.rb +7 -5
- data/lib/simplabs/excellent/checks.rb +18 -1
- data/lib/simplabs/excellent/checks/abc_metric_method_check.rb +19 -56
- data/lib/simplabs/excellent/checks/assignment_in_conditional_check.rb +16 -16
- data/lib/simplabs/excellent/checks/base.rb +30 -21
- data/lib/simplabs/excellent/checks/case_missing_else_check.rb +13 -5
- data/lib/simplabs/excellent/checks/class_line_count_check.rb +10 -8
- data/lib/simplabs/excellent/checks/class_name_check.rb +11 -10
- data/lib/simplabs/excellent/checks/control_coupling_check.rb +13 -10
- data/lib/simplabs/excellent/checks/cyclomatic_complexity_block_check.rb +25 -9
- data/lib/simplabs/excellent/checks/cyclomatic_complexity_check.rb +4 -20
- data/lib/simplabs/excellent/checks/cyclomatic_complexity_method_check.rb +25 -10
- data/lib/simplabs/excellent/checks/duplication_check.rb +50 -0
- data/lib/simplabs/excellent/checks/empty_rescue_body_check.rb +10 -18
- data/lib/simplabs/excellent/checks/flog_block_check.rb +40 -0
- data/lib/simplabs/excellent/checks/flog_check.rb +27 -0
- data/lib/simplabs/excellent/checks/flog_class_check.rb +40 -0
- data/lib/simplabs/excellent/checks/flog_method_check.rb +40 -0
- data/lib/simplabs/excellent/checks/for_loop_check.rb +20 -4
- data/lib/simplabs/excellent/checks/line_count_check.rb +3 -21
- data/lib/simplabs/excellent/checks/method_line_count_check.rb +9 -7
- data/lib/simplabs/excellent/checks/method_name_check.rb +13 -9
- data/lib/simplabs/excellent/checks/module_line_count_check.rb +9 -7
- data/lib/simplabs/excellent/checks/module_name_check.rb +11 -7
- data/lib/simplabs/excellent/checks/name_check.rb +3 -8
- data/lib/simplabs/excellent/checks/nested_iterators_check.rb +33 -0
- data/lib/simplabs/excellent/checks/parameter_number_check.rb +13 -12
- data/lib/simplabs/excellent/checks/rails.rb +17 -0
- data/lib/simplabs/excellent/checks/rails/attr_accessible_check.rb +38 -0
- data/lib/simplabs/excellent/checks/rails/attr_protected_check.rb +39 -0
- data/lib/simplabs/excellent/checks/singleton_variable_check.rb +32 -0
- data/lib/simplabs/excellent/extensions/sexp.rb +21 -0
- data/lib/simplabs/excellent/extensions/string.rb +23 -0
- data/lib/simplabs/excellent/parsing.rb +12 -0
- data/lib/simplabs/excellent/parsing/abc_measure.rb +52 -0
- data/lib/simplabs/excellent/parsing/block_context.rb +43 -0
- data/lib/simplabs/excellent/parsing/call_context.rb +36 -0
- data/lib/simplabs/excellent/parsing/case_context.rb +31 -0
- data/lib/simplabs/excellent/parsing/class_context.rb +68 -0
- data/lib/simplabs/excellent/parsing/code_processor.rb +154 -0
- data/lib/simplabs/excellent/parsing/conditional_context.rb +25 -0
- data/lib/simplabs/excellent/parsing/cvar_context.rb +28 -0
- data/lib/simplabs/excellent/parsing/cyclomatic_complexity_measure.rb +73 -0
- data/lib/simplabs/excellent/parsing/flog_measure.rb +192 -0
- data/lib/simplabs/excellent/parsing/for_loop_context.rb +15 -0
- data/lib/simplabs/excellent/parsing/if_context.rb +38 -0
- data/lib/simplabs/excellent/parsing/method_context.rb +50 -0
- data/lib/simplabs/excellent/parsing/module_context.rb +29 -0
- data/lib/simplabs/excellent/{core → parsing}/parser.rb +4 -2
- data/lib/simplabs/excellent/parsing/resbody_context.rb +39 -0
- data/lib/simplabs/excellent/parsing/scopeable.rb +34 -0
- data/lib/simplabs/excellent/parsing/sexp_context.rb +125 -0
- data/lib/simplabs/excellent/parsing/singleton_method_context.rb +55 -0
- data/lib/simplabs/excellent/parsing/until_context.rb +24 -0
- data/lib/simplabs/excellent/parsing/while_context.rb +24 -0
- data/lib/simplabs/excellent/runner.rb +105 -0
- data/lib/simplabs/excellent/warning.rb +53 -0
- data/spec/checks/abc_metric_method_check_spec.rb +36 -8
- data/spec/checks/assignment_in_conditional_check_spec.rb +31 -14
- data/spec/checks/case_missing_else_check_spec.rb +8 -8
- data/spec/checks/class_line_count_check_spec.rb +24 -11
- data/spec/checks/class_name_check_spec.rb +9 -9
- data/spec/checks/control_coupling_check_spec.rb +84 -13
- data/spec/checks/cyclomatic_complexity_block_check_spec.rb +13 -17
- data/spec/checks/cyclomatic_complexity_method_check_spec.rb +32 -6
- data/spec/checks/duplication_check_spec.rb +139 -0
- data/spec/checks/empty_rescue_body_check_spec.rb +54 -16
- data/spec/checks/flog_block_check_spec.rb +28 -0
- data/spec/checks/flog_class_check_spec.rb +28 -0
- data/spec/checks/flog_method_check_spec.rb +46 -0
- data/spec/checks/for_loop_check_spec.rb +11 -11
- data/spec/checks/method_line_count_check_spec.rb +11 -12
- data/spec/checks/method_name_check_spec.rb +34 -13
- data/spec/checks/module_line_count_check_spec.rb +11 -12
- data/spec/checks/module_name_check_spec.rb +31 -7
- data/spec/checks/nested_iterators_check_spec.rb +44 -0
- data/spec/checks/parameter_number_check_spec.rb +48 -12
- data/spec/checks/rails/attr_accessible_check_spec.rb +79 -0
- data/spec/checks/rails/attr_protected_check_spec.rb +77 -0
- data/spec/checks/singleton_variable_check_spec.rb +66 -0
- data/spec/{core/extensions/underscore_spec.rb → extensions/string_spec.rb} +1 -1
- metadata +58 -15
- data/README.markdown +0 -30
- data/lib/simplabs/excellent/checks/class_variable_check.rb +0 -25
- data/lib/simplabs/excellent/core.rb +0 -2
- data/lib/simplabs/excellent/core/checking_visitor.rb +0 -34
- data/lib/simplabs/excellent/core/error.rb +0 -31
- data/lib/simplabs/excellent/core/extensions/underscore.rb +0 -27
- data/lib/simplabs/excellent/core/iterator_visitor.rb +0 -29
- data/lib/simplabs/excellent/core/parse_tree_runner.rb +0 -88
- data/lib/simplabs/excellent/core/visitable_sexp.rb +0 -31
- data/spec/checks/class_variable_check_spec.rb +0 -26
@@ -0,0 +1,73 @@
|
|
1
|
+
module Simplabs
|
2
|
+
|
3
|
+
module Excellent
|
4
|
+
|
5
|
+
module Parsing
|
6
|
+
|
7
|
+
module CyclomaticComplexityMeasure #:nodoc:
|
8
|
+
|
9
|
+
COMPLEXITY_NODE_TYPES = [:if, :while, :until, :for, :rescue, :case, :when, :and, :or]
|
10
|
+
|
11
|
+
def process_if(exp)
|
12
|
+
add_complexity_score(1)
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def process_while(exp)
|
17
|
+
add_complexity_score(1)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def process_until(exp)
|
22
|
+
add_complexity_score(1)
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_for(exp)
|
27
|
+
add_complexity_score(1)
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def process_rescue(exp)
|
32
|
+
add_complexity_score(1)
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_case(exp)
|
37
|
+
add_complexity_score(1)
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_when(exp)
|
42
|
+
add_complexity_score(1)
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
def process_and(exp)
|
47
|
+
add_complexity_score(1)
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_or(exp)
|
52
|
+
add_complexity_score(1)
|
53
|
+
super
|
54
|
+
end
|
55
|
+
|
56
|
+
def cc_score
|
57
|
+
@cc_score + 1 rescue 1
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def add_complexity_score(score)
|
63
|
+
@cc_score ||= 0
|
64
|
+
@cc_score += score
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
module Simplabs
|
2
|
+
|
3
|
+
module Excellent
|
4
|
+
|
5
|
+
module Parsing
|
6
|
+
|
7
|
+
module FlogMeasure #:nodoc:
|
8
|
+
|
9
|
+
SCORES = Hash.new(1)
|
10
|
+
SCORES.merge!(
|
11
|
+
:define_method => 5,
|
12
|
+
:eval => 5,
|
13
|
+
:module_eval => 5,
|
14
|
+
:class_eval => 5,
|
15
|
+
:instance_eval => 5,
|
16
|
+
:alias_method => 2,
|
17
|
+
:extend => 2,
|
18
|
+
:include => 2,
|
19
|
+
:instance_method => 2,
|
20
|
+
:instance_methods => 2,
|
21
|
+
:method_added => 2,
|
22
|
+
:method_defined? => 2,
|
23
|
+
:method_removed => 2,
|
24
|
+
:method_undefined => 2,
|
25
|
+
:private_class_method => 2,
|
26
|
+
:private_instance_methods => 2,
|
27
|
+
:private_method_defined? => 2,
|
28
|
+
:protected_instance_methods => 2,
|
29
|
+
:protected_method_defined? => 2,
|
30
|
+
:public_class_method => 2,
|
31
|
+
:public_instance_methods => 2,
|
32
|
+
:public_method_defined? => 2,
|
33
|
+
:remove_method => 2,
|
34
|
+
:send => 3,
|
35
|
+
:undef_method => 2
|
36
|
+
)
|
37
|
+
BRANCHES = [:and, :case, :else, :if, :or, :rescue, :until, :when, :while]
|
38
|
+
|
39
|
+
def process_alias(exp)
|
40
|
+
add_flog_score(2)
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_and(exp)
|
45
|
+
add_flog_score(1)
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_or(exp)
|
50
|
+
add_flog_score(1)
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_attrasgn(exp)
|
55
|
+
add_flog_score(1)
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_attrset(exp)
|
60
|
+
add_flog_score(1)
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def process_block_pass(exp)
|
65
|
+
add_flog_score(1)
|
66
|
+
arg = exp.last
|
67
|
+
if arg.is_a?(Sexp)
|
68
|
+
case arg.first
|
69
|
+
when :lit, :call
|
70
|
+
add_flog_score(5)
|
71
|
+
when :iter, :dsym, :dstr, *BRANCHES
|
72
|
+
add_flog_score(10)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
def process_call(exp)
|
79
|
+
add_flog_score(SCORES[exp[2]])
|
80
|
+
super
|
81
|
+
end
|
82
|
+
|
83
|
+
def process_case(exp)
|
84
|
+
add_flog_score(1)
|
85
|
+
super
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_dasgn_curr(exp)
|
89
|
+
add_flog_score(1)
|
90
|
+
super
|
91
|
+
end
|
92
|
+
|
93
|
+
def process_iasgn(exp)
|
94
|
+
add_flog_score(1)
|
95
|
+
super
|
96
|
+
end
|
97
|
+
|
98
|
+
def process_lasgn(exp)
|
99
|
+
add_flog_score(1)
|
100
|
+
super
|
101
|
+
end
|
102
|
+
|
103
|
+
def process_else(exp)
|
104
|
+
add_flog_score(1)
|
105
|
+
super
|
106
|
+
end
|
107
|
+
|
108
|
+
def process_rescue(exp)
|
109
|
+
add_flog_score(1)
|
110
|
+
super
|
111
|
+
end
|
112
|
+
|
113
|
+
def process_when(exp)
|
114
|
+
add_flog_score(1)
|
115
|
+
super
|
116
|
+
end
|
117
|
+
|
118
|
+
def process_if(exp)
|
119
|
+
add_flog_score(1)
|
120
|
+
super
|
121
|
+
end
|
122
|
+
|
123
|
+
def process_iter(exp)
|
124
|
+
add_flog_score 1
|
125
|
+
super
|
126
|
+
end
|
127
|
+
|
128
|
+
def process_lit(exp)
|
129
|
+
value = exp.shift
|
130
|
+
case value
|
131
|
+
when 0, -1
|
132
|
+
# do nothing
|
133
|
+
when Integer
|
134
|
+
add_flog_score(0.25)
|
135
|
+
end
|
136
|
+
super
|
137
|
+
end
|
138
|
+
|
139
|
+
def process_masgn(exp)
|
140
|
+
add_flog_score(1)
|
141
|
+
super
|
142
|
+
end
|
143
|
+
|
144
|
+
def process_sclass(exp)
|
145
|
+
add_flog_score(5)
|
146
|
+
super
|
147
|
+
end
|
148
|
+
|
149
|
+
def process_super(exp)
|
150
|
+
add_flog_score(1)
|
151
|
+
super
|
152
|
+
end
|
153
|
+
|
154
|
+
def process_while(exp)
|
155
|
+
add_flog_score(1)
|
156
|
+
super
|
157
|
+
end
|
158
|
+
|
159
|
+
def process_until(exp)
|
160
|
+
add_flog_score(1)
|
161
|
+
super
|
162
|
+
end
|
163
|
+
|
164
|
+
def process_yield(exp)
|
165
|
+
add_flog_score(1)
|
166
|
+
super
|
167
|
+
end
|
168
|
+
|
169
|
+
def flog_score
|
170
|
+
initialize_values
|
171
|
+
@score
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
def add_flog_score(score)
|
177
|
+
initialize_values
|
178
|
+
@score += (score * @multiplier)
|
179
|
+
end
|
180
|
+
|
181
|
+
def initialize_values
|
182
|
+
@score ||= 0
|
183
|
+
@multiplier ||= 1
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'simplabs/excellent/parsing/conditional_context'
|
2
|
+
|
3
|
+
module Simplabs
|
4
|
+
|
5
|
+
module Excellent
|
6
|
+
|
7
|
+
module Parsing
|
8
|
+
|
9
|
+
class IfContext < ConditionalContext #:nodoc:
|
10
|
+
|
11
|
+
def initialize(exp, parent)
|
12
|
+
super
|
13
|
+
@contains_assignment = has_assignment?
|
14
|
+
@tests_parameter = contains_parameter?
|
15
|
+
end
|
16
|
+
|
17
|
+
def tests_assignment?
|
18
|
+
@contains_assignment
|
19
|
+
end
|
20
|
+
|
21
|
+
def tests_parameter?
|
22
|
+
@tests_parameter
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def has_assignment?(exp = @exp[1])
|
28
|
+
return false if exp.node_type == :iter
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'simplabs/excellent/parsing/cyclomatic_complexity_measure'
|
2
|
+
require 'simplabs/excellent/parsing/abc_measure'
|
3
|
+
require 'simplabs/excellent/parsing/flog_measure'
|
4
|
+
|
5
|
+
module Simplabs
|
6
|
+
|
7
|
+
module Excellent
|
8
|
+
|
9
|
+
module Parsing
|
10
|
+
|
11
|
+
class MethodContext < SexpContext #:nodoc:
|
12
|
+
|
13
|
+
include CyclomaticComplexityMeasure
|
14
|
+
include AbcMeasure
|
15
|
+
include FlogMeasure
|
16
|
+
|
17
|
+
attr_reader :parameters
|
18
|
+
attr_reader :calls
|
19
|
+
attr_reader :line_count
|
20
|
+
|
21
|
+
def initialize(exp, parent)
|
22
|
+
super
|
23
|
+
@parameters = []
|
24
|
+
@name = exp[1].to_s
|
25
|
+
@parent.methods << self if @parent && (@parent.is_a?(ClassContext) || @parent.is_a?(ModuleContext))
|
26
|
+
@calls = Hash.new(0)
|
27
|
+
@line_count = count_lines
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_parameter?(parameter)
|
31
|
+
@parameters.include?(parameter)
|
32
|
+
end
|
33
|
+
|
34
|
+
def full_name
|
35
|
+
parent = @parent.is_a?(BlockContext) ? @parent.parent : @parent
|
36
|
+
return @name if parent.blank?
|
37
|
+
"#{parent.full_name}##{@name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def record_call_to(exp)
|
41
|
+
@calls[exp] += 1
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'simplabs/excellent/parsing/scopeable'
|
2
|
+
|
3
|
+
module Simplabs
|
4
|
+
|
5
|
+
module Excellent
|
6
|
+
|
7
|
+
module Parsing
|
8
|
+
|
9
|
+
class ModuleContext < SexpContext #:nodoc:
|
10
|
+
|
11
|
+
include Scopeable
|
12
|
+
|
13
|
+
attr_reader :methods
|
14
|
+
attr_reader :line_count
|
15
|
+
|
16
|
+
def initialize(exp, parent)
|
17
|
+
super
|
18
|
+
@name, @full_name = get_names
|
19
|
+
@methods = []
|
20
|
+
@line_count = count_lines
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -6,14 +6,16 @@ module Simplabs
|
|
6
6
|
|
7
7
|
module Excellent
|
8
8
|
|
9
|
-
module
|
9
|
+
module Parsing
|
10
10
|
|
11
|
-
class Parser
|
11
|
+
class Parser #:nodoc:
|
12
12
|
|
13
13
|
def parse(content, filename)
|
14
14
|
silence_stream(STDERR) do
|
15
15
|
return silent_parse(content, filename)
|
16
16
|
end
|
17
|
+
rescue
|
18
|
+
#continue on errors
|
17
19
|
end
|
18
20
|
|
19
21
|
private
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Simplabs
|
2
|
+
|
3
|
+
module Excellent
|
4
|
+
|
5
|
+
module Parsing
|
6
|
+
|
7
|
+
class ResbodyContext < SexpContext #:nodoc:
|
8
|
+
|
9
|
+
STATEMENT_NODES = [:fcall, :return, :attrasgn, :vcall, :call, :str, :lit, :hash, :false, :true, :nil]
|
10
|
+
|
11
|
+
def initialize(exp, parent)
|
12
|
+
super
|
13
|
+
@contains_statements = contains_statements?
|
14
|
+
end
|
15
|
+
|
16
|
+
def has_statements?
|
17
|
+
@contains_statements
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def contains_statements?(exp = @exp)
|
23
|
+
return true if STATEMENT_NODES.include?(exp.node_type)
|
24
|
+
return true if assigning_other_than_exception_to_local_variable?(exp)
|
25
|
+
return true if (exp[1][0] == :array && exp[2][0] == :array rescue false)
|
26
|
+
return true if exp.children.any? { |child| contains_statements?(child) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def assigning_other_than_exception_to_local_variable?(exp)
|
30
|
+
exp.node_type == :lasgn && exp[2].to_a != [:gvar, :$!]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|