reek 1.2.6 → 1.2.8

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 (209) hide show
  1. data/.yardopts +10 -0
  2. data/History.txt +62 -0
  3. data/README.md +74 -0
  4. data/bin/reek +2 -2
  5. data/config/defaults.reek +44 -5
  6. data/features/api.feature +20 -0
  7. data/features/masking_smells.feature +60 -42
  8. data/features/options.feature +7 -2
  9. data/features/rake_task.feature +29 -22
  10. data/features/reports.feature +9 -41
  11. data/features/samples.feature +184 -196
  12. data/features/stdin.feature +5 -8
  13. data/features/step_definitions/reek_steps.rb +8 -4
  14. data/features/support/env.rb +2 -3
  15. data/features/yaml.feature +85 -0
  16. data/lib/reek/cli/application.rb +46 -0
  17. data/lib/reek/cli/command_line.rb +108 -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 +58 -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/code_context.rb +64 -0
  24. data/lib/reek/core/code_parser.rb +166 -0
  25. data/lib/reek/core/method_context.rb +84 -0
  26. data/lib/reek/core/module_context.rb +20 -0
  27. data/lib/reek/core/object_refs.rb +51 -0
  28. data/lib/reek/core/singleton_method_context.rb +20 -0
  29. data/lib/reek/core/smell_configuration.rb +62 -0
  30. data/lib/reek/core/sniffer.rb +105 -0
  31. data/lib/reek/core/stop_context.rb +30 -0
  32. data/lib/reek/core/warning_collector.rb +27 -0
  33. data/lib/reek/examiner.rb +104 -0
  34. data/lib/reek/rake/task.rb +142 -0
  35. data/lib/reek/smell_warning.rb +73 -23
  36. data/lib/reek/smells/attribute.rb +26 -21
  37. data/lib/reek/smells/boolean_parameter.rb +38 -0
  38. data/lib/reek/smells/class_variable.rb +22 -9
  39. data/lib/reek/smells/control_couple.rb +40 -16
  40. data/lib/reek/smells/data_clump.rb +114 -23
  41. data/lib/reek/smells/duplication.rb +55 -15
  42. data/lib/reek/smells/feature_envy.rb +16 -7
  43. data/lib/reek/smells/irresponsible_module.rb +37 -0
  44. data/lib/reek/smells/large_class.rb +37 -19
  45. data/lib/reek/smells/long_method.rb +20 -9
  46. data/lib/reek/smells/long_parameter_list.rb +22 -10
  47. data/lib/reek/smells/long_yield_list.rb +43 -7
  48. data/lib/reek/smells/nested_iterators.rb +68 -8
  49. data/lib/reek/smells/simulated_polymorphism.rb +26 -15
  50. data/lib/reek/smells/smell_detector.rb +29 -51
  51. data/lib/reek/smells/uncommunicative_method_name.rb +74 -0
  52. data/lib/reek/smells/uncommunicative_module_name.rb +74 -0
  53. data/lib/reek/smells/uncommunicative_parameter_name.rb +79 -0
  54. data/lib/reek/smells/uncommunicative_variable_name.rb +89 -0
  55. data/lib/reek/smells/utility_function.rb +51 -12
  56. data/lib/reek/smells.rb +29 -0
  57. data/lib/reek/source/code_comment.rb +37 -0
  58. data/lib/reek/source/config_file.rb +72 -0
  59. data/lib/reek/source/core_extras.rb +46 -0
  60. data/lib/reek/source/reference_collector.rb +28 -0
  61. data/lib/reek/source/sexp_formatter.rb +17 -0
  62. data/lib/reek/source/source_code.rb +44 -0
  63. data/lib/reek/source/source_file.rb +32 -0
  64. data/lib/reek/source/source_locator.rb +42 -0
  65. data/lib/reek/source/tree_dresser.rb +204 -0
  66. data/lib/reek/source.rb +18 -0
  67. data/lib/reek/spec/should_reek.rb +31 -0
  68. data/lib/reek/spec/should_reek_of.rb +37 -0
  69. data/lib/reek/spec/should_reek_only_of.rb +37 -0
  70. data/lib/reek/spec.rb +51 -0
  71. data/lib/reek.rb +8 -4
  72. data/reek.gemspec +9 -7
  73. data/spec/matchers/smell_of_matcher.rb +58 -0
  74. data/spec/reek/{help_command_spec.rb → cli/help_command_spec.rb} +3 -4
  75. data/spec/reek/cli/reek_command_spec.rb +46 -0
  76. data/spec/reek/cli/report_spec.rb +30 -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/code_context_spec.rb +145 -0
  80. data/spec/reek/{code_parser_spec.rb → core/code_parser_spec.rb} +7 -6
  81. data/spec/reek/{config_spec.rb → core/config_spec.rb} +2 -6
  82. data/spec/reek/{method_context_spec.rb → core/method_context_spec.rb} +16 -36
  83. data/spec/reek/core/module_context_spec.rb +27 -0
  84. data/spec/reek/{object_refs_spec.rb → core/object_refs_spec.rb} +5 -6
  85. data/spec/reek/core/singleton_method_context_spec.rb +9 -0
  86. data/spec/reek/core/smell_configuration_spec.rb +11 -0
  87. data/spec/reek/core/stop_context_spec.rb +17 -0
  88. data/spec/reek/core/warning_collector_spec.rb +27 -0
  89. data/spec/reek/examiner_spec.rb +103 -0
  90. data/spec/reek/smell_warning_spec.rb +74 -82
  91. data/spec/reek/smells/attribute_spec.rb +42 -23
  92. data/spec/reek/smells/behaves_like_variable_detector.rb +2 -2
  93. data/spec/reek/smells/boolean_parameter_spec.rb +66 -0
  94. data/spec/reek/smells/class_variable_spec.rb +60 -75
  95. data/spec/reek/smells/control_couple_spec.rb +37 -32
  96. data/spec/reek/smells/data_clump_spec.rb +63 -24
  97. data/spec/reek/smells/duplication_spec.rb +106 -57
  98. data/spec/reek/smells/feature_envy_spec.rb +113 -92
  99. data/spec/reek/smells/irresponsible_module_spec.rb +58 -0
  100. data/spec/reek/smells/large_class_spec.rb +67 -57
  101. data/spec/reek/smells/long_method_spec.rb +40 -10
  102. data/spec/reek/smells/long_parameter_list_spec.rb +50 -28
  103. data/spec/reek/smells/long_yield_list_spec.rb +57 -0
  104. data/spec/reek/smells/nested_iterators_spec.rb +115 -7
  105. data/spec/reek/smells/simulated_polymorphism_spec.rb +56 -20
  106. data/spec/reek/smells/smell_detector_shared.rb +42 -0
  107. data/spec/reek/smells/uncommunicative_method_name_spec.rb +42 -0
  108. data/spec/reek/smells/uncommunicative_module_name_spec.rb +66 -0
  109. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +71 -0
  110. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +120 -0
  111. data/spec/reek/smells/utility_function_spec.rb +50 -4
  112. data/spec/reek/source/code_comment_spec.rb +82 -0
  113. data/spec/reek/source/object_source_spec.rb +20 -0
  114. data/spec/reek/source/reference_collector_spec.rb +53 -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 +270 -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/config/allow_duplication.reek +3 -0
  130. data/spec/samples/config/deeper_nested_iterators.reek +3 -0
  131. data/spec/samples/corrupt_config_file/dirty.rb +1 -1
  132. data/spec/samples/demo/demo.rb +8 -0
  133. data/spec/samples/empty_config_file/dirty.rb +2 -1
  134. data/spec/samples/exceptions.reek +1 -1
  135. data/spec/samples/inline_config/dirty.rb +16 -0
  136. data/spec/samples/inline_config/masked.reek +7 -0
  137. data/spec/samples/mask_some/dirty.rb +8 -0
  138. data/spec/samples/mask_some/some.reek +8 -0
  139. data/spec/samples/masked/dirty.rb +2 -1
  140. data/spec/samples/masked/masked.reek +3 -1
  141. data/spec/samples/mixed_results/clean_one.rb +1 -0
  142. data/spec/samples/mixed_results/clean_three.rb +1 -0
  143. data/spec/samples/mixed_results/clean_two.rb +1 -0
  144. data/spec/samples/mixed_results/dirty_one.rb +1 -0
  145. data/spec/samples/mixed_results/dirty_two.rb +1 -0
  146. data/spec/samples/not_quite_masked/dirty.rb +2 -1
  147. data/spec/samples/not_quite_masked/masked.reek +1 -1
  148. data/spec/samples/overrides/masked/dirty.rb +2 -1
  149. data/spec/samples/overrides/masked/lower.reek +3 -1
  150. data/spec/samples/three_clean_files/clean_one.rb +1 -0
  151. data/spec/samples/three_clean_files/clean_three.rb +1 -0
  152. data/spec/samples/three_clean_files/clean_two.rb +1 -0
  153. data/spec/samples/two_smelly_files/dirty_one.rb +2 -1
  154. data/spec/samples/two_smelly_files/dirty_two.rb +2 -1
  155. data/spec/spec_helper.rb +10 -2
  156. data/tasks/reek.rake +2 -2
  157. data/tasks/test.rake +12 -3
  158. metadata +121 -79
  159. data/README.rdoc +0 -84
  160. data/features/profile.feature +0 -34
  161. data/lib/reek/adapters/application.rb +0 -46
  162. data/lib/reek/adapters/command_line.rb +0 -77
  163. data/lib/reek/adapters/config_file.rb +0 -31
  164. data/lib/reek/adapters/core_extras.rb +0 -64
  165. data/lib/reek/adapters/rake_task.rb +0 -121
  166. data/lib/reek/adapters/report.rb +0 -86
  167. data/lib/reek/adapters/source.rb +0 -72
  168. data/lib/reek/adapters/spec.rb +0 -133
  169. data/lib/reek/block_context.rb +0 -62
  170. data/lib/reek/class_context.rb +0 -41
  171. data/lib/reek/code_context.rb +0 -68
  172. data/lib/reek/code_parser.rb +0 -203
  173. data/lib/reek/configuration.rb +0 -57
  174. data/lib/reek/detector_stack.rb +0 -37
  175. data/lib/reek/help_command.rb +0 -14
  176. data/lib/reek/if_context.rb +0 -18
  177. data/lib/reek/masking_collection.rb +0 -33
  178. data/lib/reek/method_context.rb +0 -138
  179. data/lib/reek/module_context.rb +0 -49
  180. data/lib/reek/name.rb +0 -57
  181. data/lib/reek/object_refs.rb +0 -49
  182. data/lib/reek/reek_command.rb +0 -28
  183. data/lib/reek/sexp_formatter.rb +0 -10
  184. data/lib/reek/singleton_method_context.rb +0 -26
  185. data/lib/reek/smells/uncommunicative_name.rb +0 -84
  186. data/lib/reek/sniffer.rb +0 -177
  187. data/lib/reek/stop_context.rb +0 -35
  188. data/lib/reek/tree_dresser.rb +0 -82
  189. data/lib/reek/version_command.rb +0 -14
  190. data/lib/reek/yield_call_context.rb +0 -12
  191. data/spec/reek/adapters/report_spec.rb +0 -31
  192. data/spec/reek/adapters/should_reek_of_spec.rb +0 -138
  193. data/spec/reek/adapters/should_reek_only_of_spec.rb +0 -87
  194. data/spec/reek/block_context_spec.rb +0 -65
  195. data/spec/reek/class_context_spec.rb +0 -161
  196. data/spec/reek/code_context_spec.rb +0 -182
  197. data/spec/reek/configuration_spec.rb +0 -12
  198. data/spec/reek/if_context_spec.rb +0 -17
  199. data/spec/reek/masking_collection_spec.rb +0 -236
  200. data/spec/reek/module_context_spec.rb +0 -46
  201. data/spec/reek/name_spec.rb +0 -37
  202. data/spec/reek/object_source_spec.rb +0 -23
  203. data/spec/reek/reek_command_spec.rb +0 -45
  204. data/spec/reek/singleton_method_context_spec.rb +0 -16
  205. data/spec/reek/smells/smell_detector_spec.rb +0 -36
  206. data/spec/reek/smells/uncommunicative_name_spec.rb +0 -146
  207. data/spec/reek/sniffer_spec.rb +0 -11
  208. data/spec/reek/stop_context_spec.rb +0 -33
  209. data/spec/reek/tree_dresser_spec.rb +0 -20
@@ -1,133 +0,0 @@
1
- require 'reek/sniffer'
2
- require 'reek/adapters/core_extras'
3
- require 'reek/adapters/report'
4
-
5
- module Reek
6
-
7
- #
8
- # Provides matchers for Rspec, making it easy to check code quality.
9
- #
10
- # If you require this module somewhere within your spec (or in your spec_helper),
11
- # Reek will arrange to update Spec::Runner's config so that it knows about the
12
- # matchers defined here.
13
- #
14
- # === Examples
15
- #
16
- # Here's a spec that ensures there are no smell warnings in the current project:
17
- #
18
- # describe 'source code quality' do
19
- # Dir['lib/**/*.rb'].each do |path|
20
- # it "reports no smells in #{path}" do
21
- # File.new(path).should_not reek
22
- # end
23
- # end
24
- # end
25
- #
26
- # And here's an even simpler way to do the same:
27
- #
28
- # it 'has no code smells' do
29
- # Dir['lib/**/*.rb'].should_not reek
30
- # end
31
- #
32
- # Here's a simple check of a code fragment:
33
- #
34
- # 'def equals(other) other.thing == self.thing end'.should_not reek
35
- #
36
- # And a more complex example, making use of one of the factory methods for
37
- # +Source+ so that the code is parsed and analysed only once:
38
- #
39
- # ruby = 'def double_thing() @other.thing.foo + @other.thing.foo end'.sniff
40
- # ruby.should reek_of(:Duplication, /@other.thing[^\.]/)
41
- # ruby.should reek_of(:Duplication, /@other.thing.foo/)
42
- # ruby.should_not reek_of(:FeatureEnvy)
43
- #
44
- module Spec
45
- module ReekMatcher
46
- def create_reporter(sniffers)
47
- QuietReport.new(sniffers, false)
48
- end
49
- def report
50
- create_reporter(@sniffer.sniffers).report
51
- end
52
-
53
- module_function :create_reporter
54
- end
55
-
56
- class ShouldReek # :nodoc:
57
- include ReekMatcher
58
-
59
- def matches?(actual)
60
- @sniffer = actual.sniff
61
- @sniffer.smelly?
62
- end
63
- def failure_message_for_should
64
- "Expected #{@sniffer.desc} to reek, but it didn't"
65
- end
66
- def failure_message_for_should_not
67
- "Expected no smells, but got:\n#{report}"
68
- end
69
- end
70
-
71
- class ShouldReekOf # :nodoc:
72
- include ReekMatcher
73
-
74
- def initialize(klass, patterns)
75
- @klass = klass
76
- @patterns = patterns
77
- end
78
- def matches?(actual)
79
- @sniffer = actual.sniff
80
- @sniffer.has_smell?(@klass, @patterns)
81
- end
82
- def failure_message_for_should
83
- "Expected #{@sniffer.desc} to reek of #{@klass}, but it didn't"
84
- end
85
- def failure_message_for_should_not
86
- "Expected #{@sniffer.desc} not to reek of #{@klass}, but got:\n#{report}"
87
- end
88
- end
89
-
90
- class ShouldReekOnlyOf < ShouldReekOf # :nodoc:
91
- def matches?(actual)
92
- @sniffer = actual.sniff
93
- @sniffer.num_smells == 1 and @sniffer.has_smell?(@klass, @patterns)
94
- end
95
- def failure_message_for_should
96
- "Expected #{@sniffer.desc} to reek only of #{@klass}, but got:\n#{report}"
97
- end
98
- def failure_message_for_should_not
99
- "Expected #{@sniffer.desc} not to reek only of #{@klass}, but it did"
100
- end
101
- end
102
-
103
- #
104
- # Returns +true+ if and only if the target source code contains smells.
105
- #
106
- def reek
107
- ShouldReek.new
108
- end
109
-
110
- #
111
- # Checks the target source code for instances of +smell_class+,
112
- # and returns +true+ only if one of them has a report string matching
113
- # all of the +patterns+.
114
- #
115
- def reek_of(smell_class, *patterns)
116
- ShouldReekOf.new(smell_class, patterns)
117
- end
118
-
119
- #
120
- # As for reek_of, but the matched smell warning must be the only warning of
121
- # any kind in the target source code's Reek report.
122
- #
123
- def reek_only_of(smell_class, *patterns)
124
- ShouldReekOnlyOf.new(smell_class, patterns)
125
- end
126
- end
127
- end
128
-
129
- if Object.const_defined?(:Spec)
130
- Spec::Runner.configure do |config|
131
- config.include(Reek::Spec)
132
- end
133
- end
@@ -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
@@ -1,14 +0,0 @@
1
-
2
- module Reek
3
-
4
- class HelpCommand
5
- def initialize(parser)
6
- @parser = parser
7
- end
8
- def execute(view)
9
- view.output(@parser.to_s)
10
- view.report_success
11
- end
12
- end
13
-
14
- end
@@ -1,18 +0,0 @@
1
- require 'reek/code_context'
2
-
3
- module Reek
4
- class IfContext < CodeContext
5
- attr_reader :if_expr
6
-
7
- def initialize(outer, exp)
8
- super
9
- @name = ''
10
- @scope_connector = ''
11
- @if_expr = exp[1]
12
- end
13
-
14
- def tests_a_parameter?
15
- @if_expr[0] == :lvar and has_parameter(@if_expr[1])
16
- end
17
- end
18
- end
@@ -1,33 +0,0 @@
1
- require 'set'
2
-
3
- #
4
- # A set of items that can be "masked" or "visible". If an item is added
5
- # more than once, only the "visible" copy is retained.
6
- #
7
- class MaskingCollection
8
- def initialize
9
- @visible_items = SortedSet.new
10
- @masked_items = SortedSet.new
11
- end
12
- def found_smell(item)
13
- @visible_items.add(item)
14
- @masked_items.delete(item) if @masked_items.include?(item)
15
- end
16
- def found_masked_smell(item)
17
- @masked_items.add(item) unless @visible_items.include?(item)
18
- end
19
- def num_visible_items
20
- @visible_items.length
21
- end
22
- def num_masked_items
23
- @masked_items.length
24
- end
25
- def each_item(&blk)
26
- all = SortedSet.new(@visible_items)
27
- all.merge(@masked_items)
28
- all.each(&blk)
29
- end
30
- def each_visible_item(&blk)
31
- @visible_items.each(&blk)
32
- end
33
- end