roodi 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 07d949870658795c4a909c32faf4e50b37f29813
4
- data.tar.gz: 54f229d5e6901aa1246d5e314ab63fa462acb923
3
+ metadata.gz: 2eb90b5c384b0916cd61ec2cf8f5a8f950458f23
4
+ data.tar.gz: 76875cad67471324e5017ea7dd82e28c49307ba6
5
5
  SHA512:
6
- metadata.gz: 94c41207f62016bd29d2eb1ada674d89772e9594cebd80bf96d750137048b0a9e16451dd54280f145e4a88019da2d9ecf6b56235d57ca4dec87ae1c54ac6ef8f
7
- data.tar.gz: 6f31b01a3c5376860ad999fa8d0ff1de82847315f0d8257d19cd26b7c56ef024e725999737aebf9b541830b3fe5b5302a8b87412aaa150c5f22562fe6ddd742b
6
+ metadata.gz: b68ac64dba9440ef8088cce40aaf71e4a3e2af8b7d9315255191cda7d786ca591862c13a319c5b109cc32c93f05eb17b81a4c3ef42b94962cfb9d31bbc6f92ee
7
+ data.tar.gz: 57ca381da9ccd33455286ec37a7a0798010ccc744ebba90f23668187470eae1a6d9d28181fcb1204450a59bfdfbae3bf4d5f402fe5b009c14438a6f16f8870c5
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  doc
2
2
  pkg
3
3
  Gemfile.lock
4
+ coverage
data/Gemfile CHANGED
@@ -4,3 +4,4 @@ gemspec
4
4
 
5
5
  gem "rake"
6
6
  gem "rspec", "~> 2.14.1"
7
+ gem 'coveralls', :require => false
@@ -1,3 +1,15 @@
1
+ = 3.0.1
2
+
3
+ * Added brief class level documentation on all checks
4
+ * No longer printing out "Line: 1" every time you run roodi-describe
5
+ * Added code coverage badge from Coverall.io
6
+ * Added code coverage through Coveralls.io
7
+ * Pulled duplicated find_name method up to super class
8
+ * Added Code Climate badge
9
+ * Added info about how to contribute
10
+ * Updated copyright info to be current
11
+ * Re-added tasks for releasing new versions of the gem
12
+
1
13
  = 3.0.0
2
14
 
3
15
  * Removed MissingForeignKeyIndexCheck, since it is specific to Rails/ActiveRecord and thus doesn't belong in Roodi
data/README.md CHANGED
@@ -1,10 +1,12 @@
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
+ [![Code Climate](https://codeclimate.com/repos/5204c3fc7e00a47bf7015e4e/badges/44ede0c56a53ff100012/gpa.png)](https://codeclimate.com/repos/5204c3fc7e00a47bf7015e4e/feed)
5
+ [![Coverage Status](https://coveralls.io/repos/roodi/roodi/badge.png?branch=master)](https://coveralls.io/r/roodi/roodi?branch=master)
4
6
 
5
7
  ## Description
6
8
 
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.
9
+ 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
10
 
9
11
  ## Install
10
12
 
@@ -86,11 +88,24 @@ To change the set of checks included, or to change the default values of the che
86
88
 
87
89
  * 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.
88
90
 
91
+ ## Contributing
92
+
93
+ ### Bug reporting
94
+ Please use the GitHub issue tracker.
95
+
96
+ ### Want to submit some code?
97
+ Fantastic! Please follow this procedure:
98
+ - Fork the repository
99
+ - Create a well-named topic branch
100
+ - Add specs for any changes you make
101
+ - Write meaningful commit messages explaining why this change is needed
102
+ - Create a pull request.
103
+
89
104
  ## License
90
105
 
91
106
  (The MIT License)
92
107
 
93
- Copyright (c) 2008 Marty Andrews
108
+ Copyright (c) 2013 Peter Evjan
94
109
 
95
110
  Permission is hereby granted, free of charge, to any person obtaining
96
111
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -2,6 +2,7 @@ require 'rake'
2
2
  require 'rspec/core/rake_task'
3
3
  require 'bundler'
4
4
  require 'roodi'
5
+ require 'bundler/gem_tasks'
5
6
 
6
7
  def roodi(ruby_files)
7
8
  roodi = Roodi::Core::Runner.new
@@ -2,17 +2,13 @@ require 'roodi/checks/check'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
- # TODO: Add summary
6
- #
7
- # TODO: Add detail
5
+ # The ABC metric method check calculates the number of Assignments,
6
+ # Branches and Conditionals in your code. It is similar to
7
+ # cyclomatic complexity, so the lower the better.
8
8
  class AbcMetricMethodCheck < Check
9
- # ASSIGNMENTS = [:attrasgn, :attrset, :dasgn_curr, :iasgn, :lasgn, :masgn]
10
9
  ASSIGNMENTS = [:lasgn]
11
- # BRANCHES = [:if, :else, :while, :until, :for, :rescue, :case, :when, :and, :or]
12
10
  BRANCHES = [:vcall, :call]
13
- # CONDITIONS = [:and, :or]
14
11
  CONDITIONS = [:==, :"!=", :<=, :>=, :<, :>]
15
- # = *= /= %= += <<= >>= &= |= ^=
16
12
  OPERATORS = [:*, :/, :%, :+, :<<, :>>, :&, :|, :^]
17
13
  DEFAULT_SCORE = 10
18
14
 
@@ -2,12 +2,13 @@ require 'roodi/core/error'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
+ # Base class for all the checks
5
6
  class Check
6
7
 
7
8
  NODE_TYPES = [:defn, :module, :resbody, :lvar, :cvar, :class, :if, :while, :until, :for, :rescue, :case, :when, :and, :or]
8
9
 
9
10
  class << self
10
-
11
+
11
12
  def make(options = nil)
12
13
  check = new
13
14
  if options
@@ -23,7 +24,7 @@ module Roodi
23
24
  def initialize
24
25
  @errors = []
25
26
  end
26
-
27
+
27
28
  NODE_TYPES.each do |node|
28
29
  start_node_method = "evaluate_start_#{node}"
29
30
  end_node_method = "evaluate_end_#{node}"
@@ -37,10 +38,10 @@ module Roodi
37
38
 
38
39
  def start_file(filename)
39
40
  end
40
-
41
+
41
42
  def end_file(filename)
42
43
  end
43
-
44
+
44
45
  def evaluate_start(node)
45
46
  end
46
47
 
@@ -57,17 +58,17 @@ module Roodi
57
58
  evaluate_node(:start, node)
58
59
  evaluate_start(node)
59
60
  end
60
-
61
+
61
62
  def evaluate_node_end(node)
62
63
  evaluate_node(:end, node)
63
64
  evaluate_end(node)
64
65
  end
65
-
66
+
66
67
  def add_error(error, filename = @node.file, line = @node.line)
67
68
  @errors ||= []
68
69
  @errors << Roodi::Core::Error.new("#{filename}", "#{line}", error)
69
70
  end
70
-
71
+
71
72
  def errors
72
73
  @errors
73
74
  end
@@ -3,17 +3,17 @@ require 'roodi/checks/name_check'
3
3
  module Roodi
4
4
  module Checks
5
5
  # Checks a class name to make sure it matches the specified pattern.
6
- #
6
+ #
7
7
  # Keeping to a consistent naming convention makes your code easier to read.
8
8
  class ClassNameCheck < NameCheck
9
9
 
10
10
  DEFAULT_PATTERN = /^[A-Z][a-zA-Z0-9]*$/
11
-
11
+
12
12
  def initialize
13
13
  super()
14
14
  self.pattern = DEFAULT_PATTERN
15
15
  end
16
-
16
+
17
17
  def interesting_nodes
18
18
  [:class]
19
19
  end
@@ -22,10 +22,6 @@ module Roodi
22
22
  'Class'
23
23
  end
24
24
 
25
- def find_name(node)
26
- node[1].class == Symbol ? node[1] : node[1].last
27
- end
28
-
29
25
  end
30
26
  end
31
27
  end
@@ -2,6 +2,10 @@ require 'roodi/checks/check'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
+ # Checks if a method uses an argument to decide on what execution path to take
6
+ #
7
+ # It is a kind of duplication, since the caller knows what path should be taken.
8
+ # Also, it means the method has more than one responsibility.
5
9
  class ControlCouplingCheck < Check
6
10
  def interesting_nodes
7
11
  [:defn, :lvar]
@@ -11,7 +15,7 @@ module Roodi
11
15
  @method_name = node[1]
12
16
  @arguments = node[2][1..-1]
13
17
  end
14
-
18
+
15
19
  def evaluate_start_lvar(node)
16
20
  add_error "Method \"#{@method_name}\" uses the argument \"#{node[1]}\" for internal control." if @arguments.detect {|each| each == node[1]}
17
21
  end
@@ -2,8 +2,13 @@ require 'roodi/checks/check'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
+ # Cyclomatic complexity counts the number of linearly independent paths in
6
+ # the code. The lower the score, the better.
7
+ #
8
+ # Read more in the inventor Thomas J. McCabe's original research
9
+ # paper: www.literateprogramming.com/mccabe.pdf
5
10
  class CyclomaticComplexityCheck < Check
6
-
11
+
7
12
  COMPLEXITY_NODE_TYPES = [:if, :while, :until, :for, :rescue, :case, :when, :and, :or]
8
13
 
9
14
  attr_accessor :complexity
@@ -13,19 +18,19 @@ module Roodi
13
18
  @count = 0
14
19
  @counting = 0
15
20
  end
16
-
21
+
17
22
  COMPLEXITY_NODE_TYPES.each do |type|
18
23
  define_method "evaluate_start_#{type}" do |node|
19
24
  @count = @count + 1 if counting?
20
25
  end
21
26
  end
22
-
27
+
23
28
  protected
24
-
29
+
25
30
  def count_complexity(node)
26
31
  count_branches(node) + 1
27
32
  end
28
-
33
+
29
34
  def increase_depth
30
35
  @count = 1 unless counting?
31
36
  @counting = @counting + 1
@@ -38,9 +43,9 @@ module Roodi
38
43
  evaluate_matching_end
39
44
  end
40
45
  end
41
-
46
+
42
47
  private
43
-
48
+
44
49
  def counting?
45
50
  @counting > 0
46
51
  end
@@ -2,6 +2,7 @@ require 'roodi/checks/check'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
+ # Checks how many lines there are in a ruby_parser node
5
6
  class LineCountCheck < Check
6
7
 
7
8
  attr_accessor :line_count
@@ -3,12 +3,12 @@ require 'roodi/checks/name_check'
3
3
  module Roodi
4
4
  module Checks
5
5
  # Checks a module name to make sure it matches the specified pattern.
6
- #
6
+ #
7
7
  # Keeping to a consistent nameing convention makes your code easier to read.
8
8
  class ModuleNameCheck < NameCheck
9
9
 
10
10
  DEFAULT_PATTERN = /^[A-Z][a-zA-Z0-9]*$/
11
-
11
+
12
12
  def initialize
13
13
  super()
14
14
  self.pattern = DEFAULT_PATTERN
@@ -22,10 +22,6 @@ module Roodi
22
22
  'Module'
23
23
  end
24
24
 
25
- def find_name(node)
26
- node[1].class == Symbol ? node[1] : node[1].last
27
- end
28
-
29
25
  end
30
26
  end
31
27
  end
@@ -2,6 +2,7 @@ require 'roodi/checks/check'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
+ # Checking that a node's name matches a pattern
5
6
  class NameCheck < Check
6
7
 
7
8
  attr_accessor :pattern
@@ -11,6 +12,10 @@ module Roodi
11
12
  add_error "#{message_prefix} name \"#{name}\" should match pattern #{@pattern.inspect}" unless name.to_s =~ @pattern
12
13
  end
13
14
 
15
+ def find_name(node)
16
+ node[1].class == Symbol ? node[1] : node[1].last
17
+ end
18
+
14
19
  end
15
20
  end
16
21
  end
@@ -2,6 +2,11 @@ require 'roodi/checks/check'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
+ # Checks NPATH complexity of a node
6
+ #
7
+ # NPATH counts acyclic execution paths in a piece of code.
8
+ # Here is an article by Brian A. Nejmeh that explains it in more detail:
9
+ # http://www.accessmylibrary.com/article-1G1-6242192/npath-measure-execution-path.html
5
10
  class NpathComplexityCheck < Check
6
11
  # , :when, :and, :or
7
12
  MULTIPLYING_NODE_TYPES = [:if, :while, :until, :for, :case]
@@ -9,18 +14,18 @@ module Roodi
9
14
  COMPLEXITY_NODE_TYPES = MULTIPLYING_NODE_TYPES + ADDING_NODE_TYPES
10
15
 
11
16
  attr_accessor :complexity
12
-
17
+
13
18
  def initialize(complexity)
14
19
  super()
15
20
  @complexity = complexity
16
21
  @value_stack = []
17
22
  @current_value = 1
18
23
  end
19
-
24
+
20
25
  def evalute_start_if(node)
21
26
  push_value
22
27
  end
23
-
28
+
24
29
  def evalute_start_while(node)
25
30
  push_value
26
31
  end
@@ -40,7 +45,7 @@ module Roodi
40
45
  def evalute_start_rescue(node)
41
46
  push_value
42
47
  end
43
-
48
+
44
49
  MULTIPLYING_NODE_TYPES.each do |type|
45
50
  define_method "evaluate_end_#{type}" do |node|
46
51
  leave_multiplying_conditional
@@ -52,9 +57,9 @@ module Roodi
52
57
  leave_multiplying_conditional
53
58
  end
54
59
  end
55
-
60
+
56
61
  protected
57
-
62
+
58
63
  def push_value
59
64
  @value_stack.push @current_value
60
65
  @current_value = 1
@@ -64,7 +69,7 @@ module Roodi
64
69
  pop = @value_stack.pop
65
70
  @current_value = (@current_value + 1) * pop
66
71
  end
67
-
72
+
68
73
  def leave_adding_conditional
69
74
  pop = @value_stack.pop
70
75
  puts "#{type}, so adding #{pop}"
@@ -2,15 +2,15 @@ require 'roodi/checks/npath_complexity_check'
2
2
 
3
3
  module Roodi
4
4
  module Checks
5
- # Checks Npath complexity of a method against a specified limit.
5
+ # Checks NPATH complexity of a method against a specified limit.
6
6
  class NpathComplexityMethodCheck < NpathComplexityCheck
7
7
 
8
8
  DEFAULT_COMPLEXITY = 8
9
-
9
+
10
10
  def initialize
11
11
  super(DEFAULT_COMPLEXITY)
12
12
  end
13
-
13
+
14
14
  def interesting_nodes
15
15
  [:defn] + COMPLEXITY_NODE_TYPES
16
16
  end
@@ -9,14 +9,14 @@ module Roodi
9
9
  module Core
10
10
  class Runner
11
11
  DEFAULT_CONFIG = File.join(File.dirname(__FILE__), "..", "..", "..", "roodi.yml")
12
-
12
+
13
13
  attr_writer :config
14
-
14
+
15
15
  def initialize(*checks)
16
16
  @config = DEFAULT_CONFIG
17
17
  @checks = checks unless checks.empty?
18
18
  end
19
-
19
+
20
20
  def check(filename, content)
21
21
  @checks ||= load_checks
22
22
  @checker ||= CheckingVisitor.new(@checks)
@@ -29,34 +29,33 @@ module Roodi
29
29
  def check_content(content, filename = "dummy-file.rb")
30
30
  check(filename, content)
31
31
  end
32
-
32
+
33
33
  def check_file(filename)
34
34
  return unless File.exists?(filename)
35
35
  check(filename, File.read(filename))
36
36
  end
37
-
37
+
38
38
  def print(filename, content)
39
39
  node = parse(filename, content)
40
- puts "Line: #{node.line}"
41
40
  pp node
42
41
  end
43
42
 
44
43
  def print_content(content)
45
44
  print("dummy-file.rb", content)
46
45
  end
47
-
46
+
48
47
  def print_file(filename)
49
48
  print(filename, File.read(filename))
50
49
  end
51
-
50
+
52
51
  def errors
53
52
  @checks ||= []
54
53
  all_errors = @checks.collect {|check| check.errors}
55
54
  all_errors.flatten
56
55
  end
57
-
56
+
58
57
  private
59
-
58
+
60
59
  def parse(filename, content)
61
60
  begin
62
61
  Parser.new.parse(content, filename)
@@ -1,3 +1,3 @@
1
1
  module Roodi
2
- VERSION = '3.0.0'
2
+ VERSION = '3.0.1'
3
3
  end
@@ -5,7 +5,7 @@ Gem::Specification.new do |gem|
5
5
 
6
6
  gem.name = "roodi"
7
7
  gem.summary = "Roodi stands for Ruby Object Oriented Design Inferometer"
8
- gem.description = "Roodi stands for Ruby Object Oriented Design Inferometer"
8
+ gem.description = "Roodi parses your Ruby code and warns you about design issues you have based on the checks that is has configured"
9
9
  gem.homepage = "http://github.com/roodi/roodi"
10
10
  gem.authors = ["Marty Andrews", "Peter Evjan"]
11
11
  gem.email = "peter.evjan@gmail.com"
@@ -1,3 +1,6 @@
1
1
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
2
2
  require 'roodi'
3
3
  require 'rspec'
4
+ require 'coveralls'
5
+ Coveralls.wear!
6
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roodi
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marty Andrews
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-14 00:00:00.000000000 Z
12
+ date: 2013-08-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby_parser
@@ -25,7 +25,8 @@ dependencies:
25
25
  - - ~>
26
26
  - !ruby/object:Gem::Version
27
27
  version: 3.2.2
28
- description: Roodi stands for Ruby Object Oriented Design Inferometer
28
+ description: Roodi parses your Ruby code and warns you about design issues you have
29
+ based on the checks that is has configured
29
30
  email: peter.evjan@gmail.com
30
31
  executables:
31
32
  - roodi