reek 4.6.0 → 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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -12
  3. data/.rubocop.yml +79 -26
  4. data/.simplecov +1 -0
  5. data/.travis.yml +3 -9
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +76 -0
  8. data/CONTRIBUTING.md +1 -1
  9. data/Gemfile +5 -5
  10. data/README.md +138 -107
  11. data/Rakefile +16 -3
  12. data/bin/code_climate_reek +1 -0
  13. data/bin/reek +2 -3
  14. data/docs/API.md +2 -9
  15. data/docs/Basic-Smell-Options.md +51 -11
  16. data/docs/Code-Smells.md +1 -1
  17. data/docs/Command-Line-Options.md +14 -4
  18. data/docs/Duplicate-Method-Call.md +49 -1
  19. data/docs/Feature-Envy.md +44 -0
  20. data/docs/How-To-Write-New-Detectors.md +7 -7
  21. data/docs/Instance-Variable-Assumption.md +1 -1
  22. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  23. data/docs/Rake-Task.md +1 -1
  24. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  25. data/docs/Reek-Driven-Development.md +1 -1
  26. data/docs/Uncommunicative-Method-Name.md +45 -6
  27. data/docs/Uncommunicative-Module-Name.md +49 -7
  28. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  29. data/docs/Uncommunicative-Variable-Name.md +73 -2
  30. data/docs/Unused-Private-Method.md +3 -3
  31. data/docs/defaults.reek.yml +129 -0
  32. data/docs/yard_plugin.rb +1 -0
  33. data/features/command_line_interface/basic_usage.feature +2 -2
  34. data/features/command_line_interface/options.feature +46 -4
  35. data/features/command_line_interface/show_progress.feature +4 -4
  36. data/features/command_line_interface/smell_selection.feature +1 -1
  37. data/features/command_line_interface/smells_count.feature +6 -6
  38. data/features/command_line_interface/stdin.feature +31 -5
  39. data/features/configuration_files/accept_setting.feature +45 -28
  40. data/features/configuration_files/directory_specific_directives.feature +80 -75
  41. data/features/configuration_files/exclude_directives.feature +11 -10
  42. data/features/configuration_files/exclude_paths_directives.feature +4 -4
  43. data/features/configuration_files/masking_smells.feature +38 -9
  44. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  45. data/features/configuration_files/reject_setting.feature +52 -41
  46. data/features/configuration_files/schema_validation.feature +59 -0
  47. data/features/configuration_files/unused_private_method.feature +18 -16
  48. data/features/configuration_loading.feature +53 -10
  49. data/features/configuration_via_source_comments/erroneous_source_comments.feature +3 -3
  50. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  51. data/features/locales.feature +32 -0
  52. data/features/rake_task/rake_task.feature +58 -18
  53. data/features/reports/codeclimate.feature +59 -0
  54. data/features/reports/json.feature +3 -3
  55. data/features/reports/reports.feature +34 -34
  56. data/features/reports/yaml.feature +3 -3
  57. data/features/rspec_matcher.feature +40 -0
  58. data/features/samples.feature +287 -287
  59. data/features/step_definitions/reek_steps.rb +14 -2
  60. data/features/step_definitions/sample_file_steps.rb +9 -4
  61. data/features/support/env.rb +2 -11
  62. data/features/todo_list.feature +26 -23
  63. data/lib/reek/ast/ast_node_class_map.rb +1 -0
  64. data/lib/reek/ast/builder.rb +16 -0
  65. data/lib/reek/ast/node.rb +50 -58
  66. data/lib/reek/ast/object_refs.rb +2 -1
  67. data/lib/reek/ast/reference_collector.rb +3 -4
  68. data/lib/reek/ast/sexp_extensions/arguments.rb +1 -0
  69. data/lib/reek/ast/sexp_extensions/attribute_assignments.rb +1 -0
  70. data/lib/reek/ast/sexp_extensions/begin.rb +17 -0
  71. data/lib/reek/ast/sexp_extensions/block.rb +1 -0
  72. data/lib/reek/ast/sexp_extensions/case.rb +2 -1
  73. data/lib/reek/ast/sexp_extensions/constant.rb +1 -0
  74. data/lib/reek/ast/sexp_extensions/if.rb +9 -1
  75. data/lib/reek/ast/sexp_extensions/lambda.rb +1 -0
  76. data/lib/reek/ast/sexp_extensions/literal.rb +1 -0
  77. data/lib/reek/ast/sexp_extensions/logical_operators.rb +2 -1
  78. data/lib/reek/ast/sexp_extensions/methods.rb +5 -6
  79. data/lib/reek/ast/sexp_extensions/module.rb +55 -8
  80. data/lib/reek/ast/sexp_extensions/nested_assignables.rb +1 -0
  81. data/lib/reek/ast/sexp_extensions/self.rb +1 -0
  82. data/lib/reek/ast/sexp_extensions/send.rb +1 -4
  83. data/lib/reek/ast/sexp_extensions/super.rb +1 -0
  84. data/lib/reek/ast/sexp_extensions/symbols.rb +1 -0
  85. data/lib/reek/ast/sexp_extensions/variables.rb +1 -0
  86. data/lib/reek/ast/sexp_extensions/when.rb +1 -0
  87. data/lib/reek/ast/sexp_extensions/yield.rb +1 -0
  88. data/lib/reek/ast/sexp_extensions.rb +2 -0
  89. data/lib/reek/cli/application.rb +5 -3
  90. data/lib/reek/cli/command/base_command.rb +1 -0
  91. data/lib/reek/cli/command/report_command.rb +2 -2
  92. data/lib/reek/cli/command/todo_list_command.rb +9 -8
  93. data/lib/reek/cli/options.rb +32 -16
  94. data/lib/reek/cli/silencer.rb +15 -3
  95. data/lib/reek/cli/status.rb +1 -0
  96. data/lib/reek/code_comment.rb +14 -16
  97. data/lib/reek/configuration/app_configuration.rb +34 -28
  98. data/lib/reek/configuration/configuration_converter.rb +110 -0
  99. data/lib/reek/configuration/configuration_file_finder.rb +17 -41
  100. data/lib/reek/configuration/configuration_validator.rb +13 -23
  101. data/lib/reek/configuration/default_directive.rb +18 -3
  102. data/lib/reek/configuration/directory_directives.rb +18 -11
  103. data/lib/reek/configuration/excluded_paths.rb +2 -1
  104. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  105. data/lib/reek/configuration/schema.yml +210 -0
  106. data/lib/reek/configuration/schema_validator.rb +38 -0
  107. data/lib/reek/context/attribute_context.rb +4 -3
  108. data/lib/reek/context/class_context.rb +1 -0
  109. data/lib/reek/context/code_context.rb +49 -44
  110. data/lib/reek/context/ghost_context.rb +1 -2
  111. data/lib/reek/context/method_context.rb +26 -18
  112. data/lib/reek/context/module_context.rb +11 -11
  113. data/lib/reek/context/root_context.rb +1 -4
  114. data/lib/reek/context/send_context.rb +3 -2
  115. data/lib/reek/context/singleton_attribute_context.rb +1 -0
  116. data/lib/reek/context/singleton_method_context.rb +1 -0
  117. data/lib/reek/context/statement_counter.rb +1 -0
  118. data/lib/reek/context/visibility_tracker.rb +1 -0
  119. data/lib/reek/context_builder.rb +44 -44
  120. data/lib/reek/detector_repository.rb +12 -11
  121. data/lib/reek/documentation_link.rb +28 -0
  122. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +15 -13
  123. data/lib/reek/errors/bad_detector_in_comment_error.rb +13 -11
  124. data/lib/reek/errors/base_error.rb +3 -0
  125. data/lib/reek/errors/config_file_error.rb +11 -0
  126. data/lib/reek/errors/encoding_error.rb +43 -0
  127. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +14 -12
  128. data/lib/reek/errors/incomprehensible_source_error.rb +23 -24
  129. data/lib/reek/errors/syntax_error.rb +41 -0
  130. data/lib/reek/examiner.rb +24 -22
  131. data/lib/reek/logging_error_handler.rb +8 -5
  132. data/lib/reek/rake/task.rb +8 -5
  133. data/lib/reek/report/base_report.rb +9 -12
  134. data/lib/reek/report/code_climate/code_climate_configuration.rb +2 -1
  135. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -6
  136. data/lib/reek/report/code_climate/code_climate_fingerprint.rb +1 -0
  137. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -0
  138. data/lib/reek/report/code_climate/code_climate_report.rb +1 -0
  139. data/lib/reek/report/code_climate.rb +1 -0
  140. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  141. data/lib/reek/report/heading_formatter.rb +54 -0
  142. data/lib/reek/report/html_report.rb +1 -0
  143. data/lib/reek/report/json_report.rb +2 -1
  144. data/lib/reek/report/location_formatter.rb +40 -0
  145. data/lib/reek/report/progress_formatter.rb +79 -0
  146. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  147. data/lib/reek/report/text_report.rb +2 -2
  148. data/lib/reek/report/xml_report.rb +4 -3
  149. data/lib/reek/report/yaml_report.rb +2 -1
  150. data/lib/reek/report.rb +16 -10
  151. data/lib/reek/smell_configuration.rb +3 -2
  152. data/lib/reek/smell_detectors/attribute.rb +6 -11
  153. data/lib/reek/smell_detectors/base_detector.rb +31 -26
  154. data/lib/reek/smell_detectors/boolean_parameter.rb +4 -5
  155. data/lib/reek/smell_detectors/class_variable.rb +6 -14
  156. data/lib/reek/smell_detectors/control_parameter.rb +19 -33
  157. data/lib/reek/smell_detectors/data_clump.rb +16 -9
  158. data/lib/reek/smell_detectors/duplicate_method_call.rb +24 -17
  159. data/lib/reek/smell_detectors/feature_envy.rb +10 -7
  160. data/lib/reek/smell_detectors/instance_variable_assumption.rb +15 -23
  161. data/lib/reek/smell_detectors/irresponsible_module.rb +6 -12
  162. data/lib/reek/smell_detectors/long_parameter_list.rb +11 -7
  163. data/lib/reek/smell_detectors/long_yield_list.rb +11 -7
  164. data/lib/reek/smell_detectors/manual_dispatch.rb +5 -5
  165. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +21 -20
  166. data/lib/reek/smell_detectors/module_initialize.rb +4 -5
  167. data/lib/reek/smell_detectors/nested_iterators.rb +17 -24
  168. data/lib/reek/smell_detectors/nil_check.rb +9 -15
  169. data/lib/reek/smell_detectors/repeated_conditional.rb +14 -11
  170. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +8 -8
  171. data/lib/reek/smell_detectors/too_many_constants.rb +11 -9
  172. data/lib/reek/smell_detectors/too_many_instance_variables.rb +11 -6
  173. data/lib/reek/smell_detectors/too_many_methods.rb +12 -7
  174. data/lib/reek/smell_detectors/too_many_statements.rb +11 -6
  175. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +11 -11
  176. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +15 -18
  177. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +18 -22
  178. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +27 -27
  179. data/lib/reek/smell_detectors/unused_parameters.rb +5 -6
  180. data/lib/reek/smell_detectors/unused_private_method.rb +14 -20
  181. data/lib/reek/smell_detectors/utility_function.rb +13 -16
  182. data/lib/reek/smell_detectors.rb +2 -1
  183. data/lib/reek/smell_warning.rb +16 -8
  184. data/lib/reek/source/source_code.rb +65 -46
  185. data/lib/reek/source/source_locator.rb +9 -8
  186. data/lib/reek/spec/should_reek.rb +3 -2
  187. data/lib/reek/spec/should_reek_of.rb +13 -26
  188. data/lib/reek/spec/should_reek_only_of.rb +5 -4
  189. data/lib/reek/spec/smell_matcher.rb +2 -1
  190. data/lib/reek/spec.rb +7 -6
  191. data/lib/reek/tree_dresser.rb +9 -8
  192. data/lib/reek/version.rb +2 -1
  193. data/lib/reek.rb +1 -0
  194. data/reek.gemspec +5 -6
  195. data/samples/checkstyle.xml +1 -1
  196. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  197. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  198. data/samples/configuration/full_configuration.reek +8 -4
  199. data/samples/configuration/full_mask.reek +5 -4
  200. data/samples/configuration/partial_mask.reek +3 -2
  201. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  202. data/samples/paths.rb +5 -4
  203. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  204. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  205. data/spec/factories/factories.rb +2 -13
  206. data/spec/reek/ast/node_spec.rb +103 -10
  207. data/spec/reek/ast/reference_collector_spec.rb +1 -1
  208. data/spec/reek/ast/sexp_extensions_spec.rb +15 -34
  209. data/spec/reek/cli/application_spec.rb +52 -42
  210. data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
  211. data/spec/reek/cli/silencer_spec.rb +28 -0
  212. data/spec/reek/code_comment_spec.rb +31 -38
  213. data/spec/reek/configuration/app_configuration_spec.rb +46 -33
  214. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -51
  215. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  216. data/spec/reek/configuration/directory_directives_spec.rb +6 -7
  217. data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
  218. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  219. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  220. data/spec/reek/context/code_context_spec.rb +70 -106
  221. data/spec/reek/context/ghost_context_spec.rb +9 -9
  222. data/spec/reek/context/method_context_spec.rb +2 -2
  223. data/spec/reek/context/module_context_spec.rb +3 -3
  224. data/spec/reek/context/root_context_spec.rb +1 -1
  225. data/spec/reek/context/statement_counter_spec.rb +1 -0
  226. data/spec/reek/context_builder_spec.rb +20 -0
  227. data/spec/reek/documentation_link_spec.rb +20 -0
  228. data/spec/reek/errors/base_error_spec.rb +13 -0
  229. data/spec/reek/examiner_spec.rb +137 -29
  230. data/spec/reek/rake/task_spec.rb +25 -2
  231. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -78
  232. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  233. data/spec/reek/report/code_climate/code_climate_report_spec.rb +22 -22
  234. data/spec/reek/report/json_report_spec.rb +13 -46
  235. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  236. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  237. data/spec/reek/report/text_report_spec.rb +4 -4
  238. data/spec/reek/report/xml_report_spec.rb +3 -3
  239. data/spec/reek/report/yaml_report_spec.rb +17 -46
  240. data/spec/reek/report_spec.rb +3 -3
  241. data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
  242. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
  243. data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
  244. data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
  245. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
  246. data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
  247. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +59 -21
  248. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
  249. data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
  250. data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
  251. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  252. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  253. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  254. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  255. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +36 -15
  256. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
  257. data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
  258. data/spec/reek/smell_detectors/unused_private_method_spec.rb +21 -10
  259. data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
  260. data/spec/reek/smell_warning_spec.rb +12 -8
  261. data/spec/reek/source/source_code_spec.rb +27 -38
  262. data/spec/reek/source/source_locator_spec.rb +42 -12
  263. data/spec/reek/spec/should_reek_of_spec.rb +25 -30
  264. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  265. data/spec/reek/spec/should_reek_spec.rb +8 -8
  266. data/spec/reek/spec/smell_matcher_spec.rb +23 -23
  267. data/spec/reek/tree_dresser_spec.rb +12 -17
  268. data/spec/spec_helper.rb +7 -17
  269. data/tasks/configuration.rake +8 -5
  270. metadata +77 -40
  271. data/defaults.reek +0 -128
  272. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  273. data/lib/reek/errors/parse_error.rb +0 -19
  274. data/lib/reek/report/formatter/heading_formatter.rb +0 -51
  275. data/lib/reek/report/formatter/location_formatter.rb +0 -41
  276. data/lib/reek/report/formatter/progress_formatter.rb +0 -80
  277. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  278. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -35
  279. data/lib/reek/report/formatter.rb +0 -32
  280. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  281. data/samples/smelly_with_inline_mask.rb +0 -8
  282. data/samples/smelly_with_modifiers.rb +0 -12
  283. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  284. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  285. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  286. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  287. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  288. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  289. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  290. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  291. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  292. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  293. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  294. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
@@ -63,49 +63,43 @@ RSpec.describe Reek::SmellDetectors::ClassVariable do
63
63
  end
64
64
 
65
65
  ['class', 'module'].each do |scope|
66
- context "Scoped to #{scope}" do
67
- context 'set in a method' do
68
- it 'reports correctly' do
69
- src = <<-EOS
70
- #{scope} Alfa
71
- def bravo
72
- @@charlie = {}
73
- end
66
+ context "when examining a #{scope}" do
67
+ it 'reports a class variable set in a method' do
68
+ src = <<-EOS
69
+ #{scope} Alfa
70
+ def bravo
71
+ @@charlie = {}
74
72
  end
75
- EOS
73
+ end
74
+ EOS
76
75
 
77
- expect(src).to reek_of(:ClassVariable)
78
- end
76
+ expect(src).to reek_of(:ClassVariable, name: '@@charlie')
79
77
  end
80
78
 
81
- context 'used in a method' do
82
- it 'reports correctly' do
83
- src = <<-EOS
84
- #{scope} Alfa
85
- def bravo
86
- puts @@charlie
87
- end
79
+ it 'reports a class variable used in a method' do
80
+ src = <<-EOS
81
+ #{scope} Alfa
82
+ def bravo
83
+ puts @@charlie
88
84
  end
89
- EOS
85
+ end
86
+ EOS
90
87
 
91
- expect(src).to reek_of(:ClassVariable)
92
- end
88
+ expect(src).to reek_of(:ClassVariable, name: '@@charlie')
93
89
  end
94
90
 
95
- context "set in #{scope} and used in a method" do
96
- it 'reports correctly' do
97
- src = <<-EOS
98
- #{scope} Alfa
99
- @@bravo = 42
91
+ it "reports a class variable set in the #{scope} body and used in a method" do
92
+ src = <<-EOS
93
+ #{scope} Alfa
94
+ @@bravo = 42
100
95
 
101
- def charlie
102
- puts @@bravo
103
- end
96
+ def charlie
97
+ puts @@bravo
104
98
  end
105
- EOS
99
+ end
100
+ EOS
106
101
 
107
- expect(src).to reek_of(:ClassVariable)
108
- end
102
+ expect(src).to reek_of(:ClassVariable, name: '@@bravo')
109
103
  end
110
104
  end
111
105
  end
@@ -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
@@ -18,7 +18,7 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
18
18
  it 'does count all occurences' do
19
19
  src = <<-EOS
20
20
  class Alfa
21
- # Method is necessary because we don't count empty classes.
21
+ # Method is necessary because we don't count namespace classes.
22
22
  def bravo; end
23
23
  class Charlie
24
24
  end
@@ -40,20 +40,9 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
40
40
  expect(src).to reek_of(:IrresponsibleModule)
41
41
  end
42
42
 
43
- it "does not report re-opened #{scope}" do
44
- src = <<-EOS
45
- # Abstract base
46
- #{scope} Alfa; end
47
-
48
- #{scope} Alfa; def bravo; end; end
49
- EOS
50
-
51
- expect(src).not_to reek_of(:IrresponsibleModule)
52
- end
53
-
54
43
  it "does not report a #{scope} having a comment" do
55
44
  src = <<-EOS
56
- # Do not report me
45
+ # Do not report me, I'm responsible!
57
46
  #{scope} Alfa; end
58
47
  EOS
59
48
 
@@ -73,7 +62,7 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
73
62
 
74
63
  it "reports a #{scope} with a preceding comment with intermittent material" do
75
64
  src = <<-EOS
76
- # This is a valid comment
65
+ # This is a comment that should not be related to Bravo
77
66
 
78
67
  require 'alfa'
79
68
 
@@ -87,13 +76,13 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
87
76
  it "reports a #{scope} with only a trailing comment" do
88
77
  src = <<-EOS
89
78
  #{scope} Alfa
90
- end # end scope
79
+ end # This belongs to Alfa but doesn't count
91
80
  EOS
92
81
 
93
82
  expect(src).to reek_of(:IrresponsibleModule)
94
83
  end
95
84
 
96
- it "does not report #{scope} used only as namespaces" do
85
+ it "does not report #{scope} used only as a namespace" do
97
86
  src = <<-EOS
98
87
  #{scope} Alfa
99
88
  # Describes Bravo
@@ -104,10 +93,28 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
104
93
  end
105
94
  EOS
106
95
 
107
- expect(src).not_to reek_of(:IrresponsibleModule)
96
+ expect(src).not_to reek_of(:IrresponsibleModule, context: 'Alfa')
97
+ end
98
+
99
+ it "does not report #{scope} used only as a namespace for several nested moduless" do
100
+ src = <<-EOS
101
+ #{scope} Alfa
102
+ # Describes Bravo
103
+ class Bravo
104
+ def charlie
105
+ end
106
+ end
107
+
108
+ # Describes Delta
109
+ module Delta
110
+ end
111
+ end
112
+ EOS
113
+
114
+ expect(src).not_to reek_of(:IrresponsibleModule, context: 'Alfa')
108
115
  end
109
116
 
110
- it "reports #{scope} that have both a nested #{scope} and methods" do
117
+ it "reports #{scope} that is used as a namespace but also has methods" do
111
118
  src = <<-EOS
112
119
  #{scope} Alfa
113
120
  def bravo
@@ -122,7 +129,7 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
122
129
  expect(src).to reek_of(:IrresponsibleModule, context: 'Alfa')
123
130
  end
124
131
 
125
- it "reports #{scope} that has both a nested #{scope} and singleton methods" do
132
+ it "reports #{scope} that is used as a namespace but also has singleton methods" do
126
133
  src = <<-EOS
127
134
  #{scope} Alfa
128
135
  def self.bravo
@@ -147,10 +154,40 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
147
154
  end
148
155
  EOS
149
156
 
150
- expect(src).not_to reek_of(:IrresponsibleModule)
157
+ expect(src).not_to reek_of(:IrresponsibleModule, context: 'Alfa')
158
+ end
159
+
160
+ it "does not report #{scope} only containing constants" do
161
+ src = <<-EOS
162
+ #{scope} Alfa
163
+ Bravo = 23
164
+ end
165
+ EOS
166
+
167
+ expect(src).not_to reek_of(:IrresponsibleModule, context: 'Alfa')
168
+ end
169
+
170
+ it "reports #{scope} that contains method calls" do
171
+ src = <<-EOS
172
+ #{scope} Alfa
173
+ bravo :charlie
174
+ end
175
+ EOS
176
+
177
+ expect(src).to reek_of(:IrresponsibleModule, context: 'Alfa')
178
+ end
179
+
180
+ it "reports #{scope} that contains non-constant assignments" do
181
+ src = <<-EOS
182
+ #{scope} Alfa
183
+ bravo = charlie
184
+ end
185
+ EOS
186
+
187
+ expect(src).to reek_of(:IrresponsibleModule, context: 'Alfa')
151
188
  end
152
189
 
153
- it "reports a #{scope} defined through assignment" do
190
+ it "reports an irresponsible #{scope} defined through assignment" do
154
191
  src = <<-EOS
155
192
  # Alfa is responsible, but Bravo is not
156
193
  #{scope} Alfa
@@ -174,6 +211,7 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
174
211
 
175
212
  it 'does not report constants that are not classes' do
176
213
  src = <<-EOS
214
+ # Alfa is responsible
177
215
  #{scope} Alfa
178
216
  Bravo = 23
179
217
  Charlie = Hash.new
@@ -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