reek 1.2.6 → 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. data/.yardopts +10 -0
  2. data/History.txt +20 -0
  3. data/README.md +90 -0
  4. data/bin/reek +2 -2
  5. data/config/defaults.reek +34 -4
  6. data/features/masking_smells.feature +35 -15
  7. data/features/options.feature +2 -0
  8. data/features/rake_task.feature +11 -18
  9. data/features/reports.feature +13 -15
  10. data/features/samples.feature +90 -105
  11. data/features/stdin.feature +3 -6
  12. data/features/step_definitions/reek_steps.rb +8 -4
  13. data/features/support/env.rb +2 -3
  14. data/features/yaml.feature +124 -0
  15. data/lib/reek.rb +8 -4
  16. data/lib/reek/cli/application.rb +46 -0
  17. data/lib/reek/cli/command_line.rb +106 -0
  18. data/lib/reek/cli/help_command.rb +18 -0
  19. data/lib/reek/cli/reek_command.rb +37 -0
  20. data/lib/reek/cli/report.rb +91 -0
  21. data/lib/reek/cli/version_command.rb +19 -0
  22. data/lib/reek/cli/yaml_command.rb +32 -0
  23. data/lib/reek/core/block_context.rb +18 -0
  24. data/lib/reek/core/class_context.rb +23 -0
  25. data/lib/reek/core/code_context.rb +72 -0
  26. data/lib/reek/core/code_parser.rb +192 -0
  27. data/lib/reek/core/detector_stack.rb +29 -0
  28. data/lib/reek/core/masking_collection.rb +46 -0
  29. data/lib/reek/core/method_context.rb +132 -0
  30. data/lib/reek/core/module_context.rb +64 -0
  31. data/lib/reek/{object_refs.rb → core/object_refs.rb} +8 -6
  32. data/lib/reek/{singleton_method_context.rb → core/singleton_method_context.rb} +10 -5
  33. data/lib/reek/core/smell_configuration.rb +66 -0
  34. data/lib/reek/core/sniffer.rb +110 -0
  35. data/lib/reek/core/stop_context.rb +26 -0
  36. data/lib/reek/examiner.rb +88 -0
  37. data/lib/reek/rake/task.rb +124 -0
  38. data/lib/reek/smell_warning.rb +69 -13
  39. data/lib/reek/smells.rb +29 -0
  40. data/lib/reek/smells/attribute.rb +13 -14
  41. data/lib/reek/smells/boolean_parameter.rb +33 -0
  42. data/lib/reek/smells/class_variable.rb +8 -6
  43. data/lib/reek/smells/control_couple.rb +33 -17
  44. data/lib/reek/smells/data_clump.rb +10 -6
  45. data/lib/reek/smells/duplication.rb +24 -14
  46. data/lib/reek/smells/feature_envy.rb +11 -6
  47. data/lib/reek/smells/irresponsible_module.rb +28 -0
  48. data/lib/reek/smells/large_class.rb +9 -7
  49. data/lib/reek/smells/long_method.rb +6 -5
  50. data/lib/reek/smells/long_parameter_list.rb +11 -9
  51. data/lib/reek/smells/long_yield_list.rb +37 -7
  52. data/lib/reek/smells/nested_iterators.rb +34 -9
  53. data/lib/reek/smells/simulated_polymorphism.rb +15 -11
  54. data/lib/reek/smells/smell_detector.rb +24 -12
  55. data/lib/reek/smells/uncommunicative_method_name.rb +76 -0
  56. data/lib/reek/smells/uncommunicative_module_name.rb +76 -0
  57. data/lib/reek/smells/{uncommunicative_name.rb → uncommunicative_parameter_name.rb} +14 -26
  58. data/lib/reek/smells/uncommunicative_variable_name.rb +90 -0
  59. data/lib/reek/smells/utility_function.rb +33 -9
  60. data/lib/reek/source.rb +18 -0
  61. data/lib/reek/source/code_comment.rb +19 -0
  62. data/lib/reek/source/config_file.rb +72 -0
  63. data/lib/reek/source/core_extras.rb +46 -0
  64. data/lib/reek/source/sexp_formatter.rb +16 -0
  65. data/lib/reek/source/source_code.rb +44 -0
  66. data/lib/reek/source/source_file.rb +32 -0
  67. data/lib/reek/source/source_locator.rb +36 -0
  68. data/lib/reek/source/tree_dresser.rb +128 -0
  69. data/lib/reek/spec.rb +51 -0
  70. data/lib/reek/spec/should_reek.rb +34 -0
  71. data/lib/reek/spec/should_reek_of.rb +37 -0
  72. data/lib/reek/spec/should_reek_only_of.rb +36 -0
  73. data/reek.gemspec +5 -5
  74. data/spec/reek/{help_command_spec.rb → cli/help_command_spec.rb} +3 -4
  75. data/spec/reek/{reek_command_spec.rb → cli/reek_command_spec.rb} +8 -7
  76. data/spec/reek/cli/report_spec.rb +26 -0
  77. data/spec/reek/{version_command_spec.rb → cli/version_command_spec.rb} +3 -3
  78. data/spec/reek/cli/yaml_command_spec.rb +47 -0
  79. data/spec/reek/core/block_context_spec.rb +26 -0
  80. data/spec/reek/core/class_context_spec.rb +53 -0
  81. data/spec/reek/{code_context_spec.rb → core/code_context_spec.rb} +15 -37
  82. data/spec/reek/{code_parser_spec.rb → core/code_parser_spec.rb} +5 -5
  83. data/spec/reek/{config_spec.rb → core/config_spec.rb} +2 -6
  84. data/spec/reek/{masking_collection_spec.rb → core/masking_collection_spec.rb} +3 -4
  85. data/spec/reek/{method_context_spec.rb → core/method_context_spec.rb} +6 -7
  86. data/spec/reek/core/module_context_spec.rb +42 -0
  87. data/spec/reek/{object_refs_spec.rb → core/object_refs_spec.rb} +5 -6
  88. data/spec/reek/core/singleton_method_context_spec.rb +15 -0
  89. data/spec/reek/core/smell_configuration_spec.rb +11 -0
  90. data/spec/reek/core/stop_context_spec.rb +17 -0
  91. data/spec/reek/examiner_spec.rb +42 -0
  92. data/spec/reek/smell_warning_spec.rb +82 -33
  93. data/spec/reek/smells/attribute_spec.rb +33 -7
  94. data/spec/reek/smells/boolean_parameter_spec.rb +76 -0
  95. data/spec/reek/smells/class_variable_spec.rb +15 -6
  96. data/spec/reek/smells/control_couple_spec.rb +40 -29
  97. data/spec/reek/smells/data_clump_spec.rb +28 -7
  98. data/spec/reek/smells/duplication_spec.rb +47 -41
  99. data/spec/reek/smells/feature_envy_spec.rb +76 -18
  100. data/spec/reek/smells/irresponsible_module_spec.rb +37 -0
  101. data/spec/reek/smells/large_class_spec.rb +91 -56
  102. data/spec/reek/smells/long_method_spec.rb +32 -7
  103. data/spec/reek/smells/long_parameter_list_spec.rb +42 -13
  104. data/spec/reek/smells/long_yield_list_spec.rb +65 -0
  105. data/spec/reek/smells/nested_iterators_spec.rb +94 -3
  106. data/spec/reek/smells/simulated_polymorphism_spec.rb +48 -20
  107. data/spec/reek/smells/smell_detector_shared.rb +28 -0
  108. data/spec/reek/smells/uncommunicative_method_name_spec.rb +57 -0
  109. data/spec/reek/smells/uncommunicative_module_name_spec.rb +67 -0
  110. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +61 -0
  111. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +124 -0
  112. data/spec/reek/smells/utility_function_spec.rb +45 -3
  113. data/spec/reek/source/code_comment_spec.rb +24 -0
  114. data/spec/reek/source/object_source_spec.rb +20 -0
  115. data/spec/reek/{adapters/source_spec.rb → source/source_code_spec.rb} +7 -8
  116. data/spec/reek/source/tree_dresser_spec.rb +165 -0
  117. data/spec/reek/spec/should_reek_of_spec.rb +76 -0
  118. data/spec/reek/spec/should_reek_only_of_spec.rb +89 -0
  119. data/spec/reek/{adapters → spec}/should_reek_spec.rb +8 -32
  120. data/spec/samples/all_but_one_masked/clean_one.rb +1 -0
  121. data/spec/samples/all_but_one_masked/dirty.rb +1 -0
  122. data/spec/samples/all_but_one_masked/masked.reek +5 -1
  123. data/spec/samples/clean_due_to_masking/clean_one.rb +1 -0
  124. data/spec/samples/clean_due_to_masking/clean_three.rb +1 -0
  125. data/spec/samples/clean_due_to_masking/clean_two.rb +1 -0
  126. data/spec/samples/clean_due_to_masking/dirty_one.rb +1 -1
  127. data/spec/samples/clean_due_to_masking/dirty_two.rb +1 -1
  128. data/spec/samples/clean_due_to_masking/masked.reek +5 -1
  129. data/spec/samples/corrupt_config_file/dirty.rb +1 -1
  130. data/spec/samples/empty_config_file/dirty.rb +2 -1
  131. data/spec/samples/exceptions.reek +1 -1
  132. data/spec/samples/masked/dirty.rb +2 -1
  133. data/spec/samples/masked/masked.reek +3 -1
  134. data/spec/samples/mixed_results/clean_one.rb +1 -0
  135. data/spec/samples/mixed_results/clean_three.rb +1 -0
  136. data/spec/samples/mixed_results/clean_two.rb +1 -0
  137. data/spec/samples/mixed_results/dirty_one.rb +1 -0
  138. data/spec/samples/mixed_results/dirty_two.rb +1 -0
  139. data/spec/samples/not_quite_masked/dirty.rb +2 -1
  140. data/spec/samples/not_quite_masked/masked.reek +1 -1
  141. data/spec/samples/overrides/masked/dirty.rb +2 -1
  142. data/spec/samples/overrides/masked/lower.reek +3 -1
  143. data/spec/samples/three_clean_files/clean_one.rb +1 -0
  144. data/spec/samples/three_clean_files/clean_three.rb +1 -0
  145. data/spec/samples/three_clean_files/clean_two.rb +1 -0
  146. data/spec/samples/two_smelly_files/dirty_one.rb +2 -1
  147. data/spec/samples/two_smelly_files/dirty_two.rb +2 -1
  148. data/spec/spec_helper.rb +1 -2
  149. data/tasks/reek.rake +2 -2
  150. data/tasks/test.rake +12 -3
  151. metadata +81 -62
  152. data/README.rdoc +0 -84
  153. data/lib/reek/adapters/application.rb +0 -46
  154. data/lib/reek/adapters/command_line.rb +0 -77
  155. data/lib/reek/adapters/config_file.rb +0 -31
  156. data/lib/reek/adapters/core_extras.rb +0 -64
  157. data/lib/reek/adapters/rake_task.rb +0 -121
  158. data/lib/reek/adapters/report.rb +0 -86
  159. data/lib/reek/adapters/source.rb +0 -72
  160. data/lib/reek/adapters/spec.rb +0 -133
  161. data/lib/reek/block_context.rb +0 -62
  162. data/lib/reek/class_context.rb +0 -41
  163. data/lib/reek/code_context.rb +0 -68
  164. data/lib/reek/code_parser.rb +0 -203
  165. data/lib/reek/configuration.rb +0 -57
  166. data/lib/reek/detector_stack.rb +0 -37
  167. data/lib/reek/help_command.rb +0 -14
  168. data/lib/reek/if_context.rb +0 -18
  169. data/lib/reek/masking_collection.rb +0 -33
  170. data/lib/reek/method_context.rb +0 -138
  171. data/lib/reek/module_context.rb +0 -49
  172. data/lib/reek/name.rb +0 -57
  173. data/lib/reek/reek_command.rb +0 -28
  174. data/lib/reek/sexp_formatter.rb +0 -10
  175. data/lib/reek/sniffer.rb +0 -177
  176. data/lib/reek/stop_context.rb +0 -35
  177. data/lib/reek/tree_dresser.rb +0 -82
  178. data/lib/reek/version_command.rb +0 -14
  179. data/lib/reek/yield_call_context.rb +0 -12
  180. data/spec/reek/adapters/report_spec.rb +0 -31
  181. data/spec/reek/adapters/should_reek_of_spec.rb +0 -138
  182. data/spec/reek/adapters/should_reek_only_of_spec.rb +0 -87
  183. data/spec/reek/block_context_spec.rb +0 -65
  184. data/spec/reek/class_context_spec.rb +0 -161
  185. data/spec/reek/configuration_spec.rb +0 -12
  186. data/spec/reek/if_context_spec.rb +0 -17
  187. data/spec/reek/module_context_spec.rb +0 -46
  188. data/spec/reek/name_spec.rb +0 -37
  189. data/spec/reek/object_source_spec.rb +0 -23
  190. data/spec/reek/singleton_method_context_spec.rb +0 -16
  191. data/spec/reek/smells/smell_detector_spec.rb +0 -36
  192. data/spec/reek/smells/uncommunicative_name_spec.rb +0 -146
  193. data/spec/reek/sniffer_spec.rb +0 -11
  194. data/spec/reek/stop_context_spec.rb +0 -33
  195. data/spec/reek/tree_dresser_spec.rb +0 -20
@@ -1,62 +0,0 @@
1
- require 'set'
2
- require 'reek/code_context'
3
-
4
- module Reek
5
-
6
- module ParameterSet
7
- def names
8
- return @names if @names
9
- return (@names = []) if empty?
10
- arg = slice(1)
11
- case slice(0)
12
- when :masgn
13
- @names = arg[1..-1].map {|lasgn| Name.new(lasgn[1]) }
14
- when :lasgn, :iasgn
15
- @names = [Name.new(arg)]
16
- end
17
- end
18
-
19
- def include?(name)
20
- names.include?(name)
21
- end
22
- end
23
-
24
- class VariableContainer < CodeContext
25
-
26
- def initialize(outer, exp)
27
- super
28
- @local_variables = Set.new
29
- end
30
-
31
- def record_local_variable(sym)
32
- @local_variables << Name.new(sym)
33
- end
34
- end
35
-
36
- class BlockContext < VariableContainer
37
-
38
- def initialize(outer, exp)
39
- super
40
- @name = Name.new('block')
41
- @scope_connector = '/'
42
- @parameters = exp[2] || []
43
- @parameters.extend(ParameterSet)
44
- end
45
-
46
- def inside_a_block?
47
- true
48
- end
49
-
50
- def has_parameter(name)
51
- @parameters.include?(name) or @outer.has_parameter(name)
52
- end
53
-
54
- def nested_block?
55
- @outer.inside_a_block?
56
- end
57
-
58
- def variable_names
59
- @parameters.names + @local_variables.to_a
60
- end
61
- end
62
- end
@@ -1,41 +0,0 @@
1
- require 'set'
2
- require 'reek/module_context'
3
-
4
- class Class
5
- def is_overriding_method?(name)
6
- sym = name.to_sym
7
- mine = instance_methods(false)
8
- dads = superclass.instance_methods(true)
9
- (mine.include?(sym) and dads.include?(sym)) or (mine.include?(name) and dads.include?(name))
10
- end
11
- end
12
-
13
- module Reek
14
- class ClassContext < ModuleContext
15
-
16
- attr_reader :parsed_methods
17
-
18
- def initialize(outer, name, exp)
19
- super
20
- @superclass = exp[2]
21
- @instance_variables = Set.new
22
- end
23
-
24
- def is_overriding_method?(name)
25
- return false unless myself
26
- @myself.is_overriding_method?(name.to_s)
27
- end
28
-
29
- def is_struct?
30
- @superclass == [:const, :Struct]
31
- end
32
-
33
- def record_instance_variable(sym)
34
- @instance_variables << Name.new(sym)
35
- end
36
-
37
- def variable_names
38
- @instance_variables
39
- end
40
- end
41
- end
@@ -1,68 +0,0 @@
1
- class Module
2
-
3
- def const_or_nil(sym)
4
- const_defined?(sym) ? const_get(sym) : nil
5
- end
6
- end
7
-
8
- module Reek
9
-
10
- #
11
- # Superclass for all types of source code context. Each instance represents
12
- # a code element of some kind, and each provides behaviour relevant to that
13
- # code element. CodeContexts form a tree in the same way the code does,
14
- # with each context holding a reference to a unique outer context.
15
- #
16
- class CodeContext
17
-
18
- attr_reader :name, :exp
19
-
20
- def initialize(outer, exp)
21
- @outer = outer
22
- @exp = exp
23
- @scope_connector = ''
24
- @myself = nil
25
- end
26
-
27
- def local_nodes(type, &blk)
28
- each_node(type, [:class, :module], &blk)
29
- end
30
-
31
- def each_node(type, ignoring, &blk)
32
- if block_given?
33
- @exp.look_for(type, ignoring, &blk)
34
- else
35
- result = []
36
- @exp.look_for(type, ignoring) {|exp| result << exp}
37
- result
38
- end
39
- end
40
-
41
- # SMELL: Temporary Field -- @name isn't always initialized
42
- def matches?(strings)
43
- me = @name.to_s
44
- strings.any? do |str|
45
- re = /#{str}/
46
- re === me or re === self.full_name
47
- end
48
- end
49
-
50
- #
51
- # Bounces messages up the context tree to the first enclosing context
52
- # that knows how to deal with the request.
53
- #
54
- def method_missing(method, *args)
55
- @outer.send(method, *args)
56
- end
57
-
58
- def num_methods
59
- 0
60
- end
61
-
62
- def full_name
63
- outer = @outer ? @outer.full_name : ''
64
- prefix = outer == '' ? '' : "#{outer}#{@scope_connector}"
65
- "#{prefix}#{@name}"
66
- end
67
- end
68
- end
@@ -1,203 +0,0 @@
1
- require 'sexp'
2
- require 'reek/block_context'
3
- require 'reek/class_context'
4
- require 'reek/module_context'
5
- require 'reek/stop_context'
6
- require 'reek/if_context'
7
- require 'reek/method_context'
8
- require 'reek/singleton_method_context'
9
- require 'reek/yield_call_context'
10
-
11
- module Reek
12
- #
13
- # Traverses a Sexp abstract syntax tree and fires events whenever
14
- # it encounters specific node types.
15
- #
16
- class CodeParser
17
- def initialize(sniffer, ctx = StopContext.new)
18
- @sniffer = sniffer
19
- @element = ctx
20
- end
21
-
22
- def process(exp)
23
- meth = "process_#{exp[0]}"
24
- meth = :process_default unless self.respond_to?(meth)
25
- self.send(meth, exp)
26
- @element
27
- end
28
-
29
- def process_default(exp)
30
- exp[0..-1].each { |sub| process(sub) if Array === sub }
31
- end
32
-
33
- def do_module_or_class(exp, context_class)
34
- scope = context_class.create(@element, exp)
35
- push(scope) do
36
- process_default(exp) unless @element.is_struct?
37
- check_smells(exp[0])
38
- end
39
- scope
40
- end
41
-
42
- def process_module(exp)
43
- do_module_or_class(exp, ModuleContext)
44
- end
45
-
46
- def process_class(exp)
47
- do_module_or_class(exp, ClassContext)
48
- end
49
-
50
- def process_defn(exp)
51
- handle_context(MethodContext, exp[0], exp)
52
- end
53
-
54
- def process_defs(exp)
55
- handle_context(SingletonMethodContext, exp[0], exp)
56
- end
57
-
58
- def process_args(exp) end
59
-
60
- def process_attrset(exp)
61
- @element.record_depends_on_self if /^@/ === exp[1].to_s
62
- end
63
-
64
- def process_zsuper(exp)
65
- @element.record_use_of_self
66
- end
67
-
68
- def process_lit(exp)
69
- val = exp[1]
70
- @element.record_depends_on_self if val == :self
71
- end
72
-
73
- def process_iter(exp)
74
- process(exp[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
81
- end
82
-
83
- def process_block(exp)
84
- @element.count_statements(CodeParser.count_statements(exp))
85
- process_default(exp)
86
- end
87
-
88
- def process_yield(exp)
89
- handle_context(YieldCallContext, exp[0], exp)
90
- end
91
-
92
- def process_call(exp)
93
- @element.record_call_to(exp)
94
- process_default(exp)
95
- end
96
-
97
- def process_cfunc(exp)
98
- @element.record_depends_on_self
99
- end
100
-
101
- def process_attrasgn(exp)
102
- process_call(exp)
103
- end
104
-
105
- def process_op_asgn1(exp)
106
- process_call(exp)
107
- end
108
-
109
- def process_if(exp)
110
- count_clause(exp[2])
111
- count_clause(exp[3])
112
- handle_context(IfContext, exp[0], exp)
113
- @element.count_statements(-1)
114
- end
115
-
116
- def process_while(exp)
117
- process_until(exp)
118
- end
119
-
120
- def process_until(exp)
121
- count_clause(exp[2])
122
- process_case(exp)
123
- end
124
-
125
- def process_for(exp)
126
- count_clause(exp[3])
127
- process_case(exp)
128
- end
129
-
130
- def process_rescue(exp)
131
- count_clause(exp[1])
132
- process_case(exp)
133
- end
134
-
135
- def process_resbody(exp)
136
- process_when(exp)
137
- end
138
-
139
- def process_case(exp)
140
- process_default(exp)
141
- @element.count_statements(-1)
142
- end
143
-
144
- def process_when(exp)
145
- count_clause(exp[2])
146
- process_default(exp)
147
- end
148
-
149
- def process_ivar(exp)
150
- process_iasgn(exp)
151
- end
152
-
153
- def process_lasgn(exp)
154
- @element.record_local_variable(exp[1])
155
- process_default(exp)
156
- end
157
-
158
- def process_iasgn(exp)
159
- @element.record_instance_variable(exp[1])
160
- @element.record_depends_on_self
161
- process_default(exp)
162
- end
163
-
164
- def process_self(exp)
165
- @element.record_use_of_self
166
- end
167
-
168
- def count_clause(sexp)
169
- if sexp and !sexp.has_type?(:block)
170
- @element.count_statements(1)
171
- end
172
- end
173
-
174
- def self.count_statements(exp)
175
- stmts = exp[1..-1]
176
- ignore = 0
177
- ignore += 1 if stmts[1] == s(:nil)
178
- stmts.length - ignore
179
- end
180
-
181
- private
182
-
183
- def handle_context(klass, type, exp)
184
- scope = klass.new(@element, exp)
185
- push(scope) do
186
- process_default(exp)
187
- check_smells(type)
188
- end
189
- scope
190
- end
191
-
192
- def check_smells(type)
193
- @sniffer.examine(@element, type)
194
- end
195
-
196
- def push(context)
197
- orig = @element
198
- @element = context
199
- yield
200
- @element = orig
201
- end
202
- end
203
- end
@@ -1,57 +0,0 @@
1
- module Reek
2
-
3
- #
4
- # Represents a single set of configuration options for a smell detector
5
- #
6
- class SmellConfiguration
7
-
8
- # The name of the config field that specifies whether a smell is
9
- # enabled. Set to +true+ or +false+.
10
- ENABLED_KEY = 'enabled'
11
-
12
- # The name of the config field that sets scope-specific overrides
13
- # for other values in the current smell detector's configuration.
14
- OVERRIDES_KEY = 'overrides'
15
-
16
- def initialize(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
26
- end
27
-
28
- # SMELL: Getter
29
- def enabled?
30
- @options[ENABLED_KEY]
31
- end
32
-
33
- def overrides_for(context)
34
- Overrides.new(@options.fetch(OVERRIDES_KEY, {})).for_context(context)
35
- end
36
-
37
- # Retrieves the value, if any, for the given +key+.
38
- #
39
- # Returns +fall_back+ if this config has no value for the key.
40
- #
41
- def value(key, context, fall_back)
42
- overrides_for(context).each { |conf| return conf[key] if conf.has_key?(key) }
43
- return @options.fetch(key, fall_back)
44
- end
45
- end
46
-
47
- class Overrides
48
- def initialize(hash)
49
- @hash = hash
50
- end
51
-
52
- def for_context(context)
53
- contexts = @hash.keys.select {|ckey| context.matches?([ckey])}
54
- contexts.map { |exc| @hash[exc] }
55
- end
56
- end
57
- end
@@ -1,37 +0,0 @@
1
-
2
- module Reek
3
- class DetectorStack
4
-
5
- def initialize(default_detector)
6
- @detectors = [default_detector]
7
- end
8
-
9
- def push(config)
10
- clone = @detectors[-1].supersede_with(config)
11
- @detectors << clone
12
- end
13
-
14
- def listen_to(hooks)
15
- @detectors.each { |det| det.listen_to(hooks) }
16
- end
17
-
18
- def report_on(report)
19
- @detectors.each { |det| det.report_on(report) }
20
- end
21
-
22
- def num_smells
23
- @detectors.inject(0) { |total, detector| total += detector.num_smells }
24
- end
25
-
26
- def has_smell?(patterns)
27
- @detectors.each { |det| return true if det.has_smell?(patterns) }
28
- false
29
- end
30
-
31
- def smelly?
32
- # SMELL: Duplication: look at all those loops!
33
- @detectors.each { |det| return true if det.smelly? }
34
- false
35
- end
36
- end
37
- end