reek 4.7.3 → 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 (248) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -12
  3. data/.rubocop.yml +18 -3
  4. data/.simplecov +1 -0
  5. data/.travis.yml +3 -4
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +45 -0
  8. data/Gemfile +4 -4
  9. data/README.md +134 -104
  10. data/Rakefile +16 -3
  11. data/bin/reek +1 -3
  12. data/docs/API.md +2 -9
  13. data/docs/Basic-Smell-Options.md +51 -11
  14. data/docs/Code-Smells.md +1 -1
  15. data/docs/Command-Line-Options.md +14 -4
  16. data/docs/Duplicate-Method-Call.md +49 -1
  17. data/docs/Feature-Envy.md +44 -0
  18. data/docs/How-To-Write-New-Detectors.md +2 -3
  19. data/docs/Instance-Variable-Assumption.md +1 -1
  20. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  21. data/docs/Rake-Task.md +1 -1
  22. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  23. data/docs/Reek-Driven-Development.md +1 -1
  24. data/docs/Uncommunicative-Method-Name.md +45 -6
  25. data/docs/Uncommunicative-Module-Name.md +49 -7
  26. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  27. data/docs/Uncommunicative-Variable-Name.md +73 -2
  28. data/docs/Unused-Private-Method.md +2 -2
  29. data/docs/defaults.reek.yml +129 -0
  30. data/docs/yard_plugin.rb +1 -0
  31. data/features/command_line_interface/basic_usage.feature +2 -2
  32. data/features/command_line_interface/options.feature +46 -4
  33. data/features/command_line_interface/show_progress.feature +4 -4
  34. data/features/command_line_interface/smell_selection.feature +1 -1
  35. data/features/command_line_interface/smells_count.feature +6 -6
  36. data/features/command_line_interface/stdin.feature +30 -8
  37. data/features/configuration_files/accept_setting.feature +45 -28
  38. data/features/configuration_files/directory_specific_directives.feature +78 -73
  39. data/features/configuration_files/exclude_directives.feature +11 -10
  40. data/features/configuration_files/exclude_paths_directives.feature +4 -4
  41. data/features/configuration_files/masking_smells.feature +38 -9
  42. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  43. data/features/configuration_files/reject_setting.feature +52 -41
  44. data/features/configuration_files/schema_validation.feature +59 -0
  45. data/features/configuration_files/unused_private_method.feature +18 -16
  46. data/features/configuration_loading.feature +53 -10
  47. data/features/configuration_via_source_comments/erroneous_source_comments.feature +2 -2
  48. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  49. data/features/locales.feature +2 -2
  50. data/features/rake_task/rake_task.feature +15 -15
  51. data/features/reports/json.feature +3 -3
  52. data/features/reports/reports.feature +34 -34
  53. data/features/reports/yaml.feature +3 -3
  54. data/features/rspec_matcher.feature +9 -1
  55. data/features/samples.feature +287 -287
  56. data/features/step_definitions/reek_steps.rb +4 -0
  57. data/features/step_definitions/sample_file_steps.rb +9 -4
  58. data/features/support/env.rb +2 -2
  59. data/features/todo_list.feature +26 -23
  60. data/lib/reek/ast/node.rb +40 -55
  61. data/lib/reek/ast/object_refs.rb +1 -1
  62. data/lib/reek/ast/reference_collector.rb +2 -4
  63. data/lib/reek/ast/sexp_extensions/case.rb +1 -1
  64. data/lib/reek/ast/sexp_extensions/if.rb +8 -1
  65. data/lib/reek/ast/sexp_extensions/logical_operators.rb +1 -1
  66. data/lib/reek/ast/sexp_extensions/methods.rb +4 -6
  67. data/lib/reek/cli/application.rb +4 -3
  68. data/lib/reek/cli/command/report_command.rb +1 -2
  69. data/lib/reek/cli/command/todo_list_command.rb +8 -8
  70. data/lib/reek/cli/options.rb +29 -14
  71. data/lib/reek/cli/silencer.rb +14 -3
  72. data/lib/reek/code_comment.rb +14 -16
  73. data/lib/reek/configuration/app_configuration.rb +32 -28
  74. data/lib/reek/configuration/configuration_converter.rb +110 -0
  75. data/lib/reek/configuration/configuration_file_finder.rb +15 -40
  76. data/lib/reek/configuration/configuration_validator.rb +12 -23
  77. data/lib/reek/configuration/default_directive.rb +17 -3
  78. data/lib/reek/configuration/directory_directives.rb +17 -11
  79. data/lib/reek/configuration/excluded_paths.rb +1 -1
  80. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  81. data/lib/reek/configuration/schema.yml +210 -0
  82. data/lib/reek/configuration/schema_validator.rb +38 -0
  83. data/lib/reek/context/attribute_context.rb +1 -1
  84. data/lib/reek/context/code_context.rb +8 -11
  85. data/lib/reek/context/method_context.rb +7 -12
  86. data/lib/reek/context/module_context.rb +4 -4
  87. data/lib/reek/context_builder.rb +11 -11
  88. data/lib/reek/detector_repository.rb +6 -0
  89. data/lib/reek/documentation_link.rb +28 -0
  90. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +13 -12
  91. data/lib/reek/errors/bad_detector_in_comment_error.rb +11 -10
  92. data/lib/reek/errors/base_error.rb +3 -0
  93. data/lib/reek/errors/config_file_error.rb +11 -0
  94. data/lib/reek/errors/encoding_error.rb +16 -11
  95. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +11 -10
  96. data/lib/reek/errors/incomprehensible_source_error.rb +20 -22
  97. data/lib/reek/errors/syntax_error.rb +41 -0
  98. data/lib/reek/examiner.rb +19 -25
  99. data/lib/reek/logging_error_handler.rb +7 -5
  100. data/lib/reek/rake/task.rb +3 -3
  101. data/lib/reek/report/base_report.rb +8 -12
  102. data/lib/reek/report/code_climate/code_climate_configuration.rb +1 -1
  103. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -10
  104. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  105. data/lib/reek/report/heading_formatter.rb +54 -0
  106. data/lib/reek/report/json_report.rb +1 -1
  107. data/lib/reek/report/location_formatter.rb +40 -0
  108. data/lib/reek/report/progress_formatter.rb +79 -0
  109. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  110. data/lib/reek/report/text_report.rb +1 -2
  111. data/lib/reek/report/xml_report.rb +3 -3
  112. data/lib/reek/report/yaml_report.rb +1 -1
  113. data/lib/reek/report.rb +15 -10
  114. data/lib/reek/smell_configuration.rb +2 -2
  115. data/lib/reek/smell_detectors/attribute.rb +0 -1
  116. data/lib/reek/smell_detectors/base_detector.rb +9 -12
  117. data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
  118. data/lib/reek/smell_detectors/class_variable.rb +3 -11
  119. data/lib/reek/smell_detectors/control_parameter.rb +17 -32
  120. data/lib/reek/smell_detectors/data_clump.rb +3 -4
  121. data/lib/reek/smell_detectors/duplicate_method_call.rb +6 -7
  122. data/lib/reek/smell_detectors/feature_envy.rb +1 -1
  123. data/lib/reek/smell_detectors/instance_variable_assumption.rb +1 -10
  124. data/lib/reek/smell_detectors/irresponsible_module.rb +0 -1
  125. data/lib/reek/smell_detectors/long_parameter_list.rb +1 -2
  126. data/lib/reek/smell_detectors/long_yield_list.rb +2 -3
  127. data/lib/reek/smell_detectors/manual_dispatch.rb +3 -3
  128. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +6 -7
  129. data/lib/reek/smell_detectors/module_initialize.rb +1 -2
  130. data/lib/reek/smell_detectors/nested_iterators.rb +6 -6
  131. data/lib/reek/smell_detectors/nil_check.rb +0 -1
  132. data/lib/reek/smell_detectors/repeated_conditional.rb +3 -4
  133. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +0 -1
  134. data/lib/reek/smell_detectors/too_many_constants.rb +2 -3
  135. data/lib/reek/smell_detectors/too_many_instance_variables.rb +1 -2
  136. data/lib/reek/smell_detectors/too_many_methods.rb +1 -2
  137. data/lib/reek/smell_detectors/too_many_statements.rb +1 -2
  138. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +2 -3
  139. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +2 -3
  140. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +2 -3
  141. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +6 -7
  142. data/lib/reek/smell_detectors/unused_parameters.rb +0 -1
  143. data/lib/reek/smell_detectors/unused_private_method.rb +0 -1
  144. data/lib/reek/smell_detectors/utility_function.rb +2 -3
  145. data/lib/reek/smell_detectors.rb +1 -2
  146. data/lib/reek/smell_warning.rb +15 -8
  147. data/lib/reek/source/source_code.rb +50 -72
  148. data/lib/reek/source/source_locator.rb +7 -7
  149. data/lib/reek/spec/should_reek.rb +2 -2
  150. data/lib/reek/spec/should_reek_of.rb +9 -16
  151. data/lib/reek/spec/should_reek_only_of.rb +4 -4
  152. data/lib/reek/spec.rb +6 -6
  153. data/lib/reek/tree_dresser.rb +5 -5
  154. data/lib/reek/version.rb +1 -1
  155. data/reek.gemspec +5 -5
  156. data/samples/checkstyle.xml +1 -1
  157. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  158. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  159. data/samples/configuration/full_configuration.reek +8 -4
  160. data/samples/configuration/full_mask.reek +5 -4
  161. data/samples/configuration/partial_mask.reek +3 -2
  162. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  163. data/samples/paths.rb +5 -4
  164. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  165. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  166. data/spec/factories/factories.rb +2 -13
  167. data/spec/reek/ast/node_spec.rb +103 -10
  168. data/spec/reek/ast/reference_collector_spec.rb +1 -1
  169. data/spec/reek/ast/sexp_extensions_spec.rb +2 -2
  170. data/spec/reek/cli/application_spec.rb +50 -38
  171. data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
  172. data/spec/reek/cli/silencer_spec.rb +28 -0
  173. data/spec/reek/code_comment_spec.rb +31 -38
  174. data/spec/reek/configuration/app_configuration_spec.rb +46 -33
  175. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -49
  176. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  177. data/spec/reek/configuration/directory_directives_spec.rb +6 -7
  178. data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
  179. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  180. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  181. data/spec/reek/context/code_context_spec.rb +60 -96
  182. data/spec/reek/context/ghost_context_spec.rb +1 -1
  183. data/spec/reek/context/root_context_spec.rb +1 -1
  184. data/spec/reek/documentation_link_spec.rb +20 -0
  185. data/spec/reek/errors/base_error_spec.rb +13 -0
  186. data/spec/reek/examiner_spec.rb +100 -30
  187. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -80
  188. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  189. data/spec/reek/report/json_report_spec.rb +13 -46
  190. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  191. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  192. data/spec/reek/report/text_report_spec.rb +4 -4
  193. data/spec/reek/report/xml_report_spec.rb +3 -3
  194. data/spec/reek/report/yaml_report_spec.rb +9 -38
  195. data/spec/reek/report_spec.rb +3 -3
  196. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
  197. data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
  198. data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
  199. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
  200. data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
  201. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +9 -9
  202. data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
  203. data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
  204. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  205. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  206. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  207. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  208. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +6 -4
  209. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
  210. data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
  211. data/spec/reek/smell_detectors/unused_private_method_spec.rb +10 -10
  212. data/spec/reek/smell_detectors/utility_function_spec.rb +5 -5
  213. data/spec/reek/smell_warning_spec.rb +12 -8
  214. data/spec/reek/source/source_code_spec.rb +17 -43
  215. data/spec/reek/source/source_locator_spec.rb +17 -17
  216. data/spec/reek/spec/should_reek_of_spec.rb +7 -11
  217. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  218. data/spec/reek/spec/should_reek_spec.rb +3 -3
  219. data/spec/reek/spec/smell_matcher_spec.rb +3 -3
  220. data/spec/reek/tree_dresser_spec.rb +12 -17
  221. data/spec/spec_helper.rb +6 -17
  222. data/tasks/configuration.rake +8 -5
  223. metadata +71 -41
  224. data/defaults.reek +0 -131
  225. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  226. data/lib/reek/report/formatter/heading_formatter.rb +0 -52
  227. data/lib/reek/report/formatter/location_formatter.rb +0 -42
  228. data/lib/reek/report/formatter/progress_formatter.rb +0 -81
  229. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  230. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -36
  231. data/lib/reek/report/formatter.rb +0 -33
  232. data/lib/reek/smell_detectors/syntax.rb +0 -37
  233. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  234. data/samples/smelly_with_inline_mask.rb +0 -8
  235. data/samples/smelly_with_modifiers.rb +0 -12
  236. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  237. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  238. data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
  239. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  240. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  241. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  242. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  243. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  244. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  245. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  246. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  247. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  248. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
@@ -7,14 +7,14 @@ Every smell detector in Reek offers at least the following configuration options
7
7
  | Option | Value | Effect |
8
8
  | ---------------|-------------|---------|
9
9
  | `enabled` | Boolean | Determines whether the smell detector is active. Defaults to `true` |
10
- | `exclude` | an array of strings or regular expressions | Ignores any context whose full description (see <strong>%c</strong> in [Command-Line Options](Command-Line-Options.md)) matches any element of this array. |
10
+ | `exclude` | an array of strings that will be converted into regular expressions | Ignores any context whose full description matches any element of this array. |
11
11
 
12
- The file `defaults.reek` (shipped with the Reek gem) lists any default
12
+ The file `docs/defaults.reek.yml` (shipped with the Reek gem) lists any default
13
13
  exclusions for each smell.
14
14
 
15
15
  ## Examples
16
16
 
17
- <u>An easy one:</u>
17
+ **An easy one:**
18
18
 
19
19
  To stop Reek reporting smells in any method called `write` you might create a configuration file containing this:
20
20
 
@@ -24,15 +24,9 @@ DuplicateMethodCall:
24
24
  - write
25
25
  ```
26
26
 
27
- Or a little more sophisticated using a Ruby regex like this:
27
+ Internally Reek will convert this to the Regexp /write/.
28
28
 
29
- ```yaml
30
- DuplicateMethodCall:
31
- exclude:
32
- - !ruby/regexp /write/
33
- ```
34
-
35
- <u>A more sophisticated one:</u>
29
+ **A more sophisticated one:**
36
30
 
37
31
  ```yaml
38
32
  FeatureEnvy:
@@ -43,3 +37,49 @@ FeatureEnvy:
43
37
  ```
44
38
 
45
39
  This would not report FeatureEnvy for the instance method `MyModel#do_things`, the whole module `MyHelper` and the `respond` instance method of `ApplicationController`
40
+
41
+ ## Advanced configuration
42
+
43
+ Sometimes just strings are not enough for configuration. E.g. consider this code sample:
44
+
45
+ ```Ruby
46
+ class Klass
47
+ def foo1; end
48
+ def foo1bar; end
49
+ end
50
+ ```
51
+ Both "Klass#foo1" and "Klass#foo1bar" will smell of UncommunicativeMethodName. Now let's assume
52
+ you are ok with "Klass#foo1" but not "Klass#foo1bar".
53
+ Just having this configuration
54
+
55
+ ```yaml
56
+ UncommunicativeMethodName:
57
+ exclude:
58
+ - "Klass#foo1"
59
+ ```
60
+
61
+ wouldn't work because now "Klass#foo1bar" wouldn't smell as well.
62
+
63
+ For this reason Reek has a special syntax that allows you to use regexes by using a forward slash at the beginning and the end of the string.
64
+ Everything within the forward slashes will be loaded as a regex.
65
+
66
+ A possible configuration that hat excludes "Klass#foo1" from this scan but not "Klass#foo1bar" could look like this:
67
+
68
+ ```yaml
69
+ UncommunicativeMethodName:
70
+ exclude:
71
+ - "/Klass#foo1$/"
72
+ ```
73
+
74
+ ## Reek 4
75
+
76
+ In Reek 4 you could also pass regexes to `exclude`, meaning this was perfectly valid as well:
77
+
78
+ ```yaml
79
+ DuplicateMethodCall:
80
+ exclude:
81
+ - !ruby/regexp /write/
82
+ ```
83
+
84
+ Support for this has been scrapped with Reek 5 to make the Reek configuration more yaml standard compliant.
85
+ You can still pass in regexes, you just have to wrap them into a string. Please see "Advanced configuration" above.
data/docs/Code-Smells.md CHANGED
@@ -23,7 +23,7 @@ Reek currently includes checks for the following smells:
23
23
  * [Utility Function](Utility-Function.md)
24
24
  * [Module Initialize](Module-Initialize.md)
25
25
  * [Nested Iterators](Nested-Iterators.md)
26
- * [Prima-Donna-Method](Prima-Donna-Method.md)
26
+ * [Missing Safe Method](Missing-Safe-Method.md), formerly known as Prima Donna Method
27
27
  * [Simulated Polymorphism](Simulated-Polymorphism.md), including
28
28
  * [Manual Dispatch](Manual-Dispatch.md)
29
29
  * [Nil Check](Nil-Check.md)
@@ -12,6 +12,16 @@ reek -h
12
12
 
13
13
  for details.
14
14
 
15
+ ## Telling Reek to use a specific configuration file
16
+
17
+ In case your configuration file is not in the standard location (that would be your project directory or
18
+ whatever directory you're running Reek from) you can specify a configuration file with the `-c` option
19
+ like this:
20
+
21
+ ```Bash
22
+ reek -c /somewhere/on/your/filesystem/reek_config.yml lib/
23
+ ```
24
+
15
25
  ## Telling Reek Which Code to Check
16
26
 
17
27
  Probably the most standard use case would be to check all Ruby files in the lib directory:
@@ -91,10 +101,10 @@ mess.rb -- 2 warnings:
91
101
  [2]:x has the name 'x' (UncommunicativeMethodName)
92
102
  ```
93
103
 
94
- ### Enable the ultra-verbose mode
104
+ ### Enable the verbose mode
95
105
 
96
- _reek_ has a ultra-verbose mode which you might find helpful as a beginner. "ultra-verbose" just means that behind each warning a helpful link will be displayed which leads directly to the corresponding _reek_ wiki page.
97
- This mode can be enabled via the "-U" or "--ultra-verbose" flag.
106
+ _reek_ has a verbose mode which you might find helpful as a beginner. "verbose" just means that behind each warning a helpful link will be displayed which leads directly to the corresponding _reek_ documentation page.
107
+ This mode can be enabled via the "-U" or "--documentation" flag.
98
108
 
99
109
  So for instance, if your test file would smell of _ClassVariable_, this is what the _reek_ output would look like:
100
110
 
@@ -103,7 +113,7 @@ reek -U test.rb
103
113
  ```
104
114
  ```
105
115
  test.rb -- 1 warning:
106
- [2]:Dummy declares the class variable @@class_variable (ClassVariable) [https://github.com/troessner/reek/wiki/Class-Variable]
116
+ [2]:Dummy declares the class variable @@class_variable (ClassVariable) [https://github.com/troessner/reek/blob/master/docs/Class-Variable.md]
107
117
  ```
108
118
 
109
119
  Note the link at the end.
@@ -42,7 +42,55 @@ The approach you take will depend on balancing other factors in your code.
42
42
 
43
43
  ## Current support in Reek
44
44
 
45
- Reek's Duplicate Method Call detector checks for repeated identical method calls within any one method definition. This is intended to complement the checks performed by tools such as [Flay](http://ruby.sadi.st/Flay.html) and [Simian](http://www.redhillconsulting.com.au/products/simian/).
45
+ Reek's Duplicate Method Call detector checks for repeated identical method calls within
46
+ any one method definition. This is intended to complement the checks performed by tools
47
+ such as [Flay](http://ruby.sadi.st/Flay.html) and [Simian](http://www.redhillconsulting.com.au/products/simian/).
48
+
49
+ ## Edge cases
50
+
51
+ Be aware that there are some edge cases like this code:
52
+
53
+ ```Ruby
54
+ class Foo
55
+ def bar(switch)
56
+ case switch
57
+ when :a
58
+ ->(arg) { arg.call_me(:maybe); do_something }
59
+ when :b
60
+ ->(arg) { arg.call_me(:maybe); do_something_else }
61
+ when :c
62
+ ->(arg) { arg.call_me(:maybe); do_something_different }
63
+ end
64
+ end
65
+ end
66
+ ```
67
+
68
+ Reek cannot reliably detect that each call's receiver is a different arg and will report:
69
+
70
+ ```
71
+ [5, 7, 9]:DuplicateMethodCall: Foo#bar calls 'arg.call_me(:maybe)' 3 times
72
+ ```
73
+
74
+ If you're running into this problem you can disable this smell detector for this method either via
75
+ configuration:
76
+
77
+ ```Yaml
78
+ ---
79
+ DuplicateMethodCall:
80
+ exclude:
81
+ - 'Foo#bar'
82
+ ```
83
+
84
+ or via source code comment:
85
+
86
+ ```Ruby
87
+ class Foo
88
+ # :reek:DuplicateMethodCall
89
+ def bar(switch)
90
+ # ....
91
+ end
92
+ end
93
+ ```
46
94
 
47
95
  ## Configuration
48
96
 
data/docs/Feature-Envy.md CHANGED
@@ -40,6 +40,50 @@ belongs to the Item class, not the Warehouse.
40
40
 
41
41
  _Feature Envy_ reports any method that refers to self less often than it refers to (ie. send messages to) some other object.
42
42
 
43
+ ## Edge cases
44
+
45
+ Be aware that there are some edge cases like this code:
46
+
47
+ ```Ruby
48
+ class Foo
49
+ def initialize
50
+ @map = {
51
+ a: ->(arg) { arg.css('table') },
52
+ b: ->(arg) { arg.css('div') },
53
+ c: ->(arg) { arg.css('span') }
54
+ }
55
+ end
56
+ end
57
+ ```
58
+
59
+ Reek cannot reliably detect that each call's receiver is a different arg and will report:
60
+
61
+ ```
62
+ [4, 5, 6]:FeatureEnvy: Foo#initialize refers to 'arg' more than self (maybe move it to another class?)
63
+ ```
64
+
65
+ If you're running into this problem you can disable this smell detector for this method either via
66
+ configuration:
67
+
68
+ ```Yaml
69
+ ---
70
+ FeatureEnvy:
71
+ exclude:
72
+ - 'Foo#bar'
73
+ ```
74
+
75
+ or via source code comment:
76
+
77
+ ```Ruby
78
+ class Foo
79
+ # :reek:FeatureEnvy
80
+ def initialize
81
+ @map = {
82
+ # ....
83
+ end
84
+ end
85
+ ```
86
+
43
87
  ## Differences to _Utility Function_
44
88
 
45
89
  _Feature Envy_ is only triggered if there are some references to self and _[Utility Function](Utility-Function.md)_ is triggered if there are no references to self.
@@ -41,7 +41,6 @@ module Reek
41
41
  # "smell_warning" is defined in BaseDetector and should be used by you
42
42
  # to construct smell warnings
43
43
  smell_warning(
44
- context: context,
45
44
  lines: [], # lines on which the smell was detected
46
45
  message: "...", # the message that is printed on STDOUT
47
46
  # whatever you interpolate into the "message" should go into
@@ -62,7 +61,7 @@ end
62
61
 
63
62
  For your detector to be properly loaded you need to require it in `lib/reek/smell_detectors.rb` as well.
64
63
 
65
- ### defaults.reek
64
+ ### defaults.reek.yml
66
65
 
67
66
  After you ran
68
67
 
@@ -70,7 +69,7 @@ After you ran
70
69
  bundle exec rake
71
70
  ```
72
71
 
73
- for the first time with your shiny new detector in place the `defaults.reek`
72
+ for the first time with your shiny new detector in place the `docs/defaults.reek.yml`
74
73
  file should have been updated automatically. Make sure you don't forget to check
75
74
  in those changes as well.
76
75
 
@@ -61,7 +61,7 @@ end
61
61
  would report:
62
62
 
63
63
  ```Bash
64
- [1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
64
+ [1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar
65
65
  ```
66
66
 
67
67
  Note that this example would trigger this smell warning as well:
@@ -1,8 +1,8 @@
1
- # Prima Donna Method
1
+ # Missing Safe Method
2
2
 
3
3
  ## Introduction
4
4
 
5
- Candidate methods for the _Prima Donna Method_ smell are methods whose names
5
+ Candidate methods for the _Missing Safe Method_ smell are methods whose names
6
6
  end with an exclamation mark.
7
7
 
8
8
  An exclamation mark in method names means (the explanation below is taken from
@@ -13,14 +13,16 @@ An exclamation mark in method names means (the explanation below is taken from
13
13
  > equivalent method, with the same name minus the !. “Danger” is relative; the
14
14
  > ! doesn’t mean anything at all unless the method name it’s in corresponds to
15
15
  > a similar but bang-less method name.
16
- >
16
+ >
17
17
  > So, for example, gsub! is the dangerous version of gsub. exit! is the
18
18
  > dangerous version of exit. flatten! is the dangerous version of flatten. And
19
19
  > so forth.
20
20
 
21
- Such a method is called _Prima Donna Method_ if and only if her non-bang
21
+ Such a method is called _Missing Safe Method_ if and only if the non-bang
22
22
  version does not exist and this method is reported as a smell.
23
23
 
24
+ Missing Safe Method was formerly known as Prima Donna Method.
25
+
24
26
  ## Example
25
27
 
26
28
  Given
@@ -33,7 +35,7 @@ class C
33
35
  end
34
36
  ```
35
37
 
36
- Reek would report the _Prima Donna Method_ smell for `bar!`, but not for `foo!`.
38
+ Reek would report the _Missing Safe Method_ smell for `bar!`, but not for `foo!`.
37
39
 
38
40
  Reek reports this smell only in a class context, not in a module context in order to allow perfectly legit code like this:
39
41
 
@@ -55,12 +57,12 @@ class Daughter < Parent
55
57
  end
56
58
  ```
57
59
 
58
- In this example, Reek would not report the _Prima Donna Method_ smell for the
60
+ In this example, Reek would not report the _Missing Safe Method_ smell for the
59
61
  method `foo` of the `Dangerous` module.
60
62
 
61
63
  ## Configuration
62
64
 
63
- _Prima Donna Method_ offers the [Basic Smell Options](Basic-Smell-Options.md).
65
+ _Missing Safe Method_ offers the [Basic Smell Options](Basic-Smell-Options.md).
64
66
 
65
67
  ## Example configuration via source comment
66
68
 
@@ -77,12 +79,12 @@ This would report:
77
79
 
78
80
  >>
79
81
  ruby.rb -- 1 warning:
80
- [1]:PrimaDonnaMethod: Alfa has prima donna method 'bravo!'
82
+ [1]:MissingSafeMethod: Alfa has missing safe method 'bravo!'
81
83
 
82
84
  If you want to suppress this warning you can do this via source comment like this:
83
85
 
84
86
  ```Ruby
85
- # :reek:PrimaDonnaMethod { exclude: [ bravo! ] }
87
+ # :reek:MissingSafeMethod { exclude: [ bravo! ] }
86
88
  class Alfa
87
89
  def bravo!
88
90
  end
data/docs/Rake-Task.md CHANGED
@@ -33,7 +33,7 @@ An more sophisticated rake task that would make use of all available configurati
33
33
  ```Ruby
34
34
  Reek::Rake::Task.new do |t|
35
35
  t.name = 'custom_rake' # Whatever name you want. Defaults to "reek".
36
- t.config_file = 'config/config.reek' # Defaults to nothing.
36
+ t.config_file = 'config/.reek.yml' # Defaults to nothing.
37
37
  t.source_files = 'vendor/**/*.rb' # Glob pattern to match source files. Defaults to lib/**/*.rb
38
38
  t.reek_opts = '-U' # Defaults to ''. You can pass all the options here in that are shown by "reek -h"
39
39
  t.fail_on_error = false # Defaults to true
@@ -0,0 +1,193 @@
1
+ ## Reek 4 to Reek 5 migration
2
+
3
+ ### Schema validation
4
+
5
+ Reek now uses a schema to validate your configuration against on start up and will faily loudly in
6
+ case you misspelled an option or used the wrong data type for a value like this:
7
+
8
+ ```
9
+ Error: We found some problems with your configuration file: [/detectors/DetectorWithTypo] key 'DetectorWithTypo:' is undefined.
10
+ ```
11
+
12
+ Obviously this might affect existing configuration files that until now contained an error nobody noticed.
13
+
14
+ ### Scoping detectors under `detectors`
15
+
16
+ In Reek 4 you could just configure your detectors on top level like this:
17
+
18
+ ```yaml
19
+ UncommunicativeMethodName:
20
+ accept:
21
+ - foobar
22
+ UnusedPrivateMethod:
23
+ exclude:
24
+ - app/controllers
25
+ ```
26
+
27
+ In Reek 5 you have to scope your detector configurations under the `detectors` key:
28
+
29
+ ```yaml
30
+ detectors:
31
+ UncommunicativeMethodName:
32
+ accept:
33
+ - foobar
34
+ UnusedPrivateMethod:
35
+ exclude:
36
+ - app/controllers
37
+ ```
38
+
39
+ ### Move directory directives under a special key
40
+
41
+ In Reek 4 you could apply directory specific directives like this:
42
+
43
+ ```Yaml
44
+ ---
45
+ "web_app/app/controllers":
46
+ NestedIterators:
47
+ enabled: false
48
+ "web_app/app/helpers":
49
+ UtilityFunction:
50
+ enabled: false
51
+ ```
52
+
53
+ which was nice and easy but also quite messy. With Reek 5 you'll have to scope this under a `directories`
54
+ key like this:
55
+
56
+ ```Yaml
57
+ ---
58
+ directories:
59
+ "web_app/app/controllers":
60
+ NestedIterators:
61
+ enabled: false
62
+ "web_app/app/helpers":
63
+ UtilityFunction:
64
+ enabled: false
65
+ ```
66
+
67
+ ### No more regular expressions in Reeks configuration
68
+
69
+ In Reek 4 you could pass regular expressions to the `accept` or `reject` settings of
70
+
71
+ * [Uncommunicative Method Name](Uncommunicative-Method-Name.md)
72
+ * [Uncommunicative Module Name](Uncommunicative-Module-Name.md)
73
+ * [Uncommunicative Parameter Name](Uncommunicative-Parameter-Name.md)
74
+ * [Uncommunicative Variable Name](Uncommunicative-Variable-Name.md)
75
+
76
+ and to the `exclude` settings which are part of our [Basic Smell Options](docs/Basic-Smell-Options.md).
77
+
78
+ This means that this configuration was perfectly valid:
79
+
80
+ ```yaml
81
+ detectors:
82
+ UncommunicativeMethodName:
83
+ accept:
84
+ - !ruby/regexp /foobar/
85
+ UnusedPrivateMethod:
86
+ exclude:
87
+ - !ruby/regexp /i am(.*)unused/
88
+ ```
89
+
90
+ Support for this has been scrapped with Reek 5 to make the Reek configuration more yaml standard compliant.
91
+ You can still pass in regexes, you just have to wrap them into a string using a forward slash at the
92
+ beginning and at the end of the string like this:
93
+
94
+ ```Yaml
95
+ ---
96
+ UncommunicativeMethodName:
97
+ accept:
98
+ - "/^foobar$/"
99
+ UnusedPrivateMethod:
100
+ exclude:
101
+ - "/i am(.*)unused/"
102
+ ```
103
+
104
+ Everything within the forward slashes will be loaded as a regex.
105
+
106
+ ### No more single item shortcuts for list items
107
+
108
+ You cant use a configuration option that is supposed to be a list with a single element like this anymore:
109
+
110
+ ```Yaml
111
+ ---
112
+ UncommunicativeMethodName:
113
+ accept: foobar
114
+ UnusedPrivateMethod:
115
+ exclude: omg
116
+ ```
117
+
118
+ You'll have to use a proper list here like this:
119
+
120
+ ```Yaml
121
+ ---
122
+ UncommunicativeMethodName:
123
+ accept:
124
+ - foobar
125
+ UnusedPrivateMethod:
126
+ exclude:
127
+ - omg
128
+ ```
129
+
130
+ ## Failing on syntax errors in source files
131
+
132
+ Previously Reek would just continue on syntax errors in source files which might have been convenient but
133
+ not necessarily fitting for a tool that's all about code quality. With Reek 5, Reek will fail hard on
134
+ invalid source files.
135
+
136
+ ### API changes
137
+
138
+ This is something that will only affect very advanced users. In case you have no idea what this might be about
139
+ you can just skip it or check out our [Developer API](docs/API.md).
140
+
141
+ #### Allow only detector names in configuration hash
142
+
143
+ In Reek 4 you could build your configuration like this:
144
+
145
+ ```ruby
146
+ config_hash = { Reek::SmellDetectors::IrresponsibleModule => { 'enabled' => false } }
147
+ ```
148
+
149
+ or like this:
150
+
151
+ ```ruby
152
+ config_hash = { 'IrresponsibleModule' => { 'enabled' => false } }
153
+ ```
154
+
155
+ Starting with Reek 5, the first way is not working anymore and the latter one is what you'll have to use.
156
+
157
+ #### Do not accept a class as parameter for reek_of
158
+
159
+ In the same vein as the change above you also can't use fully qualified detector names like this:
160
+
161
+ ```Ruby
162
+ reek_of(Reek::SmellDetectors::DuplicateMethodCall)
163
+ ```
164
+
165
+ The only supported way now is either as symbol or string:
166
+
167
+ ```Ruby
168
+ reek_of(:DuplicateMethodCall)
169
+ reek_of('DuplicateMethodCall')
170
+ ```
171
+
172
+ ## Smaller changes
173
+
174
+ * `PrimaDonnaMethod` has been given the better name `MissingSafeMethod`
175
+ * `wiki-links` flag has been renamed to `documentation` flag
176
+ * Reek assumes the default configuration file to be named ".reek.yml" and will ignore all other files. You can
177
+ still use any name you want though by passing in a name via the `-c` flag
178
+ * We have dropped the legacy code comment separator ":" at the end of a detector name. If you wanted to configure
179
+ a smell detector via comment before this release you had to use g like this:
180
+
181
+ ```
182
+ # :reek:UnusedPrivateMethod: { exclude: [ bravo ] }
183
+ ```
184
+
185
+ Mind the ":" at the end of "UnusedPrivateMethod". This syntax is disallowed with Reek 5 - you have to drop the ":"
186
+ at the end now like this:
187
+
188
+ ```
189
+ # :reek:UnusedPrivateMethod { exclude: [ bravo ] }
190
+ ```
191
+
192
+ * We have dropped support for Ruby 2.1 and 2.2 since they are officially not supported by the Ruby core team anymore
193
+
@@ -14,7 +14,7 @@ Reek::Rake::Task.new do |t|
14
14
  end
15
15
  ```
16
16
 
17
- Now the command `reek` will run Reek on your source code (and in this case, it fails if it finds any smells). For more detailed information about Reek's integration with Rake, see [Rake Task](Rake-Task.md) in this wiki.
17
+ Now the command `reek` will run Reek on your source code (and in this case, it fails if it finds any smells). For more detailed information about Reek's integration with Rake, see [Rake Task](Rake-Task.md).
18
18
 
19
19
  ## reek/spec
20
20
 
@@ -21,8 +21,8 @@ Reek's _Uncommunicative Method Name_ detector supports the
21
21
 
22
22
  | Option | Value | Effect |
23
23
  | ---------------|-------------|---------|
24
- | `reject` | array of regular expressions or strings | The set of patterns / names that Reek uses to check for bad names. Defaults to `[/^[a-z]$/, /[0-9]$/, /[A-Z]/]`. |
25
- | `accept` | array of regular expressions or strings | The set of patterns / names that Reek will accept (and not report) even if they match one of the `reject` expressions. |
24
+ | `reject` | array of strings | The set of names that Reek uses to check for bad names. Defaults to single-letter names, names ending with a number or names containing upper case letters. |
25
+ | `accept` | array of strings | The set of names that Reek will accept (and not report) even if they match one of the `reject` expressions. |
26
26
 
27
27
  An example configuration could look like this:
28
28
 
@@ -30,13 +30,15 @@ An example configuration could look like this:
30
30
  ---
31
31
  UncommunicativeMethodName:
32
32
  accept:
33
- - !ruby/regexp /x/
33
+ - x
34
34
  - meth1
35
35
  reject:
36
- - !ruby/regexp /helper/
36
+ - helper
37
37
  - foobar
38
38
  ```
39
39
 
40
+ Reek will convert whatever you give it as a string to the corresponding regex, so "foobar" from above will be converted to /foobar/ internally.
41
+
40
42
  Applying a configuration to a source file like this:
41
43
 
42
44
  ```Ruby
@@ -50,6 +52,43 @@ Reek would report:
50
52
 
51
53
  ```
52
54
  smelly.rb -- 2 warnings:
53
- [4]:UncommunicativeMethodName: awesome_helper has the name 'awesome_helper' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
54
- [3]:UncommunicativeMethodName: foobar has the name 'foobar' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
55
+ [4]:UncommunicativeMethodName: awesome_helper has the name 'awesome_helper'
56
+ [3]:UncommunicativeMethodName: foobar has the name 'foobar'
57
+ ```
58
+
59
+ ## Advanced configuration
60
+
61
+ Sometimes just strings are not enough for configuration. E.g. consider this code sample:
62
+
63
+ ```Ruby
64
+ class Klass
65
+ def foo; end
66
+ def foobar; end;
67
+ end
55
68
  ```
69
+
70
+ and now imagine that you want to reject the name "foo" but not "foobar". This wouldn't be possible with just using strings.
71
+ For this reason Reek has a special syntax that allows you to use regexes by using a forward slash at the beginning and the end of the string.
72
+ Everything within the forward slashes will be loaded as a regex.
73
+
74
+ A possible configuration that allows "foobar" but rejects "foo" could look like this:
75
+
76
+ ```Yaml
77
+ ---
78
+ UncommunicativeMethodName:
79
+ reject:
80
+ - "/^foo$/"
81
+ ```
82
+
83
+ ## Reek 4
84
+
85
+ In Reek 4 you could also pass regexes to `accept` or `reject`, meaning this was perfectly valid as well:
86
+
87
+ ```yaml
88
+ UncommunicativeMethodName:
89
+ accept:
90
+ - !ruby/regexp /foobar/
91
+ ```
92
+
93
+ Support for this has been scrapped with Reek 5 to make the Reek configuration more yaml standard compliant.
94
+ You can still pass in regexes, you just have to wrap them into a string. Please see "Advanced configuration" above.