kevinrutherford-reek 1.1.3.14 → 1.1.3.15

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  === Major Changes
4
4
  * Reek passes all its tests under ruby 1.8.6, 1.8.7 and 1.9.1 (fixed #16)
5
+ * New smell -- Data Clump:
6
+ ** Looks within a class for 3 or more methods taking the same 2 or more parameters
5
7
  * New smell -- Simulated Polymorphism:
6
8
  ** Currently only performs basic check for multiple tests of same value
7
9
  * Reek's output reports are now formatted differently:
data/config/defaults.reek CHANGED
@@ -48,6 +48,12 @@ SimulatedPolymorphism:
48
48
 
49
49
  enabled: true
50
50
  max_ifs: 2
51
+ DataClump:
52
+ exclude: []
53
+
54
+ enabled: true
55
+ max_copies: 2
56
+ min_clump_size: 2
51
57
  ControlCouple:
52
58
  exclude:
53
59
  - initialize
@@ -9,8 +9,9 @@ Feature: Basic smell detection
9
9
  Then it fails with exit status 2
10
10
  And it reports:
11
11
  """
12
- spec/samples/inline.rb -- 35 warnings (+1 masked):
12
+ spec/samples/inline.rb -- 36 warnings (+1 masked):
13
13
  Inline::C has at least 13 instance variables (Large Class)
14
+ Inline::C takes parameters [options, src] to 5 methods (Data Clump)
14
15
  Inline::C tests $DEBUG at least 7 times (Simulated Polymorphism)
15
16
  Inline::C tests $TESTING at least 4 times (Simulated Polymorphism)
16
17
  Inline::C tests @@type_map.has_key?(type) at least 3 times (Simulated Polymorphism)
@@ -183,8 +184,9 @@ Feature: Basic smell detection
183
184
  Then it fails with exit status 2
184
185
  And it reports:
185
186
  """
186
- spec/samples/redcloth.rb -- 99 warnings:
187
+ spec/samples/redcloth.rb -- 100 warnings:
187
188
  RedCloth has at least 44 methods (Large Class)
189
+ RedCloth takes parameters [atts, cite, content, tag] to 3 methods (Data Clump)
188
190
  RedCloth tests atts at least 6 times (Simulated Polymorphism)
189
191
  RedCloth tests codepre.zero? at least 3 times (Simulated Polymorphism)
190
192
  RedCloth tests href at least 3 times (Simulated Polymorphism)
@@ -24,7 +24,7 @@ module Reek
24
24
  CodeParser.new(sniffer).process_class(source.syntax_tree)
25
25
  end
26
26
 
27
- attr_reader :conditionals
27
+ attr_reader :conditionals, :parsed_methods
28
28
 
29
29
  # SMELL: inconsistent with other contexts (not linked to the sexp)
30
30
  def initialize(outer, name, superclass = nil)
@@ -62,8 +62,8 @@ module Reek
62
62
  @instance_variables << Name.new(sym)
63
63
  end
64
64
 
65
- def record_method(name)
66
- @parsed_methods << name.to_s
65
+ def record_method(meth)
66
+ @parsed_methods << meth
67
67
  end
68
68
 
69
69
  def outer_name
@@ -81,5 +81,9 @@ module Reek
81
81
  def record_conditional(exp)
82
82
  @conditionals << exp
83
83
  end
84
+
85
+ def parameterized_methods(min_clump_size)
86
+ parsed_methods.select {|meth| meth.parameters.length >= min_clump_size }
87
+ end
84
88
  end
85
89
  end
@@ -74,9 +74,7 @@ module Reek
74
74
  handle_context(SingletonMethodContext, :defs, exp)
75
75
  end
76
76
 
77
- def process_args(exp)
78
- exp[1..-1].each {|sym| @element.record_parameter(sym) }
79
- end
77
+ def process_args(exp) end
80
78
 
81
79
  def process_attrset(exp)
82
80
  @element.record_depends_on_self if /^@/ === exp[1].to_s
@@ -95,11 +93,6 @@ module Reek
95
93
  process(exp[1])
96
94
  handle_context(BlockContext, :iter, exp[2..-1])
97
95
  end
98
-
99
- def process_dasgn_curr(exp)
100
- @element.record_parameter(exp[1])
101
- process_default(exp)
102
- end
103
96
 
104
97
  def process_block(exp)
105
98
  @element.count_statements(CodeParser.count_statements(exp))
@@ -2,7 +2,55 @@ require 'reek/name'
2
2
  require 'reek/code_context'
3
3
  require 'reek/object_refs'
4
4
 
5
+ class Array
6
+ def power_set
7
+ self.inject([[]]) { |cum, element| cum.cross(element) }
8
+ end
9
+
10
+ def bounded_power_set(lower_bound)
11
+ power_set.select {|ps| ps.length > lower_bound}
12
+ end
13
+
14
+ def cross(element)
15
+ result = []
16
+ self.each do |set|
17
+ result << set
18
+ result << (set + [element])
19
+ end
20
+ result
21
+ end
22
+
23
+ def intersection
24
+ self.inject { |res, elem| elem & res }
25
+ end
26
+ end
27
+
5
28
  module Reek
29
+
30
+ module MethodParameters
31
+ def self.is_arg?(param)
32
+ return false if (Array === param and param[0] == :block)
33
+ return !(param.to_s =~ /^\&/)
34
+ end
35
+
36
+ def names
37
+ return @names if @names
38
+ @names = self[1..-1].select {|arg| MethodParameters.is_arg?(arg)}.map {|arg| Name.new(arg)}
39
+ end
40
+
41
+ def length
42
+ names.length
43
+ end
44
+
45
+ def include?(name)
46
+ names.include?(name)
47
+ end
48
+
49
+ def to_s
50
+ "[#{names.map{|nm| nm.to_s}.join(', ')}]"
51
+ end
52
+ end
53
+
6
54
  class MethodContext < CodeContext
7
55
  attr_reader :parameters
8
56
  attr_reader :calls
@@ -11,14 +59,16 @@ module Reek
11
59
 
12
60
  def initialize(outer, exp, record = true)
13
61
  super(outer, exp)
14
- @parameters = []
62
+ @parameters = exp[exp[0] == :defn ? 2 : 3] # SMELL: SimulatedPolymorphism
63
+ @parameters ||= []
64
+ @parameters.extend(MethodParameters)
15
65
  @local_variables = []
16
66
  @name = Name.new(exp[1])
17
67
  @num_statements = 0
18
68
  @calls = Hash.new(0)
19
69
  @depends_on_self = false
20
70
  @refs = ObjectRefs.new
21
- @outer.record_method(@name) # TODO: should be children of outer?
71
+ @outer.record_method(self)
22
72
  end
23
73
 
24
74
  def count_statements(num)
@@ -63,14 +113,6 @@ module Reek
63
113
  @local_variables << Name.new(sym)
64
114
  end
65
115
 
66
- def self.is_block_arg?(param)
67
- (Array === param and param[0] == :block) or (param.to_s =~ /^\&/)
68
- end
69
-
70
- def record_parameter(param)
71
- @parameters << Name.new(param) unless MethodContext.is_block_arg?(param)
72
- end
73
-
74
116
  def outer_name
75
117
  "#{@outer.outer_name}#{@name}/"
76
118
  end
@@ -85,7 +127,7 @@ module Reek
85
127
  end
86
128
 
87
129
  def variable_names
88
- @parameters + @local_variables
130
+ @parameters.names + @local_variables
89
131
  end
90
132
  end
91
133
  end
data/lib/reek/name.rb CHANGED
@@ -32,16 +32,22 @@ module Reek
32
32
  @name.hash
33
33
  end
34
34
 
35
+ def eql?(other)
36
+ self == other
37
+ end
38
+
35
39
  def <=>(other) # :nodoc:
36
40
  @name <=> other.to_s
37
41
  end
38
42
 
39
- alias eql? <=>
40
-
41
43
  def effective_name
42
44
  @name.gsub(/^@*/, '')
43
45
  end
44
46
 
47
+ def inspect
48
+ @name.inspect
49
+ end
50
+
45
51
  def to_s
46
52
  @name
47
53
  end
@@ -0,0 +1,88 @@
1
+ require 'reek/smells/smell_detector'
2
+ require 'reek/smell_warning'
3
+ require 'reek/sexp_formatter'
4
+
5
+ module Reek
6
+ module Smells
7
+
8
+ #
9
+ # A Data Clump occurs when the same two or three items frequently
10
+ # appear together in classes and parameter lists, or when a group
11
+ # of instance variable names start or end with similar substrings.
12
+ #
13
+ # The recurrence of the items often means there is duplicate code
14
+ # spread around to handle them. There may be an abstraction missing
15
+ # from the code, making the system harder to understand.
16
+ #
17
+ # Currently Reek looks for a group of two or more parameters with
18
+ # the same names that are expected by three or more methods of a class.
19
+ #
20
+ class DataClump < SmellDetector
21
+
22
+ def self.contexts # :nodoc:
23
+ [:class]
24
+ end
25
+
26
+ # The name of the config field that sets the maximum allowed
27
+ # copies of any clump.
28
+ MAX_COPIES_KEY = 'max_copies'
29
+
30
+ DEFAULT_MAX_COPIES = 2
31
+
32
+ MIN_CLUMP_SIZE_KEY = 'min_clump_size'
33
+ DEFAULT_MIN_CLUMP_SIZE = 2
34
+
35
+ def self.default_config
36
+ super.adopt(
37
+ MAX_COPIES_KEY => DEFAULT_MAX_COPIES,
38
+ MIN_CLUMP_SIZE_KEY => DEFAULT_MIN_CLUMP_SIZE
39
+ )
40
+ end
41
+
42
+ def initialize(config = DataClump.default_config)
43
+ super(config)
44
+ end
45
+
46
+ #
47
+ # Checks the given ClassContext for multiple identical conditional tests.
48
+ # Remembers any smells found.
49
+ #
50
+ def examine_context(klass)
51
+ max_copies = value(MAX_COPIES_KEY, klass, DEFAULT_MAX_COPIES)
52
+ min_clump_size = value(MIN_CLUMP_SIZE_KEY, klass, DEFAULT_MIN_CLUMP_SIZE)
53
+ MethodGroup.new(klass, min_clump_size, max_copies).clumps.each do |clump, occurs|
54
+ found(klass, "takes parameters #{DataClump.print_clump(clump)} to #{occurs} methods")
55
+ end
56
+ end
57
+
58
+ def self.print_clump(clump)
59
+ "[#{clump.map {|name| name.to_s}.join(', ')}]"
60
+ end
61
+ end
62
+ end
63
+
64
+ # Represents a group of methods
65
+ class MethodGroup # :nodoc:
66
+
67
+ def self.intersection_of_parameters_of(methods)
68
+ methods.map {|meth| meth.parameters.names.sort}.intersection
69
+ end
70
+
71
+ def initialize(klass, min_clump_size, max_copies)
72
+ @klass = klass
73
+ @min_clump_size = min_clump_size
74
+ @max_copies = max_copies
75
+ end
76
+
77
+ def clumps
78
+ results = Hash.new(0)
79
+ @klass.parameterized_methods(@min_clump_size).bounded_power_set(@max_copies).each do |methods|
80
+ clump = MethodGroup.intersection_of_parameters_of(methods)
81
+ if clump.length >= @min_clump_size
82
+ results[clump] = [methods.length, results[clump]].max
83
+ end
84
+ end
85
+ results
86
+ end
87
+ end
88
+ end
data/lib/reek/sniffer.rb CHANGED
@@ -2,6 +2,7 @@ require 'reek/detector_stack'
2
2
 
3
3
  # SMELL: Duplication -- all these should be found automagically
4
4
  require 'reek/smells/control_couple'
5
+ require 'reek/smells/data_clump'
5
6
  require 'reek/smells/duplication'
6
7
  require 'reek/smells/feature_envy'
7
8
  require 'reek/smells/large_class'
@@ -44,27 +45,29 @@ end
44
45
  module Reek
45
46
  class Sniffer
46
47
 
47
- # SMELL: Duplication
48
- # This list should be calculated by looking in the source folder.
49
- SMELL_CLASSES = [
50
- Smells::ControlCouple,
51
- Smells::Duplication,
52
- Smells::FeatureEnvy,
53
- Smells::LargeClass,
54
- Smells::LongMethod,
55
- Smells::LongParameterList,
56
- Smells::LongYieldList,
57
- Smells::NestedIterators,
58
- Smells::SimulatedPolymorphism,
59
- Smells::UncommunicativeName,
60
- Smells::UtilityFunction,
61
- ]
48
+ def self.smell_classes
49
+ # SMELL: Duplication -- these should be loaded by listing the files
50
+ [
51
+ Smells::ControlCouple,
52
+ Smells::DataClump,
53
+ Smells::Duplication,
54
+ Smells::FeatureEnvy,
55
+ Smells::LargeClass,
56
+ Smells::LongMethod,
57
+ Smells::LongParameterList,
58
+ Smells::LongYieldList,
59
+ Smells::NestedIterators,
60
+ Smells::SimulatedPolymorphism,
61
+ Smells::UncommunicativeName,
62
+ Smells::UtilityFunction,
63
+ ]
64
+ end
62
65
 
63
66
  def initialize(src)
64
67
  @already_checked_for_smells = false
65
68
  @typed_detectors = nil
66
69
  @detectors = Hash.new
67
- SMELL_CLASSES.each { |klass| @detectors[klass] = DetectorStack.new(klass.new) }
70
+ Sniffer.smell_classes.each { |klass| @detectors[klass] = DetectorStack.new(klass.new) }
68
71
  @source = src
69
72
  src.configure(self)
70
73
  end
data/lib/reek.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
3
  module Reek # :doc:
4
- VERSION = '1.1.3.14'
4
+ VERSION = '1.1.3.15'
5
5
  end
data/reek.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{reek}
5
- s.version = "1.1.3.14"
5
+ s.version = "1.1.3.15"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Kevin Rutherford"]
9
- s.date = %q{2009-08-20}
9
+ s.date = %q{2009-09-03}
10
10
  s.default_executable = %q{reek}
11
11
  s.description = %q{Code smell detector for Ruby}
12
12
  s.email = ["kevin@rutherford-software.com"]
13
13
  s.executables = ["reek"]
14
14
  s.extra_rdoc_files = ["History.txt", "License.txt", "README.txt"]
15
- s.files = ["History.txt", "License.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "lib/reek.rb", "lib/reek/adapters/application.rb", "lib/reek/adapters/config_file.rb", "lib/reek/adapters/core_extras.rb", "lib/reek/adapters/object_source.rb", "lib/reek/adapters/rake_task.rb", "lib/reek/adapters/report.rb", "lib/reek/adapters/source.rb", "lib/reek/adapters/spec.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.rb", "lib/reek/command_line.rb", "lib/reek/configuration.rb", "lib/reek/detector_stack.rb", "lib/reek/exceptions.reek", "lib/reek/if_context.rb", "lib/reek/method_context.rb", "lib/reek/module_context.rb", "lib/reek/name.rb", "lib/reek/object_refs.rb", "lib/reek/sexp_formatter.rb", "lib/reek/singleton_method_context.rb", "lib/reek/smell_warning.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/duplication.rb", "lib/reek/smells/feature_envy.rb", "lib/reek/smells/large_class.rb", "lib/reek/smells/long_method.rb", "lib/reek/smells/long_parameter_list.rb", "lib/reek/smells/long_yield_list.rb", "lib/reek/smells/nested_iterators.rb", "lib/reek/smells/simulated_polymorphism.rb", "lib/reek/smells/smell_detector.rb", "lib/reek/smells/uncommunicative_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/sniffer.rb", "lib/reek/stop_context.rb", "lib/reek/yield_call_context.rb", "reek.gemspec", "spec/quality/reek_source_spec.rb", "spec/reek/adapters/report_spec.rb", "spec/reek/adapters/should_reek_of_spec.rb", "spec/reek/adapters/should_reek_only_of_spec.rb", "spec/reek/adapters/should_reek_spec.rb", "spec/reek/block_context_spec.rb", "spec/reek/class_context_spec.rb", "spec/reek/code_context_spec.rb", "spec/reek/code_parser_spec.rb", "spec/reek/config_spec.rb", "spec/reek/configuration_spec.rb", "spec/reek/if_context_spec.rb", "spec/reek/method_context_spec.rb", "spec/reek/module_context_spec.rb", "spec/reek/name_spec.rb", "spec/reek/object_refs_spec.rb", "spec/reek/object_source_spec.rb", "spec/reek/singleton_method_context_spec.rb", "spec/reek/smell_warning_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/large_class_spec.rb", "spec/reek/smells/long_method_spec.rb", "spec/reek/smells/long_parameter_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_spec.rb", "spec/reek/smells/uncommunicative_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/sniffer_spec.rb", "spec/samples/all_but_one_masked/clean_one.rb", "spec/samples/all_but_one_masked/dirty.rb", "spec/samples/all_but_one_masked/masked.reek", "spec/samples/clean_due_to_masking/clean_one.rb", "spec/samples/clean_due_to_masking/clean_three.rb", "spec/samples/clean_due_to_masking/clean_two.rb", "spec/samples/clean_due_to_masking/dirty_one.rb", "spec/samples/clean_due_to_masking/dirty_two.rb", "spec/samples/clean_due_to_masking/masked.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/exceptions.reek", "spec/samples/inline.rb", "spec/samples/masked/dirty.rb", "spec/samples/masked/masked.reek", "spec/samples/mixed_results/clean_one.rb", "spec/samples/mixed_results/clean_three.rb", "spec/samples/mixed_results/clean_two.rb", "spec/samples/mixed_results/dirty_one.rb", "spec/samples/mixed_results/dirty_two.rb", "spec/samples/not_quite_masked/dirty.rb", "spec/samples/not_quite_masked/masked.reek", "spec/samples/optparse.rb", "spec/samples/overrides/masked/dirty.rb", "spec/samples/overrides/masked/lower.reek", "spec/samples/overrides/upper.reek", "spec/samples/redcloth.rb", "spec/samples/three_clean_files/clean_one.rb", "spec/samples/three_clean_files/clean_three.rb", "spec/samples/three_clean_files/clean_two.rb", "spec/samples/two_smelly_files/dirty_one.rb", "spec/samples/two_smelly_files/dirty_two.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/test.rake"]
15
+ s.files = ["History.txt", "License.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "lib/reek.rb", "lib/reek/adapters/application.rb", "lib/reek/adapters/config_file.rb", "lib/reek/adapters/core_extras.rb", "lib/reek/adapters/object_source.rb", "lib/reek/adapters/rake_task.rb", "lib/reek/adapters/report.rb", "lib/reek/adapters/source.rb", "lib/reek/adapters/spec.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.rb", "lib/reek/command_line.rb", "lib/reek/configuration.rb", "lib/reek/detector_stack.rb", "lib/reek/exceptions.reek", "lib/reek/if_context.rb", "lib/reek/method_context.rb", "lib/reek/module_context.rb", "lib/reek/name.rb", "lib/reek/object_refs.rb", "lib/reek/sexp_formatter.rb", "lib/reek/singleton_method_context.rb", "lib/reek/smell_warning.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/data_clump.rb", "lib/reek/smells/duplication.rb", "lib/reek/smells/feature_envy.rb", "lib/reek/smells/large_class.rb", "lib/reek/smells/long_method.rb", "lib/reek/smells/long_parameter_list.rb", "lib/reek/smells/long_yield_list.rb", "lib/reek/smells/nested_iterators.rb", "lib/reek/smells/simulated_polymorphism.rb", "lib/reek/smells/smell_detector.rb", "lib/reek/smells/uncommunicative_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/sniffer.rb", "lib/reek/stop_context.rb", "lib/reek/yield_call_context.rb", "reek.gemspec", "spec/quality/reek_source_spec.rb", "spec/reek/adapters/report_spec.rb", "spec/reek/adapters/should_reek_of_spec.rb", "spec/reek/adapters/should_reek_only_of_spec.rb", "spec/reek/adapters/should_reek_spec.rb", "spec/reek/block_context_spec.rb", "spec/reek/class_context_spec.rb", "spec/reek/code_context_spec.rb", "spec/reek/code_parser_spec.rb", "spec/reek/config_spec.rb", "spec/reek/configuration_spec.rb", "spec/reek/if_context_spec.rb", "spec/reek/method_context_spec.rb", "spec/reek/module_context_spec.rb", "spec/reek/name_spec.rb", "spec/reek/object_refs_spec.rb", "spec/reek/object_source_spec.rb", "spec/reek/singleton_method_context_spec.rb", "spec/reek/smell_warning_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/data_clump_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/large_class_spec.rb", "spec/reek/smells/long_method_spec.rb", "spec/reek/smells/long_parameter_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_spec.rb", "spec/reek/smells/uncommunicative_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/sniffer_spec.rb", "spec/samples/all_but_one_masked/clean_one.rb", "spec/samples/all_but_one_masked/dirty.rb", "spec/samples/all_but_one_masked/masked.reek", "spec/samples/clean_due_to_masking/clean_one.rb", "spec/samples/clean_due_to_masking/clean_three.rb", "spec/samples/clean_due_to_masking/clean_two.rb", "spec/samples/clean_due_to_masking/dirty_one.rb", "spec/samples/clean_due_to_masking/dirty_two.rb", "spec/samples/clean_due_to_masking/masked.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/exceptions.reek", "spec/samples/inline.rb", "spec/samples/masked/dirty.rb", "spec/samples/masked/masked.reek", "spec/samples/mixed_results/clean_one.rb", "spec/samples/mixed_results/clean_three.rb", "spec/samples/mixed_results/clean_two.rb", "spec/samples/mixed_results/dirty_one.rb", "spec/samples/mixed_results/dirty_two.rb", "spec/samples/not_quite_masked/dirty.rb", "spec/samples/not_quite_masked/masked.reek", "spec/samples/optparse.rb", "spec/samples/overrides/masked/dirty.rb", "spec/samples/overrides/masked/lower.reek", "spec/samples/overrides/upper.reek", "spec/samples/redcloth.rb", "spec/samples/three_clean_files/clean_one.rb", "spec/samples/three_clean_files/clean_three.rb", "spec/samples/three_clean_files/clean_two.rb", "spec/samples/two_smelly_files/dirty_one.rb", "spec/samples/two_smelly_files/dirty_two.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/test.rake"]
16
16
  s.homepage = %q{http://wiki.github.com/kevinrutherford/reek}
17
17
  s.post_install_message = %q{
18
18
  For more information on reek, see http://wiki.github.com/kevinrutherford/reek
@@ -27,7 +27,7 @@ describe BlockContext do
27
27
  end
28
28
 
29
29
  it "should not pass parameters upward" do
30
- mc = MethodContext.new(StopContext.new, s(:defn, :help))
30
+ mc = MethodContext.new(StopContext.new, s(:defn, :help, s(:args)))
31
31
  element = BlockContext.new(mc, s(s(:lasgn, :x)))
32
32
  mc.variable_names.should be_empty
33
33
  end
@@ -11,3 +11,27 @@ describe Name, 'resolving symbols' do
11
11
  res[1].should == "LargeClass"
12
12
  end
13
13
  end
14
+
15
+ describe Name do
16
+ it 'compares correctly' do
17
+ a1 = [Name.new('conts'), Name.new('p1'), Name.new('p2'), Name.new('p3')]
18
+ a2 = [Name.new('name'), Name.new('windowH'), Name.new('windowW')]
19
+ (a1 & a2).should == []
20
+ end
21
+
22
+ it do
23
+ [Name.new(:fred)].should include(Name.new(:fred))
24
+ end
25
+
26
+ it do
27
+ set = Set.new
28
+ set << Name.new(:fred)
29
+ set.should include(Name.new(:fred))
30
+ end
31
+
32
+ it do
33
+ fred = Name.new(:fred)
34
+ fred.should eql(fred)
35
+ fred.should eql(Name.new(:fred))
36
+ end
37
+ end
@@ -11,7 +11,7 @@ describe SingletonMethodContext, 'outer_name' do
11
11
  it "should report full context" do
12
12
  element = StopContext.new
13
13
  element = ModuleContext.new(element, Name.new(:mod))
14
- element = SingletonMethodContext.new(element, [:defs, [:call, nil, :a, [:arglist]], :b, nil])
14
+ element = SingletonMethodContext.new(element, s(:defs, s(:call, nil, :a, s(:arglist)), :b, s(:args)))
15
15
  element.outer_name.should match(/mod::a\.b/)
16
16
  end
17
17
  end
@@ -0,0 +1,87 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ require 'reek/smells/data_clump'
4
+
5
+ include Reek::Smells
6
+
7
+ describe DataClump do
8
+ it 'should not report small parameter sets' do
9
+ src = <<EOS
10
+ class Scrunch
11
+ def first(pa) @field == :sym ? 0 : 3; end
12
+ def second(pa) @field == :sym; end
13
+ def third(pa) pa - pb + @fred; end
14
+ end
15
+ EOS
16
+
17
+ src.should_not reek
18
+ end
19
+
20
+ it 'should report 3 identical pairs in a class' do
21
+ src = <<EOS
22
+ class Scrunch
23
+ def first(pa, pb) @field == :sym ? 0 : 3; end
24
+ def second(pa, pb) @field == :sym; end
25
+ def third(pa, pb) pa - pb + @fred; end
26
+ end
27
+ EOS
28
+
29
+ src.should reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
30
+ end
31
+
32
+ it 'should report 3 swapped pairs in a class' do
33
+ src = <<EOS
34
+ class Scrunch
35
+ def one(pa, pb) @field == :sym ? 0 : 3; end
36
+ def two(pb, pa) @field == :sym; end
37
+ def tri(pa, pb) pa - pb + @fred; end
38
+ end
39
+ EOS
40
+
41
+ src.should reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
42
+ end
43
+
44
+ it 'should report 3 identical parameter sets in a class' do
45
+ src = <<EOS
46
+ class Scrunch
47
+ def first(pa, pb, pc) @field == :sym ? 0 : 3; end
48
+ def second(pa, pb, pc) @field == :sym; end
49
+ def third(pa, pb, pc) pa - pb + @fred; end
50
+ end
51
+ EOS
52
+
53
+ src.should reek_of(:DataClump, /\[pa, pb, pc\]/, /3 methods/)
54
+ src.should_not reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
55
+ src.should_not reek_of(:DataClump, /\[pa, pc\]/, /3 methods/)
56
+ src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
57
+ end
58
+
59
+ it 'should recognise re-ordered identical parameter sets' do
60
+ src = <<EOS
61
+ class Scrunch
62
+ def first(pb, pa, pc) @field == :sym ? 0 : 3; end
63
+ def second(pc, pb, pa) @field == :sym; end
64
+ def third(pa, pb, pc) pa - pb + @fred; end
65
+ end
66
+ EOS
67
+
68
+ src.should reek_of(:DataClump, /\[pa, pb, pc\]/, /3 methods/)
69
+ src.should_not reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
70
+ src.should_not reek_of(:DataClump, /\[pa, pc\]/, /3 methods/)
71
+ src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
72
+ end
73
+
74
+ it 'should count only identical parameter sets' do
75
+ src = <<EOS
76
+ class RedCloth
77
+ def fa(p1, p2, p3, conten) end
78
+ def fb(p1, p2, p3, conten) end
79
+ def fc(name, windowW, windowH) end
80
+ end
81
+ EOS
82
+
83
+ src.should_not reek_of(:DataClump)
84
+ end
85
+
86
+ # TODO: include singleton methods in the calcs
87
+ end
@@ -39,7 +39,7 @@ describe LargeClass, 'checking Class objects' do
39
39
  it 'should not report class with 10 ivars' do
40
40
  pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
41
41
  class ManyIvars
42
- def method
42
+ def meth
43
43
  @vara = @varb = @varc = @vard = @vare
44
44
  @varf = @varg = @varh = @vari = @varj
45
45
  end
@@ -125,12 +125,12 @@ describe UncommunicativeName, '#examine' do
125
125
  end
126
126
 
127
127
  it 'should return true when reporting a smell' do
128
- mc = MethodContext.new(StopContext.new, [:defn, :x, nil])
128
+ mc = MethodContext.new(StopContext.new, s(:defn, :x, s(:args)))
129
129
  @uc.examine(mc).should == true
130
130
  end
131
131
 
132
132
  it 'should return false when not reporting a smell' do
133
- mc = MethodContext.new(StopContext.new, [:defn, :not_bad, nil])
133
+ mc = MethodContext.new(StopContext.new, s(:defn, :not_bad, s(:args)))
134
134
  @uc.examine(mc).should == false
135
135
  end
136
136
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kevinrutherford-reek
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3.14
4
+ version: 1.1.3.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Rutherford
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-20 00:00:00 -07:00
12
+ date: 2009-09-03 00:00:00 -07:00
13
13
  default_executable: reek
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -93,6 +93,7 @@ files:
93
93
  - lib/reek/singleton_method_context.rb
94
94
  - lib/reek/smell_warning.rb
95
95
  - lib/reek/smells/control_couple.rb
96
+ - lib/reek/smells/data_clump.rb
96
97
  - lib/reek/smells/duplication.rb
97
98
  - lib/reek/smells/feature_envy.rb
98
99
  - lib/reek/smells/large_class.rb
@@ -128,6 +129,7 @@ files:
128
129
  - spec/reek/singleton_method_context_spec.rb
129
130
  - spec/reek/smell_warning_spec.rb
130
131
  - spec/reek/smells/control_couple_spec.rb
132
+ - spec/reek/smells/data_clump_spec.rb
131
133
  - spec/reek/smells/duplication_spec.rb
132
134
  - spec/reek/smells/feature_envy_spec.rb
133
135
  - spec/reek/smells/large_class_spec.rb
@@ -179,7 +181,6 @@ files:
179
181
  - tasks/test.rake
180
182
  has_rdoc: false
181
183
  homepage: http://wiki.github.com/kevinrutherford/reek
182
- licenses:
183
184
  post_install_message: |
184
185
 
185
186
  For more information on reek, see http://wiki.github.com/kevinrutherford/reek
@@ -204,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
204
205
  requirements: []
205
206
 
206
207
  rubyforge_project: reek
207
- rubygems_version: 1.3.5
208
+ rubygems_version: 1.2.0
208
209
  signing_key:
209
210
  specification_version: 3
210
211
  summary: Code smell detector for Ruby