roodi 2.2.0 → 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/.gitignore +3 -0
- data/.travis.yml +11 -0
- data/Gemfile +2 -2
- data/History.txt +10 -0
- data/{README.txt → README.md} +47 -31
- data/Rakefile +3 -7
- data/lib/roodi/checks.rb +1 -1
- data/lib/roodi/checks/abc_metric_method_check.rb +13 -13
- data/lib/roodi/checks/core_method_override_check.rb +23 -0
- data/lib/roodi/checks/empty_rescue_body_check.rb +1 -1
- data/lib/roodi/checks/line_count_check.rb +11 -3
- data/lib/roodi/checks/parameter_number_check.rb +1 -1
- data/lib/roodi/core/parser.rb +19 -1
- data/lib/roodi/core/runner.rb +2 -1
- data/lib/roodi/version.rb +1 -1
- data/roodi.gemspec +9 -4
- data/roodi.yml +12 -14
- data/spec/roodi/checks/core_method_override_check_spec.rb +31 -0
- data/spec/roodi/checks/empty_rescue_body_check_spec.rb +14 -0
- data/spec/roodi/checks/npath_complexity_method_check_spec.rb +0 -22
- data/spec/spec_helper.rb +1 -1
- metadata +50 -36
- data/Gemfile.lock +0 -22
- data/lib/roodi/checks/missing_foreign_key_index_check.rb +0 -99
- data/spec/roodi/checks/missing_foreign_key_index_check_spec.rb +0 -33
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 07d949870658795c4a909c32faf4e50b37f29813
|
4
|
+
data.tar.gz: 54f229d5e6901aa1246d5e314ab63fa462acb923
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 94c41207f62016bd29d2eb1ada674d89772e9594cebd80bf96d750137048b0a9e16451dd54280f145e4a88019da2d9ecf6b56235d57ca4dec87ae1c54ac6ef8f
|
7
|
+
data.tar.gz: 6f31b01a3c5376860ad999fa8d0ff1de82847315f0d8257d19cd26b7c56ef024e725999737aebf9b541830b3fe5b5302a8b87412aaa150c5f22562fe6ddd742b
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
= 3.0.0
|
2
|
+
|
3
|
+
* Removed MissingForeignKeyIndexCheck, since it is specific to Rails/ActiveRecord and thus doesn't belong in Roodi
|
4
|
+
* A build is now running on Travis for the following Ruby versions: 1.8, 1.9, 2.0, JRuby 1.8 mode, JRuby 1.9 mode, Rubinius 1.8 mode, Rubinius 1.9 mode, Ruby Enterprise Edition
|
5
|
+
* Using ruby_parser 3.2.2
|
6
|
+
* Better check if OS is windows (#2 Martin Gotink)
|
7
|
+
* Accept 'next' in a rescue block (#1 Virgil Mihailovici)
|
8
|
+
* Rescue line count when there are no lines
|
9
|
+
* Pull down updates from https://github.com/zdennis/roodi that includes updates from https://github.com/hooroo/roodi and https://github.com/aselder/roodi re: pull request https://github.com/martinjandrews/roodi/pull/12 https://github.com/martinjandrews/roodi/pull/11
|
10
|
+
|
1
11
|
= 2.0.1
|
2
12
|
|
3
13
|
* Fixed a bug where roodi.yml was not being loaded. Patch supplied by Rob Mitchell.
|
data/{README.txt → README.md}
RENAMED
@@ -1,56 +1,72 @@
|
|
1
|
-
|
1
|
+
# roodi
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/roodi/roodi)
|
4
4
|
|
5
|
-
|
5
|
+
## Description
|
6
6
|
|
7
7
|
Roodi stands for Ruby Object Oriented Design Inferometer. It parses your Ruby code and warns you about design issues you have based on the checks that is has configured.
|
8
8
|
|
9
|
-
|
9
|
+
## Install
|
10
10
|
|
11
|
-
|
11
|
+
`$ sudo gem install roodi`
|
12
12
|
|
13
|
-
|
13
|
+
## Synopsis
|
14
14
|
|
15
15
|
To check one or more files using the default configuration that comes with Roodi, use:
|
16
|
-
roodi [-config=file] [pattern ...]
|
17
16
|
|
18
|
-
|
17
|
+
`$ roodi [-config=file] [pattern ...]`
|
18
|
+
|
19
|
+
## Example Usage
|
19
20
|
|
20
21
|
Check all ruby files in a rails app:
|
21
|
-
|
22
|
+
|
23
|
+
`$ roodi "rails_app/**/*.rb"`
|
22
24
|
|
23
25
|
Check one controller and one model file in a rails app:
|
24
|
-
|
26
|
+
|
27
|
+
`$ roodi app/controller/sample_controller.rb app/models/sample.rb`
|
25
28
|
|
26
29
|
Check one controller and all model files in a rails app:
|
27
|
-
|
30
|
+
|
31
|
+
`$ roodi app/controller/sample_controller.rb "app/models/*.rb"`
|
28
32
|
|
29
33
|
Check all ruby files in a rails app with a custom configuration file:
|
30
|
-
|
34
|
+
|
35
|
+
`$ roodi -config=my_roodi_config.yml "rails_app/**/*.rb"`
|
31
36
|
|
32
37
|
If you're writing a check, it is useful to see the structure of a file the way that Roodi tokenizes it (via ruby_parser). Use:
|
33
|
-
roodi-describe [filename]
|
34
38
|
|
35
|
-
|
39
|
+
`$ roodi-describe [filename]`
|
40
|
+
|
41
|
+
## Custom Configuration
|
36
42
|
|
37
43
|
To change the set of checks included, or to change the default values of the checks, you can provide your own config file. The config file is a YAML file that lists the checks to be included. Each check can optionally include a hash of options that are passed to the check to configure it. For example, the default config file looks like this:
|
38
44
|
|
39
|
-
AssignmentInConditionalCheck:
|
40
|
-
CaseMissingElseCheck:
|
41
|
-
ClassLineCountCheck:
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
45
|
+
AssignmentInConditionalCheck:
|
46
|
+
CaseMissingElseCheck:
|
47
|
+
ClassLineCountCheck:
|
48
|
+
line_count: 300
|
49
|
+
ClassNameCheck:
|
50
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
51
|
+
ClassVariableCheck:
|
52
|
+
CyclomaticComplexityBlockCheck:
|
53
|
+
complexity: 4
|
54
|
+
CyclomaticComplexityMethodCheck:
|
55
|
+
complexity: 8
|
56
|
+
EmptyRescueBodyCheck:
|
57
|
+
ForLoopCheck:
|
58
|
+
MethodLineCountCheck:
|
59
|
+
line_count: 20
|
60
|
+
MethodNameCheck:
|
61
|
+
pattern: !ruby/regexp /^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
62
|
+
ModuleLineCountCheck:
|
63
|
+
line_count: 300
|
64
|
+
ModuleNameCheck:
|
65
|
+
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
66
|
+
ParameterNumberCheck:
|
67
|
+
parameter_count: 5
|
68
|
+
|
69
|
+
## Supported Checks
|
54
70
|
|
55
71
|
* AssignmentInConditionalCheck - Check for an assignment inside a conditional. It's probably a mistaken equality comparison.
|
56
72
|
* CaseMissingElseCheck - Check that case statements have an else statement so that all cases are covered.
|
@@ -66,11 +82,11 @@ To change the set of checks included, or to change the default values of the che
|
|
66
82
|
* ModuleNameCheck - Check that module names match convention.
|
67
83
|
* ParameterNumberCheck - Check that the number of parameters on a method is below the threshold.
|
68
84
|
|
69
|
-
|
85
|
+
## Suggested Checks
|
70
86
|
|
71
87
|
* BlockVariableShadowCheck - Check that a block variable does not have the same name as a method parameter or local variable. It may be mistakenly referenced within the block.
|
72
88
|
|
73
|
-
|
89
|
+
## License
|
74
90
|
|
75
91
|
(The MIT License)
|
76
92
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require '
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
require 'bundler'
|
4
4
|
require 'roodi'
|
5
5
|
|
6
|
-
Bundler::GemHelper.install_tasks
|
7
|
-
|
8
6
|
def roodi(ruby_files)
|
9
7
|
roodi = Roodi::Core::Runner.new
|
10
8
|
ruby_files.each { |file| roodi.check_file(file) }
|
@@ -13,9 +11,7 @@ def roodi(ruby_files)
|
|
13
11
|
end
|
14
12
|
|
15
13
|
desc "Run all specs"
|
16
|
-
|
17
|
-
t.spec_files = FileList['spec/**/*spec.rb']
|
18
|
-
end
|
14
|
+
RSpec::Core::RakeTask.new(:spec)
|
19
15
|
|
20
16
|
desc "Run Roodi against all source files"
|
21
17
|
task :roodi do
|
@@ -23,4 +19,4 @@ task :roodi do
|
|
23
19
|
roodi(Dir.glob(pattern))
|
24
20
|
end
|
25
21
|
|
26
|
-
task :default => :spec
|
22
|
+
task :default => [:spec, :roodi]
|
data/lib/roodi/checks.rb
CHANGED
@@ -5,13 +5,13 @@ require 'roodi/checks/class_line_count_check'
|
|
5
5
|
require 'roodi/checks/class_name_check'
|
6
6
|
require 'roodi/checks/class_variable_check'
|
7
7
|
require 'roodi/checks/control_coupling_check'
|
8
|
+
require 'roodi/checks/core_method_override_check'
|
8
9
|
require 'roodi/checks/cyclomatic_complexity_block_check'
|
9
10
|
require 'roodi/checks/cyclomatic_complexity_method_check'
|
10
11
|
require 'roodi/checks/empty_rescue_body_check'
|
11
12
|
require 'roodi/checks/for_loop_check'
|
12
13
|
require 'roodi/checks/method_line_count_check'
|
13
14
|
require 'roodi/checks/method_name_check'
|
14
|
-
require 'roodi/checks/missing_foreign_key_index_check'
|
15
15
|
require 'roodi/checks/module_line_count_check'
|
16
16
|
require 'roodi/checks/module_name_check'
|
17
17
|
require 'roodi/checks/npath_complexity_method_check'
|
@@ -3,7 +3,7 @@ require 'roodi/checks/check'
|
|
3
3
|
module Roodi
|
4
4
|
module Checks
|
5
5
|
# TODO: Add summary
|
6
|
-
#
|
6
|
+
#
|
7
7
|
# TODO: Add detail
|
8
8
|
class AbcMetricMethodCheck < Check
|
9
9
|
# ASSIGNMENTS = [:attrasgn, :attrset, :dasgn_curr, :iasgn, :lasgn, :masgn]
|
@@ -11,18 +11,18 @@ module Roodi
|
|
11
11
|
# BRANCHES = [:if, :else, :while, :until, :for, :rescue, :case, :when, :and, :or]
|
12
12
|
BRANCHES = [:vcall, :call]
|
13
13
|
# CONDITIONS = [:and, :or]
|
14
|
-
CONDITIONS = [:==, :<=, :>=, :<, :>]
|
14
|
+
CONDITIONS = [:==, :"!=", :<=, :>=, :<, :>]
|
15
15
|
# = *= /= %= += <<= >>= &= |= ^=
|
16
16
|
OPERATORS = [:*, :/, :%, :+, :<<, :>>, :&, :|, :^]
|
17
17
|
DEFAULT_SCORE = 10
|
18
|
-
|
18
|
+
|
19
19
|
attr_accessor :score
|
20
20
|
|
21
21
|
def initialize
|
22
22
|
super()
|
23
23
|
self.score = DEFAULT_SCORE
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def interesting_nodes
|
27
27
|
[:defn]
|
28
28
|
end
|
@@ -35,7 +35,7 @@ module Roodi
|
|
35
35
|
score = Math.sqrt(a*a + b*b + c*c)
|
36
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
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
private
|
40
40
|
|
41
41
|
def count_assignments(node)
|
@@ -44,7 +44,7 @@ module Roodi
|
|
44
44
|
node.children.each {|node| count += count_assignments(node)}
|
45
45
|
count
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def count_branches(node)
|
49
49
|
count = 0
|
50
50
|
count = count + 1 if branch?(node)
|
@@ -58,22 +58,22 @@ module Roodi
|
|
58
58
|
node.children.each {|node| count += count_conditionals(node)}
|
59
59
|
count
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
def assignment?(node)
|
63
63
|
ASSIGNMENTS.include?(node.node_type)
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
def branch?(node)
|
67
67
|
BRANCHES.include?(node.node_type) && !conditional?(node) && !operator?(node)
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
def conditional?(node)
|
71
|
-
(:call == node.node_type) && CONDITIONS.include?(node[2])
|
71
|
+
(:call == node.node_type) && CONDITIONS.include?(node[2])
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
def operator?(node)
|
75
|
-
(:call == node.node_type) && OPERATORS.include?(node[2])
|
76
|
-
end
|
75
|
+
(:call == node.node_type) && OPERATORS.include?(node[2])
|
76
|
+
end
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'roodi/checks/check'
|
2
|
+
|
3
|
+
module Roodi
|
4
|
+
module Checks
|
5
|
+
# Checks a class to make sure it doesn't override core methods on Object.
|
6
|
+
#
|
7
|
+
# An example is when the 'class' method of a class is overriden. This causes code
|
8
|
+
# that tests the class of an object to fail.
|
9
|
+
class CoreMethodOverrideCheck < Check
|
10
|
+
|
11
|
+
def interesting_nodes
|
12
|
+
[:defn]
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate_start(node)
|
16
|
+
[ :class ].each do |core_name|
|
17
|
+
add_error("Class overrides method '#{core_name}'.") if node[1] == core_name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -7,7 +7,7 @@ module Roodi
|
|
7
7
|
# When the body of a rescue block is empty, exceptions can get caught and swallowed without
|
8
8
|
# any feedback to the user.
|
9
9
|
class EmptyRescueBodyCheck < Check
|
10
|
-
STATEMENT_NODES = [:fcall, :return, :attrasgn, :vcall, :nil, :call, :lasgn, :true, :false]
|
10
|
+
STATEMENT_NODES = [:fcall, :return, :attrasgn, :vcall, :nil, :call, :lasgn, :true, :false, :next]
|
11
11
|
|
12
12
|
def interesting_nodes
|
13
13
|
[:resbody]
|
@@ -3,7 +3,7 @@ require 'roodi/checks/check'
|
|
3
3
|
module Roodi
|
4
4
|
module Checks
|
5
5
|
class LineCountCheck < Check
|
6
|
-
|
6
|
+
|
7
7
|
attr_accessor :line_count
|
8
8
|
|
9
9
|
def evaluate_start(node)
|
@@ -12,9 +12,17 @@ module Roodi
|
|
12
12
|
end
|
13
13
|
|
14
14
|
protected
|
15
|
-
|
15
|
+
|
16
16
|
def count_lines(node)
|
17
|
-
node.last.line
|
17
|
+
node.last.respond_to?(:line) ? node.last.line - node.line : 0
|
18
|
+
|
19
|
+
rescue NoMethodError => e
|
20
|
+
#TODO: Add spec for this, nothing breaks when removing it.
|
21
|
+
if ENV['DEBUG'] =~ /true/i
|
22
|
+
STDERR.puts "!! line counting error #{e.message}\t #{node.inspect}"
|
23
|
+
STDERR.puts "!! Does the node have any lines?"
|
24
|
+
end
|
25
|
+
0
|
18
26
|
end
|
19
27
|
|
20
28
|
end
|
@@ -25,7 +25,7 @@ module Roodi
|
|
25
25
|
def evaluate_start(node)
|
26
26
|
method_name = node[1]
|
27
27
|
arguments = node[2]
|
28
|
-
actual_parameter_count = arguments.
|
28
|
+
actual_parameter_count = arguments.select {|arg| [Sexp, Symbol].include? arg.class}.count - 1
|
29
29
|
add_error "Method name \"#{method_name}\" has #{actual_parameter_count} parameters. It should have #{@parameter_count} or less." unless actual_parameter_count <= @parameter_count
|
30
30
|
end
|
31
31
|
|
data/lib/roodi/core/parser.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'ruby_parser'
|
3
|
+
require 'rbconfig'
|
3
4
|
|
4
5
|
module Roodi
|
5
6
|
module Core
|
@@ -14,7 +15,7 @@ module Roodi
|
|
14
15
|
|
15
16
|
def silence_stream(stream)
|
16
17
|
old_stream = stream.dup
|
17
|
-
stream.reopen(
|
18
|
+
stream.reopen(null_stream_output)
|
18
19
|
stream.sync = true
|
19
20
|
yield
|
20
21
|
ensure
|
@@ -25,6 +26,23 @@ module Roodi
|
|
25
26
|
@parser ||= RubyParser.new
|
26
27
|
@parser.parse(content, filename)
|
27
28
|
end
|
29
|
+
|
30
|
+
def null_stream_output
|
31
|
+
null_output_for_platform(RbConfig::CONFIG['host_os'])
|
32
|
+
end
|
33
|
+
|
34
|
+
def null_output_for_platform(host_os)
|
35
|
+
case host_os
|
36
|
+
when windows_host_os_matcher
|
37
|
+
'NUL:'
|
38
|
+
else
|
39
|
+
'/dev/null'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def windows_host_os_matcher
|
44
|
+
/mingw|mswin32|cygwin/o
|
45
|
+
end
|
28
46
|
end
|
29
47
|
end
|
30
48
|
end
|
data/lib/roodi/core/runner.rb
CHANGED
@@ -31,11 +31,12 @@ module Roodi
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def check_file(filename)
|
34
|
+
return unless File.exists?(filename)
|
34
35
|
check(filename, File.read(filename))
|
35
36
|
end
|
36
37
|
|
37
38
|
def print(filename, content)
|
38
|
-
node = parse(
|
39
|
+
node = parse(filename, content)
|
39
40
|
puts "Line: #{node.line}"
|
40
41
|
pp node
|
41
42
|
end
|
data/lib/roodi/version.rb
CHANGED
data/roodi.gemspec
CHANGED
@@ -6,13 +6,18 @@ Gem::Specification.new do |gem|
|
|
6
6
|
gem.name = "roodi"
|
7
7
|
gem.summary = "Roodi stands for Ruby Object Oriented Design Inferometer"
|
8
8
|
gem.description = "Roodi stands for Ruby Object Oriented Design Inferometer"
|
9
|
-
gem.homepage = "http://roodi
|
10
|
-
gem.authors = ["Marty Andrews"]
|
11
|
-
gem.email = "
|
9
|
+
gem.homepage = "http://github.com/roodi/roodi"
|
10
|
+
gem.authors = ["Marty Andrews", "Peter Evjan"]
|
11
|
+
gem.email = "peter.evjan@gmail.com"
|
12
12
|
gem.files = Dir['lib/**/*.rb'] + Dir['bin/*'] + Dir['[A-Za-z]*'] + Dir['spec/**/*']
|
13
13
|
gem.version = Roodi::VERSION.dup
|
14
14
|
gem.platform = Gem::Platform::RUBY
|
15
|
-
gem.add_runtime_dependency("ruby_parser", "~> 2.
|
15
|
+
gem.add_runtime_dependency("ruby_parser", "~> 3.2.2")
|
16
16
|
gem.executables = ["roodi", "roodi-describe"]
|
17
|
+
gem.files = `git ls-files`.split($\)
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
20
|
+
gem.require_paths = ["lib"]
|
21
|
+
gem.license = 'MIT'
|
17
22
|
|
18
23
|
end
|
data/roodi.yml
CHANGED
@@ -1,25 +1,23 @@
|
|
1
1
|
AssignmentInConditionalCheck:
|
2
2
|
CaseMissingElseCheck:
|
3
|
-
ClassLineCountCheck:
|
4
|
-
line_count: 300
|
5
|
-
ClassNameCheck:
|
3
|
+
ClassLineCountCheck:
|
4
|
+
line_count: 300
|
5
|
+
ClassNameCheck:
|
6
6
|
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
7
7
|
ClassVariableCheck:
|
8
|
-
CyclomaticComplexityBlockCheck:
|
8
|
+
CyclomaticComplexityBlockCheck:
|
9
9
|
complexity: 4
|
10
|
-
CyclomaticComplexityMethodCheck:
|
10
|
+
CyclomaticComplexityMethodCheck:
|
11
11
|
complexity: 8
|
12
12
|
EmptyRescueBodyCheck:
|
13
13
|
ForLoopCheck:
|
14
|
-
MethodLineCountCheck:
|
15
|
-
line_count: 20
|
16
|
-
MethodNameCheck:
|
17
|
-
pattern: !ruby/regexp /^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
18
|
-
|
19
|
-
ModuleLineCountCheck:
|
14
|
+
MethodLineCountCheck:
|
15
|
+
line_count: 20
|
16
|
+
MethodNameCheck:
|
17
|
+
pattern: !ruby/regexp /^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
|
18
|
+
ModuleLineCountCheck:
|
20
19
|
line_count: 300
|
21
|
-
ModuleNameCheck:
|
20
|
+
ModuleNameCheck:
|
22
21
|
pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
|
23
|
-
ParameterNumberCheck:
|
22
|
+
ParameterNumberCheck:
|
24
23
|
parameter_count: 5
|
25
|
-
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Roodi::Checks::CoreMethodOverrideCheck do
|
4
|
+
before(:each) do
|
5
|
+
@roodi = Roodi::Core::Runner.new(Roodi::Checks::CoreMethodOverrideCheck.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should accept a class with a method" do
|
9
|
+
content = <<-END
|
10
|
+
class WellBehavedClass
|
11
|
+
def well_behaved_method
|
12
|
+
end
|
13
|
+
end
|
14
|
+
END
|
15
|
+
@roodi.check_content(content)
|
16
|
+
@roodi.errors.should be_empty
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should reject a class which overrides the class method" do
|
20
|
+
content = <<-END
|
21
|
+
class BadClass
|
22
|
+
def class
|
23
|
+
end
|
24
|
+
end
|
25
|
+
END
|
26
|
+
@roodi.check_content(content)
|
27
|
+
errors = @roodi.errors
|
28
|
+
errors.should_not be_empty
|
29
|
+
errors[0].to_s.should eql("dummy-file.rb:2 - Class overrides method 'class'.")
|
30
|
+
end
|
31
|
+
end
|
@@ -137,4 +137,18 @@ describe Roodi::Checks::EmptyRescueBodyCheck do
|
|
137
137
|
errors = @roodi.errors
|
138
138
|
errors.should be_empty
|
139
139
|
end
|
140
|
+
|
141
|
+
it "should accept a rescue block that has only a next statement" do
|
142
|
+
content = <<-END
|
143
|
+
begin
|
144
|
+
call_method
|
145
|
+
rescue Exception => e
|
146
|
+
next
|
147
|
+
end
|
148
|
+
END
|
149
|
+
@roodi.check_content(content)
|
150
|
+
errors = @roodi.errors
|
151
|
+
errors.should be_empty
|
152
|
+
end
|
153
|
+
|
140
154
|
end
|
@@ -28,26 +28,4 @@ describe Roodi::Checks::NpathComplexityMethodCheck do
|
|
28
28
|
END
|
29
29
|
verify_content_complexity(content, 2)
|
30
30
|
end
|
31
|
-
|
32
|
-
it "should find nested if block" do
|
33
|
-
pending "NPath Complexity implementation that can support 'else' blocks"
|
34
|
-
content = <<-END
|
35
|
-
def method_name
|
36
|
-
if (value1)
|
37
|
-
foo
|
38
|
-
else
|
39
|
-
bar
|
40
|
-
end
|
41
|
-
if (value2)
|
42
|
-
bam
|
43
|
-
else
|
44
|
-
baz
|
45
|
-
end
|
46
|
-
if (value3)
|
47
|
-
one
|
48
|
-
end
|
49
|
-
end
|
50
|
-
END
|
51
|
-
verify_content_complexity(content, 8)
|
52
|
-
end
|
53
31
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,40 +1,49 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roodi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 3.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Marty Andrews
|
8
|
+
- Peter Evjan
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby_parser
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
17
|
requirements:
|
19
18
|
- - ~>
|
20
19
|
- !ruby/object:Gem::Version
|
21
|
-
version: 2.
|
20
|
+
version: 3.2.2
|
22
21
|
type: :runtime
|
23
22
|
prerelease: false
|
24
23
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
24
|
requirements:
|
27
25
|
- - ~>
|
28
26
|
- !ruby/object:Gem::Version
|
29
|
-
version: 2.
|
27
|
+
version: 3.2.2
|
30
28
|
description: Roodi stands for Ruby Object Oriented Design Inferometer
|
31
|
-
email:
|
29
|
+
email: peter.evjan@gmail.com
|
32
30
|
executables:
|
33
31
|
- roodi
|
34
32
|
- roodi-describe
|
35
33
|
extensions: []
|
36
34
|
extra_rdoc_files: []
|
37
35
|
files:
|
36
|
+
- .gitignore
|
37
|
+
- .travis.yml
|
38
|
+
- Gemfile
|
39
|
+
- History.txt
|
40
|
+
- Manifest.txt
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- bin/roodi
|
44
|
+
- bin/roodi-describe
|
45
|
+
- lib/roodi.rb
|
46
|
+
- lib/roodi/checks.rb
|
38
47
|
- lib/roodi/checks/abc_metric_method_check.rb
|
39
48
|
- lib/roodi/checks/assignment_in_conditional_check.rb
|
40
49
|
- lib/roodi/checks/case_missing_else_check.rb
|
@@ -43,6 +52,7 @@ files:
|
|
43
52
|
- lib/roodi/checks/class_name_check.rb
|
44
53
|
- lib/roodi/checks/class_variable_check.rb
|
45
54
|
- lib/roodi/checks/control_coupling_check.rb
|
55
|
+
- lib/roodi/checks/core_method_override_check.rb
|
46
56
|
- lib/roodi/checks/cyclomatic_complexity_block_check.rb
|
47
57
|
- lib/roodi/checks/cyclomatic_complexity_check.rb
|
48
58
|
- lib/roodi/checks/cyclomatic_complexity_method_check.rb
|
@@ -51,31 +61,20 @@ files:
|
|
51
61
|
- lib/roodi/checks/line_count_check.rb
|
52
62
|
- lib/roodi/checks/method_line_count_check.rb
|
53
63
|
- lib/roodi/checks/method_name_check.rb
|
54
|
-
- lib/roodi/checks/missing_foreign_key_index_check.rb
|
55
64
|
- lib/roodi/checks/module_line_count_check.rb
|
56
65
|
- lib/roodi/checks/module_name_check.rb
|
57
66
|
- lib/roodi/checks/name_check.rb
|
58
67
|
- lib/roodi/checks/npath_complexity_check.rb
|
59
68
|
- lib/roodi/checks/npath_complexity_method_check.rb
|
60
69
|
- lib/roodi/checks/parameter_number_check.rb
|
61
|
-
- lib/roodi/
|
70
|
+
- lib/roodi/core.rb
|
62
71
|
- lib/roodi/core/checking_visitor.rb
|
63
72
|
- lib/roodi/core/error.rb
|
64
73
|
- lib/roodi/core/parser.rb
|
65
74
|
- lib/roodi/core/runner.rb
|
66
75
|
- lib/roodi/core/visitable_sexp.rb
|
67
|
-
- lib/roodi/core.rb
|
68
76
|
- lib/roodi/version.rb
|
69
|
-
- lib/roodi.rb
|
70
77
|
- lib/roodi_task.rb
|
71
|
-
- bin/roodi
|
72
|
-
- bin/roodi-describe
|
73
|
-
- Gemfile
|
74
|
-
- Gemfile.lock
|
75
|
-
- History.txt
|
76
|
-
- Manifest.txt
|
77
|
-
- Rakefile
|
78
|
-
- README.txt
|
79
78
|
- roodi.gemspec
|
80
79
|
- roodi.yml
|
81
80
|
- spec/roodi/checks/abc_metric_method_check_spec.rb
|
@@ -85,13 +84,13 @@ files:
|
|
85
84
|
- spec/roodi/checks/class_name_check_spec.rb
|
86
85
|
- spec/roodi/checks/class_variable_check_spec.rb
|
87
86
|
- spec/roodi/checks/control_coupling_check_spec.rb
|
87
|
+
- spec/roodi/checks/core_method_override_check_spec.rb
|
88
88
|
- spec/roodi/checks/cyclomatic_complexity_block_check_spec.rb
|
89
89
|
- spec/roodi/checks/cyclomatic_complexity_method_check_spec.rb
|
90
90
|
- spec/roodi/checks/empty_rescue_body_check_spec.rb
|
91
91
|
- spec/roodi/checks/for_loop_check_spec.rb
|
92
92
|
- spec/roodi/checks/method_line_count_check_spec.rb
|
93
93
|
- spec/roodi/checks/method_name_check_spec.rb
|
94
|
-
- spec/roodi/checks/missing_foreign_key_index_check_spec.rb
|
95
94
|
- spec/roodi/checks/module_line_count_check_spec.rb
|
96
95
|
- spec/roodi/checks/module_name_check_spec.rb
|
97
96
|
- spec/roodi/checks/npath_complexity_method_check_spec.rb
|
@@ -99,34 +98,49 @@ files:
|
|
99
98
|
- spec/roodi/core/runner_spec.rb
|
100
99
|
- spec/roodi/roodi.yml
|
101
100
|
- spec/spec_helper.rb
|
102
|
-
homepage: http://roodi
|
103
|
-
licenses:
|
101
|
+
homepage: http://github.com/roodi/roodi
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
104
105
|
post_install_message:
|
105
106
|
rdoc_options: []
|
106
107
|
require_paths:
|
107
108
|
- lib
|
108
109
|
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
-
none: false
|
110
110
|
requirements:
|
111
|
-
- -
|
111
|
+
- - '>='
|
112
112
|
- !ruby/object:Gem::Version
|
113
113
|
version: '0'
|
114
|
-
segments:
|
115
|
-
- 0
|
116
|
-
hash: -2141010416866692951
|
117
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
-
none: false
|
119
115
|
requirements:
|
120
|
-
- -
|
116
|
+
- - '>='
|
121
117
|
- !ruby/object:Gem::Version
|
122
118
|
version: '0'
|
123
|
-
segments:
|
124
|
-
- 0
|
125
|
-
hash: -2141010416866692951
|
126
119
|
requirements: []
|
127
120
|
rubyforge_project:
|
128
|
-
rubygems_version:
|
121
|
+
rubygems_version: 2.0.3
|
129
122
|
signing_key:
|
130
|
-
specification_version:
|
123
|
+
specification_version: 4
|
131
124
|
summary: Roodi stands for Ruby Object Oriented Design Inferometer
|
132
|
-
test_files:
|
125
|
+
test_files:
|
126
|
+
- spec/roodi/checks/abc_metric_method_check_spec.rb
|
127
|
+
- spec/roodi/checks/assignment_in_conditional_check_spec.rb
|
128
|
+
- spec/roodi/checks/case_missing_else_check_spec.rb
|
129
|
+
- spec/roodi/checks/class_line_count_check_spec.rb
|
130
|
+
- spec/roodi/checks/class_name_check_spec.rb
|
131
|
+
- spec/roodi/checks/class_variable_check_spec.rb
|
132
|
+
- spec/roodi/checks/control_coupling_check_spec.rb
|
133
|
+
- spec/roodi/checks/core_method_override_check_spec.rb
|
134
|
+
- spec/roodi/checks/cyclomatic_complexity_block_check_spec.rb
|
135
|
+
- spec/roodi/checks/cyclomatic_complexity_method_check_spec.rb
|
136
|
+
- spec/roodi/checks/empty_rescue_body_check_spec.rb
|
137
|
+
- spec/roodi/checks/for_loop_check_spec.rb
|
138
|
+
- spec/roodi/checks/method_line_count_check_spec.rb
|
139
|
+
- spec/roodi/checks/method_name_check_spec.rb
|
140
|
+
- spec/roodi/checks/module_line_count_check_spec.rb
|
141
|
+
- spec/roodi/checks/module_name_check_spec.rb
|
142
|
+
- spec/roodi/checks/npath_complexity_method_check_spec.rb
|
143
|
+
- spec/roodi/checks/parameter_number_check_spec.rb
|
144
|
+
- spec/roodi/core/runner_spec.rb
|
145
|
+
- spec/roodi/roodi.yml
|
146
|
+
- spec/spec_helper.rb
|
data/Gemfile.lock
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
roodi (2.2.0)
|
5
|
-
ruby_parser (~> 2.3.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: http://rubygems.org/
|
9
|
-
specs:
|
10
|
-
rake (10.0.3)
|
11
|
-
rspec (1.3.2)
|
12
|
-
ruby_parser (2.3.0)
|
13
|
-
sexp_processor (~> 3.0)
|
14
|
-
sexp_processor (3.2.0)
|
15
|
-
|
16
|
-
PLATFORMS
|
17
|
-
ruby
|
18
|
-
|
19
|
-
DEPENDENCIES
|
20
|
-
rake
|
21
|
-
roodi!
|
22
|
-
rspec (~> 1.3.2)
|
@@ -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,33 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
describe Roodi::Checks::MissingForeignKeyIndexCheck do
|
4
|
-
before(:each) do
|
5
|
-
@roodi = Roodi::Core::Runner.new(Roodi::Checks::MissingForeignKeyIndexCheck.make)
|
6
|
-
end
|
7
|
-
|
8
|
-
it "should warn about a missing foreign key" do
|
9
|
-
content = <<-END
|
10
|
-
ActiveRecord::Schema.define(:version => 20091215233604) do
|
11
|
-
create_table "projects", :force => true do |t|
|
12
|
-
t.string "name"
|
13
|
-
end
|
14
|
-
|
15
|
-
create_table "revisions", :force => true do |t|
|
16
|
-
t.integer "project_id"
|
17
|
-
t.string "key"
|
18
|
-
end
|
19
|
-
|
20
|
-
add_index "revisions", ["project_id"], :name => "index_revisions_on_project_id"
|
21
|
-
|
22
|
-
create_table "source_files", :force => true do |t|
|
23
|
-
t.integer "revision_id"
|
24
|
-
t.string "filename"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
END
|
28
|
-
@roodi.check_content(content, "schema.rb")
|
29
|
-
errors = @roodi.errors
|
30
|
-
errors.should_not be_empty
|
31
|
-
errors[0].to_s.should eql("schema.rb:1 - Table 'source_files' is missing an index on the foreign key 'revision_id'")
|
32
|
-
end
|
33
|
-
end
|