metric_fu-roodi 2.2.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.
Files changed (66) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +6 -0
  4. data/History.txt +93 -0
  5. data/Manifest.txt +56 -0
  6. data/README.txt +98 -0
  7. data/Rakefile +35 -0
  8. data/bin/metric_fu-roodi +21 -0
  9. data/bin/metric_fu-roodi-describe +7 -0
  10. data/lib/roodi.rb +3 -0
  11. data/lib/roodi/checks.rb +18 -0
  12. data/lib/roodi/checks/abc_metric_method_check.rb +79 -0
  13. data/lib/roodi/checks/assignment_in_conditional_check.rb +32 -0
  14. data/lib/roodi/checks/case_missing_else_check.rb +20 -0
  15. data/lib/roodi/checks/check.rb +76 -0
  16. data/lib/roodi/checks/class_line_count_check.rb +28 -0
  17. data/lib/roodi/checks/class_name_check.rb +31 -0
  18. data/lib/roodi/checks/class_variable_check.rb +24 -0
  19. data/lib/roodi/checks/control_coupling_check.rb +20 -0
  20. data/lib/roodi/checks/cyclomatic_complexity_block_check.rb +41 -0
  21. data/lib/roodi/checks/cyclomatic_complexity_check.rb +50 -0
  22. data/lib/roodi/checks/cyclomatic_complexity_method_check.rb +42 -0
  23. data/lib/roodi/checks/empty_rescue_body_check.rb +32 -0
  24. data/lib/roodi/checks/for_loop_check.rb +20 -0
  25. data/lib/roodi/checks/line_count_check.rb +22 -0
  26. data/lib/roodi/checks/method_line_count_check.rb +29 -0
  27. data/lib/roodi/checks/method_name_check.rb +31 -0
  28. data/lib/roodi/checks/missing_foreign_key_index_check.rb +99 -0
  29. data/lib/roodi/checks/module_line_count_check.rb +28 -0
  30. data/lib/roodi/checks/module_name_check.rb +31 -0
  31. data/lib/roodi/checks/name_check.rb +16 -0
  32. data/lib/roodi/checks/npath_complexity_check.rb +75 -0
  33. data/lib/roodi/checks/npath_complexity_method_check.rb +29 -0
  34. data/lib/roodi/checks/parameter_number_check.rb +34 -0
  35. data/lib/roodi/core.rb +1 -0
  36. data/lib/roodi/core/checking_visitor.rb +26 -0
  37. data/lib/roodi/core/error.rb +17 -0
  38. data/lib/roodi/core/parser.rb +30 -0
  39. data/lib/roodi/core/runner.rb +81 -0
  40. data/lib/roodi/core/visitable_sexp.rb +25 -0
  41. data/lib/roodi/version.rb +3 -0
  42. data/lib/roodi_task.rb +35 -0
  43. data/roodi.gemspec +26 -0
  44. data/roodi.yml +25 -0
  45. data/spec/roodi/checks/abc_metric_method_check_spec.rb +89 -0
  46. data/spec/roodi/checks/assignment_in_conditional_check_spec.rb +105 -0
  47. data/spec/roodi/checks/case_missing_else_check_spec.rb +32 -0
  48. data/spec/roodi/checks/class_line_count_check_spec.rb +39 -0
  49. data/spec/roodi/checks/class_name_check_spec.rb +39 -0
  50. data/spec/roodi/checks/class_variable_check_spec.rb +17 -0
  51. data/spec/roodi/checks/control_coupling_check_spec.rb +23 -0
  52. data/spec/roodi/checks/cyclomatic_complexity_block_check_spec.rb +67 -0
  53. data/spec/roodi/checks/cyclomatic_complexity_method_check_spec.rb +200 -0
  54. data/spec/roodi/checks/empty_rescue_body_check_spec.rb +140 -0
  55. data/spec/roodi/checks/for_loop_check_spec.rb +18 -0
  56. data/spec/roodi/checks/method_line_count_check_spec.rb +56 -0
  57. data/spec/roodi/checks/method_name_check_spec.rb +76 -0
  58. data/spec/roodi/checks/missing_foreign_key_index_check_spec.rb +33 -0
  59. data/spec/roodi/checks/module_line_count_check_spec.rb +39 -0
  60. data/spec/roodi/checks/module_name_check_spec.rb +27 -0
  61. data/spec/roodi/checks/npath_complexity_method_check_spec.rb +53 -0
  62. data/spec/roodi/checks/parameter_number_check_spec.rb +47 -0
  63. data/spec/roodi/core/runner_spec.rb +25 -0
  64. data/spec/roodi/roodi.yml +2 -0
  65. data/spec/spec_helper.rb +3 -0
  66. metadata +149 -0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ doc
2
+ pkg
3
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "rspec", "~> 2.11.0"
data/History.txt ADDED
@@ -0,0 +1,93 @@
1
+ = 2.2.0
2
+
3
+ * 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
4
+ * Did not pull in updates from https://github.com/ssassi/roodi/commits/master re: https://github.com/martinjandrews/roodi/pull/10
5
+
6
+ = 2.0.1
7
+
8
+ * Fixed a bug where roodi.yml was not being loaded. Patch supplied by Rob Mitchell.
9
+
10
+ = 2.0.0
11
+
12
+ * Changed internal structure to use a more pure visitor like pattern.
13
+ * Got *much* faster as a result of the change.
14
+ * Design change fixed 'feature' where nested blocks would all get listed if the inner one exceeded complexity.
15
+ * Outline for NPath complexity check is now possible. Not working yet though.
16
+ * Removed dependency on facets library.
17
+
18
+ = 1.4.0
19
+
20
+ * Upgraded from ParseTree to ruby_parser.
21
+
22
+ = 1.3.7
23
+
24
+ * Fixed a bug in the rake task where it always failed even if no errors existed.
25
+
26
+ = 1.3.6
27
+
28
+ * Added nil as a valid response for an empty rescue block
29
+
30
+ = 1.3.5
31
+
32
+ * Fixed bug in rake task
33
+
34
+ = 1.3.4
35
+
36
+ * Minor cleanup
37
+
38
+ = 1.3.3
39
+
40
+ * Added a rake task
41
+
42
+ = 1.3.1
43
+
44
+ * wrapped errors in an object to become more usable as an API.
45
+
46
+ = 1.3.0
47
+
48
+ * added case missing else check.
49
+ * updated checks to take a hash of options with built-in defaults.
50
+ * added support for complete configuration via external file.
51
+ * added support for passing in a custom config file via 'roodi -config=<filename> [pattern]'
52
+ * added assignment in conditional check.
53
+ * refactored checks to remove duplicate code.
54
+
55
+ = 1.2.0
56
+
57
+ * added module name check.
58
+ * added parameter number check.
59
+ * added module line count check.
60
+ * added class line count check.
61
+
62
+ = 1.1.1
63
+
64
+ * I'd initially published to Rubyforge under a 1.0.0 gem, and I've since tried to retrospectively fix up the version number system. It turns out that Rubyforge caches old gems permanently, so I have to re-start at a larger number again.
65
+ * class name check no longer gets confused about scoped class names like Module::Classname.
66
+
67
+ = 0.5
68
+
69
+ * expanded regex matching for method name check.
70
+ * suppressed noisy output from ParseTree using facets API.
71
+ * updated dependencies and version as a result of facets change.
72
+ * made Roodi tolerant of being asked to parse files which aren't really Ruby files.
73
+ * updated the documentation with usage examples.
74
+
75
+ = 0.4
76
+
77
+ * Added support back in for line numbers in error messages.
78
+ * Re-enabled MethodLineCountCheck as part of the default check set.
79
+
80
+ = 0.3
81
+
82
+ * First version of Roodi to be published to Rubyforge.
83
+
84
+ = 0.2
85
+
86
+ * Now use ParseTree instead of JRuby, which makes the tool much more accessible.
87
+ * Removed MagicNumberCheck
88
+ * Line numbers no longer supported as a result of the move.
89
+
90
+ = 0.1
91
+
92
+ * A first version of a design checking tool for Ruby, with a few checks built in to get started.
93
+
data/Manifest.txt ADDED
@@ -0,0 +1,56 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/roodi
6
+ bin/roodi-describe
7
+ lib/roodi.rb
8
+ lib/roodi/checks.rb
9
+ lib/roodi/checks/abc_metric_method_check.rb
10
+ lib/roodi/checks/assignment_in_conditional_check.rb
11
+ lib/roodi/checks/case_missing_else_check.rb
12
+ lib/roodi/checks/check.rb
13
+ lib/roodi/checks/class_line_count_check.rb
14
+ lib/roodi/checks/class_name_check.rb
15
+ lib/roodi/checks/class_variable_check.rb
16
+ lib/roodi/checks/control_coupling_check.rb
17
+ lib/roodi/checks/cyclomatic_complexity_block_check.rb
18
+ lib/roodi/checks/cyclomatic_complexity_check.rb
19
+ lib/roodi/checks/cyclomatic_complexity_method_check.rb
20
+ lib/roodi/checks/empty_rescue_body_check.rb
21
+ lib/roodi/checks/for_loop_check.rb
22
+ lib/roodi/checks/line_count_check.rb
23
+ lib/roodi/checks/method_line_count_check.rb
24
+ lib/roodi/checks/method_name_check.rb
25
+ lib/roodi/checks/module_line_count_check.rb
26
+ lib/roodi/checks/module_name_check.rb
27
+ lib/roodi/checks/name_check.rb
28
+ lib/roodi/checks/npath_complexity_check.rb
29
+ lib/roodi/checks/npath_complexity_method_check.rb
30
+ lib/roodi/checks/parameter_number_check.rb
31
+ lib/roodi/core.rb
32
+ lib/roodi/core/checking_visitor.rb
33
+ lib/roodi/core/error.rb
34
+ lib/roodi/core/parser.rb
35
+ lib/roodi/core/runner.rb
36
+ lib/roodi/core/visitable_sexp.rb
37
+ lib/roodi_task.rb
38
+ roodi.yml
39
+ spec/roodi/checks/abc_metric_method_check_spec.rb
40
+ spec/roodi/checks/assignment_in_conditional_check_spec.rb
41
+ spec/roodi/checks/case_missing_else_check_spec.rb
42
+ spec/roodi/checks/class_line_count_check_spec.rb
43
+ spec/roodi/checks/class_name_check_spec.rb
44
+ spec/roodi/checks/class_variable_check_spec.rb
45
+ spec/roodi/checks/control_coupling_check_spec.rb
46
+ spec/roodi/checks/cyclomatic_complexity_block_check_spec.rb
47
+ spec/roodi/checks/cyclomatic_complexity_method_check_spec.rb
48
+ spec/roodi/checks/empty_rescue_body_check_spec.rb
49
+ spec/roodi/checks/for_loop_check_spec.rb
50
+ spec/roodi/checks/method_line_count_check_spec.rb
51
+ spec/roodi/checks/method_name_check_spec.rb
52
+ spec/roodi/checks/module_line_count_check_spec.rb
53
+ spec/roodi/checks/module_name_check_spec.rb
54
+ spec/roodi/checks/npath_complexity_method_check_spec.rb
55
+ spec/roodi/checks/parameter_number_check_spec.rb
56
+ spec/spec_helper.rb
data/README.txt ADDED
@@ -0,0 +1,98 @@
1
+ = roodi
2
+
3
+ * http://roodi.rubyforge.org
4
+
5
+ == DESCRIPTION:
6
+
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
+
9
+ This is a fork for use with metric_fu that includes 1.9 compatibility and continued development
10
+
11
+ == INSTALL:
12
+
13
+ * gem install roodi
14
+
15
+ == SYNOPSIS:
16
+
17
+ To check one or more files using the default configuration that comes with Roodi, use:
18
+ metric_fu-roodi [-config=file] [pattern ...]
19
+
20
+ === EXAMPLE USAGE
21
+
22
+ Check all ruby files in a rails app:
23
+ metric_fu-roodi "rails_app/**/*.rb"
24
+
25
+ Check one controller and one model file in a rails app:
26
+ metric_fu-roodi app/controller/sample_controller.rb app/models/sample.rb
27
+
28
+ Check one controller and all model files in a rails app:
29
+ metric_fu-roodi app/controller/sample_controller.rb "app/models/*.rb"
30
+
31
+ Check all ruby files in a rails app with a custom configuration file:
32
+ metric_fu-roodi -config=my_roodi_config.yml "rails_app/**/*.rb"
33
+
34
+ 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:
35
+ metric_fu-roodi-describe [filename]
36
+
37
+ == CUSTOM CONFIGURATION
38
+
39
+ 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:
40
+
41
+ AssignmentInConditionalCheck: { }
42
+ CaseMissingElseCheck: { }
43
+ ClassLineCountCheck: { line_count: 300 }
44
+ ClassNameCheck: { pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/ }
45
+ CyclomaticComplexityBlockCheck: { complexity: 4 }
46
+ CyclomaticComplexityMethodCheck: { complexity: 8 }
47
+ EmptyRescueBodyCheck: { }
48
+ ForLoopCheck: { }
49
+ MethodLineCountCheck: { line_count: 20 }
50
+ MethodNameCheck: { pattern: !ruby/regexp /^[_a-z<>=\[\]|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/ }
51
+ ModuleLineCountCheck: { line_count: 300 }
52
+ ModuleNameCheck: { pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/ }
53
+ ParameterNumberCheck: { parameter_count: 5 }
54
+
55
+ == SUPPORTED CHECKS:
56
+
57
+ * AssignmentInConditionalCheck - Check for an assignment inside a conditional. It's probably a mistaken equality comparison.
58
+ * CaseMissingElseCheck - Check that case statements have an else statement so that all cases are covered.
59
+ * ClassLineCountCheck - Check that the number of lines in a class is below the threshold.
60
+ * ClassNameCheck - Check that class names match convention.
61
+ * CyclomaticComplexityBlockCheck - Check that the cyclomatic complexity of all blocks is below the threshold.
62
+ * CyclomaticComplexityMethodCheck - Check that the cyclomatic complexity of all methods is below the threshold.
63
+ * EmptyRescueBodyCheck - Check that there are no empty rescue blocks.
64
+ * ForLoopCheck - Check that for loops aren't used (Use Enumerable.each instead)
65
+ * MethodLineCountCheck - Check that the number of lines in a method is below the threshold.
66
+ * MethodNameCheck - Check that method names match convention.
67
+ * ModuleLineCountCheck - Check that the number of lines in a module is below the threshold.
68
+ * ModuleNameCheck - Check that module names match convention.
69
+ * ParameterNumberCheck - Check that the number of parameters on a method is below the threshold.
70
+
71
+ == SUGGESTED CHECKS:
72
+
73
+ * 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.
74
+
75
+ == LICENSE:
76
+
77
+ (The MIT License)
78
+
79
+ Copyright (c) 2008 Marty Andrews
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining
82
+ a copy of this software and associated documentation files (the
83
+ 'Software'), to deal in the Software without restriction, including
84
+ without limitation the rights to use, copy, modify, merge, publish,
85
+ distribute, sublicense, and/or sell copies of the Software, and to
86
+ permit persons to whom the Software is furnished to do so, subject to
87
+ the following conditions:
88
+
89
+ The above copyright notice and this permission notice shall be
90
+ included in all copies or substantial portions of the Software.
91
+
92
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
93
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
94
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
95
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
96
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
97
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
98
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'rake'
2
+ require 'bundler/gem_tasks'
3
+ begin
4
+ require 'spec/rake/spectask'
5
+ desc "Run all specs in spec directory"
6
+ Spec::Rake::SpecTask.new(:spec) do |t|
7
+ t.spec_files = FileList['spec/**/*_spec.rb']
8
+ end
9
+ rescue LoadError
10
+ require 'rspec/core/rake_task'
11
+ desc "Run all specs in spec directory"
12
+ RSpec::Core::RakeTask.new(:spec)
13
+ end
14
+
15
+ require File.expand_path('lib/roodi',File.dirname(__FILE__))
16
+
17
+ def roodi(ruby_files)
18
+ roodi = Roodi::Core::Runner.new
19
+ ruby_files.each { |file| roodi.check_file(file) }
20
+ roodi.errors.each {|error| puts error}
21
+ puts "\nFound #{roodi.errors.size} errors."
22
+ end
23
+
24
+ desc "Run all specs"
25
+ Spec::Rake::SpecTask.new('spec') do |t|
26
+ t.spec_files = FileList['spec/**/*spec.rb']
27
+ end
28
+
29
+ desc "Run Roodi against all source files"
30
+ task :roodi do
31
+ pattern = File.join(File.dirname(__FILE__), "**", "*.rb")
32
+ roodi(Dir.glob(pattern))
33
+ end
34
+
35
+ task :default => :spec
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
4
+
5
+ require 'roodi'
6
+
7
+ runner = Roodi::Core::Runner.new
8
+
9
+ config_param = ARGV.detect {|arg| arg =~ /-config=.*/}
10
+ runner.config = config_param.split("=")[1] if config_param
11
+ ARGV.delete config_param
12
+
13
+ ARGV.each do |arg|
14
+ Dir.glob(arg).each { |file| runner.check_file(file) }
15
+ end
16
+
17
+ runner.errors.each {|error| puts error}
18
+
19
+ puts "\nFound #{runner.errors.size} errors."
20
+
21
+ exit runner.errors.size
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
4
+ require 'roodi'
5
+
6
+ roodi = Roodi::Core::Runner.new
7
+ roodi.print_file(ARGV[0])
data/lib/roodi.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'roodi/checks'
2
+ require 'roodi/core'
3
+ require 'roodi/version'
@@ -0,0 +1,18 @@
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'
@@ -0,0 +1,79 @@
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
@@ -0,0 +1,32 @@
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