reek 4.8.1 → 5.6.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 (280) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +22 -68
  3. data/.rubocop_todo.yml +63 -0
  4. data/.simplecov +8 -2
  5. data/.travis.yml +8 -8
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +84 -0
  8. data/CONTRIBUTING.md +25 -0
  9. data/Dockerfile +1 -1
  10. data/Gemfile +14 -18
  11. data/README.md +152 -135
  12. data/Rakefile +16 -3
  13. data/bin/reek +1 -3
  14. data/docs/API.md +6 -13
  15. data/docs/Basic-Smell-Options.md +51 -11
  16. data/docs/Code-Smells.md +1 -1
  17. data/docs/Command-Line-Options.md +14 -4
  18. data/docs/Duplicate-Method-Call.md +117 -2
  19. data/docs/Feature-Envy.md +44 -0
  20. data/docs/How-To-Write-New-Detectors.md +6 -7
  21. data/docs/Instance-Variable-Assumption.md +30 -1
  22. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  23. data/docs/Rake-Task.md +1 -1
  24. data/docs/Reek-4-to-Reek-5-migration.md +188 -0
  25. data/docs/Reek-Driven-Development.md +19 -12
  26. data/docs/Uncommunicative-Method-Name.md +45 -6
  27. data/docs/Uncommunicative-Module-Name.md +49 -7
  28. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  29. data/docs/Uncommunicative-Variable-Name.md +73 -2
  30. data/docs/Unused-Private-Method.md +1 -1
  31. data/docs/defaults.reek.yml +129 -0
  32. data/docs/templates/default/docstring/setup.rb +3 -0
  33. data/docs/yard_plugin.rb +1 -0
  34. data/features/command_line_interface/basic_usage.feature +2 -2
  35. data/features/command_line_interface/options.feature +49 -5
  36. data/features/command_line_interface/show_progress.feature +4 -4
  37. data/features/command_line_interface/smell_selection.feature +1 -1
  38. data/features/command_line_interface/smells_count.feature +6 -6
  39. data/features/command_line_interface/stdin.feature +30 -8
  40. data/features/configuration_files/accept_setting.feature +45 -28
  41. data/features/configuration_files/directory_specific_directives.feature +78 -73
  42. data/features/configuration_files/exclude_directives.feature +11 -10
  43. data/features/configuration_files/exclude_paths_directives.feature +12 -13
  44. data/features/configuration_files/masking_smells.feature +38 -9
  45. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  46. data/features/configuration_files/reject_setting.feature +52 -41
  47. data/features/configuration_files/schema_validation.feature +59 -0
  48. data/features/configuration_files/show_configuration_file.feature +44 -0
  49. data/features/configuration_files/unused_private_method.feature +18 -16
  50. data/features/configuration_loading.feature +53 -10
  51. data/features/configuration_via_source_comments/erroneous_source_comments.feature +2 -2
  52. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  53. data/features/locales.feature +2 -2
  54. data/features/rake_task/rake_task.feature +16 -16
  55. data/features/reports/json.feature +3 -3
  56. data/features/reports/reports.feature +34 -34
  57. data/features/reports/yaml.feature +3 -3
  58. data/features/rspec_matcher.feature +10 -1
  59. data/features/samples.feature +287 -287
  60. data/features/step_definitions/reek_steps.rb +4 -0
  61. data/features/step_definitions/sample_file_steps.rb +20 -11
  62. data/features/support/env.rb +3 -3
  63. data/features/todo_list.feature +60 -44
  64. data/lib/reek/ast/node.rb +7 -6
  65. data/lib/reek/ast/object_refs.rb +1 -1
  66. data/lib/reek/ast/sexp_extensions/case.rb +3 -1
  67. data/lib/reek/ast/sexp_extensions/if.rb +22 -2
  68. data/lib/reek/ast/sexp_extensions/logical_operators.rb +1 -1
  69. data/lib/reek/ast/sexp_extensions/methods.rb +2 -1
  70. data/lib/reek/ast/sexp_extensions/yield.rb +0 -4
  71. data/lib/reek/ast/sexp_extensions.rb +0 -2
  72. data/lib/reek/cli/application.rb +29 -3
  73. data/lib/reek/cli/command/report_command.rb +1 -2
  74. data/lib/reek/cli/command/todo_list_command.rb +25 -8
  75. data/lib/reek/cli/options.rb +49 -27
  76. data/lib/reek/cli/silencer.rb +14 -3
  77. data/lib/reek/code_comment.rb +33 -33
  78. data/lib/reek/configuration/app_configuration.rb +29 -28
  79. data/lib/reek/configuration/configuration_converter.rb +110 -0
  80. data/lib/reek/configuration/configuration_file_finder.rb +15 -40
  81. data/lib/reek/configuration/configuration_validator.rb +12 -23
  82. data/lib/reek/configuration/default_directive.rb +17 -3
  83. data/lib/reek/configuration/directory_directives.rb +46 -12
  84. data/lib/reek/configuration/excluded_paths.rb +4 -4
  85. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  86. data/lib/reek/configuration/schema.yml +210 -0
  87. data/lib/reek/configuration/schema_validator.rb +39 -0
  88. data/lib/reek/context/attribute_context.rb +1 -1
  89. data/lib/reek/context/code_context.rb +4 -4
  90. data/lib/reek/context/method_context.rb +3 -2
  91. data/lib/reek/context/module_context.rb +6 -5
  92. data/lib/reek/context/visibility_tracker.rb +7 -4
  93. data/lib/reek/context_builder.rb +10 -9
  94. data/lib/reek/detector_repository.rb +7 -0
  95. data/lib/reek/documentation_link.rb +28 -0
  96. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +4 -3
  97. data/lib/reek/errors/bad_detector_in_comment_error.rb +4 -3
  98. data/lib/reek/errors/config_file_error.rb +11 -0
  99. data/lib/reek/errors/encoding_error.rb +2 -2
  100. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +4 -3
  101. data/lib/reek/errors/incomprehensible_source_error.rb +4 -4
  102. data/lib/reek/errors/syntax_error.rb +45 -0
  103. data/lib/reek/examiner.rb +14 -23
  104. data/lib/reek/logging_error_handler.rb +1 -1
  105. data/lib/reek/rake/task.rb +3 -3
  106. data/lib/reek/report/base_report.rb +8 -12
  107. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -10
  108. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  109. data/lib/reek/report/heading_formatter.rb +54 -0
  110. data/lib/reek/report/json_report.rb +1 -1
  111. data/lib/reek/report/location_formatter.rb +40 -0
  112. data/lib/reek/report/progress_formatter.rb +79 -0
  113. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  114. data/lib/reek/report/text_report.rb +4 -4
  115. data/lib/reek/report/xml_report.rb +3 -3
  116. data/lib/reek/report/yaml_report.rb +1 -1
  117. data/lib/reek/report.rb +20 -15
  118. data/lib/reek/smell_configuration.rb +2 -2
  119. data/lib/reek/smell_detectors/attribute.rb +0 -1
  120. data/lib/reek/smell_detectors/base_detector.rb +10 -13
  121. data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
  122. data/lib/reek/smell_detectors/class_variable.rb +0 -1
  123. data/lib/reek/smell_detectors/control_parameter.rb +19 -128
  124. data/lib/reek/smell_detectors/control_parameter_helpers/call_in_condition_finder.rb +91 -0
  125. data/lib/reek/smell_detectors/control_parameter_helpers/candidate.rb +38 -0
  126. data/lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb +94 -0
  127. data/lib/reek/smell_detectors/data_clump.rb +4 -5
  128. data/lib/reek/smell_detectors/duplicate_method_call.rb +6 -6
  129. data/lib/reek/smell_detectors/feature_envy.rb +3 -1
  130. data/lib/reek/smell_detectors/instance_variable_assumption.rb +0 -1
  131. data/lib/reek/smell_detectors/irresponsible_module.rb +1 -1
  132. data/lib/reek/smell_detectors/long_parameter_list.rb +2 -2
  133. data/lib/reek/smell_detectors/long_yield_list.rb +2 -3
  134. data/lib/reek/smell_detectors/manual_dispatch.rb +3 -2
  135. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +7 -7
  136. data/lib/reek/smell_detectors/module_initialize.rb +0 -1
  137. data/lib/reek/smell_detectors/nested_iterators.rb +5 -5
  138. data/lib/reek/smell_detectors/nil_check.rb +0 -1
  139. data/lib/reek/smell_detectors/repeated_conditional.rb +4 -4
  140. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +3 -8
  141. data/lib/reek/smell_detectors/too_many_constants.rb +2 -3
  142. data/lib/reek/smell_detectors/too_many_instance_variables.rb +2 -2
  143. data/lib/reek/smell_detectors/too_many_methods.rb +2 -2
  144. data/lib/reek/smell_detectors/too_many_statements.rb +2 -2
  145. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +2 -3
  146. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +2 -3
  147. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +2 -3
  148. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +6 -5
  149. data/lib/reek/smell_detectors/unused_parameters.rb +1 -1
  150. data/lib/reek/smell_detectors/unused_private_method.rb +0 -1
  151. data/lib/reek/smell_detectors/utility_function.rb +1 -2
  152. data/lib/reek/smell_detectors.rb +1 -2
  153. data/lib/reek/smell_warning.rb +31 -20
  154. data/lib/reek/source/source_code.rb +42 -56
  155. data/lib/reek/source/source_locator.rb +10 -7
  156. data/lib/reek/spec/should_reek.rb +2 -2
  157. data/lib/reek/spec/should_reek_of.rb +9 -16
  158. data/lib/reek/spec/should_reek_only_of.rb +5 -4
  159. data/lib/reek/spec/smell_matcher.rb +1 -0
  160. data/lib/reek/spec.rb +8 -14
  161. data/lib/reek/tree_dresser.rb +6 -5
  162. data/lib/reek/version.rb +1 -1
  163. data/lib/reek.rb +7 -0
  164. data/reek.gemspec +5 -4
  165. data/samples/checkstyle.xml +1 -1
  166. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  167. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  168. data/samples/configuration/full_configuration.reek +8 -4
  169. data/samples/configuration/full_mask.reek +5 -4
  170. data/samples/configuration/partial_mask.reek +3 -2
  171. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  172. data/samples/configuration/with_excluded_paths.reek +1 -0
  173. data/samples/paths.rb +5 -4
  174. data/samples/smelly_source/ruby.rb +368 -0
  175. data/samples/{source_with_hidden_directories/.hidden/uncommunicative_method_name.rb → source_with_exclude_paths/nested/uncommunicative_variable_name.rb} +2 -1
  176. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  177. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  178. data/spec/factories/factories.rb +12 -22
  179. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +17 -0
  180. data/spec/quality/documentation_spec.rb +40 -0
  181. data/spec/reek/ast/node_spec.rb +7 -7
  182. data/spec/reek/ast/sexp_extensions_spec.rb +20 -20
  183. data/spec/reek/cli/application_spec.rb +48 -5
  184. data/spec/reek/cli/command/todo_list_command_spec.rb +65 -45
  185. data/spec/reek/cli/silencer_spec.rb +28 -0
  186. data/spec/reek/code_comment_spec.rb +6 -13
  187. data/spec/reek/configuration/app_configuration_spec.rb +106 -45
  188. data/spec/reek/configuration/configuration_file_finder_spec.rb +143 -49
  189. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  190. data/spec/reek/configuration/directory_directives_spec.rb +45 -7
  191. data/spec/reek/configuration/excluded_paths_spec.rb +6 -9
  192. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  193. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  194. data/spec/reek/context/code_context_spec.rb +3 -3
  195. data/spec/reek/context_builder_spec.rb +30 -30
  196. data/spec/reek/detector_repository_spec.rb +2 -2
  197. data/spec/reek/documentation_link_spec.rb +20 -0
  198. data/spec/reek/examiner_spec.rb +39 -11
  199. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +22 -22
  200. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +5 -5
  201. data/spec/reek/report/code_climate/code_climate_report_spec.rb +21 -21
  202. data/spec/reek/report/json_report_spec.rb +16 -49
  203. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  204. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  205. data/spec/reek/report/text_report_spec.rb +3 -9
  206. data/spec/reek/report/xml_report_spec.rb +1 -1
  207. data/spec/reek/report/yaml_report_spec.rb +12 -41
  208. data/spec/reek/report_spec.rb +3 -3
  209. data/spec/reek/smell_configuration_spec.rb +2 -0
  210. data/spec/reek/smell_detectors/attribute_spec.rb +32 -32
  211. data/spec/reek/smell_detectors/base_detector_spec.rb +3 -6
  212. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +4 -4
  213. data/spec/reek/smell_detectors/class_variable_spec.rb +16 -16
  214. data/spec/reek/smell_detectors/control_parameter_spec.rb +33 -16
  215. data/spec/reek/smell_detectors/data_clump_spec.rb +16 -16
  216. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +20 -20
  217. data/spec/reek/smell_detectors/feature_envy_spec.rb +71 -26
  218. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +12 -12
  219. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +36 -36
  220. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +6 -6
  221. data/spec/reek/smell_detectors/long_yield_list_spec.rb +6 -6
  222. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +10 -10
  223. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +17 -17
  224. data/spec/reek/smell_detectors/module_initialize_spec.rb +12 -12
  225. data/spec/reek/smell_detectors/nested_iterators_spec.rb +48 -48
  226. data/spec/reek/smell_detectors/nil_check_spec.rb +16 -16
  227. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +8 -8
  228. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +10 -10
  229. data/spec/reek/smell_detectors/too_many_constants_spec.rb +25 -25
  230. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +17 -17
  231. data/spec/reek/smell_detectors/too_many_methods_spec.rb +6 -6
  232. data/spec/reek/smell_detectors/too_many_statements_spec.rb +10 -10
  233. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +8 -8
  234. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +8 -6
  235. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +11 -9
  236. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +24 -24
  237. data/spec/reek/smell_detectors/unused_parameters_spec.rb +4 -4
  238. data/spec/reek/smell_detectors/unused_private_method_spec.rb +25 -25
  239. data/spec/reek/smell_detectors/utility_function_spec.rb +30 -30
  240. data/spec/reek/smell_warning_spec.rb +21 -28
  241. data/spec/reek/source/source_code_spec.rb +16 -22
  242. data/spec/reek/source/source_locator_spec.rb +16 -17
  243. data/spec/reek/spec/should_reek_of_spec.rb +2 -6
  244. data/spec/reek/spec/should_reek_only_of_spec.rb +8 -15
  245. data/spec/reek/spec/should_reek_spec.rb +1 -1
  246. data/spec/reek/spec/smell_matcher_spec.rb +1 -2
  247. data/spec/reek/tree_dresser_spec.rb +2 -6
  248. data/spec/spec_helper.rb +5 -5
  249. data/tasks/configuration.rake +9 -5
  250. data/tasks/test.rake +4 -0
  251. metadata +89 -43
  252. data/.codeclimate.yml +0 -21
  253. data/ataru_setup.rb +0 -13
  254. data/defaults.reek +0 -131
  255. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  256. data/lib/reek/ast/sexp_extensions/attribute_assignments.rb +0 -14
  257. data/lib/reek/ast/sexp_extensions/literal.rb +0 -14
  258. data/lib/reek/report/formatter/heading_formatter.rb +0 -52
  259. data/lib/reek/report/formatter/location_formatter.rb +0 -42
  260. data/lib/reek/report/formatter/progress_formatter.rb +0 -81
  261. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  262. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -36
  263. data/lib/reek/report/formatter.rb +0 -33
  264. data/lib/reek/smell_detectors/syntax.rb +0 -37
  265. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  266. data/samples/smelly_with_inline_mask.rb +0 -8
  267. data/samples/smelly_with_modifiers.rb +0 -12
  268. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  269. data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
  270. data/tasks/ataru.rake +0 -5
  271. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  272. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  273. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  274. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  275. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  276. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  277. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  278. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  279. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  280. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
data/README.md CHANGED
@@ -39,13 +39,18 @@
39
39
  * [![Gem Version](https://badge.fury.io/rb/reek.svg)](https://badge.fury.io/rb/reek)
40
40
  * ![](http://img.shields.io/github/tag/troessner/reek.svg)
41
41
  * ![](http://img.shields.io/badge/license-MIT-brightgreen.svg)
42
- * [![Dependency Status](https://gemnasium.com/badges/github.com/troessner/reek.svg)](https://gemnasium.com/github.com/troessner/reek)
43
42
  * [![Inline docs](https://inch-ci.org/github/troessner/reek.png)](https://inch-ci.org/github/troessner/reek)
44
43
  * [![Code Climate](https://codeclimate.com/github/troessner/reek/badges/gpa.svg)](https://codeclimate.com/github/troessner/reek)
45
44
  * [![codebeat](https://codebeat.co/badges/42fed4ff-3e55-4aed-8ecc-409b4aa539b3)](https://codebeat.co/projects/github-com-troessner-reek)
46
45
  * ![](http://ruby-gem-downloads-badge.herokuapp.com/reek?type=total)
47
46
  * ![](http://ruby-gem-downloads-badge.herokuapp.com/reek?label=downloads-current-version)
48
47
 
48
+ ## Reek 5 is out!
49
+
50
+ Reek 5 is out and with it a bunch of breaking changes. If you're a new user you can just
51
+ continue with the quickstart below. If you're a Reek 4 user and would like to upgrade to 5, don't
52
+ worry, this shouldn't take you more than 10 minutes. Check out our [Upgrade Guide](docs/Reek-4-to-Reek-5-migration.md).
53
+
49
54
  ## Quickstart
50
55
 
51
56
  Reek is a tool that examines Ruby classes, modules and methods and reports any
@@ -84,26 +89,24 @@ end
84
89
  Reek will report the following code smells in this file:
85
90
 
86
91
  ```
87
- $ reek demo.rb
92
+ $ reek --no-documentation demo.rb
88
93
  Inspecting 1 file(s):
89
94
  S
90
95
 
91
96
  demo.rb -- 2 warnings:
92
- [4]:UncommunicativeMethodName: Smelly#x has the name 'x' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
93
- [5]:UncommunicativeVariableName: Smelly#x has the variable name 'y' [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Variable-Name.md]
97
+ [4]:UncommunicativeMethodName: Smelly#x has the name 'x'
98
+ [5]:UncommunicativeVariableName: Smelly#x has the variable name 'y'
94
99
  ```
95
100
 
96
101
  ## Supported Ruby versions
97
102
 
98
- Reek is officially supported for the following CRuby versions:
103
+ Reek is officially supported for CRuby 2.3 to 2.6 and for JRuby 9.1 and 9.2.
104
+ Other Ruby implementations (like Rubinius) are not officially supported but
105
+ should work as well.
99
106
 
100
- - 2.1
101
- - 2.2
102
- - 2.3
103
- - 2.4
104
- - 2.5
105
-
106
- Other Ruby implementations (like Rubinius or JRuby) are not officially supported but should work as well.
107
+ Note that, on each Ruby version, Reek will use the parser for that version of
108
+ Ruby. So, you should always run Reek using one of your project's target Ruby
109
+ versions.
107
110
 
108
111
  ## Fixing Smell Warnings
109
112
 
@@ -254,12 +257,13 @@ For a summary of those CLI options see [Command-Line Options](docs/Command-Line-
254
257
  #### Configuration loading
255
258
 
256
259
  Configuring Reek via a configuration file is by far the most powerful way.
260
+ Reek expects this filename to be `.reek.yml` but you can override this via the CLI `-c` switch (see below).
257
261
 
258
- There are three ways of passing Reek a configuration file:
262
+ There are three ways of passing Reek the configuration file:
259
263
 
260
264
  1. Using the CLI `-c` switch (see [_Command-line interface_](#command-line-interface) above)
261
- 2. Having a file ending with `.reek` either in your current working directory or in a parent directory (more on that later)
262
- 3. Having a file ending with `.reek` in your home directory
265
+ 2. Having the configuration file either in your current working directory or in a parent directory (more on that later)
266
+ 3. Having the configuration file in your home directory
263
267
 
264
268
  The order in which Reek tries to find such a configuration
265
269
  file is exactly the above: first it checks if we have given
@@ -277,52 +281,70 @@ of how many `*.reek` files you might have on your filesystem.
277
281
 
278
282
  We put a lot of effort into making Reek's configuration as self explanatory as possible so the
279
283
  best way to understand it is by looking at a simple
280
- example (e.g. `config.reek` in your project directory):
284
+ example (e.g. `.reek.yml` in your project directory):
281
285
 
282
286
  ```yaml
283
287
  ---
284
288
 
285
289
  ### Generic smell configuration
286
290
 
287
- # You can disable smells completely
288
- IrresponsibleModule:
289
- enabled: false
290
-
291
- # You can use filters to silence Reek warnings.
292
- # Either because you simply disagree with Reek (we are not the police) or
293
- # because you want to fix this at a later point in time.
294
- NestedIterators:
295
- exclude:
296
- - "MyWorker#self.class_method" # should be refactored
297
- - "AnotherWorker#instance_method" # should be refactored as well
298
-
299
- # A lot of smells allow fine tuning their configuration. You can look up all available options
300
- # in the corresponding smell documentation in /docs. In most cases you probably can just go
301
- # with the defaults as documented in defaults.reek.
302
- DataClump:
303
- max_copies: 3
304
- min_clump_size: 3
291
+ detectors:
292
+ # You can disable smells completely
293
+ IrresponsibleModule:
294
+ enabled: false
295
+
296
+ # You can use filters to silence Reek warnings.
297
+ # Either because you simply disagree with Reek (we are not the police) or
298
+ # because you want to fix this at a later point in time.
299
+ NestedIterators:
300
+ exclude:
301
+ - "MyWorker#self.class_method" # should be refactored
302
+ - "AnotherWorker#instance_method" # should be refactored as well
303
+
304
+ # A lot of smells allow fine tuning their configuration. You can look up all available options
305
+ # in the corresponding smell documentation in /docs. In most cases you probably can just go
306
+ # with the defaults as documented in defaults.reek.yml.
307
+ DataClump:
308
+ max_copies: 3
309
+ min_clump_size: 3
305
310
 
306
311
  ### Directory specific configuration
307
312
 
308
313
  # You can configure smells on a per-directory base.
309
314
  # E.g. the classic Rails case: controllers smell of NestedIterators (see /docs/Nested-Iterators.md) and
310
315
  # helpers smell of UtilityFunction (see docs/Utility-Function.md)
311
- "web_app/app/controllers":
312
- NestedIterators:
313
- enabled: false
314
- "web_app/app/helpers":
315
- UtilityFunction:
316
- enabled: false
316
+ #
317
+ # Note that we only allow configuration on a directory level, not a file level,
318
+ # so all paths have to point to directories.
319
+ # A Dir.glob pattern can be used.
320
+ directories:
321
+ "web_app/app/controllers":
322
+ NestedIterators:
323
+ enabled: false
324
+ "web_app/app/helpers**":
325
+ UtilityFunction:
326
+ enabled: false
327
+ "web_app/lib/**/test/**":
328
+ UtilityFunction:
329
+ enabled: false
317
330
 
318
331
  ### Excluding directories
319
332
 
320
- # Directories below will not be scanned at all
333
+ # Directories and files below will not be scanned at all
321
334
  exclude_paths:
322
335
  - lib/legacy
323
336
  - lib/rake/legacy_tasks
337
+ - lib/smelly.rb
324
338
  ```
325
339
 
340
+ As you see above, Reek's configuration consists of 3 different sections denoted by 3 different keys:
341
+
342
+ * detectors
343
+ * directories
344
+ * exclude_paths
345
+
346
+ Whatever you add to your configuration should be scoped under one of those keys.
347
+
326
348
  If you have a directory directive for which a default directive exists, the more specific
327
349
  one (which is the directory directive) will take precedence.
328
350
 
@@ -330,15 +352,12 @@ This configuration for instance:
330
352
 
331
353
  ```yaml
332
354
  ---
333
- IrresponsibleModule:
334
- enabled: false
335
-
336
- TooManyStatements:
337
- max_statements: 5
338
-
339
- "app/controllers":
355
+ detectors:
356
+ IrresponsibleModule:
357
+ enabled: false
358
+
340
359
  TooManyStatements:
341
- max_statements: 10
360
+ max_statements: 5
342
361
  ```
343
362
 
344
363
  translates to:
@@ -347,16 +366,63 @@ translates to:
347
366
  * TooManyStatements#max_statements is 10 in "app/controllers"
348
367
  * TooManyStatements#max_statements is 5 everywhere else
349
368
 
350
- For more details please check out the [Basic Smell Options](docs/Basic-Smell-Options.md)
351
- which are supported by every smell type. As you can see above, certain smell
352
- types offer a configuration that goes beyond that of the basic smell options, for instance
369
+ Every smell detector supports our [Basic Smell Options](docs/Basic-Smell-Options.md). As you can see above,
370
+ certain smell types offer a configuration that goes beyond that of the basic smell options, for instance
353
371
  [Data Clump](docs/Data-Clump.md).
354
372
  All options that go beyond the [Basic Smell Options](docs/Basic-Smell-Options.md)
355
373
  are documented in the corresponding smell type /docs page (if you want to get a quick overview over all possible
356
- configurations you can also check out [the `default.reek` file in this repository](defaults.reek).
374
+ configurations you can also check out [the `defaults.reek.yml` file in this repository](docs/defaults.reek.yml).
357
375
 
358
376
  Note that you do not need a configuration file at all.
359
- If you're fine with all the [defaults](defaults.reek) we set you can skip this completely.
377
+ If you're fine with all the [defaults.reek.yml](docs/defaults.reek.yml) we set you can skip this completely.
378
+
379
+ Don't worry about introducing a mistake in your configuration file that might go unnoticed - Reek uses a
380
+ schema to validate your configuration against on start up and will faily loudly in case you
381
+ misspelled an option or used the wrong data type for a value like this:
382
+
383
+ ```
384
+ Error: We found some problems with your configuration file: [/detectors/DetectorWithTypo] key 'DetectorWithTypo:' is undefined.
385
+ ```
386
+
387
+ Reek takes one configuration file and one configuration file only with `.reek.yml` being the default name.
388
+
389
+ In case you have to have one or more configuration files in the directory (e.g. you're
390
+ toying around with different, mutually exclusive settings) you need to tell Reek
391
+ explicitly which file to use via `reek -c config.reek`.
392
+
393
+ ### Source code comments
394
+
395
+ In case you need to suppress a smell warning and you can't or don't want to
396
+ use configuration files for whatever reasons you can also use special
397
+ source code comments like this:
398
+
399
+ ```Ruby
400
+ # This method smells of :reek:NestedIterators
401
+ def smelly_method foo
402
+ foo.each {|bar| bar.each {|baz| baz.qux}}
403
+ end
404
+ ```
405
+
406
+ You can even pass in smell specific configuration settings:
407
+
408
+ ```Ruby
409
+ # :reek:NestedIterators { max_allowed_nesting: 2 }
410
+ def smelly_method foo
411
+ foo.each {|bar| bar.each {|baz| baz.qux}}
412
+ end
413
+ ```
414
+
415
+ This is an incredibly powerful feature and further explained under [Smell Suppresion](docs/Smell-Suppression.md).
416
+
417
+ #### Debugging trouble with the configuration
418
+
419
+ With Reeks dynamic mechanism of finding a configuration file you might run into a situation where you are not
420
+ 100% sure what configuration file Reek is using. E.g. you have a project specific configuration file in your
421
+ project root and also another Reek configuration in your HOME directory that you use for all your other projects
422
+ and for whatever reasons Reek seems to be using another configuration file than the one you assumed it would.
423
+
424
+ In this case you can pass the flag `--show-configuration-path` to Reek which will cause Reek to output the path
425
+ to the configuration file it is using.
360
426
 
361
427
  ### Generating a 'todo' list
362
428
 
@@ -371,29 +437,28 @@ suppress all smell warnings for the current codebase:
371
437
  reek --todo lib/
372
438
  ```
373
439
 
374
- This will create the file '.todo.reek' in your current working directory.
440
+ This will create the file '.reek.yml' in your current working directory.
375
441
 
376
442
  You can then use this as your configuration - since your working directory
377
443
  probably is your project root in most cases you don't have to tell Reek
378
- explicitly to use '.todo.reek' because Reek will automatically pick it up
444
+ explicitly to use '.reek.yml' because Reek will automatically pick it up
379
445
  and use it as configuration file. See [Configuration Loading](#configuration-loading) above.
380
446
 
381
- If for whatever reasons you decide to put '.todo.reek' somewhere else where
447
+ If for whatever reasons you decide to put '.reek.yml' somewhere else where
382
448
  Reek won't pick it up automatically you need to tell Reek explicitly to do so
383
449
  via:
384
450
 
385
451
  ```Bash
386
- reek -c whatever/.todo.reek lib/
452
+ reek -c whatever/.reek.yml lib/
387
453
  ```
388
454
 
389
455
  It's important to understand that the number one use case of the `--todo` flag
390
456
  is to be run once at the beginning of the introduction of Reek to ease the transition.
391
- If you find yourself re-running Reek with the `--todo` flag in order to silence new warnings
457
+ If you find yourself wanting to re-run Reek with the `--todo` flag in order to silence a lot of new warnings
392
458
  you're defeating the purpose of both the `--todo` flag and of Reek itself.
393
459
 
394
- As a consequence, running Reek with the `--todo` flag again will overwrite '.todo.reek' without
395
- asking (should not be a problem since this file is supposed to be versioned) and
396
- without taking **any** other configuration file you might have into account.
460
+ As a consequence, running Reek with the `--todo` flag again will not overwrite an existing '.reek.yml'
461
+ and instead abort execution. It also will not take **any** other configuration file you might have into account.
397
462
 
398
463
  This means that when you run
399
464
 
@@ -401,44 +466,10 @@ This means that when you run
401
466
  reek -c other_configuration.reek --todo lib/
402
467
  ```
403
468
 
404
- `other_configuration.reek` will simply be ignored (as outlined before, Reek
405
- is supposed to have one configuration file and one file only).
406
-
407
- ### Beware of multiple configuration files
408
-
409
- Reek takes one configuration file and one configuration file only.
410
-
411
- If you have more than one configuration file in the same directory Reek
412
- will not know what configuration file to use. If this happens Reek will
413
- print a warning on STDERR and exit with the failure exit status 1.
469
+ `other_configuration.reek` will simply be ignored.
414
470
 
415
- In case you have to have one or more configuration files in the directory (e.g. you're
416
- toying around with different, mutually exclusive settings) you need to tell Reek
417
- explicitly which file to use via `reek -c config.reek`.
418
-
419
- ### Source code comments
420
-
421
- In case you need to suppress a smell warning and you can't or don't want to
422
- use configuration files for whatever reasons you can also use special
423
- source code comments like this:
424
-
425
- ```Ruby
426
- # This method smells of :reek:NestedIterators
427
- def smelly_method foo
428
- foo.each {|bar| bar.each {|baz| baz.qux}}
429
- end
430
- ```
431
-
432
- You can even pass in smell specific configuration settings:
433
-
434
- ```Ruby
435
- # :reek:NestedIterators { max_allowed_nesting: 2 }
436
- def smelly_method foo
437
- foo.each {|bar| bar.each {|baz| baz.qux}}
438
- end
439
- ```
440
-
441
- This is an incredible powerful feature and further explained under [Smell Suppresion](docs/Smell-Suppression.md).
471
+ Of course you can always just delete the existing .reek.yml file and then run Reek with the `--todo` flag
472
+ but keep in mind that this is not the intended use case of this feature.
442
473
 
443
474
  ## Usage
444
475
 
@@ -479,16 +510,6 @@ bundle exec rake
479
510
 
480
511
  This will run the tests (RSpec and Cucumber), RuboCop and Reek itself.
481
512
 
482
- You can also run:
483
-
484
- ```
485
- bundle exec rake ci
486
- ```
487
-
488
- This will run everything the default task runs and also
489
- [Ataru](https://github.com/CodePadawans/ataru). This is the task that we run on
490
- Travis as well and that determines if your pull request is green or red.
491
-
492
513
  Another useful Rake task is the `console` task. This will throw you right into an environment where you can play around with Reeks modules and classes:
493
514
 
494
515
  ```
@@ -508,15 +529,6 @@ require 'pry'
508
529
  binding.pry
509
530
  ```
510
531
 
511
- If you do this, you need to also run the specs with `DEBUG=1` set, e.g.:
512
-
513
- ```
514
- DEBUG=1 bundle exec rspec spec/your/file_spec.rb:23
515
- ```
516
-
517
- This is necessary because normally all specs run with a timeout of 5 seconds,
518
- which isn't much if you're busy using Pry.
519
-
520
532
  Have a look at our [Developer API](docs/API.md) for more inspiration.
521
533
 
522
534
  From then on you should check out:
@@ -559,23 +571,27 @@ Making Reek "Rails"-friendly is fairly simple since we support directory specifi
559
571
  Just add this to your configuration file:
560
572
 
561
573
  ```Yaml
562
- "app/controllers":
563
- IrresponsibleModule:
564
- enabled: false
565
- NestedIterators:
566
- max_allowed_nesting: 2
567
- UnusedPrivateMethod:
568
- enabled: false
569
- InstanceVariableAssumption:
570
- enabled: false
571
- "app/helpers":
572
- IrresponsibleModule:
573
- enabled: false
574
- UtilityFunction:
575
- enabled: false
576
- "app/mailers":
577
- InstanceVariableAssumption:
578
- enabled: false
574
+ directories:
575
+ "app/controllers":
576
+ IrresponsibleModule:
577
+ enabled: false
578
+ NestedIterators:
579
+ max_allowed_nesting: 2
580
+ UnusedPrivateMethod:
581
+ enabled: false
582
+ InstanceVariableAssumption:
583
+ enabled: false
584
+ "app/helpers":
585
+ IrresponsibleModule:
586
+ enabled: false
587
+ UtilityFunction:
588
+ enabled: false
589
+ "app/mailers":
590
+ InstanceVariableAssumption:
591
+ enabled: false
592
+ "app/models":
593
+ InstanceVariableAssumption:
594
+ enabled: false
579
595
  ```
580
596
 
581
597
  Be careful though, Reek does not merge your configuration entries, so if you already have a directory directive for "app/controllers" or "app/helpers" you need to update those directives instead of copying the above YAML sample into your configuration file.
@@ -588,6 +604,7 @@ Be careful though, Reek does not merge your configuration entries, so if you alr
588
604
  * [TextMate Bundle](https://github.com/peeyush1234/reek.tmbundle)
589
605
  * [Atom plugin](https://atom.io/packages/linter-reek)
590
606
  * [SublimeLinter plugin](https://packagecontrol.io/packages/SublimeLinter-contrib-reek)
607
+ * [VS Code plugin](https://github.com/rubyide/vscode-ruby)
591
608
  * [Emacs plugin](https://github.com/hanmoi-choi/reek-emacs)
592
609
 
593
610
  ### Projects that use or support us
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
+ 'test:performance',
10
+ 'configuration:update_default_configuration',
11
+ 'test:features',
12
+ :rubocop,
13
+ 'test:quality'
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
@@ -23,13 +23,13 @@ Code says more than a thousand words:
23
23
  ```ruby
24
24
  require 'reek'
25
25
 
26
- source = <<-EOS
26
+ source = <<-RUBY
27
27
  class Dirty
28
28
  def m(a,b,c)
29
29
  puts a,b
30
30
  end
31
31
  end
32
- EOS
32
+ RUBY
33
33
 
34
34
  reporter = Reek::Report::TextReport.new
35
35
  examiner = Reek::Examiner.new source
@@ -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:
@@ -117,13 +117,13 @@ require 'reek'
117
117
  config_hash = { 'IrresponsibleModule' => { 'enabled' => false } }
118
118
  configuration = Reek::Configuration::AppConfiguration.from_hash config_hash
119
119
 
120
- source = <<-EOS
120
+ source = <<-RUBY
121
121
  class Dirty
122
122
  def call_me(a,b)
123
123
  puts a,b
124
124
  end
125
125
  end
126
- EOS
126
+ RUBY
127
127
 
128
128
  reporter = Reek::Report::TextReport.new
129
129
  examiner = Reek::Examiner.new(source, configuration: configuration); nil
@@ -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.