reek 4.8.2 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. checksums.yaml +5 -5
  2. data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  3. data/.rubocop.yml +17 -3
  4. data/.simplecov +1 -0
  5. data/.travis.yml +0 -5
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +28 -0
  8. data/Gemfile +1 -1
  9. data/README.md +113 -98
  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/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  20. data/docs/Rake-Task.md +1 -1
  21. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  22. data/docs/Reek-Driven-Development.md +1 -1
  23. data/docs/Uncommunicative-Method-Name.md +43 -4
  24. data/docs/Uncommunicative-Module-Name.md +48 -6
  25. data/docs/Uncommunicative-Parameter-Name.md +42 -4
  26. data/docs/Uncommunicative-Variable-Name.md +73 -2
  27. data/docs/Unused-Private-Method.md +1 -1
  28. data/docs/defaults.reek.yml +129 -0
  29. data/docs/yard_plugin.rb +1 -0
  30. data/features/command_line_interface/options.feature +46 -4
  31. data/features/command_line_interface/stdin.feature +27 -5
  32. data/features/configuration_files/accept_setting.feature +39 -22
  33. data/features/configuration_files/directory_specific_directives.feature +58 -53
  34. data/features/configuration_files/exclude_directives.feature +8 -7
  35. data/features/configuration_files/masking_smells.feature +35 -6
  36. data/features/configuration_files/mix_accept_reject_setting.feature +24 -21
  37. data/features/configuration_files/reject_setting.feature +45 -34
  38. data/features/configuration_files/schema_validation.feature +59 -0
  39. data/features/configuration_files/unused_private_method.feature +14 -12
  40. data/features/configuration_loading.feature +50 -7
  41. data/features/rake_task/rake_task.feature +5 -5
  42. data/features/reports/json.feature +4 -1
  43. data/features/reports/reports.feature +12 -12
  44. data/features/reports/yaml.feature +3 -0
  45. data/features/rspec_matcher.feature +9 -1
  46. data/features/step_definitions/reek_steps.rb +4 -0
  47. data/features/step_definitions/sample_file_steps.rb +9 -4
  48. data/features/support/env.rb +2 -2
  49. data/features/todo_list.feature +16 -13
  50. data/lib/reek/ast/node.rb +3 -6
  51. data/lib/reek/ast/object_refs.rb +1 -1
  52. data/lib/reek/ast/sexp_extensions/if.rb +1 -1
  53. data/lib/reek/ast/sexp_extensions/methods.rb +1 -1
  54. data/lib/reek/cli/application.rb +4 -3
  55. data/lib/reek/cli/command/report_command.rb +1 -2
  56. data/lib/reek/cli/command/todo_list_command.rb +4 -2
  57. data/lib/reek/cli/options.rb +27 -13
  58. data/lib/reek/cli/silencer.rb +14 -3
  59. data/lib/reek/code_comment.rb +14 -16
  60. data/lib/reek/configuration/app_configuration.rb +32 -28
  61. data/lib/reek/configuration/configuration_converter.rb +110 -0
  62. data/lib/reek/configuration/configuration_file_finder.rb +15 -40
  63. data/lib/reek/configuration/configuration_validator.rb +12 -23
  64. data/lib/reek/configuration/default_directive.rb +17 -3
  65. data/lib/reek/configuration/directory_directives.rb +17 -11
  66. data/lib/reek/configuration/excluded_paths.rb +1 -1
  67. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  68. data/lib/reek/configuration/schema.yml +210 -0
  69. data/lib/reek/configuration/schema_validator.rb +38 -0
  70. data/lib/reek/context/attribute_context.rb +1 -1
  71. data/lib/reek/context/code_context.rb +4 -4
  72. data/lib/reek/context/method_context.rb +2 -2
  73. data/lib/reek/context/module_context.rb +1 -1
  74. data/lib/reek/context_builder.rb +9 -9
  75. data/lib/reek/detector_repository.rb +6 -0
  76. data/lib/reek/documentation_link.rb +2 -2
  77. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +1 -1
  78. data/lib/reek/errors/bad_detector_in_comment_error.rb +1 -1
  79. data/lib/reek/errors/config_file_error.rb +11 -0
  80. data/lib/reek/errors/encoding_error.rb +2 -2
  81. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +1 -1
  82. data/lib/reek/errors/incomprehensible_source_error.rb +2 -2
  83. data/lib/reek/errors/syntax_error.rb +41 -0
  84. data/lib/reek/examiner.rb +9 -19
  85. data/lib/reek/rake/task.rb +3 -3
  86. data/lib/reek/report.rb +15 -10
  87. data/lib/reek/report/base_report.rb +8 -12
  88. data/lib/reek/report/code_climate/code_climate_configuration.yml +5 -9
  89. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  90. data/lib/reek/report/heading_formatter.rb +54 -0
  91. data/lib/reek/report/json_report.rb +1 -1
  92. data/lib/reek/report/location_formatter.rb +40 -0
  93. data/lib/reek/report/progress_formatter.rb +79 -0
  94. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  95. data/lib/reek/report/text_report.rb +1 -2
  96. data/lib/reek/report/xml_report.rb +3 -3
  97. data/lib/reek/report/yaml_report.rb +1 -1
  98. data/lib/reek/smell_configuration.rb +2 -2
  99. data/lib/reek/smell_detectors.rb +1 -2
  100. data/lib/reek/smell_detectors/attribute.rb +0 -1
  101. data/lib/reek/smell_detectors/base_detector.rb +8 -11
  102. data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
  103. data/lib/reek/smell_detectors/class_variable.rb +0 -1
  104. data/lib/reek/smell_detectors/control_parameter.rb +17 -32
  105. data/lib/reek/smell_detectors/data_clump.rb +3 -4
  106. data/lib/reek/smell_detectors/duplicate_method_call.rb +5 -6
  107. data/lib/reek/smell_detectors/feature_envy.rb +0 -1
  108. data/lib/reek/smell_detectors/instance_variable_assumption.rb +0 -1
  109. data/lib/reek/smell_detectors/irresponsible_module.rb +0 -1
  110. data/lib/reek/smell_detectors/long_parameter_list.rb +1 -2
  111. data/lib/reek/smell_detectors/long_yield_list.rb +2 -3
  112. data/lib/reek/smell_detectors/manual_dispatch.rb +2 -2
  113. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +6 -7
  114. data/lib/reek/smell_detectors/module_initialize.rb +0 -1
  115. data/lib/reek/smell_detectors/nested_iterators.rb +4 -5
  116. data/lib/reek/smell_detectors/nil_check.rb +0 -1
  117. data/lib/reek/smell_detectors/repeated_conditional.rb +3 -4
  118. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +0 -1
  119. data/lib/reek/smell_detectors/too_many_constants.rb +1 -2
  120. data/lib/reek/smell_detectors/too_many_instance_variables.rb +1 -2
  121. data/lib/reek/smell_detectors/too_many_methods.rb +1 -2
  122. data/lib/reek/smell_detectors/too_many_statements.rb +1 -2
  123. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +2 -3
  124. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +2 -3
  125. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +2 -3
  126. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +4 -5
  127. data/lib/reek/smell_detectors/unused_parameters.rb +0 -1
  128. data/lib/reek/smell_detectors/unused_private_method.rb +0 -1
  129. data/lib/reek/smell_detectors/utility_function.rb +1 -2
  130. data/lib/reek/smell_warning.rb +10 -8
  131. data/lib/reek/source/source_code.rb +40 -55
  132. data/lib/reek/source/source_locator.rb +7 -7
  133. data/lib/reek/spec.rb +6 -6
  134. data/lib/reek/spec/should_reek.rb +2 -2
  135. data/lib/reek/spec/should_reek_of.rb +9 -16
  136. data/lib/reek/spec/should_reek_only_of.rb +4 -4
  137. data/lib/reek/tree_dresser.rb +5 -5
  138. data/lib/reek/version.rb +1 -1
  139. data/reek.gemspec +3 -3
  140. data/samples/checkstyle.xml +1 -1
  141. data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  142. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  143. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  144. data/samples/configuration/full_configuration.reek +8 -4
  145. data/samples/configuration/full_mask.reek +5 -4
  146. data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  147. data/samples/configuration/partial_mask.reek +3 -2
  148. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  149. data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  150. data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  151. data/samples/paths.rb +5 -4
  152. data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  153. data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  154. data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  155. data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  156. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  157. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  158. data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
  159. data/spec/reek/ast/node_spec.rb +5 -5
  160. data/spec/reek/cli/application_spec.rb +18 -4
  161. data/spec/reek/cli/command/todo_list_command_spec.rb +4 -2
  162. data/spec/reek/cli/silencer_spec.rb +28 -0
  163. data/spec/reek/code_comment_spec.rb +0 -7
  164. data/spec/reek/configuration/app_configuration_spec.rb +44 -31
  165. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -49
  166. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  167. data/spec/reek/configuration/directory_directives_spec.rb +3 -4
  168. data/spec/reek/configuration/excluded_paths_spec.rb +5 -5
  169. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  170. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  171. data/spec/reek/context/code_context_spec.rb +1 -1
  172. data/spec/reek/examiner_spec.rb +28 -1
  173. data/spec/reek/report/json_report_spec.rb +13 -46
  174. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  175. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  176. data/spec/reek/report/text_report_spec.rb +4 -4
  177. data/spec/reek/report/xml_report_spec.rb +1 -1
  178. data/spec/reek/report/yaml_report_spec.rb +9 -38
  179. data/spec/reek/report_spec.rb +3 -3
  180. data/spec/reek/smell_detectors/feature_envy_spec.rb +2 -2
  181. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +9 -9
  182. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  183. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  184. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  185. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  186. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +6 -4
  187. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +6 -6
  188. data/spec/reek/smell_detectors/unused_private_method_spec.rb +1 -1
  189. data/spec/reek/smell_warning_spec.rb +4 -0
  190. data/spec/reek/source/source_code_spec.rb +16 -22
  191. data/spec/reek/source/source_locator_spec.rb +11 -11
  192. data/spec/reek/spec/should_reek_of_spec.rb +0 -4
  193. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  194. data/spec/reek/spec/should_reek_spec.rb +1 -1
  195. data/spec/reek/tree_dresser_spec.rb +2 -6
  196. data/spec/spec_helper.rb +3 -5
  197. data/tasks/configuration.rake +8 -5
  198. metadata +56 -35
  199. data/defaults.reek +0 -131
  200. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  201. data/lib/reek/report/formatter.rb +0 -33
  202. data/lib/reek/report/formatter/heading_formatter.rb +0 -52
  203. data/lib/reek/report/formatter/location_formatter.rb +0 -42
  204. data/lib/reek/report/formatter/progress_formatter.rb +0 -81
  205. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  206. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -23
  207. data/lib/reek/smell_detectors/syntax.rb +0 -37
  208. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  209. data/samples/smelly_with_inline_mask.rb +0 -8
  210. data/samples/smelly_with_modifiers.rb +0 -12
  211. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  212. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  213. data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
data/Rakefile CHANGED
@@ -3,6 +3,19 @@ require 'rake/clean'
3
3
 
4
4
  Dir['tasks/**/*.rake'].each { |t| load t }
5
5
 
6
- task local_test_run: [:test, :rubocop, 'test:quality']
7
- task ci: [:test, :rubocop, 'test:quality', :ataru]
8
- task default: :local_test_run
6
+ task :ci do
7
+ [
8
+ 'test:spec',
9
+ 'configuration:update_default_configuration',
10
+ 'test:features',
11
+ :rubocop,
12
+ 'test:quality',
13
+ :ataru
14
+ ].each do |name|
15
+ puts "\n=== Running #{name}...\n"
16
+ Rake::Task[name].invoke
17
+ puts "\n=== Running #{name} -> Done\n"
18
+ end
19
+ end
20
+
21
+ task default: :ci
data/bin/reek CHANGED
@@ -3,9 +3,7 @@
3
3
 
4
4
  #
5
5
  # Reek examines Ruby source code for smells.
6
- # Visit https://wiki.github.com/troessner/reek for docs etc.
7
- #
8
- # Author: Kevin Rutherford
6
+ # Visit https://github.com/troessner/reek for docs etc.
9
7
  #
10
8
 
11
9
  require_relative '../lib/reek'
data/docs/API.md CHANGED
@@ -89,7 +89,7 @@ XMLReport
89
89
 
90
90
  ## Configuration
91
91
 
92
- Given you have the following configuration file called `config.reek` in your root directory:
92
+ Given you have the following configuration file called `.reek.yml` in your root directory:
93
93
 
94
94
  ```Yaml
95
95
  ---
@@ -106,7 +106,7 @@ You can now use either
106
106
  Reek::Configuration::AppConfiguration.from_path Pathname.new('config.reek')
107
107
  ```
108
108
 
109
- but you can also pass a hash with the contents of the `config.reek` YAML file
109
+ but you can also pass a hash with the contents of the `.reek.yml` YAML file
110
110
  to `Reek::Configuration::AppConfiguration.from_hash`.
111
111
 
112
112
  Given the example above you would load that as follows:
@@ -140,13 +140,6 @@ string -- 2 warnings:
140
140
  Dirty#call_me has the parameter name 'b' (UncommunicativeParameterName)
141
141
  ```
142
142
 
143
- Instead of the smell detector names you can also use the full detector class in
144
- your configuration hash, for example:
145
-
146
- ```ruby
147
- config_hash = { Reek::SmellDetectors::IrresponsibleModule => { 'enabled' => false } }
148
- ```
149
-
150
143
  Of course, directory specific configuration and excluded paths are supported as
151
144
  well:
152
145
 
@@ -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
 
@@ -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
+