reek 1.2.1 → 1.2.3

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 (68) hide show
  1. data/History.txt +10 -0
  2. data/Rakefile +0 -1
  3. data/config/defaults.reek +8 -6
  4. data/features/masking_smells.feature +9 -9
  5. data/features/options.feature +2 -2
  6. data/features/profile.feature +34 -0
  7. data/features/rake_task.feature +74 -0
  8. data/features/reports.feature +1 -1
  9. data/features/samples.feature +4 -4
  10. data/features/stdin.feature +1 -1
  11. data/features/step_definitions/reek_steps.rb +11 -7
  12. data/features/support/env.rb +26 -18
  13. data/lib/reek/adapters/application.rb +9 -2
  14. data/lib/reek/adapters/command_line.rb +2 -2
  15. data/lib/reek/adapters/core_extras.rb +0 -8
  16. data/lib/reek/adapters/source.rb +4 -1
  17. data/lib/reek/adapters/spec.rb +1 -4
  18. data/lib/reek/block_context.rb +14 -8
  19. data/lib/reek/class_context.rb +6 -55
  20. data/lib/reek/code_context.rb +10 -0
  21. data/lib/reek/code_parser.rb +26 -53
  22. data/lib/reek/configuration.rb +12 -6
  23. data/lib/reek/if_context.rb +2 -3
  24. data/lib/reek/method_context.rb +8 -12
  25. data/lib/reek/module_context.rb +35 -16
  26. data/lib/reek/name.rb +2 -0
  27. data/lib/reek/object_refs.rb +0 -3
  28. data/lib/reek/sexp_formatter.rb +0 -2
  29. data/lib/reek/smells/attribute.rb +48 -0
  30. data/lib/reek/smells/class_variable.rb +17 -4
  31. data/lib/reek/smells/control_couple.rb +3 -10
  32. data/lib/reek/smells/data_clump.rb +10 -10
  33. data/lib/reek/smells/feature_envy.rb +1 -8
  34. data/lib/reek/smells/large_class.rb +3 -3
  35. data/lib/reek/smells/simulated_polymorphism.rb +17 -3
  36. data/lib/reek/smells/smell_detector.rb +11 -2
  37. data/lib/reek/smells/utility_function.rb +1 -1
  38. data/lib/reek/sniffer.rb +2 -8
  39. data/lib/reek/stop_context.rb +1 -1
  40. data/lib/reek/tree_dresser.rb +74 -0
  41. data/lib/reek.rb +1 -1
  42. data/reek.gemspec +3 -3
  43. data/spec/reek/adapters/should_reek_of_spec.rb +7 -1
  44. data/spec/reek/block_context_spec.rb +6 -6
  45. data/spec/reek/class_context_spec.rb +2 -23
  46. data/spec/reek/code_context_spec.rb +149 -67
  47. data/spec/reek/code_parser_spec.rb +35 -51
  48. data/spec/reek/method_context_spec.rb +4 -4
  49. data/spec/reek/singleton_method_context_spec.rb +1 -1
  50. data/spec/reek/smells/attribute_spec.rb +26 -0
  51. data/spec/reek/smells/behaves_like_variable_detector.rb +39 -0
  52. data/spec/reek/smells/class_variable_spec.rb +77 -43
  53. data/spec/reek/smells/control_couple_spec.rb +1 -1
  54. data/spec/reek/smells/data_clump_spec.rb +31 -13
  55. data/spec/reek/smells/feature_envy_spec.rb +1 -1
  56. data/spec/reek/smells/large_class_spec.rb +32 -69
  57. data/spec/reek/smells/long_parameter_list_spec.rb +0 -12
  58. data/spec/reek/smells/simulated_polymorphism_spec.rb +66 -18
  59. data/spec/reek/smells/utility_function_spec.rb +0 -21
  60. data/spec/reek/sniffer_spec.rb +1 -0
  61. data/spec/samples/not_quite_masked/dirty.rb +2 -0
  62. data/spec/spec_helper.rb +1 -1
  63. data/tasks/reek.rake +1 -1
  64. data/tasks/test.rake +3 -4
  65. metadata +8 -5
  66. data/lib/reek/adapters/object_source.rb +0 -52
  67. data/lib/reek/exceptions.reek +0 -20
  68. data/spec/quality/reek_source_spec.rb +0 -15
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'sexp'
3
2
  require 'reek/block_context'
4
3
  require 'reek/class_context'
@@ -9,31 +8,12 @@ require 'reek/method_context'
9
8
  require 'reek/singleton_method_context'
10
9
  require 'reek/yield_call_context'
11
10
 
12
- #
13
- # Extensions to +Sexp+ to allow +CodeParser+ to navigate the abstract
14
- # syntax tree more easily.
15
- #
16
- class Sexp
17
- def children
18
- find_all { |item| Sexp === item }
19
- end
20
-
21
- def is_language_node?
22
- first.class == Symbol
23
- end
24
-
25
- def has_type?(type)
26
- is_language_node? and first == type
27
- end
28
- end
29
-
30
11
  module Reek
31
-
12
+ #
13
+ # Traverses a Sexp abstract syntax tree and fires events whenever
14
+ # it encounters specific node types.
15
+ #
32
16
  class CodeParser
33
-
34
- #
35
- # Creates a new Ruby code checker.
36
- #
37
17
  def initialize(sniffer, ctx = StopContext.new)
38
18
  @sniffer = sniffer
39
19
  @element = ctx
@@ -50,42 +30,29 @@ module Reek
50
30
  exp[0..-1].each { |sub| process(sub) if Array === sub }
51
31
  end
52
32
 
53
- def process_module(exp)
54
- scope = ModuleContext.create(@element, exp)
55
- push(scope) do
56
- process_default(exp)
57
- check_smells(:module)
58
- end
59
- scope
60
- end
61
-
62
- def process_class(exp)
63
- scope = ClassContext.create(@element, exp)
33
+ def do_module_or_class(exp, context_class)
34
+ scope = context_class.create(@element, exp)
64
35
  push(scope) do
65
36
  process_default(exp) unless @element.is_struct?
66
- check_smells(:class)
37
+ check_smells(exp[0])
67
38
  end
68
39
  scope
69
40
  end
70
41
 
71
- def process_cvar(exp)
72
- @element.record_class_variable(exp[1])
73
- end
74
-
75
- def process_cvasgn(exp)
76
- process_cvar(exp)
42
+ def process_module(exp)
43
+ do_module_or_class(exp, ModuleContext)
77
44
  end
78
45
 
79
- def process_cvdecl(exp)
80
- process_cvar(exp)
46
+ def process_class(exp)
47
+ do_module_or_class(exp, ClassContext)
81
48
  end
82
49
 
83
50
  def process_defn(exp)
84
- handle_context(MethodContext, :defn, exp)
51
+ handle_context(MethodContext, exp[0], exp)
85
52
  end
86
53
 
87
54
  def process_defs(exp)
88
- handle_context(SingletonMethodContext, :defs, exp)
55
+ handle_context(SingletonMethodContext, exp[0], exp)
89
56
  end
90
57
 
91
58
  def process_args(exp) end
@@ -105,7 +72,12 @@ module Reek
105
72
 
106
73
  def process_iter(exp)
107
74
  process(exp[1])
108
- handle_context(BlockContext, :iter, exp[2..-1])
75
+ scope = BlockContext.new(@element, exp)
76
+ push(scope) do
77
+ process_default(exp[2..-1])
78
+ check_smells(exp[0])
79
+ end
80
+ scope
109
81
  end
110
82
 
111
83
  def process_block(exp)
@@ -114,11 +86,12 @@ module Reek
114
86
  end
115
87
 
116
88
  def process_yield(exp)
117
- handle_context(YieldCallContext, :yield, exp)
89
+ handle_context(YieldCallContext, exp[0], exp)
118
90
  end
119
91
 
120
92
  def process_call(exp)
121
93
  @element.record_call_to(exp)
94
+ @element.check_for_attribute_declaration(exp)
122
95
  process_default(exp)
123
96
  end
124
97
 
@@ -135,10 +108,9 @@ module Reek
135
108
  end
136
109
 
137
110
  def process_if(exp)
138
- @element.record_conditional(exp[1])
139
111
  count_clause(exp[2])
140
112
  count_clause(exp[3])
141
- handle_context(IfContext, :if, exp)
113
+ handle_context(IfContext, exp[0], exp)
142
114
  @element.count_statements(-1)
143
115
  end
144
116
 
@@ -154,12 +126,14 @@ module Reek
154
126
 
155
127
  def process_for(exp)
156
128
  count_clause(exp[3])
157
- process_case(exp)
129
+ process_default(exp)
130
+ @element.count_statements(-1)
158
131
  end
159
132
 
160
133
  def process_rescue(exp)
161
134
  count_clause(exp[1])
162
- process_case(exp)
135
+ process_default(exp)
136
+ @element.count_statements(-1)
163
137
  end
164
138
 
165
139
  def process_resbody(exp)
@@ -167,7 +141,6 @@ module Reek
167
141
  end
168
142
 
169
143
  def process_case(exp)
170
- @element.record_conditional(exp[1])
171
144
  process_default(exp)
172
145
  @element.count_statements(-1)
173
146
  end
@@ -13,19 +13,25 @@ module Reek
13
13
  # for other values in the current smell detector's configuration.
14
14
  OVERRIDES_KEY = 'overrides'
15
15
 
16
- attr_reader :hash
17
-
18
16
  def initialize(hash)
19
- @hash = hash
17
+ @options = hash
18
+ end
19
+
20
+ def adopt!(options)
21
+ @options.adopt!(options)
22
+ end
23
+
24
+ def deep_copy
25
+ @options.deep_copy # SMELL: Open Secret -- returns a Hash
20
26
  end
21
27
 
22
28
  # SMELL: Getter
23
29
  def enabled?
24
- @hash[ENABLED_KEY]
30
+ @options[ENABLED_KEY]
25
31
  end
26
32
 
27
33
  def overrides_for(context)
28
- Overrides.new(@hash.fetch(OVERRIDES_KEY, {})).for_context(context)
34
+ Overrides.new(@options.fetch(OVERRIDES_KEY, {})).for_context(context)
29
35
  end
30
36
 
31
37
  # Retrieves the value, if any, for the given +key+.
@@ -34,7 +40,7 @@ module Reek
34
40
  #
35
41
  def value(key, context, fall_back)
36
42
  overrides_for(context).each { |conf| return conf[key] if conf.has_key?(key) }
37
- return @hash.fetch(key, fall_back)
43
+ return @options.fetch(key, fall_back)
38
44
  end
39
45
  end
40
46
 
@@ -5,8 +5,7 @@ module Reek
5
5
  attr_reader :if_expr
6
6
 
7
7
  def initialize(outer, exp)
8
- @outer = outer
9
- @exp = exp
8
+ super
10
9
  @if_expr = exp[1]
11
10
  end
12
11
 
@@ -18,7 +17,7 @@ module Reek
18
17
  @outer.outer_name
19
18
  end
20
19
 
21
- def to_s
20
+ def to_s # SMELL: should be unnecessary :(
22
21
  @outer.to_s
23
22
  end
24
23
  end
@@ -1,5 +1,5 @@
1
1
  require 'reek/name'
2
- require 'reek/code_context'
2
+ require 'reek/block_context'
3
3
  require 'reek/object_refs'
4
4
 
5
5
  class Array
@@ -51,7 +51,7 @@ module Reek
51
51
  end
52
52
  end
53
53
 
54
- class MethodContext < CodeContext
54
+ class MethodContext < VariableContainer
55
55
  attr_reader :parameters
56
56
  attr_reader :calls
57
57
  attr_reader :refs
@@ -62,7 +62,6 @@ module Reek
62
62
  @parameters = exp[exp[0] == :defn ? 2 : 3] # SMELL: SimulatedPolymorphism
63
63
  @parameters ||= []
64
64
  @parameters.extend(MethodParameters)
65
- @local_variables = []
66
65
  @name = Name.new(exp[1])
67
66
  @num_statements = 0
68
67
  @calls = Hash.new(0)
@@ -85,6 +84,11 @@ module Reek
85
84
 
86
85
  def record_call_to(exp)
87
86
  @calls[exp] += 1
87
+ record_receiver(exp)
88
+ check_for_attribute_declaration(exp)
89
+ end
90
+
91
+ def record_receiver(exp)
88
92
  receiver, meth = exp[1..2]
89
93
  receiver ||= [:self]
90
94
  case receiver[0]
@@ -109,25 +113,17 @@ module Reek
109
113
  @depends_on_self = true
110
114
  end
111
115
 
112
- def record_local_variable(sym)
113
- @local_variables << Name.new(sym)
114
- end
115
-
116
116
  def outer_name
117
117
  "#{@outer.outer_name}#{@name}/"
118
118
  end
119
119
 
120
- def to_s
121
- "#{@outer.outer_name}#{@name}"
122
- end
123
-
124
120
  def envious_receivers
125
121
  return [] if @refs.self_is_max?
126
122
  @refs.max_keys
127
123
  end
128
124
 
129
125
  def variable_names
130
- @parameters.names + @local_variables
126
+ @parameters.names + @local_variables.to_a
131
127
  end
132
128
  end
133
129
  end
@@ -1,25 +1,30 @@
1
1
  require 'reek/code_context'
2
+ require 'reek/code_parser'
3
+ require 'reek/sniffer'
2
4
 
3
5
  module Reek
4
6
  class ModuleContext < CodeContext
5
7
 
6
- def ModuleContext.create(outer, exp)
7
- res = Name.resolve(exp[1], outer)
8
- ModuleContext.new(res[0], res[1])
9
- end
8
+ class << self
9
+ def create(outer, exp)
10
+ res = Name.resolve(exp[1], outer)
11
+ new(res[0], res[1], exp)
12
+ end
10
13
 
11
- def ModuleContext.from_s(src)
12
- source = src.to_reek_source
13
- sniffer = Sniffer.new(source)
14
- CodeParser.new(sniffer).process_module(source.syntax_tree)
14
+ def from_s(src)
15
+ source = src.to_reek_source
16
+ sniffer = Sniffer.new(source)
17
+ CodeParser.new(sniffer).do_module_or_class(source.syntax_tree, self)
18
+ end
15
19
  end
16
20
 
17
- attr_reader :class_variables
21
+ attr_reader :attributes
18
22
 
19
- def initialize(outer, name)
20
- super(outer, nil)
23
+ def initialize(outer, name, exp)
24
+ super(outer, exp)
21
25
  @name = name
22
- @class_variables = Set.new
26
+ @attributes = Set.new
27
+ @parsed_methods = []
23
28
  end
24
29
 
25
30
  def myself
@@ -31,12 +36,26 @@ module Reek
31
36
  @myself.const_or_nil(modname.to_s)
32
37
  end
33
38
 
34
- def outer_name
35
- "#{@outer.outer_name}#{@name}::"
39
+ def parameterized_methods(min_clump_size)
40
+ @parsed_methods.select {|meth| meth.parameters.length >= min_clump_size }
36
41
  end
37
42
 
38
- def record_class_variable(cvar)
39
- @class_variables << Name.new(cvar)
43
+ def record_attribute(attr)
44
+ @attributes << Name.new(attr)
45
+ end
46
+
47
+ def record_method(meth)
48
+ @parsed_methods << meth
49
+ end
50
+
51
+ def check_for_attribute_declaration(exp)
52
+ if [:attr, :attr_reader, :attr_writer, :attr_accessor].include? exp[2]
53
+ exp[3][1..-1].each {|arg| record_attribute(arg[1])}
54
+ end
55
+ end
56
+
57
+ def outer_name
58
+ "#{@outer.outer_name}#{@name}::"
40
59
  end
41
60
 
42
61
  def variable_names
data/lib/reek/name.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'ruby_parser'
2
+
1
3
  module Reek
2
4
  class Name
3
5
  include Comparable
@@ -1,6 +1,3 @@
1
- require 'rubygems'
2
- require 'sexp_processor'
3
-
4
1
  module Reek
5
2
 
6
3
  class ObjectRefs # :nodoc:
@@ -1,5 +1,3 @@
1
- require 'rubygems'
2
- require 'ruby_parser'
3
1
  require 'ruby2ruby'
4
2
 
5
3
  module Reek
@@ -0,0 +1,48 @@
1
+ require 'reek/smells/smell_detector'
2
+
3
+ module Reek
4
+ module Smells
5
+
6
+ #
7
+ # A class that publishes a getter or setter for an instance variable
8
+ # invites client classes to become too intimate with its inner workings,
9
+ # and in particular with its representation of state.
10
+ #
11
+ # Currently this detector raises a warning for every +attr+,
12
+ # +attr_reader+, +attr_writer+ and +attr_accessor+ -- including those
13
+ # that are private.
14
+ #
15
+ # TODO:
16
+ # * eliminate private attributes
17
+ # * catch attributes declared "by hand"
18
+ #
19
+ class Attribute < SmellDetector
20
+
21
+ def self.contexts # :nodoc:
22
+ [:class, :module]
23
+ end
24
+
25
+ def self.default_config
26
+ super.adopt(SmellConfiguration::ENABLED_KEY => false)
27
+ end
28
+
29
+ def initialize(config = Attribute.default_config)
30
+ super(config)
31
+ end
32
+
33
+ #
34
+ # Checks whether the given class declares any attributes.
35
+ # Remembers any smells found.
36
+ #
37
+ def examine_context(mod)
38
+ # SMELL: Duplication
39
+ # MethodContext, ClassContext and ModuleContext all know which
40
+ # calls constitute attribute declarations. Need a method on
41
+ # ModuleContext: each_public_call.select [names] {...}
42
+ mod.attributes.each do |attr|
43
+ found(mod, "declares the attribute #{attr}")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -18,14 +18,27 @@ module Reek
18
18
  end
19
19
 
20
20
  #
21
- # Checks whether the given class declares any class variables.
21
+ # Checks whether the given class or module declares any class variables.
22
22
  # Remembers any smells found.
23
23
  #
24
- def examine_context(klass)
25
- klass.class_variables.each do |cvar|
26
- found(klass, "declares the class variable #{cvar}")
24
+ def examine_context(mod)
25
+ class_variables_in(mod).each do |cvar_name|
26
+ found(mod, "declares the class variable #{cvar_name}")
27
27
  end
28
28
  end
29
+
30
+ #
31
+ # Collects the names of the class variables declared and/or used
32
+ # in the given module.
33
+ #
34
+ def class_variables_in(mod)
35
+ result = Set.new
36
+ collector = proc { |cvar_node| result << cvar_node.name }
37
+ [:cvar, :cvasgn, :cvdecl].each do |stmt_type|
38
+ mod.each(stmt_type, [:class, :module], &collector)
39
+ end
40
+ result
41
+ end
29
42
  end
30
43
  end
31
44
  end
@@ -34,19 +34,12 @@ module Reek
34
34
  # because it includes at least two different code paths.
35
35
  #
36
36
  class ControlCouple < SmellDetector
37
+ include ExcludeInitialize
37
38
 
38
39
  def self.contexts # :nodoc:
39
40
  [:if]
40
41
  end
41
42
 
42
- def self.default_config
43
- super.adopt(EXCLUDE_KEY => ['initialize'])
44
- end
45
-
46
- def initialize(config = ControlCouple.default_config)
47
- super
48
- end
49
-
50
43
  #
51
44
  # Checks whether the given conditional statement relies on a control couple.
52
45
  # Remembers any smells found.
@@ -56,8 +49,8 @@ module Reek
56
49
  # SMELL: Duplication
57
50
  # This smell is reported once for each conditional that tests the
58
51
  # same parameter. Which means that the same smell can recur within
59
- # a single sniffer. Which in turn means that the sniffer can't count
60
- # its smells without knowing which are duplicates.
52
+ # a single detector. Which in turn means that SmellDetector must
53
+ # use a Set to hold smells found.
61
54
  found(cond, "is controlled by argument #{SexpFormatter.format(cond.if_expr)}")
62
55
  end
63
56
  end
@@ -20,7 +20,7 @@ module Reek
20
20
  class DataClump < SmellDetector
21
21
 
22
22
  def self.contexts # :nodoc:
23
- [:class]
23
+ [:class, :module]
24
24
  end
25
25
 
26
26
  # The name of the config field that sets the maximum allowed
@@ -44,14 +44,14 @@ module Reek
44
44
  end
45
45
 
46
46
  #
47
- # Checks the given ClassContext for multiple identical conditional tests.
47
+ # Checks the given class or module for multiple identical parameter sets.
48
48
  # Remembers any smells found.
49
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")
50
+ def examine_context(ctx)
51
+ max_copies = value(MAX_COPIES_KEY, ctx, DEFAULT_MAX_COPIES)
52
+ min_clump_size = value(MIN_CLUMP_SIZE_KEY, ctx, DEFAULT_MIN_CLUMP_SIZE)
53
+ MethodGroup.new(ctx, min_clump_size, max_copies).clumps.each do |clump, occurs|
54
+ found(ctx, "takes parameters #{DataClump.print_clump(clump)} to #{occurs} methods")
55
55
  end
56
56
  end
57
57
 
@@ -68,15 +68,15 @@ module Reek
68
68
  methods.map {|meth| meth.parameters.names.sort}.intersection
69
69
  end
70
70
 
71
- def initialize(klass, min_clump_size, max_copies)
72
- @klass = klass
71
+ def initialize(ctx, min_clump_size, max_copies)
72
+ @ctx = ctx
73
73
  @min_clump_size = min_clump_size
74
74
  @max_copies = max_copies
75
75
  end
76
76
 
77
77
  def clumps
78
78
  results = Hash.new(0)
79
- @klass.parameterized_methods(@min_clump_size).bounded_power_set(@max_copies).each do |methods|
79
+ @ctx.parameterized_methods(@min_clump_size).bounded_power_set(@max_copies).each do |methods|
80
80
  clump = MethodGroup.intersection_of_parameters_of(methods)
81
81
  if clump.length >= @min_clump_size
82
82
  results[clump] = [methods.length, results[clump]].max
@@ -33,14 +33,7 @@ module Reek
33
33
  # often than it refers to (ie. send messages to) some other object.
34
34
  #
35
35
  class FeatureEnvy < SmellDetector
36
-
37
- def self.default_config
38
- super.adopt(EXCLUDE_KEY => ['initialize'])
39
- end
40
-
41
- def initialize(config = FeatureEnvy.default_config)
42
- super
43
- end
36
+ include ExcludeInitialize
44
37
 
45
38
  #
46
39
  # Checks whether the given +context+ includes any code fragment that
@@ -45,9 +45,9 @@ module Reek
45
45
  end
46
46
 
47
47
  def check_num_methods(klass) # :nodoc:
48
- count = klass.num_methods
49
- return if count <= value(MAX_ALLOWED_METHODS_KEY, klass, DEFAULT_MAX_METHODS)
50
- found(klass, "has at least #{count} methods")
48
+ actual = klass.each(:defn, [:class, :module]).length
49
+ return if actual <= value(MAX_ALLOWED_METHODS_KEY, klass, DEFAULT_MAX_METHODS)
50
+ found(klass, "has at least #{actual} methods")
51
51
  end
52
52
 
53
53
  def check_num_ivars(klass) # :nodoc:
@@ -47,12 +47,26 @@ module Reek
47
47
  # Remembers any smells found.
48
48
  #
49
49
  def examine_context(klass)
50
- counts = Hash.new(0)
51
- klass.conditionals.each {|cond| counts[cond] += 1}
52
- counts.each do |key, val|
50
+ conditional_counts(klass).each do |key, val|
53
51
  found(klass, "tests #{SexpFormatter.format(key)} at least #{val} times") if val > value(MAX_IDENTICAL_IFS_KEY, klass, DEFAULT_MAX_IFS)
54
52
  end
55
53
  end
54
+
55
+ #
56
+ # Returns a Hash listing all of the conditional expressions in
57
+ # the given syntax tree together with the number of times each
58
+ # occurs. Ignores nested classes and modules.
59
+ #
60
+ def conditional_counts(klass)
61
+ result = Hash.new(0)
62
+ collector = proc { |node|
63
+ condition = node.condition
64
+ result[condition] += 1 unless condition == s(:call, nil, :block_given?, s(:arglist))
65
+ }
66
+ klass.each(:if, [:class, :module], &collector)
67
+ klass.each(:case, [:class, :module], &collector)
68
+ result
69
+ end
56
70
  end
57
71
  end
58
72
  end
@@ -10,6 +10,15 @@ end
10
10
  module Reek
11
11
  module Smells
12
12
 
13
+ module ExcludeInitialize
14
+ def self.default_config
15
+ super.adopt(EXCLUDE_KEY => ['initialize'])
16
+ end
17
+ def initialize(config = self.class.default_config)
18
+ super
19
+ end
20
+ end
21
+
13
22
  class SmellDetector
14
23
 
15
24
  # The name of the config field that lists the names of code contexts
@@ -70,11 +79,11 @@ module Reek
70
79
  end
71
80
 
72
81
  def configure_with(config)
73
- @config.hash.adopt!(config)
82
+ @config.adopt!(config)
74
83
  end
75
84
 
76
85
  def copy
77
- self.class.new(@config.hash.deep_copy)
86
+ self.class.new(@config.deep_copy)
78
87
  end
79
88
 
80
89
  def supersede_with(config)
@@ -30,7 +30,7 @@ module Reek
30
30
  super.adopt(HELPER_CALLS_LIMIT_KEY => DEFAULT_HELPER_CALLS_LIMIT)
31
31
  end
32
32
 
33
- def initialize(config = Duplication.default_config)
33
+ def initialize(config = UtilityFunction.default_config)
34
34
  super(config)
35
35
  end
36
36
 
data/lib/reek/sniffer.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'reek/detector_stack'
2
2
 
3
3
  # SMELL: Duplication -- all these should be found automagically
4
+ require 'reek/smells/attribute'
4
5
  require 'reek/smells/class_variable'
5
6
  require 'reek/smells/control_couple'
6
7
  require 'reek/smells/data_clump'
@@ -49,6 +50,7 @@ module Reek
49
50
  def self.smell_classes
50
51
  # SMELL: Duplication -- these should be loaded by listing the files
51
52
  [
53
+ Smells::Attribute,
52
54
  Smells::ClassVariable,
53
55
  Smells::ControlCouple,
54
56
  Smells::DataClump,
@@ -123,10 +125,6 @@ module Reek
123
125
  stack.has_smell?(patterns)
124
126
  end
125
127
 
126
- def smells_only_of?(klass, patterns)
127
- num_smells == 1 and has_smell?(klass, patterns)
128
- end
129
-
130
128
  def sniff
131
129
  self
132
130
  end
@@ -173,10 +171,6 @@ private
173
171
  total
174
172
  end
175
173
 
176
- def smells_only_of?(klass, patterns)
177
- num_smells == 1 and has_smell?(klass, patterns)
178
- end
179
-
180
174
  def sniff
181
175
  self
182
176
  end
@@ -5,11 +5,11 @@ module Reek
5
5
  @refs = ObjectRefs.new
6
6
  @myself = Object
7
7
  end
8
+
8
9
  def method_missing(method, *args)
9
10
  nil
10
11
  end
11
12
 
12
-
13
13
  def count_statements(num)
14
14
  0
15
15
  end