metric_fu-roodi 2.2.2 → 3.0.0
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.
- 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
data/Rakefile
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
|
-
require 'bundler/setup'
|
3
|
-
require 'bundler/gem_tasks'
|
4
|
-
begin
|
5
|
-
require 'spec/rake/spectask'
|
6
|
-
desc "Run all specs in spec directory"
|
7
|
-
Spec::Rake::SpecTask.new(:spec) do |t|
|
8
|
-
t.spec_files = FileList['spec/**/*_spec.rb']
|
9
|
-
end
|
10
|
-
rescue LoadError
|
11
|
-
require 'rspec/core/rake_task'
|
12
|
-
desc "Run all specs in spec directory"
|
13
|
-
RSpec::Core::RakeTask.new(:spec)
|
14
|
-
end
|
15
|
-
|
16
|
-
require File.expand_path('lib/roodi',File.dirname(__FILE__))
|
17
|
-
|
18
|
-
def roodi(ruby_files)
|
19
|
-
roodi = Roodi::Core::Runner.new
|
20
|
-
ruby_files.each { |file| roodi.check_file(file) }
|
21
|
-
roodi.errors.each {|error| puts error}
|
22
|
-
puts "\nFound #{roodi.errors.size} errors."
|
23
|
-
end
|
24
|
-
|
25
|
-
desc "Run Roodi against all source files"
|
26
|
-
task :roodi do
|
27
|
-
pattern = File.join(File.dirname(__FILE__), "**", "*.rb")
|
28
|
-
roodi(Dir.glob(pattern))
|
29
|
-
end
|
30
|
-
|
31
|
-
task :default => :spec
|
data/TODO.md
DELETED
data/lib/roodi/checks.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'roodi/checks/abc_metric_method_check'
|
2
|
-
require 'roodi/checks/assignment_in_conditional_check'
|
3
|
-
require 'roodi/checks/case_missing_else_check'
|
4
|
-
require 'roodi/checks/class_line_count_check'
|
5
|
-
require 'roodi/checks/class_name_check'
|
6
|
-
require 'roodi/checks/class_variable_check'
|
7
|
-
require 'roodi/checks/control_coupling_check'
|
8
|
-
require 'roodi/checks/cyclomatic_complexity_block_check'
|
9
|
-
require 'roodi/checks/cyclomatic_complexity_method_check'
|
10
|
-
require 'roodi/checks/empty_rescue_body_check'
|
11
|
-
require 'roodi/checks/for_loop_check'
|
12
|
-
require 'roodi/checks/method_line_count_check'
|
13
|
-
require 'roodi/checks/method_name_check'
|
14
|
-
require 'roodi/checks/missing_foreign_key_index_check'
|
15
|
-
require 'roodi/checks/module_line_count_check'
|
16
|
-
require 'roodi/checks/module_name_check'
|
17
|
-
require 'roodi/checks/npath_complexity_method_check'
|
18
|
-
require 'roodi/checks/parameter_number_check'
|
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# TODO: Add summary
|
6
|
-
#
|
7
|
-
# TODO: Add detail
|
8
|
-
class AbcMetricMethodCheck < Check
|
9
|
-
# ASSIGNMENTS = [:attrasgn, :attrset, :dasgn_curr, :iasgn, :lasgn, :masgn]
|
10
|
-
ASSIGNMENTS = [:lasgn]
|
11
|
-
# BRANCHES = [:if, :else, :while, :until, :for, :rescue, :case, :when, :and, :or]
|
12
|
-
BRANCHES = [:vcall, :call]
|
13
|
-
# CONDITIONS = [:and, :or]
|
14
|
-
CONDITIONS = [:==, :<=, :>=, :<, :>]
|
15
|
-
# = *= /= %= += <<= >>= &= |= ^=
|
16
|
-
OPERATORS = [:*, :/, :%, :+, :<<, :>>, :&, :|, :^]
|
17
|
-
DEFAULT_SCORE = 10
|
18
|
-
|
19
|
-
attr_accessor :score
|
20
|
-
|
21
|
-
def initialize
|
22
|
-
super()
|
23
|
-
self.score = DEFAULT_SCORE
|
24
|
-
end
|
25
|
-
|
26
|
-
def interesting_nodes
|
27
|
-
[:defn]
|
28
|
-
end
|
29
|
-
|
30
|
-
def evaluate_start(node)
|
31
|
-
method_name = node[1]
|
32
|
-
a = count_assignments(node)
|
33
|
-
b = count_branches(node)
|
34
|
-
c = count_conditionals(node)
|
35
|
-
score = Math.sqrt(a*a + b*b + c*c)
|
36
|
-
add_error "Method name \"#{method_name}\" has an ABC metric score of <#{a},#{b},#{c}> = #{score}. It should be #{@score} or less." unless score <= @score
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def count_assignments(node)
|
42
|
-
count = 0
|
43
|
-
count = count + 1 if assignment?(node)
|
44
|
-
node.children.each {|node| count += count_assignments(node)}
|
45
|
-
count
|
46
|
-
end
|
47
|
-
|
48
|
-
def count_branches(node)
|
49
|
-
count = 0
|
50
|
-
count = count + 1 if branch?(node)
|
51
|
-
node.children.each {|node| count += count_branches(node)}
|
52
|
-
count
|
53
|
-
end
|
54
|
-
|
55
|
-
def count_conditionals(node)
|
56
|
-
count = 0
|
57
|
-
count = count + 1 if conditional?(node)
|
58
|
-
node.children.each {|node| count += count_conditionals(node)}
|
59
|
-
count
|
60
|
-
end
|
61
|
-
|
62
|
-
def assignment?(node)
|
63
|
-
ASSIGNMENTS.include?(node.node_type)
|
64
|
-
end
|
65
|
-
|
66
|
-
def branch?(node)
|
67
|
-
BRANCHES.include?(node.node_type) && !conditional?(node) && !operator?(node)
|
68
|
-
end
|
69
|
-
|
70
|
-
def conditional?(node)
|
71
|
-
(:call == node.node_type) && CONDITIONS.include?(node[2])
|
72
|
-
end
|
73
|
-
|
74
|
-
def operator?(node)
|
75
|
-
(:call == node.node_type) && OPERATORS.include?(node[2])
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks a conditional to see if it contains an assignment.
|
6
|
-
#
|
7
|
-
# A conditional containing an assignment is likely to be a mistyped equality check. You
|
8
|
-
# should either fix the typo or factor out the assignment so that the code is clearer.
|
9
|
-
class AssignmentInConditionalCheck < Check
|
10
|
-
|
11
|
-
def interesting_nodes
|
12
|
-
[:if, :while]
|
13
|
-
end
|
14
|
-
|
15
|
-
def evaluate_start(node)
|
16
|
-
add_error("Found = in conditional. It should probably be an ==") if has_assignment?(node[1])
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def has_assignment?(node)
|
22
|
-
found_assignment = false
|
23
|
-
found_assignment = found_assignment || node.node_type == :lasgn
|
24
|
-
if (node.node_type == :and or node.node_type == :or)
|
25
|
-
node.children.each { |child| found_assignment = found_assignment || has_assignment?(child) }
|
26
|
-
end
|
27
|
-
found_assignment
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks a case statement to make sure it has an 'else' clause.
|
6
|
-
#
|
7
|
-
# It's usually a good idea to have an else clause in every case statement. Even if the
|
8
|
-
# developer is sure that all currently possible cases are covered, this should be
|
9
|
-
# expressed in the else clause. This way the code is protected aginst later changes,
|
10
|
-
class CaseMissingElseCheck < Check
|
11
|
-
def interesting_nodes
|
12
|
-
[:case]
|
13
|
-
end
|
14
|
-
|
15
|
-
def evaluate_start(node)
|
16
|
-
add_error "Case statement is missing an else clause." unless node.last
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/lib/roodi/checks/check.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'roodi/core/error'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
class Check
|
6
|
-
|
7
|
-
NODE_TYPES = [:defn, :module, :resbody, :lvar, :cvar, :class, :if, :while, :until, :for, :rescue, :case, :when, :and, :or]
|
8
|
-
|
9
|
-
class << self
|
10
|
-
|
11
|
-
def make(options = nil)
|
12
|
-
check = new
|
13
|
-
if options
|
14
|
-
options.each do |name, value|
|
15
|
-
check.send("#{name}=", value)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
check
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
def initialize
|
24
|
-
@errors = []
|
25
|
-
end
|
26
|
-
|
27
|
-
NODE_TYPES.each do |node|
|
28
|
-
start_node_method = "evaluate_start_#{node}"
|
29
|
-
end_node_method = "evaluate_end_#{node}"
|
30
|
-
define_method(start_node_method) { |node| return } unless self.respond_to?(start_node_method)
|
31
|
-
define_method(end_node_method) { |node| return } unless self.respond_to?(end_node_method)
|
32
|
-
end
|
33
|
-
|
34
|
-
def position(offset = 0)
|
35
|
-
"#{@line[2]}:#{@line[1] + offset}"
|
36
|
-
end
|
37
|
-
|
38
|
-
def start_file(filename)
|
39
|
-
end
|
40
|
-
|
41
|
-
def end_file(filename)
|
42
|
-
end
|
43
|
-
|
44
|
-
def evaluate_start(node)
|
45
|
-
end
|
46
|
-
|
47
|
-
def evaluate_end(node)
|
48
|
-
end
|
49
|
-
|
50
|
-
def evaluate_node(position, node)
|
51
|
-
@node = node
|
52
|
-
eval_method = "evaluate_#{position}_#{node.node_type}"
|
53
|
-
self.send(eval_method, node)
|
54
|
-
end
|
55
|
-
|
56
|
-
def evaluate_node_start(node)
|
57
|
-
evaluate_node(:start, node)
|
58
|
-
evaluate_start(node)
|
59
|
-
end
|
60
|
-
|
61
|
-
def evaluate_node_end(node)
|
62
|
-
evaluate_node(:end, node)
|
63
|
-
evaluate_end(node)
|
64
|
-
end
|
65
|
-
|
66
|
-
def add_error(error, filename = @node.file, line = @node.line)
|
67
|
-
@errors ||= []
|
68
|
-
@errors << Roodi::Core::Error.new("#{filename}", "#{line}", error)
|
69
|
-
end
|
70
|
-
|
71
|
-
def errors
|
72
|
-
@errors
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'roodi/checks/line_count_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks a class to make sure the number of lines it has is under the specified limit.
|
6
|
-
#
|
7
|
-
# A class 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 classes.
|
9
|
-
class ClassLineCountCheck < 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
|
-
[:class]
|
20
|
-
end
|
21
|
-
|
22
|
-
def message_prefix
|
23
|
-
'Class'
|
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 class name to make sure it matches the specified pattern.
|
6
|
-
#
|
7
|
-
# Keeping to a consistent naming convention makes your code easier to read.
|
8
|
-
class ClassNameCheck < 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
|
-
[:class]
|
19
|
-
end
|
20
|
-
|
21
|
-
def message_prefix
|
22
|
-
'Class'
|
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,24 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks to make sure class variables are not being used..
|
6
|
-
#
|
7
|
-
# Class variables in Ruby have a complicated inheritance policy, and their use
|
8
|
-
# can lead to mistakes. Often an alternate design can be used to solve the
|
9
|
-
# problem instead.
|
10
|
-
#
|
11
|
-
# This check is looking for a code smell rather than a definite error. If you're
|
12
|
-
# sure that you're doing the right thing, try turning this check off in your
|
13
|
-
# config file.
|
14
|
-
class ClassVariableCheck < Check
|
15
|
-
def interesting_nodes
|
16
|
-
[:cvar]
|
17
|
-
end
|
18
|
-
|
19
|
-
def evaluate_start(node)
|
20
|
-
add_error "Don't use class variables. You might want to try a different design."
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
class ControlCouplingCheck < Check
|
6
|
-
def interesting_nodes
|
7
|
-
[:defn, :lvar]
|
8
|
-
end
|
9
|
-
|
10
|
-
def evaluate_start_defn(node)
|
11
|
-
@method_name = node[1]
|
12
|
-
@arguments = node[2][1..-1]
|
13
|
-
end
|
14
|
-
|
15
|
-
def evaluate_start_lvar(node)
|
16
|
-
add_error "Method \"#{@method_name}\" uses the argument \"#{node[1]}\" for internal control." if @arguments.detect {|each| each == node[1]}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'roodi/checks/cyclomatic_complexity_check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
# Checks cyclomatic complexity of a block 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 block, 1-2 is considered good, 3-4 ok, 5-8 consider re-factoring, and 8+
|
13
|
-
# re-factor now!
|
14
|
-
class CyclomaticComplexityBlockCheck < CyclomaticComplexityCheck
|
15
|
-
|
16
|
-
DEFAULT_COMPLEXITY = 4
|
17
|
-
|
18
|
-
def initialize
|
19
|
-
super()
|
20
|
-
self.complexity = DEFAULT_COMPLEXITY
|
21
|
-
end
|
22
|
-
|
23
|
-
def interesting_nodes
|
24
|
-
[:iter] + COMPLEXITY_NODE_TYPES
|
25
|
-
end
|
26
|
-
|
27
|
-
def evaluate_start_iter(node)
|
28
|
-
increase_depth
|
29
|
-
end
|
30
|
-
|
31
|
-
def evaluate_end_iter(node)
|
32
|
-
decrease_depth
|
33
|
-
end
|
34
|
-
|
35
|
-
def evaluate_matching_end
|
36
|
-
add_error "Block cyclomatic complexity is #{@count}. It should be #{@complexity} or less." unless @count <= @complexity
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'roodi/checks/check'
|
2
|
-
|
3
|
-
module Roodi
|
4
|
-
module Checks
|
5
|
-
class CyclomaticComplexityCheck < Check
|
6
|
-
|
7
|
-
COMPLEXITY_NODE_TYPES = [:if, :while, :until, :for, :rescue, :case, :when, :and, :or]
|
8
|
-
|
9
|
-
attr_accessor :complexity
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
super()
|
13
|
-
@count = 0
|
14
|
-
@counting = 0
|
15
|
-
end
|
16
|
-
|
17
|
-
COMPLEXITY_NODE_TYPES.each do |type|
|
18
|
-
define_method "evaluate_start_#{type}" do |node|
|
19
|
-
@count = @count + 1 if counting?
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
protected
|
24
|
-
|
25
|
-
def count_complexity(node)
|
26
|
-
count_branches(node) + 1
|
27
|
-
end
|
28
|
-
|
29
|
-
def increase_depth
|
30
|
-
@count = 1 unless counting?
|
31
|
-
@counting = @counting + 1
|
32
|
-
end
|
33
|
-
|
34
|
-
def decrease_depth
|
35
|
-
@counting = @counting - 1
|
36
|
-
if @counting <= 0
|
37
|
-
@counting = 0
|
38
|
-
evaluate_matching_end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def counting?
|
45
|
-
@counting > 0
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|