metric_fu-roodi 2.2.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/metric_fu-roodi +2 -19
- data/bin/metric_fu-roodi-describe +2 -5
- data/lib/roodi.rb +6 -2
- data/lib/roodi/version.rb +1 -1
- metadata +13 -119
- data/.gitignore +0 -3
- data/.rspec +0 -2
- data/Gemfile +0 -6
- data/History.txt +0 -111
- data/Manifest.txt +0 -56
- data/README.txt +0 -98
- data/Rakefile +0 -31
- data/TODO.md +0 -3
- data/lib/roodi/checks.rb +0 -18
- data/lib/roodi/checks/abc_metric_method_check.rb +0 -79
- data/lib/roodi/checks/assignment_in_conditional_check.rb +0 -32
- data/lib/roodi/checks/case_missing_else_check.rb +0 -20
- data/lib/roodi/checks/check.rb +0 -76
- data/lib/roodi/checks/class_line_count_check.rb +0 -28
- data/lib/roodi/checks/class_name_check.rb +0 -31
- data/lib/roodi/checks/class_variable_check.rb +0 -24
- data/lib/roodi/checks/control_coupling_check.rb +0 -20
- data/lib/roodi/checks/cyclomatic_complexity_block_check.rb +0 -41
- data/lib/roodi/checks/cyclomatic_complexity_check.rb +0 -50
- data/lib/roodi/checks/cyclomatic_complexity_method_check.rb +0 -42
- data/lib/roodi/checks/empty_rescue_body_check.rb +0 -32
- data/lib/roodi/checks/for_loop_check.rb +0 -20
- data/lib/roodi/checks/line_count_check.rb +0 -28
- data/lib/roodi/checks/method_line_count_check.rb +0 -29
- data/lib/roodi/checks/method_name_check.rb +0 -31
- data/lib/roodi/checks/missing_foreign_key_index_check.rb +0 -99
- data/lib/roodi/checks/module_line_count_check.rb +0 -28
- data/lib/roodi/checks/module_name_check.rb +0 -31
- data/lib/roodi/checks/name_check.rb +0 -16
- data/lib/roodi/checks/npath_complexity_check.rb +0 -75
- data/lib/roodi/checks/npath_complexity_method_check.rb +0 -29
- data/lib/roodi/checks/parameter_number_check.rb +0 -34
- data/lib/roodi/core.rb +0 -1
- data/lib/roodi/core/checking_visitor.rb +0 -26
- data/lib/roodi/core/error.rb +0 -17
- data/lib/roodi/core/parser.rb +0 -48
- data/lib/roodi/core/runner.rb +0 -81
- data/lib/roodi/core/visitable_sexp.rb +0 -25
- data/lib/roodi_task.rb +0 -35
- data/roodi.gemspec +0 -26
- data/roodi.yml +0 -25
- data/spec/roodi/checks/abc_metric_method_check_spec.rb +0 -89
- data/spec/roodi/checks/assignment_in_conditional_check_spec.rb +0 -105
- data/spec/roodi/checks/case_missing_else_check_spec.rb +0 -32
- data/spec/roodi/checks/class_line_count_check_spec.rb +0 -39
- data/spec/roodi/checks/class_name_check_spec.rb +0 -39
- data/spec/roodi/checks/class_variable_check_spec.rb +0 -17
- data/spec/roodi/checks/control_coupling_check_spec.rb +0 -23
- data/spec/roodi/checks/cyclomatic_complexity_block_check_spec.rb +0 -67
- data/spec/roodi/checks/cyclomatic_complexity_method_check_spec.rb +0 -200
- data/spec/roodi/checks/empty_rescue_body_check_spec.rb +0 -154
- data/spec/roodi/checks/for_loop_check_spec.rb +0 -18
- data/spec/roodi/checks/method_line_count_check_spec.rb +0 -56
- data/spec/roodi/checks/method_name_check_spec.rb +0 -76
- data/spec/roodi/checks/missing_foreign_key_index_check_spec.rb +0 -33
- data/spec/roodi/checks/module_line_count_check_spec.rb +0 -39
- data/spec/roodi/checks/module_name_check_spec.rb +0 -27
- data/spec/roodi/checks/npath_complexity_method_check_spec.rb +0 -53
- data/spec/roodi/checks/parameter_number_check_spec.rb +0 -47
- data/spec/roodi/core/runner_spec.rb +0 -25
- data/spec/roodi/roodi.yml +0 -2
- data/spec/spec_helper.rb +0 -3
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'roodi/checks/cyclomatic_complexity_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks cyclomatic complexity of a method against a specified limit.
|
6
|
-
#
|
7
|
-
# The cyclomatic complexity is measured by the number of "if", "unless", "elsif", "?:",
|
8
|
-
# "while", "until", "for", "rescue", "case", "when", "&&", "and", "||" and "or"
|
9
|
-
# statements (plus one) in the body of the member. It is a measure of the minimum
|
10
|
-
# number of possible paths through the source and therefore the number of required tests.
|
11
|
-
#
|
12
|
-
# Generally, for a method, 1-4 is considered good, 5-8 ok, 9-10 consider re-factoring, and
|
13
|
-
# 11+ re-factor now!
|
14
|
-
class CyclomaticComplexityMethodCheck < CyclomaticComplexityCheck
|
15
|
-
|
16
|
-
DEFAULT_COMPLEXITY = 8
|
17
|
-
|
18
|
-
def initialize
|
19
|
-
super()
|
20
|
-
self.complexity = DEFAULT_COMPLEXITY
|
21
|
-
end
|
22
|
-
|
23
|
-
def interesting_nodes
|
24
|
-
[:defn] + COMPLEXITY_NODE_TYPES
|
25
|
-
end
|
26
|
-
|
27
|
-
def evaluate_start_defn(node)
|
28
|
-
@method_name = @node[1]
|
29
|
-
increase_depth
|
30
|
-
end
|
31
|
-
|
32
|
-
def evaluate_end_defn(node)
|
33
|
-
decrease_depth
|
34
|
-
end
|
35
|
-
|
36
|
-
def evaluate_matching_end
|
37
|
-
add_error "Method name \"#{@method_name}\" cyclomatic complexity is #{@count}. It should be #{@complexity} or less." unless @count <= @complexity
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks the body of a rescue block to make sure it's not empty..
|
6
|
-
#
|
7
|
-
# When the body of a rescue block is empty, exceptions can get caught and swallowed without
|
8
|
-
# any feedback to the user.
|
9
|
-
class EmptyRescueBodyCheck < Check
|
10
|
-
STATEMENT_NODES = [:fcall, :return, :attrasgn, :vcall, :nil, :call, :lasgn, :true, :false, :next]
|
11
|
-
|
12
|
-
def interesting_nodes
|
13
|
-
[:resbody]
|
14
|
-
end
|
15
|
-
|
16
|
-
def evaluate_start(node)
|
17
|
-
add_error("Rescue block should not be empty.") unless has_statement?(node.children[1])
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def has_statement?(node)
|
23
|
-
false unless node
|
24
|
-
has_local_statement?(node) or node.children.any? { |child| has_statement?(child) } if node
|
25
|
-
end
|
26
|
-
|
27
|
-
def has_local_statement?(node)
|
28
|
-
STATEMENT_NODES.include?(node.node_type)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks to make sure for loops are not being used..
|
6
|
-
#
|
7
|
-
# Using a for loop is not idiomatic use of Ruby, and is usually a sign that someone with
|
8
|
-
# more experience in a different programming language is trying out Ruby. Use
|
9
|
-
# Enumerable.each with a block instead.
|
10
|
-
class ForLoopCheck < Check
|
11
|
-
def interesting_nodes
|
12
|
-
[:for]
|
13
|
-
end
|
14
|
-
|
15
|
-
def evaluate_start(node)
|
16
|
-
add_error "Don't use 'for' loops. Use Enumerable.each instead."
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
class LineCountCheck < Check
|
6
|
-
|
7
|
-
attr_accessor :line_count
|
8
|
-
|
9
|
-
def evaluate_start(node)
|
10
|
-
line_count = count_lines(node)
|
11
|
-
add_error "#{message_prefix} \"#{node[1]}\" has #{line_count} lines. It should have #{@line_count} or less." unless line_count <= @line_count
|
12
|
-
end
|
13
|
-
|
14
|
-
protected
|
15
|
-
|
16
|
-
def count_lines(node)
|
17
|
-
node.last.line - node.line - 1
|
18
|
-
rescue NoMethodError => e
|
19
|
-
if ENV['DEBUG'] =~ /true/i
|
20
|
-
STDERR.puts "!! line counting error #{e.message}\t #{node.inspect}"
|
21
|
-
STDERR.puts "!! Does the node have any lines?"
|
22
|
-
end
|
23
|
-
0
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'roodi/checks/line_count_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks a method to make sure the number of lines it has is under the specified limit.
|
6
|
-
#
|
7
|
-
# A method getting too large is a code smell that indicates it might be doing more than one
|
8
|
-
# thing and becoming hard to test. It should probably be refactored into multiple methods
|
9
|
-
# that each do a single thing well.
|
10
|
-
class MethodLineCountCheck < LineCountCheck
|
11
|
-
|
12
|
-
DEFAULT_LINE_COUNT = 20
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
super()
|
16
|
-
self.line_count = DEFAULT_LINE_COUNT
|
17
|
-
end
|
18
|
-
|
19
|
-
def interesting_nodes
|
20
|
-
[:defn]
|
21
|
-
end
|
22
|
-
|
23
|
-
def message_prefix
|
24
|
-
'Method'
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'roodi/checks/name_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks a method name to make sure it matches the specified pattern.
|
6
|
-
#
|
7
|
-
# Keeping to a consistent nameing convention makes your code easier to read.
|
8
|
-
class MethodNameCheck < NameCheck
|
9
|
-
|
10
|
-
DEFAULT_PATTERN = /^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
super()
|
14
|
-
self.pattern = DEFAULT_PATTERN
|
15
|
-
end
|
16
|
-
|
17
|
-
def interesting_nodes
|
18
|
-
[:defn]
|
19
|
-
end
|
20
|
-
|
21
|
-
def message_prefix
|
22
|
-
'Method'
|
23
|
-
end
|
24
|
-
|
25
|
-
def find_name(node)
|
26
|
-
node[1]
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
require 'pathname'
|
3
|
-
|
4
|
-
module Roodi
|
5
|
-
module Checks
|
6
|
-
# Checks to make sure for loops are not being used..
|
7
|
-
#
|
8
|
-
# Using a for loop is not idiomatic use of Ruby, and is usually a sign that someone with
|
9
|
-
# more experience in a different programming language is trying out Ruby. Use
|
10
|
-
# Enumerable.each with a block instead.
|
11
|
-
class MissingForeignKeyIndexCheck < Check
|
12
|
-
def initialize
|
13
|
-
super()
|
14
|
-
@foreign_keys = {}
|
15
|
-
@indexes = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
def interesting_nodes
|
19
|
-
[:call]
|
20
|
-
end
|
21
|
-
|
22
|
-
def evaluate_start_call(node)
|
23
|
-
if analyzing_schema(node)
|
24
|
-
if creating_table(node)
|
25
|
-
@current_table = create_table_name(node)
|
26
|
-
end
|
27
|
-
|
28
|
-
if creating_foreign_key(node)
|
29
|
-
@foreign_keys[@current_table] ||= []
|
30
|
-
@foreign_keys[@current_table] << foreign_key_column_name(node)
|
31
|
-
end
|
32
|
-
|
33
|
-
if adding_index(node)
|
34
|
-
@indexes[index_table_name(node)] ||= []
|
35
|
-
@indexes[index_table_name(node)] << index_column_name(node)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def evaluate_end_call(node)
|
41
|
-
#ignored
|
42
|
-
end
|
43
|
-
|
44
|
-
def analyzing_schema(node)
|
45
|
-
pathname = Pathname.new(node.file)
|
46
|
-
@analyzing_schema ||= ("schema.rb" == pathname.basename.to_s)
|
47
|
-
end
|
48
|
-
|
49
|
-
def creating_table(node)
|
50
|
-
:create_table == node[2]
|
51
|
-
end
|
52
|
-
|
53
|
-
def create_table_name(node)
|
54
|
-
# Get table name out of this:
|
55
|
-
# s(:call, nil, :create_table, s(:arglist, s(:str, "duplicate_blocks"), s(:hash, s(:lit, :force), s(:true))))
|
56
|
-
node[3][1][1]
|
57
|
-
end
|
58
|
-
|
59
|
-
def creating_foreign_key(node)
|
60
|
-
#s(:call, s(:lvar, :t), :integer, s(:arglist, s(:str, "duplicate_set_id"), s(:hash, s(:lit, :null), s(:false))))
|
61
|
-
column_type = node[2]
|
62
|
-
column_name = node[3][1][1]
|
63
|
-
:integer == column_type && "_id" == column_name[-3,3]
|
64
|
-
end
|
65
|
-
|
66
|
-
def foreign_key_column_name(node)
|
67
|
-
#s(:call, s(:lvar, :t), :integer, s(:arglist, s(:str, "duplicate_set_id"), s(:hash, s(:lit, :null), s(:false))))
|
68
|
-
column_name = node[3][1][1]
|
69
|
-
end
|
70
|
-
|
71
|
-
def adding_index(node)
|
72
|
-
:add_index == node[2]
|
73
|
-
end
|
74
|
-
|
75
|
-
def index_table_name(node)
|
76
|
-
# Get table name out of this:
|
77
|
-
# s(:call, nil, :add_index, s(:arglist, s(:str, "duplicate_blocks"), s(:array, s(:str, "duplicate_set_id")), s(:hash, s(:lit, :name), s(:str, "index_duplicate_blocks_on_duplicate_set_id"))))
|
78
|
-
node[3][1][1]
|
79
|
-
end
|
80
|
-
|
81
|
-
def index_column_name(node)
|
82
|
-
# Get index column name out of this:
|
83
|
-
# s(:call, nil, :add_index, s(:arglist, s(:str, "duplicate_blocks"), s(:array, s(:str, "duplicate_set_id")), s(:hash, s(:lit, :name), s(:str, "index_duplicate_blocks_on_duplicate_set_id"))))
|
84
|
-
node[3][2][1][1]
|
85
|
-
end
|
86
|
-
|
87
|
-
def end_file(filename)
|
88
|
-
@foreign_keys.keys.each do |table|
|
89
|
-
foreign_keys = @foreign_keys[table] || []
|
90
|
-
indexes = @indexes[table] || []
|
91
|
-
missing_indexes = foreign_keys - indexes
|
92
|
-
missing_indexes.each do |fkey|
|
93
|
-
add_error("Table '#{table}' is missing an index on the foreign key '#{fkey}'", filename, 1)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'roodi/checks/line_count_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks a module to make sure the number of lines it has is under the specified limit.
|
6
|
-
#
|
7
|
-
# A module getting too large is a code smell that indicates it might be taking on too many
|
8
|
-
# responsibilities. It should probably be refactored into multiple smaller modules.
|
9
|
-
class ModuleLineCountCheck < LineCountCheck
|
10
|
-
|
11
|
-
DEFAULT_LINE_COUNT = 300
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
super()
|
15
|
-
self.line_count = DEFAULT_LINE_COUNT
|
16
|
-
end
|
17
|
-
|
18
|
-
def interesting_nodes
|
19
|
-
[:module]
|
20
|
-
end
|
21
|
-
|
22
|
-
def message_prefix
|
23
|
-
'Module'
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'roodi/checks/name_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks a module name to make sure it matches the specified pattern.
|
6
|
-
#
|
7
|
-
# Keeping to a consistent nameing convention makes your code easier to read.
|
8
|
-
class ModuleNameCheck < NameCheck
|
9
|
-
|
10
|
-
DEFAULT_PATTERN = /^[A-Z][a-zA-Z0-9]*$/
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
super()
|
14
|
-
self.pattern = DEFAULT_PATTERN
|
15
|
-
end
|
16
|
-
|
17
|
-
def interesting_nodes
|
18
|
-
[:module]
|
19
|
-
end
|
20
|
-
|
21
|
-
def message_prefix
|
22
|
-
'Module'
|
23
|
-
end
|
24
|
-
|
25
|
-
def find_name(node)
|
26
|
-
node[1].class == Symbol ? node[1] : node[1].last
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
class NameCheck < Check
|
6
|
-
|
7
|
-
attr_accessor :pattern
|
8
|
-
|
9
|
-
def evaluate_start(node)
|
10
|
-
name = find_name(node)
|
11
|
-
add_error "#{message_prefix} name \"#{name}\" should match pattern #{@pattern.inspect}" unless name.to_s =~ @pattern
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
class NpathComplexityCheck < Check
|
6
|
-
# , :when, :and, :or
|
7
|
-
MULTIPLYING_NODE_TYPES = [:if, :while, :until, :for, :case]
|
8
|
-
ADDING_NODE_TYPES = [:rescue]
|
9
|
-
COMPLEXITY_NODE_TYPES = MULTIPLYING_NODE_TYPES + ADDING_NODE_TYPES
|
10
|
-
|
11
|
-
attr_accessor :complexity
|
12
|
-
|
13
|
-
def initialize(complexity)
|
14
|
-
super()
|
15
|
-
@complexity = complexity
|
16
|
-
@value_stack = []
|
17
|
-
@current_value = 1
|
18
|
-
end
|
19
|
-
|
20
|
-
def evalute_start_if(node)
|
21
|
-
push_value
|
22
|
-
end
|
23
|
-
|
24
|
-
def evalute_start_while(node)
|
25
|
-
push_value
|
26
|
-
end
|
27
|
-
|
28
|
-
def evalute_start_until(node)
|
29
|
-
push_value
|
30
|
-
end
|
31
|
-
|
32
|
-
def evalute_start_for(node)
|
33
|
-
push_value
|
34
|
-
end
|
35
|
-
|
36
|
-
def evalute_start_case(node)
|
37
|
-
push_value
|
38
|
-
end
|
39
|
-
|
40
|
-
def evalute_start_rescue(node)
|
41
|
-
push_value
|
42
|
-
end
|
43
|
-
|
44
|
-
MULTIPLYING_NODE_TYPES.each do |type|
|
45
|
-
define_method "evaluate_end_#{type}" do |node|
|
46
|
-
leave_multiplying_conditional
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
ADDING_NODE_TYPES.each do |type|
|
51
|
-
define_method "evaluate_end_#{type}" do |node|
|
52
|
-
leave_multiplying_conditional
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
protected
|
57
|
-
|
58
|
-
def push_value
|
59
|
-
@value_stack.push @current_value
|
60
|
-
@current_value = 1
|
61
|
-
end
|
62
|
-
|
63
|
-
def leave_multiplying_conditional
|
64
|
-
pop = @value_stack.pop
|
65
|
-
@current_value = (@current_value + 1) * pop
|
66
|
-
end
|
67
|
-
|
68
|
-
def leave_adding_conditional
|
69
|
-
pop = @value_stack.pop
|
70
|
-
puts "#{type}, so adding #{pop}"
|
71
|
-
@current_value = @current_value - 1 + pop
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'roodi/checks/npath_complexity_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks Npath complexity of a method against a specified limit.
|
6
|
-
class NpathComplexityMethodCheck < NpathComplexityCheck
|
7
|
-
|
8
|
-
DEFAULT_COMPLEXITY = 8
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
super(DEFAULT_COMPLEXITY)
|
12
|
-
end
|
13
|
-
|
14
|
-
def interesting_nodes
|
15
|
-
[:defn] + COMPLEXITY_NODE_TYPES
|
16
|
-
end
|
17
|
-
|
18
|
-
def evaluate_start_defn(node)
|
19
|
-
@method_name = @node[1]
|
20
|
-
push_value
|
21
|
-
end
|
22
|
-
|
23
|
-
def evaluate_end_defn(node)
|
24
|
-
add_error "Method name \"#{@method_name}\" n-path complexity is #{@current_value}. It should be #{@complexity} or less." unless @current_value <= @complexity
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|