reek 4.7.1 → 5.0.0

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 (260) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -12
  3. data/.rubocop.yml +36 -7
  4. data/.simplecov +1 -0
  5. data/.travis.yml +3 -9
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +59 -0
  8. data/CONTRIBUTING.md +1 -1
  9. data/Gemfile +5 -5
  10. data/README.md +134 -104
  11. data/Rakefile +16 -3
  12. data/bin/reek +1 -3
  13. data/docs/API.md +2 -9
  14. data/docs/Basic-Smell-Options.md +51 -11
  15. data/docs/Code-Smells.md +1 -1
  16. data/docs/Command-Line-Options.md +14 -4
  17. data/docs/Duplicate-Method-Call.md +49 -1
  18. data/docs/Feature-Envy.md +44 -0
  19. data/docs/How-To-Write-New-Detectors.md +7 -7
  20. data/docs/Instance-Variable-Assumption.md +1 -1
  21. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  22. data/docs/Rake-Task.md +1 -1
  23. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  24. data/docs/Reek-Driven-Development.md +1 -1
  25. data/docs/Uncommunicative-Method-Name.md +45 -6
  26. data/docs/Uncommunicative-Module-Name.md +49 -7
  27. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  28. data/docs/Uncommunicative-Variable-Name.md +73 -2
  29. data/docs/Unused-Private-Method.md +3 -3
  30. data/docs/defaults.reek.yml +129 -0
  31. data/docs/yard_plugin.rb +1 -0
  32. data/features/command_line_interface/basic_usage.feature +2 -2
  33. data/features/command_line_interface/options.feature +46 -4
  34. data/features/command_line_interface/show_progress.feature +4 -4
  35. data/features/command_line_interface/smell_selection.feature +1 -1
  36. data/features/command_line_interface/smells_count.feature +6 -6
  37. data/features/command_line_interface/stdin.feature +30 -8
  38. data/features/configuration_files/accept_setting.feature +45 -28
  39. data/features/configuration_files/directory_specific_directives.feature +80 -75
  40. data/features/configuration_files/exclude_directives.feature +11 -10
  41. data/features/configuration_files/exclude_paths_directives.feature +4 -4
  42. data/features/configuration_files/masking_smells.feature +38 -9
  43. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  44. data/features/configuration_files/reject_setting.feature +52 -41
  45. data/features/configuration_files/schema_validation.feature +59 -0
  46. data/features/configuration_files/unused_private_method.feature +18 -16
  47. data/features/configuration_loading.feature +53 -10
  48. data/features/configuration_via_source_comments/erroneous_source_comments.feature +3 -3
  49. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  50. data/features/locales.feature +32 -0
  51. data/features/rake_task/rake_task.feature +58 -18
  52. data/features/reports/json.feature +3 -3
  53. data/features/reports/reports.feature +34 -34
  54. data/features/reports/yaml.feature +3 -3
  55. data/features/rspec_matcher.feature +40 -0
  56. data/features/samples.feature +287 -287
  57. data/features/step_definitions/reek_steps.rb +2 -2
  58. data/features/step_definitions/sample_file_steps.rb +9 -4
  59. data/features/support/env.rb +2 -11
  60. data/features/todo_list.feature +26 -23
  61. data/lib/reek/ast/builder.rb +1 -1
  62. data/lib/reek/ast/node.rb +40 -58
  63. data/lib/reek/ast/object_refs.rb +1 -1
  64. data/lib/reek/ast/reference_collector.rb +2 -4
  65. data/lib/reek/ast/sexp_extensions/case.rb +1 -1
  66. data/lib/reek/ast/sexp_extensions/if.rb +8 -1
  67. data/lib/reek/ast/sexp_extensions/logical_operators.rb +1 -1
  68. data/lib/reek/ast/sexp_extensions/methods.rb +4 -6
  69. data/lib/reek/ast/sexp_extensions/send.rb +0 -4
  70. data/lib/reek/cli/application.rb +4 -3
  71. data/lib/reek/cli/command/report_command.rb +1 -2
  72. data/lib/reek/cli/command/todo_list_command.rb +8 -8
  73. data/lib/reek/cli/options.rb +31 -16
  74. data/lib/reek/cli/silencer.rb +14 -3
  75. data/lib/reek/code_comment.rb +14 -16
  76. data/lib/reek/configuration/app_configuration.rb +32 -27
  77. data/lib/reek/configuration/configuration_converter.rb +110 -0
  78. data/lib/reek/configuration/configuration_file_finder.rb +16 -41
  79. data/lib/reek/configuration/configuration_validator.rb +12 -23
  80. data/lib/reek/configuration/default_directive.rb +17 -3
  81. data/lib/reek/configuration/directory_directives.rb +17 -11
  82. data/lib/reek/configuration/excluded_paths.rb +1 -1
  83. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  84. data/lib/reek/configuration/schema.yml +210 -0
  85. data/lib/reek/configuration/schema_validator.rb +38 -0
  86. data/lib/reek/context/attribute_context.rb +3 -3
  87. data/lib/reek/context/code_context.rb +47 -43
  88. data/lib/reek/context/ghost_context.rb +0 -2
  89. data/lib/reek/context/method_context.rb +22 -15
  90. data/lib/reek/context/module_context.rb +5 -9
  91. data/lib/reek/context/root_context.rb +0 -4
  92. data/lib/reek/context/send_context.rb +2 -2
  93. data/lib/reek/context_builder.rb +43 -44
  94. data/lib/reek/detector_repository.rb +11 -11
  95. data/lib/reek/documentation_link.rb +28 -0
  96. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +14 -13
  97. data/lib/reek/errors/bad_detector_in_comment_error.rb +12 -11
  98. data/lib/reek/errors/base_error.rb +3 -0
  99. data/lib/reek/errors/config_file_error.rb +11 -0
  100. data/lib/reek/errors/encoding_error.rb +43 -0
  101. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +13 -12
  102. data/lib/reek/errors/incomprehensible_source_error.rb +22 -24
  103. data/lib/reek/errors/syntax_error.rb +41 -0
  104. data/lib/reek/examiner.rb +24 -26
  105. data/lib/reek/logging_error_handler.rb +7 -5
  106. data/lib/reek/rake/task.rb +8 -4
  107. data/lib/reek/report/base_report.rb +8 -12
  108. data/lib/reek/report/code_climate/code_climate_configuration.rb +1 -1
  109. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -10
  110. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  111. data/lib/reek/report/heading_formatter.rb +54 -0
  112. data/lib/reek/report/json_report.rb +1 -1
  113. data/lib/reek/report/location_formatter.rb +40 -0
  114. data/lib/reek/report/progress_formatter.rb +79 -0
  115. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  116. data/lib/reek/report/text_report.rb +1 -2
  117. data/lib/reek/report/xml_report.rb +3 -3
  118. data/lib/reek/report/yaml_report.rb +1 -1
  119. data/lib/reek/report.rb +15 -10
  120. data/lib/reek/smell_configuration.rb +2 -2
  121. data/lib/reek/smell_detectors/attribute.rb +5 -11
  122. data/lib/reek/smell_detectors/base_detector.rb +30 -26
  123. data/lib/reek/smell_detectors/boolean_parameter.rb +3 -5
  124. data/lib/reek/smell_detectors/class_variable.rb +5 -14
  125. data/lib/reek/smell_detectors/control_parameter.rb +18 -33
  126. data/lib/reek/smell_detectors/data_clump.rb +15 -9
  127. data/lib/reek/smell_detectors/duplicate_method_call.rb +23 -17
  128. data/lib/reek/smell_detectors/feature_envy.rb +9 -7
  129. data/lib/reek/smell_detectors/instance_variable_assumption.rb +14 -23
  130. data/lib/reek/smell_detectors/irresponsible_module.rb +5 -12
  131. data/lib/reek/smell_detectors/long_parameter_list.rb +10 -7
  132. data/lib/reek/smell_detectors/long_yield_list.rb +10 -7
  133. data/lib/reek/smell_detectors/manual_dispatch.rb +4 -5
  134. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +20 -20
  135. data/lib/reek/smell_detectors/module_initialize.rb +3 -5
  136. data/lib/reek/smell_detectors/nested_iterators.rb +16 -24
  137. data/lib/reek/smell_detectors/nil_check.rb +8 -15
  138. data/lib/reek/smell_detectors/repeated_conditional.rb +13 -11
  139. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +7 -8
  140. data/lib/reek/smell_detectors/too_many_constants.rb +10 -9
  141. data/lib/reek/smell_detectors/too_many_instance_variables.rb +10 -6
  142. data/lib/reek/smell_detectors/too_many_methods.rb +11 -7
  143. data/lib/reek/smell_detectors/too_many_statements.rb +10 -6
  144. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +10 -11
  145. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +14 -18
  146. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +17 -22
  147. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +26 -27
  148. data/lib/reek/smell_detectors/unused_parameters.rb +4 -6
  149. data/lib/reek/smell_detectors/unused_private_method.rb +11 -18
  150. data/lib/reek/smell_detectors/utility_function.rb +12 -16
  151. data/lib/reek/smell_detectors.rb +1 -2
  152. data/lib/reek/smell_warning.rb +15 -8
  153. data/lib/reek/source/source_code.rb +57 -58
  154. data/lib/reek/source/source_locator.rb +8 -8
  155. data/lib/reek/spec/should_reek.rb +2 -2
  156. data/lib/reek/spec/should_reek_of.rb +9 -16
  157. data/lib/reek/spec/should_reek_only_of.rb +4 -4
  158. data/lib/reek/spec.rb +6 -6
  159. data/lib/reek/tree_dresser.rb +8 -8
  160. data/lib/reek/version.rb +1 -1
  161. data/reek.gemspec +5 -7
  162. data/samples/checkstyle.xml +1 -1
  163. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  164. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  165. data/samples/configuration/full_configuration.reek +8 -4
  166. data/samples/configuration/full_mask.reek +5 -4
  167. data/samples/configuration/partial_mask.reek +3 -2
  168. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  169. data/samples/paths.rb +5 -4
  170. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  171. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  172. data/spec/factories/factories.rb +2 -13
  173. data/spec/reek/ast/node_spec.rb +103 -10
  174. data/spec/reek/ast/reference_collector_spec.rb +1 -1
  175. data/spec/reek/ast/sexp_extensions_spec.rb +14 -34
  176. data/spec/reek/cli/application_spec.rb +52 -42
  177. data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
  178. data/spec/reek/cli/silencer_spec.rb +28 -0
  179. data/spec/reek/code_comment_spec.rb +31 -38
  180. data/spec/reek/configuration/app_configuration_spec.rb +46 -33
  181. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -51
  182. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  183. data/spec/reek/configuration/directory_directives_spec.rb +6 -7
  184. data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
  185. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  186. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  187. data/spec/reek/context/code_context_spec.rb +70 -106
  188. data/spec/reek/context/ghost_context_spec.rb +9 -9
  189. data/spec/reek/context/method_context_spec.rb +2 -2
  190. data/spec/reek/context/module_context_spec.rb +3 -3
  191. data/spec/reek/context/root_context_spec.rb +1 -1
  192. data/spec/reek/context_builder_spec.rb +20 -0
  193. data/spec/reek/documentation_link_spec.rb +20 -0
  194. data/spec/reek/errors/base_error_spec.rb +13 -0
  195. data/spec/reek/examiner_spec.rb +136 -29
  196. data/spec/reek/rake/task_spec.rb +25 -2
  197. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -80
  198. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  199. data/spec/reek/report/json_report_spec.rb +13 -46
  200. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  201. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  202. data/spec/reek/report/text_report_spec.rb +4 -4
  203. data/spec/reek/report/xml_report_spec.rb +3 -3
  204. data/spec/reek/report/yaml_report_spec.rb +9 -38
  205. data/spec/reek/report_spec.rb +3 -3
  206. data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
  207. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
  208. data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
  209. data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
  210. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
  211. data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
  212. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -11
  213. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
  214. data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
  215. data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
  216. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  217. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  218. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  219. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  220. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +36 -15
  221. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
  222. data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
  223. data/spec/reek/smell_detectors/unused_private_method_spec.rb +21 -10
  224. data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
  225. data/spec/reek/smell_warning_spec.rb +12 -8
  226. data/spec/reek/source/source_code_spec.rb +22 -21
  227. data/spec/reek/source/source_locator_spec.rb +17 -17
  228. data/spec/reek/spec/should_reek_of_spec.rb +25 -29
  229. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  230. data/spec/reek/spec/should_reek_spec.rb +8 -8
  231. data/spec/reek/spec/smell_matcher_spec.rb +23 -23
  232. data/spec/reek/tree_dresser_spec.rb +12 -17
  233. data/spec/spec_helper.rb +6 -17
  234. data/tasks/configuration.rake +8 -5
  235. metadata +74 -41
  236. data/defaults.reek +0 -131
  237. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  238. data/lib/reek/report/formatter/heading_formatter.rb +0 -52
  239. data/lib/reek/report/formatter/location_formatter.rb +0 -42
  240. data/lib/reek/report/formatter/progress_formatter.rb +0 -81
  241. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  242. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -36
  243. data/lib/reek/report/formatter.rb +0 -33
  244. data/lib/reek/smell_detectors/syntax.rb +0 -37
  245. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  246. data/samples/smelly_with_inline_mask.rb +0 -8
  247. data/samples/smelly_with_modifiers.rb +0 -12
  248. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  249. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  250. data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
  251. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  252. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  253. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  254. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  255. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  256. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  257. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  258. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  259. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  260. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
@@ -30,7 +30,7 @@ RSpec.describe Reek::SmellDetectors::ControlParameter do
30
30
  and reek_of(:ControlParameter, lines: [3], argument: 'charlie')
31
31
  end
32
32
 
33
- context 'parameter not used to determine code path' do
33
+ context 'when a parameter is not used to determine code path' do
34
34
  it 'does not report a ternary check on an ivar' do
35
35
  src = 'def alfa(bravo) @charlie ? bravo : false end'
36
36
  expect(src).not_to reek_of(:ControlParameter)
@@ -52,7 +52,7 @@ RSpec.describe Reek::SmellDetectors::ControlParameter do
52
52
  end
53
53
  end
54
54
 
55
- context 'parameter only used to determine code path' do
55
+ context 'when a parameter is only used to determine code path' do
56
56
  it 'reports a ternary check on a parameter' do
57
57
  src = 'def alfa(bravo); bravo ? true : false; end'
58
58
  expect(src).to reek_of(:ControlParameter)
@@ -144,7 +144,7 @@ RSpec.describe Reek::SmellDetectors::ControlParameter do
144
144
  expect(src).to reek_of(:ControlParameter)
145
145
  end
146
146
 
147
- it 'reports on nested if statements where the inner if is a control parameter' do
147
+ it 'reports on nested suffix if statements where the inner if is a control parameter' do
148
148
  src = <<-EOS
149
149
  def nested(bravo)
150
150
  if true
@@ -157,6 +157,36 @@ RSpec.describe Reek::SmellDetectors::ControlParameter do
157
157
  expect(src).to reek_of(:ControlParameter)
158
158
  end
159
159
 
160
+ it 'reports on nested full if statements where the inner if is a control parameter' do
161
+ src = <<-EOS
162
+ def alfa(bravo)
163
+ if true
164
+ charlie
165
+ else
166
+ if bravo
167
+ delta
168
+ end
169
+ end
170
+ end
171
+ EOS
172
+
173
+ expect(src).to reek_of(:ControlParameter)
174
+ end
175
+
176
+ it 'reports on elsif statements' do
177
+ src = <<-EOS
178
+ def alfa(bravo)
179
+ if true
180
+ charlie
181
+ elsif bravo
182
+ delta
183
+ end
184
+ end
185
+ EOS
186
+
187
+ expect(src).to reek_of(:ControlParameter)
188
+ end
189
+
160
190
  it 'reports on explicit comparison in the condition' do
161
191
  src = 'def alfa(bravo); if bravo == charlie then charlie end; end'
162
192
  expect(src).to reek_of(:ControlParameter)
@@ -188,7 +218,7 @@ RSpec.describe Reek::SmellDetectors::ControlParameter do
188
218
  end
189
219
  end
190
220
 
191
- context 'parameter used besides determining code path' do
221
+ context 'when a parameter is used besides determining code path' do
192
222
  it 'does not report on if conditional expression' do
193
223
  src = 'def alfa(bravo); if bravo then charlie(bravo); end end'
194
224
  expect(src).not_to reek_of(:ControlParameter)
@@ -150,7 +150,7 @@ RSpec.describe Reek::SmellDetectors::DuplicateMethodCall do
150
150
  end
151
151
  end
152
152
 
153
- context 'non-repeated method calls' do
153
+ context 'with non-repeated method calls' do
154
154
  it 'does not report similar calls' do
155
155
  src = 'def alfa(bravo) bravo.charlie == self.charlie end'
156
156
  expect(src).not_to reek_of(:DuplicateMethodCall)
@@ -162,7 +162,7 @@ RSpec.describe Reek::SmellDetectors::DuplicateMethodCall do
162
162
  end
163
163
  end
164
164
 
165
- context 'allowing up to 3 calls' do
165
+ context 'when allowing up to 3 calls' do
166
166
  let(:config) do
167
167
  { Reek::SmellDetectors::DuplicateMethodCall::MAX_ALLOWED_CALLS_KEY => 3 }
168
168
  end
@@ -189,7 +189,7 @@ RSpec.describe Reek::SmellDetectors::DuplicateMethodCall do
189
189
  end
190
190
  end
191
191
 
192
- context 'allowing calls to some methods' do
192
+ context 'when allowing calls to some methods' do
193
193
  it 'does not report calls to some methods' do
194
194
  config = { Reek::SmellDetectors::DuplicateMethodCall::ALLOW_CALLS_KEY => ['@bravo.charlie'] }
195
195
  src = 'def alfa; @bravo.charlie + @bravo.charlie; end'
@@ -130,7 +130,7 @@ RSpec.describe Reek::SmellDetectors::FeatureEnvy do
130
130
  delta += bravo.foxtrot
131
131
  delta *= 1.15
132
132
  end
133
- EOS
133
+ EOS
134
134
 
135
135
  expect(src).
136
136
  to reek_of(:FeatureEnvy, name: 'delta').
@@ -145,7 +145,7 @@ RSpec.describe Reek::SmellDetectors::FeatureEnvy do
145
145
  delta += bravo.echo
146
146
  delta += bravo.foxtrot
147
147
  end
148
- EOS
148
+ EOS
149
149
 
150
150
  expect(src).
151
151
  to reek_of(:FeatureEnvy, name: 'delta').
@@ -247,4 +247,49 @@ RSpec.describe Reek::SmellDetectors::FeatureEnvy do
247
247
 
248
248
  expect(src).not_to reek_of(:FeatureEnvy)
249
249
  end
250
+
251
+ it 'does not report on class methods defined by opening the metaclass' do
252
+ src = <<-EOS
253
+ class Alfa
254
+ class << self
255
+ def bravo(charlie)
256
+ delta = new(charlie)
257
+ delta.echo
258
+ delta.echo
259
+ end
260
+ end
261
+ end
262
+ EOS
263
+
264
+ expect(src).not_to reek_of(:FeatureEnvy)
265
+ end
266
+
267
+ it 'does not report on class methods defined with an explicit receiver' do
268
+ src = <<-EOS
269
+ class Alfa
270
+ def self.bravo(charlie)
271
+ delta = new(charlie)
272
+ delta.echo
273
+ delta.echo
274
+ end
275
+ end
276
+ EOS
277
+
278
+ expect(src).not_to reek_of(:FeatureEnvy)
279
+ end
280
+
281
+ it 'does not report module functions' do
282
+ src = <<-EOF
283
+ module Alfa
284
+ module_function
285
+ def bravo(charlie)
286
+ echo = delta(charlie)
287
+ echo.foxtrot
288
+ echo.foxtrot
289
+ end
290
+ end
291
+ EOF
292
+
293
+ expect(src).not_to reek_of(:FeatureEnvy)
294
+ end
250
295
  end
@@ -49,17 +49,6 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
49
49
  expect(src).not_to reek_of(:IrresponsibleModule)
50
50
  end
51
51
 
52
- it "does not report re-opened #{scope} in the same file" do
53
- src = <<-EOS
54
- # This comment describes Alfa
55
- #{scope} Alfa; end
56
-
57
- #{scope} Alfa; def bravo; end; end
58
- EOS
59
-
60
- expect(src).not_to reek_of(:IrresponsibleModule)
61
- end
62
-
63
52
  it "reports a #{scope} with an empty comment" do
64
53
  src = <<-EOS
65
54
  #
@@ -1,7 +1,7 @@
1
1
  require_relative '../../spec_helper'
2
- require_lib 'reek/smell_detectors/prima_donna_method'
2
+ require_lib 'reek/smell_detectors/missing_safe_method'
3
3
 
4
- RSpec.describe Reek::SmellDetectors::PrimaDonnaMethod do
4
+ RSpec.describe Reek::SmellDetectors::MissingSafeMethod do
5
5
  it 'reports the right values' do
6
6
  src = <<-EOS
7
7
  class Alfa
@@ -10,10 +10,10 @@ RSpec.describe Reek::SmellDetectors::PrimaDonnaMethod do
10
10
  end
11
11
  EOS
12
12
 
13
- expect(src).to reek_of(:PrimaDonnaMethod,
14
- lines: [1],
13
+ expect(src).to reek_of(:MissingSafeMethod,
14
+ lines: [2],
15
15
  context: 'Alfa',
16
- message: "has prima donna method 'bravo!'",
16
+ message: "has missing safe method 'bravo!'",
17
17
  source: 'string',
18
18
  name: 'bravo!')
19
19
  end
@@ -30,8 +30,8 @@ RSpec.describe Reek::SmellDetectors::PrimaDonnaMethod do
30
30
  EOS
31
31
 
32
32
  expect(src).
33
- to reek_of(:PrimaDonnaMethod, lines: [1], name: 'bravo!').
34
- and reek_of(:PrimaDonnaMethod, lines: [1], name: 'charlie!')
33
+ to reek_of(:MissingSafeMethod, lines: [2], name: 'bravo!').
34
+ and reek_of(:MissingSafeMethod, lines: [5], name: 'charlie!')
35
35
  end
36
36
 
37
37
  it 'reports nothing when method and bang counterpart exist' do
@@ -45,18 +45,18 @@ RSpec.describe Reek::SmellDetectors::PrimaDonnaMethod do
45
45
  end
46
46
  EOS
47
47
 
48
- expect(src).not_to reek_of(:PrimaDonnaMethod)
48
+ expect(src).not_to reek_of(:MissingSafeMethod)
49
49
  end
50
50
 
51
51
  it 'does not report methods we excluded via comment' do
52
52
  source = <<-EOF
53
- # :reek:PrimaDonnaMethod: { exclude: [ bravo! ] }
53
+ # :reek:MissingSafeMethod: { exclude: [ bravo! ] }
54
54
  class Alfa
55
55
  def bravo!
56
56
  end
57
57
  end
58
58
  EOF
59
59
 
60
- expect(source).not_to reek_of(:PrimaDonnaMethod)
60
+ expect(source).not_to reek_of(:MissingSafeMethod)
61
61
  end
62
62
  end
@@ -50,6 +50,20 @@ RSpec.describe Reek::SmellDetectors::ModuleInitialize do
50
50
  expect(src).not_to reek_of(:ModuleInitialize)
51
51
  end
52
52
 
53
+ it 'reports nothing for a method named initialize in a nested dynamic class' do
54
+ src = <<-EOF
55
+ module Alfa
56
+ def self.bravo
57
+ Class.new do
58
+ def initialize; end
59
+ end
60
+ end
61
+ end
62
+ EOF
63
+
64
+ expect(src).not_to reek_of(:ModuleInitialize)
65
+ end
66
+
53
67
  it 'can be disabled via comment' do
54
68
  src = <<-EOS
55
69
  # :reek:ModuleInitialize
@@ -223,7 +223,7 @@ RSpec.describe Reek::SmellDetectors::NestedIterators do
223
223
  expect(src).not_to reek_of(:NestedIterators)
224
224
  end
225
225
 
226
- context 'setting the allowed nesting depth to 3' do
226
+ context 'when setting the allowed nesting depth to 3' do
227
227
  let(:config) do
228
228
  { Reek::SmellDetectors::NestedIterators::MAX_ALLOWED_NESTING_KEY => 3 }
229
229
  end
@@ -33,7 +33,7 @@ RSpec.describe Reek::SmellDetectors::TooManyConstants do
33
33
 
34
34
  it 'does not report when increasing default' do
35
35
  src = <<-EOS
36
- # :reek:TooManyConstants: { max_constants: 3 }
36
+ # :reek:TooManyConstants { max_constants: 3 }
37
37
  class Alfa
38
38
  Bravo = Charlie = Delta = 1
39
39
  end
@@ -44,7 +44,7 @@ RSpec.describe Reek::SmellDetectors::TooManyConstants do
44
44
 
45
45
  it 'does not report when disabled' do
46
46
  src = <<-EOS
47
- # :reek:TooManyConstants: { enabled: false }
47
+ # :reek:TooManyConstants { enabled: false }
48
48
  class Alfa
49
49
  Bravo = Charlie = Delta = 1
50
50
  end
@@ -96,7 +96,7 @@ RSpec.describe Reek::SmellDetectors::TooManyConstants do
96
96
  it 'does not report outer module when inner module suppressed' do
97
97
  src = <<-EOS
98
98
  module Alfa
99
- # ignore :reek:TooManyConstants:
99
+ # ignore :reek:TooManyConstants
100
100
  module Bravo
101
101
  Charlie = Delta = Echo = 1
102
102
  end
@@ -37,7 +37,7 @@ RSpec.describe Reek::SmellDetectors::TooManyInstanceVariables do
37
37
 
38
38
  it 'has a configurable maximum' do
39
39
  src = <<-EOS
40
- # :reek:TooManyInstanceVariables: { max_instance_variables: 3 }
40
+ # :reek:TooManyInstanceVariables { max_instance_variables: 3 }
41
41
  class Alfa
42
42
  def bravo
43
43
  @charlie = @delta = @echo = 1
@@ -41,18 +41,18 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeMethodName do
41
41
  describe '`accept` patterns' do
42
42
  let(:source) { 'def x; end' }
43
43
 
44
- it 'make smelly names pass via regex / strings given by list / literal' do
45
- [[/x/], /x/, ['x'], 'x'].each do |pattern|
46
- expect(source).not_to reek_of(:UncommunicativeMethodName).with_config('accept' => pattern)
47
- end
44
+ it 'make smelly names pass' do
45
+ pattern = /x/
46
+ expect(source).not_to reek_of(:UncommunicativeMethodName).with_config('accept' => pattern)
48
47
  end
49
48
  end
50
49
 
51
50
  describe '`reject` patterns' do
52
51
  let(:source) { 'def alfa; end' }
53
52
 
54
- it 'reject smelly names via regex / strings given by list / literal' do
55
- [[/alfa/], /alfa/, ['alfa'], 'alfa'].each do |pattern|
53
+ it 'reject smelly names' do
54
+ patterns = [/alf/, /lfa/]
55
+ patterns.each do |pattern|
56
56
  expect(source).to reek_of(:UncommunicativeMethodName).with_config('reject' => pattern)
57
57
  end
58
58
  end
@@ -39,8 +39,9 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeModuleName do
39
39
  describe '`accept` patterns' do
40
40
  let(:source) { 'class Alfa1; end' }
41
41
 
42
- it 'makes smelly names pass via regex / strings given by list / literal' do
43
- [[/lfa/], /lfa/, ['lfa'], 'lfa'].each do |pattern|
42
+ it 'make smelly names pass ' do
43
+ patterns = [/lfa1/, /Alfa1/]
44
+ patterns.each do |pattern|
44
45
  expect(source).not_to reek_of(:UncommunicativeModuleName).with_config('accept' => pattern)
45
46
  end
46
47
  end
@@ -49,8 +50,9 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeModuleName do
49
50
  describe '`reject` patterns' do
50
51
  let(:source) { 'class Alfa; end' }
51
52
 
52
- it 'rejects smelly names via regex / strings given by list / literal' do
53
- [[/Alfa/], /Alfa/, ['Alfa'], 'Alfa'].each do |pattern|
53
+ it 'reject smelly names' do
54
+ patterns = [/lfa/, /Alf/]
55
+ patterns.each do |pattern|
54
56
  expect(source).to reek_of(:UncommunicativeModuleName).with_config('reject' => pattern)
55
57
  end
56
58
  end
@@ -32,15 +32,6 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
32
32
  { 'alfa.' => 'with a receiver',
33
33
  '' => 'without a receiver' }.each do |host, description|
34
34
  context "in a method definition #{description}" do
35
- it 'does not recognise *' do
36
- expect("def #{host}bravo(*); end").not_to reek_of(:UncommunicativeParameterName)
37
- end
38
-
39
- it 'does not report unused parameters' do
40
- src = "def #{host}bravo(x); charlie; end"
41
- expect(src).not_to reek_of(:UncommunicativeParameterName)
42
- end
43
-
44
35
  it 'does not report two-letter parameter names' do
45
36
  src = "def #{host}bravo(ab); charlie(ab); end"
46
37
  expect(src).not_to reek_of(:UncommunicativeParameterName)
@@ -56,6 +47,26 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
56
47
  expect(src).to reek_of(:UncommunicativeParameterName, name: 'param2')
57
48
  end
58
49
 
50
+ it 'reports unused parameters' do
51
+ src = "def #{host}bravo(x); charlie; end"
52
+ expect(src).to reek_of(:UncommunicativeParameterName)
53
+ end
54
+
55
+ it 'reports splat parameters' do
56
+ expect("def #{host}bravo(*a); charlie(a); end").
57
+ to reek_of(:UncommunicativeParameterName, name: 'a')
58
+ end
59
+
60
+ it 'reports double splat parameters' do
61
+ expect("def #{host}bravo(**a); charlie(a); end").
62
+ to reek_of(:UncommunicativeParameterName, name: 'a')
63
+ end
64
+
65
+ it 'reports block parameters' do
66
+ expect("def #{host}bravo(&a); charlie(a); end").
67
+ to reek_of(:UncommunicativeParameterName, name: 'a')
68
+ end
69
+
59
70
  it 'does not report unused anonymous parameter' do
60
71
  src = "def #{host}bravo(_); charlie; end"
61
72
  expect(src).not_to reek_of(:UncommunicativeParameterName)
@@ -63,12 +74,20 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
63
74
 
64
75
  it 'reports used anonymous parameter' do
65
76
  src = "def #{host}bravo(_); charlie(_) end"
66
- expect(src).to reek_of(:UncommunicativeParameterName)
77
+ expect(src).to reek_of(:UncommunicativeParameterName, name: '_')
67
78
  end
68
79
 
69
80
  it 'reports used parameters marked as unused' do
70
81
  src = "def #{host}bravo(_unused) charlie(_unused) end"
71
- expect(src).to reek_of(:UncommunicativeParameterName)
82
+ expect(src).to reek_of(:UncommunicativeParameterName, name: '_unused')
83
+ end
84
+
85
+ it 'does not report anonymous splat' do
86
+ expect("def #{host}bravo(*); end").not_to reek_of(:UncommunicativeParameterName)
87
+ end
88
+
89
+ it 'does not report anonymous double splat' do
90
+ expect("def #{host}bravo(**); end").not_to reek_of(:UncommunicativeParameterName)
72
91
  end
73
92
 
74
93
  it 'reports names inside array decomposition' do
@@ -88,8 +107,9 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
88
107
  describe '`accept` patterns' do
89
108
  let(:source) { 'def alfa(bar2); charlie(bar2); end' }
90
109
 
91
- it 'make smelly names pass via regex / strings given by list / literal' do
92
- [[/bar2/], /bar2/, ['bar2'], 'bar2'].each do |pattern|
110
+ it 'make smelly names pass' do
111
+ patterns = [/bar2/, /ar2/]
112
+ patterns.each do |pattern|
93
113
  expect(source).not_to reek_of(:UncommunicativeParameterName).with_config('accept' => pattern)
94
114
  end
95
115
  end
@@ -98,8 +118,9 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
98
118
  describe '`reject` patterns' do
99
119
  let(:source) { 'def alfa(bravo); charlie(bravo); end' }
100
120
 
101
- it 'reject smelly names via regex / strings given by list / literal' do
102
- [[/bravo/], /bravo/, ['bravo'], 'bravo'].each do |pattern|
121
+ it 'reject smelly names' do
122
+ patterns = [/brav/, /ravo/]
123
+ patterns.each do |pattern|
103
124
  expect(source).to reek_of(:UncommunicativeParameterName).with_config('reject' => pattern)
104
125
  end
105
126
  end
@@ -29,7 +29,7 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeVariableName do
29
29
  and reek_of(:UncommunicativeVariableName, lines: [3], name: 'y')
30
30
  end
31
31
 
32
- context 'instance variables' do
32
+ context 'when examining instance variables' do
33
33
  it 'does not report use of one-letter names' do
34
34
  src = 'class Alfa; def bravo; @x; end; end'
35
35
  expect(src).not_to reek_of(:UncommunicativeVariableName)
@@ -41,7 +41,7 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeVariableName do
41
41
  end
42
42
  end
43
43
 
44
- context 'local variables' do
44
+ context 'when examining local variables' do
45
45
  it 'does not report single underscore as a variable name' do
46
46
  src = 'def alfa; _ = bravo(); end'
47
47
  expect(src).not_to reek_of(:UncommunicativeVariableName)
@@ -78,7 +78,7 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeVariableName do
78
78
  end
79
79
  end
80
80
 
81
- context 'block parameters' do
81
+ context 'when examining block parameters' do
82
82
  it 'reports all relevant block parameters' do
83
83
  src = <<-EOS
84
84
  def alfa
@@ -159,9 +159,9 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeVariableName do
159
159
  describe '`accept` patterns' do
160
160
  let(:src) { 'def alfa; bravo2 = 42; end' }
161
161
 
162
- # FIXME: Move the loop out of the it?
163
- it 'make smelly names pass via regex / strings given by list / literal' do
164
- [[/bravo2/], /bravo2/, ['bravo2'], 'bravo2'].each do |pattern|
162
+ it 'make smelly names pass' do
163
+ patterns = [/ravo2/, /bravo2/]
164
+ patterns.each do |pattern|
165
165
  expect(src).to reek_of(:UncommunicativeVariableName).
166
166
  and not_reek_of(:UncommunicativeVariableName).with_config('accept' => pattern)
167
167
  end
@@ -171,9 +171,9 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeVariableName do
171
171
  describe '`reject` patterns' do
172
172
  let(:src) { 'def alfa; foobar = 42; end' }
173
173
 
174
- # FIXME: Move the loop out of the it?
175
- it 'reject smelly names via regex / strings given by list / literal' do
176
- [[/foobar/], /foobar/, ['foobar'], 'foobar'].each do |pattern|
174
+ it 'reject smelly names' do
175
+ patterns = [/fooba/, /oobar/]
176
+ patterns.each do |pattern|
177
177
  expect(src).to not_reek_of(:UncommunicativeVariableName).
178
178
  and reek_of(:UncommunicativeVariableName).with_config('reject' => pattern)
179
179
  end
@@ -61,7 +61,7 @@ RSpec.describe Reek::SmellDetectors::UnusedParameters do
61
61
  expect(src).not_to reek_of(:UnusedParameters)
62
62
  end
63
63
 
64
- context 'using super' do
64
+ context 'when using super' do
65
65
  it 'reports nothing with implicit arguments' do
66
66
  src = 'def alfa(*bravo); super; end'
67
67
  expect(src).not_to reek_of(:UnusedParameters)
@@ -83,7 +83,7 @@ RSpec.describe Reek::SmellDetectors::UnusedParameters do
83
83
  end
84
84
  end
85
85
 
86
- context 'anonymous parameters' do
86
+ context 'with anonymous parameters' do
87
87
  it 'reports nothing for unused anonymous parameter' do
88
88
  src = 'def alfa(_); end'
89
89
  expect(src).not_to reek_of(:UnusedParameters)
@@ -95,7 +95,7 @@ RSpec.describe Reek::SmellDetectors::UnusedParameters do
95
95
  end
96
96
  end
97
97
 
98
- context 'splatted parameters' do
98
+ context 'with splatted parameters' do
99
99
  it 'reports nothing for used splatted parameter' do
100
100
  src = 'def alfa(*bravo); bravo; end'
101
101
  expect(src).not_to reek_of(:UnusedParameters)
@@ -38,7 +38,7 @@ RSpec.describe Reek::SmellDetectors::UnusedPrivateMethod do
38
38
  and reek_of(:UnusedPrivateMethod, lines: [7], name: 'charlie')
39
39
  end
40
40
 
41
- context 'unused private methods' do
41
+ context 'when a class has unused private methods' do
42
42
  it 'reports instance methods' do
43
43
  source = <<-EOF
44
44
  class Alfa
@@ -103,12 +103,23 @@ RSpec.describe Reek::SmellDetectors::UnusedPrivateMethod do
103
103
  to reek_of(:UnusedPrivateMethod, name: 'bravo', lines: [3]).
104
104
  and reek_of(:UnusedPrivateMethod, name: 'charlie', lines: [4])
105
105
  end
106
+
107
+ it 'reports instance methods defined as private with a modifier' do
108
+ source = <<-EOF
109
+ class Alfa
110
+ private def bravo; end
111
+ end
112
+ EOF
113
+
114
+ expect(source).
115
+ to reek_of(:UnusedPrivateMethod, name: 'bravo')
116
+ end
106
117
  end
107
118
 
108
- describe 'configuring the detector via source code comment' do
119
+ context 'when the detector is configured via a source code comment' do
109
120
  it 'does not report methods we excluded' do
110
121
  source = <<-EOF
111
- # :reek:UnusedPrivateMethod: { exclude: [ bravo ] }
122
+ # :reek:UnusedPrivateMethod { exclude: [ bravo ] }
112
123
  class Alfa
113
124
  private
114
125
  def bravo; end
@@ -122,8 +133,8 @@ RSpec.describe Reek::SmellDetectors::UnusedPrivateMethod do
122
133
  end
123
134
  end
124
135
 
125
- context 'used private methods' do
126
- it 'are not reported' do
136
+ context 'when a class has only used private methods' do
137
+ it 'reports nothing' do
127
138
  source = <<-EOF
128
139
  class Alfa
129
140
  def bravo
@@ -139,8 +150,8 @@ RSpec.describe Reek::SmellDetectors::UnusedPrivateMethod do
139
150
  end
140
151
  end
141
152
 
142
- context 'unused protected methods' do
143
- it 'are not reported' do
153
+ context 'when a class has unused protected methods' do
154
+ it 'reports nothing' do
144
155
  source = <<-EOF
145
156
  class Alfa
146
157
  protected
@@ -152,8 +163,8 @@ RSpec.describe Reek::SmellDetectors::UnusedPrivateMethod do
152
163
  end
153
164
  end
154
165
 
155
- context 'unused public methods' do
156
- it 'are not reported' do
166
+ context 'when a class has unused public methods' do
167
+ it 'reports nothing' do
157
168
  source = <<-EOF
158
169
  class Alfa
159
170
  def bravo; end
@@ -164,7 +175,7 @@ RSpec.describe Reek::SmellDetectors::UnusedPrivateMethod do
164
175
  end
165
176
  end
166
177
 
167
- describe 'prevent methods from being reported' do
178
+ describe 'preventing methods from being reported' do
168
179
  let(:source) do
169
180
  <<-EOF
170
181
  class Alfa