kevinrutherford-reek 1.1.3.14 → 1.1.3.15

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.
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