reek 6.0.2 → 6.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +52 -0
  4. data/.rubocop_todo.yml +6 -4
  5. data/CHANGELOG.md +20 -0
  6. data/CONTRIBUTING.md +3 -0
  7. data/Dockerfile +1 -1
  8. data/Gemfile +6 -6
  9. data/bin/code_climate_reek +2 -3
  10. data/lib/reek/ast/ast_node_class_map.rb +1 -1
  11. data/lib/reek/ast/node.rb +1 -1
  12. data/lib/reek/code_comment.rb +22 -17
  13. data/lib/reek/configuration/excluded_paths.rb +2 -1
  14. data/lib/reek/context/code_context.rb +1 -1
  15. data/lib/reek/context/refinement_context.rb +16 -0
  16. data/lib/reek/context_builder.rb +16 -2
  17. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -3
  18. data/lib/reek/smell_detectors/base_detector.rb +1 -1
  19. data/lib/reek/smell_warning.rb +1 -1
  20. data/lib/reek/source/source_locator.rb +1 -3
  21. data/lib/reek/version.rb +2 -2
  22. data/reek.gemspec +5 -3
  23. metadata +11 -239
  24. data/.travis.yml +0 -40
  25. data/docs/API.md +0 -174
  26. data/docs/Attribute.md +0 -39
  27. data/docs/Basic-Smell-Options.md +0 -85
  28. data/docs/Boolean-Parameter.md +0 -54
  29. data/docs/Class-Variable.md +0 -40
  30. data/docs/Code-Smells.md +0 -39
  31. data/docs/Command-Line-Options.md +0 -119
  32. data/docs/Control-Couple.md +0 -26
  33. data/docs/Control-Parameter.md +0 -32
  34. data/docs/Data-Clump.md +0 -46
  35. data/docs/Duplicate-Method-Call.md +0 -264
  36. data/docs/Feature-Envy.md +0 -93
  37. data/docs/How-To-Write-New-Detectors.md +0 -132
  38. data/docs/How-reek-works-internally.md +0 -114
  39. data/docs/Instance-Variable-Assumption.md +0 -163
  40. data/docs/Irresponsible-Module.md +0 -47
  41. data/docs/Large-Class.md +0 -16
  42. data/docs/Long-Parameter-List.md +0 -39
  43. data/docs/Long-Yield-List.md +0 -37
  44. data/docs/Manual-Dispatch.md +0 -30
  45. data/docs/Missing-Safe-Method.md +0 -92
  46. data/docs/Module-Initialize.md +0 -62
  47. data/docs/Nested-Iterators.md +0 -59
  48. data/docs/Nil-Check.md +0 -47
  49. data/docs/RSpec-matchers.md +0 -129
  50. data/docs/Rake-Task.md +0 -66
  51. data/docs/Reek-4-to-Reek-5-migration.md +0 -188
  52. data/docs/Reek-Driven-Development.md +0 -46
  53. data/docs/Repeated-Conditional.md +0 -47
  54. data/docs/Simulated-Polymorphism.md +0 -16
  55. data/docs/Smell-Suppression.md +0 -96
  56. data/docs/Style-Guide.md +0 -19
  57. data/docs/Subclassed-From-Core-Class.md +0 -79
  58. data/docs/Too-Many-Constants.md +0 -37
  59. data/docs/Too-Many-Instance-Variables.md +0 -43
  60. data/docs/Too-Many-Methods.md +0 -56
  61. data/docs/Too-Many-Statements.md +0 -54
  62. data/docs/Uncommunicative-Method-Name.md +0 -94
  63. data/docs/Uncommunicative-Module-Name.md +0 -92
  64. data/docs/Uncommunicative-Name.md +0 -18
  65. data/docs/Uncommunicative-Parameter-Name.md +0 -90
  66. data/docs/Uncommunicative-Variable-Name.md +0 -96
  67. data/docs/Unused-Parameters.md +0 -28
  68. data/docs/Unused-Private-Method.md +0 -101
  69. data/docs/Utility-Function.md +0 -56
  70. data/docs/Versioning-Policy.md +0 -7
  71. data/docs/YAML-Reports.md +0 -93
  72. data/docs/defaults.reek.yml +0 -129
  73. data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
  74. data/docs/templates/default/docstring/setup.rb +0 -37
  75. data/docs/templates/default/fulldoc/html/css/common.css +0 -1
  76. data/docs/yard_plugin.rb +0 -17
  77. data/features/command_line_interface/basic_usage.feature +0 -15
  78. data/features/command_line_interface/options.feature +0 -123
  79. data/features/command_line_interface/show_progress.feature +0 -33
  80. data/features/command_line_interface/smell_selection.feature +0 -15
  81. data/features/command_line_interface/smells_count.feature +0 -38
  82. data/features/command_line_interface/stdin.feature +0 -65
  83. data/features/configuration_files/accept_setting.feature +0 -87
  84. data/features/configuration_files/directory_specific_directives.feature +0 -274
  85. data/features/configuration_files/exclude_directives.feature +0 -35
  86. data/features/configuration_files/exclude_paths_directives.feature +0 -42
  87. data/features/configuration_files/masking_smells.feature +0 -94
  88. data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
  89. data/features/configuration_files/reject_setting.feature +0 -89
  90. data/features/configuration_files/schema_validation.feature +0 -59
  91. data/features/configuration_files/show_configuration_file.feature +0 -44
  92. data/features/configuration_files/unused_private_method.feature +0 -68
  93. data/features/configuration_loading.feature +0 -91
  94. data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
  95. data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
  96. data/features/locales.feature +0 -32
  97. data/features/programmatic_access.feature +0 -41
  98. data/features/rake_task/rake_task.feature +0 -138
  99. data/features/reports/codeclimate.feature +0 -59
  100. data/features/reports/json.feature +0 -59
  101. data/features/reports/reports.feature +0 -219
  102. data/features/reports/yaml.feature +0 -52
  103. data/features/rspec_matcher.feature +0 -41
  104. data/features/samples.feature +0 -305
  105. data/features/step_definitions/.rubocop.yml +0 -5
  106. data/features/step_definitions/reek_steps.rb +0 -102
  107. data/features/step_definitions/sample_file_steps.rb +0 -63
  108. data/features/support/env.rb +0 -33
  109. data/features/todo_list.feature +0 -108
  110. data/samples/checkstyle.xml +0 -7
  111. data/samples/clean_source/clean.rb +0 -6
  112. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
  113. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
  114. data/samples/configuration/corrupt.reek +0 -1
  115. data/samples/configuration/empty.reek +0 -0
  116. data/samples/configuration/full_configuration.reek +0 -13
  117. data/samples/configuration/full_mask.reek +0 -6
  118. data/samples/configuration/home/home.reek.yml +0 -4
  119. data/samples/configuration/partial_mask.reek +0 -4
  120. data/samples/configuration/regular_configuration/.reek.yml +0 -4
  121. data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
  122. data/samples/configuration/with_excluded_paths.reek +0 -5
  123. data/samples/no_config_file/.keep +0 -0
  124. data/samples/paths.rb +0 -5
  125. data/samples/smelly_source/inline.rb +0 -704
  126. data/samples/smelly_source/optparse.rb +0 -1788
  127. data/samples/smelly_source/redcloth.rb +0 -1130
  128. data/samples/smelly_source/ruby.rb +0 -368
  129. data/samples/smelly_source/smelly.rb +0 -7
  130. data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
  131. data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
  132. data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
  133. data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
  134. data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
  135. data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
  136. data/samples/source_with_non_ruby_files/gibberish +0 -1
  137. data/samples/source_with_non_ruby_files/python_source.py +0 -1
  138. data/samples/source_with_non_ruby_files/ruby.rb +0 -6
  139. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -15
  140. data/spec/quality/documentation_spec.rb +0 -41
  141. data/spec/quality/reek_source_spec.rb +0 -11
  142. data/spec/reek/ast/node_spec.rb +0 -211
  143. data/spec/reek/ast/object_refs_spec.rb +0 -83
  144. data/spec/reek/ast/reference_collector_spec.rb +0 -47
  145. data/spec/reek/ast/sexp_extensions_spec.rb +0 -498
  146. data/spec/reek/cli/application_spec.rb +0 -168
  147. data/spec/reek/cli/command/report_command_spec.rb +0 -44
  148. data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
  149. data/spec/reek/cli/options_spec.rb +0 -51
  150. data/spec/reek/cli/silencer_spec.rb +0 -28
  151. data/spec/reek/code_comment_spec.rb +0 -184
  152. data/spec/reek/configuration/app_configuration_spec.rb +0 -195
  153. data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
  154. data/spec/reek/configuration/default_directive_spec.rb +0 -13
  155. data/spec/reek/configuration/directory_directives_spec.rb +0 -122
  156. data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
  157. data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
  158. data/spec/reek/configuration/schema_validator_spec.rb +0 -165
  159. data/spec/reek/context/code_context_spec.rb +0 -192
  160. data/spec/reek/context/ghost_context_spec.rb +0 -60
  161. data/spec/reek/context/method_context_spec.rb +0 -72
  162. data/spec/reek/context/module_context_spec.rb +0 -55
  163. data/spec/reek/context/root_context_spec.rb +0 -12
  164. data/spec/reek/context/statement_counter_spec.rb +0 -24
  165. data/spec/reek/context_builder_spec.rb +0 -457
  166. data/spec/reek/detector_repository_spec.rb +0 -22
  167. data/spec/reek/documentation_link_spec.rb +0 -20
  168. data/spec/reek/errors/base_error_spec.rb +0 -13
  169. data/spec/reek/examiner_spec.rb +0 -309
  170. data/spec/reek/logging_error_handler_spec.rb +0 -24
  171. data/spec/reek/rake/task_spec.rb +0 -56
  172. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -22
  173. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
  174. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
  175. data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
  176. data/spec/reek/report/html_report_spec.rb +0 -19
  177. data/spec/reek/report/json_report_spec.rb +0 -58
  178. data/spec/reek/report/location_formatter_spec.rb +0 -32
  179. data/spec/reek/report/progress_formatter_spec.rb +0 -68
  180. data/spec/reek/report/text_report_spec.rb +0 -89
  181. data/spec/reek/report/xml_report_spec.rb +0 -24
  182. data/spec/reek/report/yaml_report_spec.rb +0 -55
  183. data/spec/reek/report_spec.rb +0 -28
  184. data/spec/reek/smell_configuration_spec.rb +0 -56
  185. data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
  186. data/spec/reek/smell_detectors/base_detector_spec.rb +0 -50
  187. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
  188. data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
  189. data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
  190. data/spec/reek/smell_detectors/data_clump_spec.rb +0 -134
  191. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
  192. data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
  193. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
  194. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
  195. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
  196. data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
  197. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
  198. data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -68
  199. data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
  200. data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
  201. data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
  202. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
  203. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
  204. data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
  205. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
  206. data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
  207. data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
  208. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
  209. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
  210. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
  211. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
  212. data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
  213. data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
  214. data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
  215. data/spec/reek/smell_warning_spec.rb +0 -137
  216. data/spec/reek/source/source_code_spec.rb +0 -79
  217. data/spec/reek/source/source_locator_spec.rb +0 -166
  218. data/spec/reek/spec/should_reek_of_spec.rb +0 -153
  219. data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
  220. data/spec/reek/spec/should_reek_spec.rb +0 -52
  221. data/spec/reek/spec/smell_matcher_spec.rb +0 -87
  222. data/spec/reek/tree_dresser_spec.rb +0 -46
  223. data/spec/spec_helper.rb +0 -110
  224. data/tasks/configuration.rake +0 -18
  225. data/tasks/console.rake +0 -5
  226. data/tasks/reek.rake +0 -6
  227. data/tasks/rubocop.rake +0 -11
  228. data/tasks/test.rake +0 -32
@@ -1,264 +0,0 @@
1
- # Duplicate Method Call
2
-
3
- ## Introduction
4
-
5
- Duplication occurs when two fragments of code look nearly identical, or when two fragments of code have nearly identical effects at some conceptual level.
6
-
7
- Let's look at an example that is quite common in the Rails world:
8
-
9
- ```Ruby
10
- def not_production?
11
- Rails.env.development? || Rails.env.test?
12
- end
13
- ```
14
-
15
- While this duplicate usage of `Rails.env` might seem innocuous there are 2 problems with it:
16
-
17
- 1.) Efficiency
18
-
19
- ```Ruby
20
- Rails.env.development? || Rails.env.test?
21
- ```
22
-
23
- is not as efficient as it could be. If the call to `env` is not memoized your basically paying twice in terms of computation for something that you should only pay once.
24
-
25
- Here
26
-
27
- ```Ruby
28
- Rails.env.development? || Rails.env.test?
29
- ```
30
-
31
- you have 4 method calls while here:
32
-
33
- ```Ruby
34
- env = Rails.env
35
- env.development? || env.test?
36
- ```
37
-
38
- you have one assignment (which is very cheap in terms of computation) and 3 method calls.
39
- The difference might not be much here but just imagine you're writing a high performance app or you doing some expensive database calls in each method call.
40
-
41
- It doesn't really matter though if the efficiency difference is significant. This is a matter of principle - we believe that being efficient is one of the vital traits of good software.
42
-
43
- 2.) Maintainability
44
-
45
- The second point is a bit more subtle. This
46
-
47
- ```Ruby
48
- env = Rails.env
49
- env.development? || env.test?
50
- ```
51
-
52
- is a lot more intention revealing than
53
-
54
- ```Ruby
55
- Rails.env.development? || Rails.env.test?
56
- ```
57
-
58
- Here
59
-
60
- ```Ruby
61
- env = Rails.env
62
- env.development? || env.test?
63
- ```
64
-
65
- I'm very clear on what I do: I get the environment and then I run some checks on it.
66
-
67
- Here
68
-
69
- ```Ruby
70
- Rails.env.development? || Rails.env.test?
71
- ```
72
-
73
- I'm not very clear on what I do and it requires quite more mental effort: Ok, so I'm talking to Rails, getting the environment and then running a check on it ...or .....oh, I get the same Rails constant again, get the same environment and run another check on it.
74
-
75
- ## Example
76
-
77
- Here's a very much simplified and contrived example. The following method will report a warning:
78
-
79
- ```Ruby
80
- def double_thing
81
- @other.thing + @other.thing
82
- end
83
- ```
84
-
85
- One quick approach to silence Reek would be to refactor the code thus:
86
-
87
- ```Ruby
88
- def double_thing
89
- thing = @other.thing
90
- thing + thing
91
- end
92
- ```
93
-
94
- A slightly different approach would be to replace all calls in `double_thing` by calls to `thing`:
95
-
96
- ```Ruby
97
- class Other
98
- def double_thing
99
- thing + thing
100
- end
101
-
102
- def thing
103
- @other.thing
104
- end
105
- end
106
- ```
107
-
108
- The approach you take will depend on balancing other factors in your code.
109
-
110
- ## Current support in Reek
111
-
112
- Reek's Duplicate Method Call detector checks for repeated identical method calls within
113
- any one method definition. This is intended to complement the checks performed by tools
114
- such as [Flay](http://ruby.sadi.st/Flay.html) and [Simian](http://www.redhillconsulting.com.au/products/simian/).
115
-
116
- ## Edge cases
117
-
118
- Be aware that there are some edge cases like this code:
119
-
120
- ```Ruby
121
- class Foo
122
- def bar(switch)
123
- case switch
124
- when :a
125
- ->(arg) { arg.call_me(:maybe); do_something }
126
- when :b
127
- ->(arg) { arg.call_me(:maybe); do_something_else }
128
- when :c
129
- ->(arg) { arg.call_me(:maybe); do_something_different }
130
- end
131
- end
132
- end
133
- ```
134
-
135
- Reek cannot reliably detect that each call's receiver is a different arg and will report:
136
-
137
- ```
138
- [5, 7, 9]:DuplicateMethodCall: Foo#bar calls 'arg.call_me(:maybe)' 3 times
139
- ```
140
-
141
- If you're running into this problem you can disable this smell detector for this method either via
142
- configuration:
143
-
144
- ```Yaml
145
- ---
146
- DuplicateMethodCall:
147
- exclude:
148
- - 'Foo#bar'
149
- ```
150
-
151
- or via source code comment:
152
-
153
- ```Ruby
154
- class Foo
155
- # :reek:DuplicateMethodCall
156
- def bar(switch)
157
- # ....
158
- end
159
- end
160
- ```
161
-
162
- ## Configuration
163
-
164
- Reek's Duplicate Method Call detector currently offers the [Basic Smell Options](Basic-Smell-Options.md), plus:
165
-
166
- Option | Value | Effect
167
- -------|-------|-------
168
- `max_calls` | integer | The maximum number of duplicate calls allowed within a method. Defaults to 1.
169
- `allow_calls` | an array of strings or regular expressions | Ignores any context who matches it |
170
-
171
- ## Example configuration
172
-
173
- ### Adjusting `max_calls`
174
-
175
- Imagine code like this:
176
-
177
- ```Ruby
178
- class Alfa
179
- def bravo
180
- charlie.delta
181
- charlie.delta
182
- end
183
- end
184
- ```
185
-
186
- This would report:
187
-
188
- >>
189
- src.rb -- 1 warning:
190
- [4, 5]:DuplicateMethodCall: Alfa#bravo calls 'charlie.delta' 2 times
191
-
192
- If you want to allow those double calls here you can disable it in 2 different ways:
193
-
194
- 1.) Via source code comment:
195
-
196
- ```Ruby
197
- class Alfa
198
- # :reek:DuplicateMethodCall { max_calls: 2 }
199
- def bravo
200
- charlie.delta
201
- charlie.delta
202
- end
203
- end
204
- ```
205
-
206
- 2.) Via configuration file:
207
-
208
- ```Yaml
209
- DuplicateMethodCall:
210
- max_calls: 2
211
- ```
212
-
213
- Note though that the latter way will set `max_calls` to 2 for all instances
214
- of the smell detector which might not be what you want - in this case
215
- you'll have to use source code comments.
216
-
217
- ### Adjusting `allow_calls`
218
-
219
- Imagine code like this:
220
-
221
- ```Ruby
222
- class Alfa
223
- def bravo
224
- charlie.delta
225
- charlie.delta
226
- echo.foxtrot
227
- echo.foxtrot
228
- end
229
- end
230
- ```
231
-
232
- This would report:
233
-
234
- >>
235
- src.rb -- 2 warnings:
236
- [4, 5]:DuplicateMethodCall: Alfa#bravo calls charlie.delta 2 times
237
- [6, 7]:DuplicateMethodCall: Alfa#bravo calls echo.foxtrot 2 times
238
-
239
- So let's say you're ok with the `echo.foxtrot` calls you can stop reporting them like this:
240
-
241
- 1.) Via source code comment:
242
-
243
- ```Ruby
244
- class Alfa
245
- # :reek:DuplicateMethodCall { allow_calls: ['echo.foxtrot'] }
246
- def bravo
247
- charlie.delta
248
- charlie.delta
249
- echo.foxtrot
250
- echo.foxtrot
251
- end
252
- end
253
- ```
254
-
255
- 2.) Via configuration file:
256
-
257
- ```Yaml
258
- DuplicateMethodCall:
259
- allow_calls:
260
- - 'echo.foxtrot'
261
- ```
262
-
263
- Note though that the latter way will allow those calls across your source code which might not be what you want.
264
- In this case you'll have to use source code comments.
data/docs/Feature-Envy.md DELETED
@@ -1,93 +0,0 @@
1
- # Feature Envy
2
-
3
- ## Introduction
4
-
5
- _Feature Envy_ occurs when a code fragment references another object more often than it references itself, or when several clients do the same series of manipulations on a particular type of object.
6
-
7
- _Feature Envy_ reduces the code's ability to communicate intent: code that "belongs" on one class but which is located in another can be hard to find, and may upset the "System of Names" in the host class.
8
-
9
- _Feature Envy_ also affects the design's flexibility: A code fragment that is in the wrong class creates couplings that may not be natural within the application's domain, and creates a loss of cohesion in the unwilling host class.
10
-
11
- _Feature Envy_ often arises because it must manipulate other objects (usually its arguments) to get them into a useful form, and one force preventing them (the arguments) doing this themselves is that the common knowledge lives outside the arguments, or the arguments are of too basic a type to justify extending that type. Therefore there must be something which 'knows' about the contents or purposes of the arguments. That thing would have to be more than just a basic type, because the basic types are either containers which don't know about their contents, or they are single objects which can't capture their relationship with their fellows of the same type. So, this thing with the extra knowledge should be reified into a class, and the utility method will most likely belong there.
12
-
13
- ## Example
14
-
15
- Running Reek on:
16
-
17
- ```Ruby
18
- class Warehouse
19
- def sale_price(item)
20
- (item.price - item.rebate) * @vat
21
- end
22
- end
23
- ```
24
-
25
- would report:
26
-
27
- ```Bash
28
- Warehouse#sale_price refers to item more than self (FeatureEnvy)
29
- ```
30
-
31
- since this:
32
-
33
- ```Ruby
34
- (item.price - item.rebate)
35
- ```
36
-
37
- belongs to the Item class, not the Warehouse.
38
-
39
- ## Current Support in Reek
40
-
41
- _Feature Envy_ reports any method that refers to self less often than it refers to (ie. send messages to) some other object.
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
-
87
- ## Differences to _Utility Function_
88
-
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.
90
-
91
- ## Configuration
92
-
93
- _Feature Envy_ supports the [Basic Smell Options](Basic-Smell-Options.md).
@@ -1,132 +0,0 @@
1
- ## How to write new detectors
2
-
3
- ### Outline what you have in mind
4
-
5
- Before starting to code you should discuss the overall idea for your new smell detector with
6
- us in a corresponding github issue.
7
- We all should have a solid understanding of what this detector actually reports, the edgecases
8
- it covers and the overall rationale behind it.
9
-
10
- ### Structure
11
-
12
- All smell detectors reside in `lib/reek/smell_detectors` and have the following base structure:
13
-
14
- ```Ruby
15
- require_relative 'base_detector'
16
- require_relative 'smell_warning'
17
-
18
- module Reek
19
- module SmellDetectors
20
- #
21
- # Here goes your introduction for this detector.
22
- #
23
- # See {file:docs/Your-Detector.md} for details.
24
- class YourDetector < BaseDetector
25
- def self.contexts
26
- [:class] # In case you're operating on class contexts only - just an example.
27
- end
28
-
29
- #
30
- # Here you should document what you expect the detector's context to look
31
- # like.
32
- #
33
- # @return [Array<SmellWarning>]
34
- #
35
- def sniff
36
- # "found_smells" below is just an abstraction for
37
- # "find the smells in question" and iterate over them.
38
- # This can just be a method but it can also be a more sophisticated set up.
39
- # Check out other smell detectors to get a feeling for what to do here.
40
- found_smells.map do |smell|
41
- # "smell_warning" is defined in BaseDetector and should be used by you
42
- # to construct smell warnings
43
- smell_warning(
44
- lines: [], # lines on which the smell was detected
45
- message: "...", # the message that is printed on STDOUT
46
- # whatever you interpolate into the "message" should go into
47
- # parameters below - if you do not interpolate anything you
48
- # can omit this
49
- parameters: { })
50
- end
51
- end
52
- end
53
-
54
- private
55
-
56
- # Here goes everything you need for finding smells.
57
- end
58
- end
59
- end
60
- ```
61
-
62
- For your detector to be properly loaded you need to require it in `lib/reek/smell_detectors.rb` as well.
63
-
64
- ### defaults.reek.yml
65
-
66
- After you ran
67
-
68
- ```
69
- bundle exec rake
70
- ```
71
-
72
- for the first time with your shiny new detector in place the `docs/defaults.reek.yml`
73
- file should have been updated automatically. Make sure you don't forget to check
74
- in those changes as well.
75
-
76
- ### Documentation
77
-
78
- * Above every `SmellDetector::sniff` method it should be documented what the expected AST is
79
- * Every detector should have a separate documentation page in /docs. You can
80
- take any arbitrary existing smell detector documentation page as template (since
81
- they all have the same structure already)
82
- * The detector should be listed under [Code Smells](docs/Code-Smells.md)
83
- * Depending on what your detector does it might make sense to add it to other doc pages as
84
- well e.g. [Simulated Polymorphism](docs/Simulated-Polymorphism.md)
85
-
86
- ### Rspec examples
87
-
88
- All smell detector specs start out with 2 generic examples like below - the second one
89
- only if it makes sense.
90
- Here's what it looks like for `UncommunicativeVariableName`:
91
-
92
- ```Ruby
93
- it 'reports the right values' do
94
- src = <<-RUBY
95
- def alfa
96
- bravo = 5
97
- end
98
- RUBY
99
-
100
- expect(src).to reek_of(:UncommunicativeVariableName,
101
- lines: [2],
102
- context: 'alfa',
103
- message: "has the variable name 'bravo'",
104
- source: 'string',
105
- name: 'bravo')
106
- end
107
-
108
- it 'does count all occurences' do
109
- src = <<-RUBY
110
- def alfa
111
- bravo = 3
112
- charlie = 7
113
- end
114
- RUBY
115
-
116
- expect(src).to reek_of(:UncommunicativeVariableName,
117
- lines: [2],
118
- name: 'bravo')
119
- expect(src).to reek_of(:UncommunicativeVariableName,
120
- lines: [3],
121
- name: 'charlie')
122
- end
123
- ```
124
-
125
- The following examples should then cover the detector specific features.
126
-
127
- ### Cucumber features
128
-
129
- We are trying to write as few Cucumber features as possible.
130
- Normally, there should be no need to write a new feature for a new smell detector.
131
- If you feel like this is necessary in this case, please discuss this with us via
132
- github issue or in your work-in-progress pull request before doing anything.