roodi 2.2.0 → 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/.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
|
+
[![Build Status](https://travis-ci.org/roodi/roodi.png?branch=master)](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
|