reek 2.0.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +13 -0
  3. data/.rubocop.yml +47 -0
  4. data/.travis.yml +31 -0
  5. data/.yardopts +3 -6
  6. data/CHANGELOG +24 -0
  7. data/CONTRIBUTING.md +111 -0
  8. data/Gemfile +16 -0
  9. data/README.md +112 -59
  10. data/bin/reek +2 -2
  11. data/config/cucumber.yml +3 -0
  12. data/config/defaults.reek +0 -1
  13. data/docs/API.md +79 -0
  14. data/docs/Attribute.md +43 -0
  15. data/docs/Basic-Smell-Options.md +44 -0
  16. data/docs/Boolean-Parameter.md +52 -0
  17. data/docs/Class-Variable.md +40 -0
  18. data/docs/Code-Smells.md +34 -0
  19. data/docs/Command-Line-Options.md +84 -0
  20. data/docs/Configuration-Files.md +49 -0
  21. data/docs/Control-Couple.md +22 -0
  22. data/docs/Control-Parameter.md +29 -0
  23. data/docs/Data-Clump.md +44 -0
  24. data/docs/Duplicate-Method-Call.md +49 -0
  25. data/docs/Feature-Envy.md +49 -0
  26. data/docs/How-reek-works-internally.md +114 -0
  27. data/docs/Irresponsible-Module.md +39 -0
  28. data/docs/Large-Class.md +20 -0
  29. data/docs/Long-Parameter-List.md +38 -0
  30. data/docs/Long-Yield-List.md +36 -0
  31. data/docs/Module-Initialize.md +62 -0
  32. data/docs/Nested-Iterators.md +38 -0
  33. data/docs/Nil-Check.md +39 -0
  34. data/docs/Prima-Donna-Method.md +53 -0
  35. data/docs/RSpec-matchers.md +137 -0
  36. data/docs/Rake-Task.md +58 -0
  37. data/docs/Reek-Driven-Development.md +37 -0
  38. data/docs/Repeated-Conditional.md +44 -0
  39. data/docs/Simulated-Polymorphism.md +16 -0
  40. data/docs/Smell-Suppression.md +32 -0
  41. data/docs/Too-Many-Instance-Variables.md +43 -0
  42. data/docs/Too-Many-Methods.md +55 -0
  43. data/docs/Too-Many-Statements.md +50 -0
  44. data/docs/Uncommunicative-Method-Name.md +24 -0
  45. data/docs/Uncommunicative-Module-Name.md +23 -0
  46. data/docs/Uncommunicative-Name.md +16 -0
  47. data/docs/Uncommunicative-Parameter-Name.md +24 -0
  48. data/docs/Uncommunicative-Variable-Name.md +24 -0
  49. data/docs/Unused-Parameters.md +27 -0
  50. data/docs/Utility-Function.md +44 -0
  51. data/docs/Versioning-Policy.md +7 -0
  52. data/docs/YAML-Reports.md +111 -0
  53. data/docs/yard_plugin.rb +14 -0
  54. data/features/{ruby_api/api.feature → command_line_interface/basic_usage.feature} +6 -5
  55. data/features/command_line_interface/options.feature +1 -0
  56. data/features/command_line_interface/smell_selection.feature +4 -8
  57. data/features/command_line_interface/smells_count.feature +25 -32
  58. data/features/command_line_interface/stdin.feature +2 -2
  59. data/features/configuration_files/masking_smells.feature +30 -41
  60. data/features/configuration_files/overrides_defaults.feature +5 -3
  61. data/features/configuration_loading.feature +26 -23
  62. data/features/programmatic_access.feature +43 -0
  63. data/features/rake_task/rake_task.feature +25 -22
  64. data/features/reports/json.feature +24 -26
  65. data/features/reports/reports.feature +77 -103
  66. data/features/reports/yaml.feature +26 -20
  67. data/features/samples.feature +26 -31
  68. data/features/step_definitions/.rubocop.yml +5 -0
  69. data/features/step_definitions/reek_steps.rb +16 -28
  70. data/features/step_definitions/sample_file_steps.rb +158 -0
  71. data/features/support/env.rb +16 -27
  72. data/lib/reek/{source → ast}/ast_node_class_map.rb +11 -12
  73. data/lib/reek/ast/node.rb +132 -0
  74. data/lib/reek/{core → ast}/object_refs.rb +2 -1
  75. data/lib/reek/ast/reference_collector.rb +32 -0
  76. data/lib/reek/{source → ast}/sexp_extensions.rb +43 -7
  77. data/lib/reek/ast/sexp_formatter.rb +31 -0
  78. data/lib/reek/cli/application.rb +5 -4
  79. data/lib/reek/cli/command.rb +2 -1
  80. data/lib/reek/cli/input.rb +6 -5
  81. data/lib/reek/cli/option_interpreter.rb +13 -9
  82. data/lib/reek/cli/options.rb +16 -8
  83. data/lib/reek/cli/reek_command.rb +4 -3
  84. data/lib/reek/cli/silencer.rb +14 -0
  85. data/lib/reek/{core → cli}/warning_collector.rb +2 -1
  86. data/lib/reek/code_comment.rb +36 -0
  87. data/lib/reek/configuration/app_configuration.rb +18 -3
  88. data/lib/reek/configuration/configuration_file_finder.rb +18 -32
  89. data/lib/reek/{core → context}/code_context.rb +8 -6
  90. data/lib/reek/{core → context}/method_context.rb +11 -5
  91. data/lib/reek/{core → context}/module_context.rb +9 -4
  92. data/lib/reek/{core/stop_context.rb → context/root_context.rb} +4 -2
  93. data/lib/reek/{core → context}/singleton_method_context.rb +3 -6
  94. data/lib/reek/examiner.rb +32 -29
  95. data/lib/reek/report/formatter.rb +70 -0
  96. data/lib/reek/report/heading_formatter.rb +45 -0
  97. data/lib/reek/report/location_formatter.rb +35 -0
  98. data/lib/reek/report/report.rb +198 -0
  99. data/lib/reek/smells/attribute.rb +41 -11
  100. data/lib/reek/smells/boolean_parameter.rb +4 -2
  101. data/lib/reek/smells/class_variable.rb +4 -2
  102. data/lib/reek/smells/control_parameter.rb +4 -2
  103. data/lib/reek/smells/data_clump.rb +4 -3
  104. data/lib/reek/smells/duplicate_method_call.rb +15 -5
  105. data/lib/reek/smells/feature_envy.rb +8 -2
  106. data/lib/reek/smells/irresponsible_module.rb +13 -8
  107. data/lib/reek/smells/long_parameter_list.rb +6 -4
  108. data/lib/reek/smells/long_yield_list.rb +4 -2
  109. data/lib/reek/smells/module_initialize.rb +4 -2
  110. data/lib/reek/smells/nested_iterators.rb +4 -2
  111. data/lib/reek/smells/nil_check.rb +6 -3
  112. data/lib/reek/smells/prima_donna_method.rb +21 -12
  113. data/lib/reek/smells/repeated_conditional.rb +7 -4
  114. data/lib/reek/{core → smells}/smell_configuration.rb +3 -1
  115. data/lib/reek/smells/smell_detector.rb +11 -5
  116. data/lib/reek/{core → smells}/smell_repository.rb +9 -5
  117. data/lib/reek/smells/smell_warning.rb +101 -0
  118. data/lib/reek/smells/too_many_instance_variables.rb +4 -2
  119. data/lib/reek/smells/too_many_methods.rb +4 -2
  120. data/lib/reek/smells/too_many_statements.rb +4 -2
  121. data/lib/reek/smells/uncommunicative_method_name.rb +4 -2
  122. data/lib/reek/smells/uncommunicative_module_name.rb +4 -2
  123. data/lib/reek/smells/uncommunicative_parameter_name.rb +4 -2
  124. data/lib/reek/smells/uncommunicative_variable_name.rb +4 -2
  125. data/lib/reek/smells/unused_parameters.rb +4 -2
  126. data/lib/reek/smells/utility_function.rb +11 -22
  127. data/lib/reek/smells.rb +24 -11
  128. data/lib/reek/source/source_code.rb +69 -12
  129. data/lib/reek/source/source_locator.rb +34 -19
  130. data/lib/reek/spec/should_reek.rb +4 -3
  131. data/lib/reek/spec/should_reek_of.rb +2 -1
  132. data/lib/reek/spec/should_reek_only_of.rb +4 -3
  133. data/lib/reek/spec.rb +3 -3
  134. data/lib/reek/tree_dresser.rb +32 -0
  135. data/lib/reek/tree_walker.rb +182 -0
  136. data/lib/reek/version.rb +1 -1
  137. data/lib/reek.rb +3 -3
  138. data/reek.gemspec +18 -25
  139. data/spec/factories/factories.rb +4 -2
  140. data/spec/gem/updates_spec.rb +1 -1
  141. data/spec/gem/yard_spec.rb +2 -2
  142. data/spec/quality/reek_source_spec.rb +3 -3
  143. data/spec/reek/{source/sexp_node_spec.rb → ast/node_spec.rb} +4 -6
  144. data/spec/reek/{core → ast}/object_refs_spec.rb +4 -6
  145. data/spec/reek/{source → ast}/reference_collector_spec.rb +27 -19
  146. data/spec/reek/{source → ast}/sexp_extensions_spec.rb +7 -19
  147. data/spec/reek/{source → ast}/sexp_formatter_spec.rb +13 -8
  148. data/spec/reek/cli/option_interpreter_spec.rb +15 -0
  149. data/spec/reek/cli/options_spec.rb +19 -0
  150. data/spec/reek/cli/warning_collector_spec.rb +28 -0
  151. data/spec/reek/{source/code_comment_spec.rb → code_comment_spec.rb} +19 -17
  152. data/spec/reek/configuration/app_configuration_spec.rb +37 -26
  153. data/spec/reek/configuration/configuration_file_finder_spec.rb +67 -21
  154. data/spec/reek/{core → context}/code_context_spec.rb +18 -21
  155. data/spec/reek/{core → context}/method_context_spec.rb +33 -27
  156. data/spec/reek/{core → context}/module_context_spec.rb +5 -7
  157. data/spec/reek/context/root_context_spec.rb +14 -0
  158. data/spec/reek/context/singleton_method_context_spec.rb +17 -0
  159. data/spec/reek/examiner_spec.rb +9 -50
  160. data/spec/reek/{cli → report}/html_report_spec.rb +6 -9
  161. data/spec/reek/report/json_report_spec.rb +20 -0
  162. data/spec/reek/{cli → report}/text_report_spec.rb +16 -19
  163. data/spec/reek/report/xml_report_spec.rb +34 -0
  164. data/spec/reek/report/yaml_report_spec.rb +20 -0
  165. data/spec/reek/smells/attribute_spec.rb +93 -88
  166. data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
  167. data/spec/reek/smells/boolean_parameter_spec.rb +31 -5
  168. data/spec/reek/smells/class_variable_spec.rb +10 -10
  169. data/spec/reek/smells/control_parameter_spec.rb +5 -5
  170. data/spec/reek/smells/data_clump_spec.rb +6 -6
  171. data/spec/reek/smells/duplicate_method_call_spec.rb +7 -7
  172. data/spec/reek/smells/feature_envy_spec.rb +12 -13
  173. data/spec/reek/smells/irresponsible_module_spec.rb +28 -32
  174. data/spec/reek/smells/long_parameter_list_spec.rb +7 -7
  175. data/spec/reek/smells/long_yield_list_spec.rb +6 -6
  176. data/spec/reek/smells/module_initialize_spec.rb +4 -4
  177. data/spec/reek/smells/nested_iterators_spec.rb +6 -6
  178. data/spec/reek/smells/nil_check_spec.rb +6 -6
  179. data/spec/reek/smells/prima_donna_method_spec.rb +8 -5
  180. data/spec/reek/smells/repeated_conditional_spec.rb +18 -17
  181. data/spec/reek/{core → smells}/smell_configuration_spec.rb +5 -7
  182. data/spec/reek/smells/smell_detector_shared.rb +6 -7
  183. data/spec/reek/smells/smell_repository_spec.rb +29 -0
  184. data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -9
  185. data/spec/reek/smells/too_many_instance_variables_spec.rb +5 -5
  186. data/spec/reek/smells/too_many_methods_spec.rb +12 -8
  187. data/spec/reek/smells/too_many_statements_spec.rb +10 -9
  188. data/spec/reek/smells/uncommunicative_method_name_spec.rb +5 -5
  189. data/spec/reek/smells/uncommunicative_module_name_spec.rb +8 -8
  190. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +18 -6
  191. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +10 -7
  192. data/spec/reek/smells/unused_parameters_spec.rb +4 -4
  193. data/spec/reek/smells/utility_function_spec.rb +65 -39
  194. data/spec/reek/source/source_code_spec.rb +10 -10
  195. data/spec/reek/source/source_locator_spec.rb +30 -0
  196. data/spec/reek/spec/should_reek_of_spec.rb +9 -25
  197. data/spec/reek/spec/should_reek_only_of_spec.rb +4 -7
  198. data/spec/reek/spec/should_reek_spec.rb +4 -32
  199. data/spec/reek/tree_dresser_spec.rb +16 -0
  200. data/spec/reek/{core/tree_walker_spec.rb → tree_walker_spec.rb} +5 -7
  201. data/spec/samples/checkstyle.xml +2 -0
  202. data/spec/samples/configuration/with_excluded_paths.reek +4 -0
  203. data/spec/samples/{overrides/masked/lower.reek → masked_by_dotfile/.reek} +3 -1
  204. data/spec/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +5 -0
  205. data/spec/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +2 -0
  206. data/spec/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +6 -0
  207. data/spec/samples/{ruby20_syntax.rb → unusual_syntax.rb} +8 -0
  208. data/spec/spec_helper.rb +21 -10
  209. data/tasks/develop.rake +2 -2
  210. data/tasks/reek.rake +1 -1
  211. metadata +158 -141
  212. data/features/support/hooks.rb +0 -15
  213. data/lib/reek/cli/report/formatter.rb +0 -69
  214. data/lib/reek/cli/report/heading_formatter.rb +0 -45
  215. data/lib/reek/cli/report/location_formatter.rb +0 -34
  216. data/lib/reek/cli/report/report.rb +0 -131
  217. data/lib/reek/core/tree_walker.rb +0 -180
  218. data/lib/reek/smell_warning.rb +0 -87
  219. data/lib/reek/source/ast_node.rb +0 -38
  220. data/lib/reek/source/code_comment.rb +0 -37
  221. data/lib/reek/source/core_extras.rb +0 -46
  222. data/lib/reek/source/reference_collector.rb +0 -27
  223. data/lib/reek/source/sexp_formatter.rb +0 -22
  224. data/lib/reek/source/sexp_node.rb +0 -79
  225. data/lib/reek/source/source_file.rb +0 -16
  226. data/lib/reek/source/source_repository.rb +0 -45
  227. data/lib/reek/source/tree_dresser.rb +0 -24
  228. data/lib/reek/source.rb +0 -16
  229. data/spec/reek/cli/json_report_spec.rb +0 -20
  230. data/spec/reek/cli/option_interperter_spec.rb +0 -14
  231. data/spec/reek/cli/yaml_report_spec.rb +0 -23
  232. data/spec/reek/core/singleton_method_context_spec.rb +0 -9
  233. data/spec/reek/core/smell_repository_spec.rb +0 -17
  234. data/spec/reek/core/stop_context_spec.rb +0 -17
  235. data/spec/reek/core/warning_collector_spec.rb +0 -30
  236. data/spec/reek/source/object_source_spec.rb +0 -20
  237. data/spec/reek/source/tree_dresser_spec.rb +0 -18
  238. data/spec/samples/config/allow_duplication.reek +0 -3
  239. data/spec/samples/config/deeper_nested_iterators.reek +0 -3
  240. data/spec/samples/configuration_loading/minimal_dirty.rb +0 -4
  241. data/spec/samples/configuration_loading/reek-test-run-disable_smells.reek +0 -7
  242. data/spec/samples/configuration_loading/reek-test-run-enable_smells.reek +0 -7
  243. data/spec/samples/corrupt_config_file/corrupt.reek +0 -1
  244. data/spec/samples/corrupt_config_file/dirty.rb +0 -8
  245. data/spec/samples/demo/demo.rb +0 -8
  246. data/spec/samples/empty_config_file/dirty.rb +0 -8
  247. data/spec/samples/empty_config_file/empty.reek +0 -0
  248. data/spec/samples/inline_config/dirty.rb +0 -16
  249. data/spec/samples/inline_config/masked.reek +0 -7
  250. data/spec/samples/mask_some/dirty.rb +0 -8
  251. data/spec/samples/mask_some/some.reek +0 -8
  252. data/spec/samples/masked/dirty.rb +0 -8
  253. data/spec/samples/masked/masked.reek +0 -5
  254. data/spec/samples/minimal_smelly_and_masked/config.reek +0 -7
  255. data/spec/samples/minimal_smelly_and_masked/minimal_dirty.rb +0 -4
  256. data/spec/samples/mixed_results/clean_one.rb +0 -7
  257. data/spec/samples/mixed_results/clean_three.rb +0 -7
  258. data/spec/samples/mixed_results/clean_two.rb +0 -7
  259. data/spec/samples/mixed_results/dirty_one.rb +0 -8
  260. data/spec/samples/mixed_results/dirty_two.rb +0 -8
  261. data/spec/samples/not_quite_masked/dirty.rb +0 -8
  262. data/spec/samples/not_quite_masked/masked.reek +0 -5
  263. data/spec/samples/not_quite_masked/smelly.rb +0 -3
  264. data/spec/samples/one_smelly_file/dirty.rb +0 -3
  265. data/spec/samples/overrides/masked/dirty.rb +0 -8
  266. data/spec/samples/overrides/upper.reek +0 -5
  267. data/spec/samples/overrides_defaults/camel_case.rb +0 -14
  268. data/spec/samples/overrides_defaults/config.reek +0 -6
  269. data/spec/samples/ruby21_syntax.rb +0 -5
  270. data/spec/samples/standard_smelly/dirty.rb +0 -8
  271. data/spec/samples/standard_smelly/minimal_dirty.rb +0 -4
  272. data/spec/samples/three_smelly_files/dirty_one.rb +0 -3
  273. data/spec/samples/three_smelly_files/dirty_three.rb +0 -5
  274. data/spec/samples/three_smelly_files/dirty_two.rb +0 -4
  275. /data/spec/samples/{simple_configuration.reek → configuration/simple_configuration.reek} +0 -0
@@ -0,0 +1,44 @@
1
+ # Repeated Conditional
2
+
3
+ ## Introduction
4
+
5
+ `Repeated Conditional` is a special case of [Simulated Polymorphism](Simulated-Polymorphism.md). Basically it means you are checking the same value throughout a single class and take decisions based on this.
6
+
7
+ ## Example
8
+
9
+ Given
10
+
11
+ ```Ruby
12
+ class RepeatedConditionals
13
+ attr_accessor :switch
14
+
15
+ def repeat_1
16
+ puts "Repeat 1!" if switch
17
+ end
18
+
19
+ def repeat_2
20
+ puts "Repeat 2!" if switch
21
+ end
22
+
23
+ def repeat_3
24
+ puts "Repeat 3!" if switch
25
+ end
26
+ end
27
+ ```
28
+
29
+ `reek` would emit the following warning:
30
+
31
+ ```
32
+ test.rb -- 4 warnings:
33
+ [5, 9, 13]:RepeatedConditionals tests switch at least 3 times (RepeatedConditional)
34
+ ```
35
+
36
+ If you get this warning then you are probably not using the right abstraction or even more probable, missing an additional abstraction.
37
+
38
+ ## Configuration
39
+
40
+ `reek`'s `Repeated Conditional` detector offers the [Basic Smell Options](Basic-Smell-Options.md), plus:
41
+
42
+ | Option | Value | Effect |
43
+ | ---------------|-------------|---------|
44
+ | `max_ifs` | integer | The maximum number of identical conditional tests permitted before Reek raises a warning. Defaults to 2. |
@@ -0,0 +1,16 @@
1
+ # Simulated Polymorphism
2
+
3
+ ## Introduction
4
+
5
+ Simulated Polymorphism occurs when
6
+
7
+ * code uses a case statement (especially on a type field);
8
+ * or code has several if statements in a row (especially if they're comparing against the same value);
9
+ * or code uses instance_of?, kind_of?, is_a?, or === to decide what type it's working with;
10
+ * or multiple conditionals in different places test the same value.
11
+
12
+ Conditional code is hard to read and understand, because the reader must hold more state in his head. When the same value is tested in multiple places throughout an application, any change to the set of possible values will require many methods and classes to change. Tests for the type of an object may indicate that the abstraction represented by that type is not completely defined (or understood).
13
+
14
+ ## Current Support in reek
15
+
16
+ `reek` checks for [Repeated Conditional](Repeated-Conditional.md) and for [Nil Check](Nil-Check.md).
@@ -0,0 +1,32 @@
1
+ ## Introduction
2
+
3
+ In some cases, it might be necessary to suppress one or more of `reek`'s smell warnings for a particular method or class.
4
+
5
+ Possible reasons for this could be:
6
+
7
+ * The code is outside of your control and you can't fix it
8
+ * `reek` is not the police. You might have legit reasons why your source code is good as it is.
9
+
10
+ ## How to disable smell detection
11
+
12
+ First and foremost, there are the [Basic Smell Options](Basic-Smell-Options.md) you can use.
13
+
14
+ Besides from that, you can use special comments, like so:
15
+
16
+ ```ruby
17
+ # This method smells of :reek:NestedIterators
18
+ def smelly_method foo
19
+ foo.each {|bar| bar.each {|baz| baz.qux}}
20
+ end
21
+ ```
22
+
23
+ The method `smelly_method` will not be reported. The general pattern is to put the string ':reek:', followed by the smell class, in a comment before the method or class.
24
+
25
+ It is also possible to specify options for a particular smell detector, like so:
26
+
27
+ ```ruby
28
+ # :reek:LongParameterList: { max_params: 4 }
29
+ def many_parameters_it_has foo, bar, baz, qux
30
+ # ...
31
+ end
32
+ ```
@@ -0,0 +1,43 @@
1
+ ## Introduction
2
+
3
+ `Too Many Instance Variables` is a special case of `LargeClass`.
4
+
5
+ ## Example
6
+
7
+ Given this configuration
8
+
9
+ ```yaml
10
+ TooManyInstanceVariables:
11
+ max_instance_variables: 3
12
+ ```
13
+
14
+ and this code:
15
+
16
+ ```Ruby
17
+ class TooManyInstanceVariables
18
+ def initialize
19
+ @arg_1 = :dummy
20
+ @arg_2 = :dummy
21
+ @arg_3 = :dummy
22
+ @arg_4 = :dummy
23
+ end
24
+ end
25
+ ```
26
+
27
+ `reek` would emit the following warning:
28
+
29
+ ```
30
+ test.rb -- 5 warnings:
31
+ [1]:TooManyInstanceVariables has at least 4 instance variables (TooManyInstanceVariables)
32
+ ```
33
+ ## Current Support in `reek`
34
+
35
+ `reek` only counts the instance variables you use explicitly like in the example above. Class macros like `attr_accessor` are disregarded.
36
+
37
+ ## Configuration
38
+
39
+ `reek`'s `Too Many Instance Variables` detector offers the [Basic Smell Options](Basic-Smell-Options.md), plus:
40
+
41
+ | Option | Value | Effect |
42
+ | ---------------|-------------|---------|
43
+ | max_instance_variables | integer | The maximum number of instance variables that are permitted. Defaults to 9 |
@@ -0,0 +1,55 @@
1
+ ## Introduction
2
+
3
+ `Too Many Methods` is a special case of `LargeClass`.
4
+
5
+ ## Example
6
+
7
+ Given this configuration
8
+
9
+ ```yaml
10
+ TooManyMethods:
11
+ max_methods: 3
12
+ ```
13
+
14
+ and this code:
15
+
16
+ ```Ruby
17
+ class TooManyMethods
18
+ def one; end
19
+ def two; end
20
+ def three; end
21
+ def four; end
22
+ end
23
+ ```
24
+
25
+ `reek` would emit the following warning:
26
+
27
+ ```
28
+ test.rb -- 1 warning:
29
+ [1]:TooManyMethods has at least 4 methods (TooManyMethods)
30
+ ```
31
+ ## Current Support in `reek`
32
+
33
+ `reek` counts all the methods it can find in a `class` - instance *and* class methods. So given `max_methods` from above is 4, this:
34
+
35
+ ```Ruby
36
+ class TooManyMethods
37
+ class << self
38
+ def one; end
39
+ def two; end
40
+ end
41
+
42
+ def three; end
43
+ def four; end
44
+ end
45
+ ```
46
+
47
+ would cause reek to emit the same warning as in the example above.
48
+
49
+ ## Configuration
50
+
51
+ `reek`'s `Too Many Methods` detector offers the [Basic Smell Options](Basic-Smell-Options.md), plus:
52
+
53
+ | Option | Value | Effect |
54
+ | ---------------|-------------|---------|
55
+ | max_methods | integer | The maximum number of methods that are permitted. Defaults to 25 |
@@ -0,0 +1,50 @@
1
+ # Too Many Statements
2
+
3
+ ## Introduction
4
+
5
+ A method with `Too Many Statements` is any method that has a large number of lines.
6
+
7
+ ## Current Support in Reek
8
+
9
+ `Too Many Statements` warns about any method that has more than 5 statements. `reek`'s smell detector for `Too Many Statements` counts +1 for every simple statement in a method and +1 for every statement within a control structure (`if`, `else`, `case`, `when`, `for`, `while`, `until`, `begin`, `rescue`) but it doesn't count the control structure itself.
10
+
11
+ So the following method would score +6 in Reek's statement-counting algorithm:
12
+
13
+ ```Ruby
14
+ def parse(arg, argv, &error)
15
+ if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
16
+ return nil, block, nil # +1
17
+ end
18
+ opt = (val = parse_arg(val, &error))[1] # +2
19
+ val = conv_arg(*val) # +3
20
+ if opt and !arg
21
+ argv.shift # +4
22
+ else
23
+ val[0] = nil # +5
24
+ end
25
+ val # +6
26
+ end
27
+ ```
28
+
29
+ (You might argue that the two assigments within the first @if@ should count as statements, and that perhaps the nested assignment should count as +2.)
30
+
31
+ ## Configuration
32
+
33
+ `reek`'s `Too Many Statements` detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
34
+
35
+ | Option | Value | Effect |
36
+ | ---------------|-------------|---------|
37
+ | `max_statements` | integer | The maximum number of statements allowed in a method before a warning is issued. Defaults to 5. |
38
+
39
+ `Too Many Statements`'s default configuration is:
40
+
41
+ ```yaml
42
+ ---
43
+ TooManyStatements:
44
+ enabled: true
45
+ exclude:
46
+ - initialize
47
+ max_statements: 5
48
+ ```
49
+
50
+ By default, `initialize` is not checked for length; any class's constructor can be as long as necessary.
@@ -0,0 +1,24 @@
1
+ # Uncommunicative Method Name
2
+
3
+ ## Introduction
4
+
5
+ An `Uncommunicative Method Name` is a method name that doesn't communicate its intent well enough.
6
+
7
+ Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.
8
+
9
+ ## Current Support in reek
10
+
11
+ `Uncommunicative Method Name` checks for:
12
+
13
+ * 1-character names
14
+ * any name ending with a number
15
+ * camelCaseVariableNames
16
+
17
+ ## Configuration
18
+
19
+ `reek`'s Uncommunicative Method Name detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
20
+
21
+ | Option | Value | Effect |
22
+ | ---------------|-------------|---------|
23
+ | `reject` | array of regular expressions | The set of regular expressions that `reek` uses to check for bad names. Defaults to `[/^[a-z]$/, /[0-9]$/, /[A-Z]/]`. |
24
+ | `accept` | array of strings or regular expressions | Name that will be accepted (not reported) even if they match one of the `reject` expressions. |
@@ -0,0 +1,23 @@
1
+ # Uncommunicative Module Name
2
+
3
+ ## Introduction
4
+
5
+ An `Uncommunicative Module Name` is a module name that doesn't communicate its intent well enough.
6
+
7
+ Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.
8
+
9
+ ## Current Support in reek
10
+
11
+ `Uncommunicative Module Name` checks for:
12
+
13
+ * 1-character names
14
+ * any name ending with a number
15
+
16
+ ## Configuration
17
+
18
+ `reek`'s `Uncommunicative Module Name` detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
19
+
20
+ | Option | Value | Effect |
21
+ | ---------------|-------------|---------|
22
+ | `reject` | array of regular expressions | The set of regular expressions that `reek` uses to check for bad names. Defaults to `[/^.$/, /[0-9]$/]`. |
23
+ | `accept` | array of strings or regular expressions | Name that will be accepted (not reported) even if they match one of the `reject` expressions. Defaults to `['Inline::C']`.|
@@ -0,0 +1,16 @@
1
+ # Uncommunicative Name
2
+
3
+ ## Introduction
4
+
5
+ An `Uncommunicative Name` is a name that doesn't communicate its intent well enough.
6
+
7
+ Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.
8
+
9
+ ## Current Support in Reek
10
+
11
+ `reek` offers four related checks:
12
+
13
+ * [Uncommunicative Method Name](Uncommunicative-Method-Name.md)
14
+ * [Uncommunicative Module Name](Uncommunicative-Module-Name.md)
15
+ * [Uncommunicative Parameter Name](Uncommunicative-Parameter-Name.md)
16
+ * [Uncommunicative Variable Name](Uncommunicative-Variable-Name.md)
@@ -0,0 +1,24 @@
1
+ # Uncommunicative Parameter Name
2
+
3
+ ## Introduction
4
+
5
+ An `Uncommunicative Parameter Name` is a parameter name that doesn't communicate its intent well enough.
6
+
7
+ Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.
8
+
9
+ ## Current Support in reek
10
+
11
+ `Uncommunicative Parameter Name` checks for:
12
+
13
+ * 1-character names
14
+ * any name ending with a number
15
+ * camelCaseVariableNames
16
+
17
+ ## Configuration
18
+
19
+ `reek`'s Uncommunicative Parameter Name detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
20
+
21
+ | Option | Value | Effect |
22
+ | ---------------|-------------|---------|
23
+ | `reject` | array of regular expressions | The set of regular expressions that `reek` uses to check for bad names. Defaults to `[/^.$/, /[0-9]$/, /[A-Z]/]@. |
24
+ | `accept` | array of strings or regular expressions | Name that will be accepted (not reported) even if they match one of the `reject` expressions. |
@@ -0,0 +1,24 @@
1
+ # Uncommunicative Variable Name
2
+
3
+ ## Introduction
4
+
5
+ An `Uncommunicative Variable Name` is a variable name that doesn't communicate its intent well enough.
6
+
7
+ Poor names make it hard for the reader to build a mental picture of what's going on in the code. They can also be mis-interpreted; and they hurt the flow of reading, because the reader must slow down to interpret the names.
8
+
9
+ ## Current Support in Reek
10
+
11
+ `Uncommunicative Variable Name` checks for:
12
+
13
+ * 1-character names
14
+ * any name ending with a number
15
+ * camelCaseVariableNames
16
+
17
+ ## Configuration
18
+
19
+ `reek`'s `Uncommunicative Variable Name` detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
20
+
21
+ | Option | Value | Effect |
22
+ | ---------------|-------------|---------|
23
+ | `reject` | array of regular expressions | The set of regular expressions that `reek` uses to check for bad names. Defaults to `[/^.$/, /[0-9]$/, /[A-Z]/]`. |
24
+ | `accept` | array of strings or regular expressions | Name that will be accepted (not reported) even if they match one of the `reject` expressions. Defaults to @['_']@.|
@@ -0,0 +1,27 @@
1
+ ## Introduction
2
+
3
+ `Unused Parameter` refers to methods with parameters that are unused in scope of the method.
4
+
5
+ Having unused parameters in a method is code smell because leaving dead code in a method can never improve the method and it makes the code confusing to read.
6
+
7
+ ## Example
8
+
9
+ Given:
10
+
11
+ ```Ruby
12
+ class Klass
13
+ def unused_parameters(x,y,z)
14
+ puts x,y # but not z
15
+ end
16
+ end
17
+ ```
18
+
19
+ `reek` would emit the following warning:
20
+
21
+ ```
22
+ [2]:Klass#unused_parameters has unused parameter 'z' (UnusedParameters)
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ `Unused Parameter` offers the [Basic Smell Options](Basic-Smell-Options.md).
@@ -0,0 +1,44 @@
1
+ # Utility Function
2
+
3
+ ## Introduction
4
+
5
+ A _Utility Function_ is any instance method that has no dependency on the state of the instance.
6
+
7
+ _Utility Function_ is heavily related to _[Feature Envy](Feature-Envy.md)_, please check out the explanation there why _Utility Function_ is something you should care about.
8
+
9
+ ## Example
10
+
11
+ Given
12
+
13
+ ```Ruby
14
+ class UtilityFunction
15
+ def showcase(argument)
16
+ argument.to_s + argument.to_i
17
+ end
18
+ end
19
+ ```
20
+
21
+ `reek` would report:
22
+
23
+ ```
24
+ test.rb -- 2 warnings:
25
+ [2]:UtilityFunction#showcase doesn't depend on instance state (UtilityFunction)
26
+ ```
27
+
28
+ ## Current Support in reek
29
+
30
+ _Utility Function_ will warn about any method that:
31
+
32
+ * is non-empty
33
+ * does not override an inherited method
34
+ * calls at least one method on another object
35
+ * doesn't use any of self's instance variables
36
+ * doesn't use any of self's methods
37
+
38
+ ## Differences to _Feature Envy_
39
+
40
+ _[Feature Envy](Feature-Envy.md)_ is only triggered if there are some references to self and _Utility Function_ is triggered if there are no references to self.
41
+
42
+ ## Configuration
43
+
44
+ `reek`'s _Utility Function_ detector supports the [Basic Smell Options](Basic-Smell-Options.md).
@@ -0,0 +1,7 @@
1
+ # Versioning Policy
2
+
3
+ * CLI interface: Adding options is a non-breaking change, and would warrant an update of the minor version. Removing options is a breaking change and requires a major version update (we did this going to reek 2). Adding a report format probably also warrents a minor version upgrade.
4
+ * API: We haven't really defined a 'public' API for using Reek programmatically, and we've only just started testing it. So, this is basically a blank slate at the moment. We will work on this as a part of the reek 3 release.
5
+ * List of detected smells: Adding a smell warrants a minor release, removing a smell is a breaking change. This makes sense if you consider that the CLI allows running a single smell detector.
6
+ * Consistency of detected smells: This is very hard to guarantee. If we fix a bug in one of the detectors, some fragrant code may become smelly, or vice versa. Right now we don't bother with this.
7
+ * Smell configuration: The detectors are quite tolerant regarding configuration options that they don't recognize, so we regard any change here as only requiring a minor release.
@@ -0,0 +1,111 @@
1
+ # YAML Reports
2
+
3
+ ## Introduction
4
+
5
+ `Reek`'s `--yaml` option writes on $stdout a YAML dump of the smells found. Each reported smell has a number of standard fields and a number of fields that are specific to the smell's type. The common fields are as follows:
6
+
7
+ | Field | Type | Value |
8
+ | ---------------|-------------|---------|
9
+ | source | string | The name of the source file containing the smell, or `$stdin` |
10
+ | lines | array | The source file line number(s) that contribute to this smell |
11
+ | context | string | The name of the class, module or method containing the smell |
12
+ | class | string | The class to which this smell belongs |
13
+ | subclass | string | This smell's subclass within the above class |
14
+ | message | string | The message that would have been printed in a standard Reek report |
15
+ | is_active | boolean | `false` if the smell is masked by a config file; `true` otherwise |
16
+
17
+ All of these fields are grouped into hashes `location`, `smell` and `status` (see the examples below).
18
+
19
+ ## Examples
20
+
21
+ Duplication:
22
+
23
+ <pre>
24
+ - !ruby/object:Reek::SmellWarning
25
+ location:
26
+ source: spec/samples/masked/dirty.rb
27
+ lines:
28
+ - 5
29
+ - 7
30
+ context: Dirty#a
31
+ smell:
32
+ class: Duplication
33
+ subclass: DuplicateMethodCall
34
+ occurrences: 2
35
+ call: puts(@s.title)
36
+ message: calls puts(@s.title) twice
37
+ status:
38
+ is_active: true
39
+ </pre>
40
+
41
+ [Nested Iterators](Nested-Iterators.md):
42
+
43
+ <pre>
44
+ - !ruby/object:Reek::SmellWarning
45
+ location:
46
+ source: spec/samples/masked/dirty.rb
47
+ lines:
48
+ - 5
49
+ context: Dirty#a
50
+ smell:
51
+ class: NestedIterators
52
+ subclass: ""
53
+ depth: 2
54
+ message: contains iterators nested 2 deep
55
+ status:
56
+ is_active: true
57
+ </pre>
58
+
59
+ [Uncommunicative Method Name](Uncommunicative-Method-Name.md):
60
+
61
+ <pre>
62
+ - !ruby/object:Reek::SmellWarning
63
+ location:
64
+ source: spec/samples/masked/dirty.rb
65
+ lines:
66
+ - 3
67
+ context: Dirty#a
68
+ smell:
69
+ class: UncommunicativeName
70
+ subclass: UncommunicativeMethodName
71
+ method_name: a
72
+ message: has the name 'a'
73
+ status:
74
+ is_active: false
75
+ </pre>
76
+
77
+ [Uncommunicative Variable Name](Uncommunicative-Variable-Name.md):
78
+
79
+ <pre>
80
+ - !ruby/object:Reek::SmellWarning
81
+ location:
82
+ source: spec/samples/masked/dirty.rb
83
+ lines:
84
+ - 5
85
+ context: Dirty#a
86
+ smell:
87
+ class: UncommunicativeName
88
+ subclass: UncommunicativeVariableName
89
+ variable_name: x
90
+ message: has the variable name 'x'
91
+ status:
92
+ is_active: true
93
+ </pre>
94
+
95
+ [Control Couple](Control-Couple.md):
96
+
97
+ <pre>
98
+ - !ruby/object:Reek::SmellWarning
99
+ location:
100
+ source: $stdin
101
+ lines:
102
+ - 2
103
+ context: Turn#fred
104
+ smell:
105
+ class: ControlCouple
106
+ subclass: BooleanParameter
107
+ parameter: arg
108
+ message: has boolean parameter 'arg'
109
+ status:
110
+ is_active: true
111
+ </pre>
@@ -0,0 +1,14 @@
1
+ require 'yard'
2
+
3
+ # Template helper to modify processing of links in HTML generated from our
4
+ # markdown files.
5
+ module LocalLinkHelper
6
+ # Rewrites links to (assumed local) markdown files so they're processed as
7
+ # {file: } directives.
8
+ def resolve_links(text)
9
+ text = text.gsub(%r{<a href="([^"]*.md)">([^<]*)</a>}, '{file:\1 \2}')
10
+ super text
11
+ end
12
+ end
13
+
14
+ YARD::Templates::Template.extra_includes << LocalLinkHelper
@@ -1,20 +1,21 @@
1
- Feature: The Reek API maintains backwards compatibility
1
+ Feature: The Reek CLI maintains backwards compatibility
2
2
  In order to use Reek without fuss
3
3
  As a developer
4
- I want to have a stable API
4
+ I want to have a stable basic command line interface
5
5
 
6
6
  Scenario: the demo example reports as expected
7
- When I run reek spec/samples/demo
7
+ Given the smelly file 'demo.rb' from the example in the README
8
+ When I run reek demo.rb
8
9
  Then the exit status indicates smells
9
10
  And it reports:
10
11
  """
11
- spec/samples/demo/demo.rb -- 8 warnings:
12
+ demo.rb -- 8 warnings:
12
13
  [1]:Dirty has no descriptive comment (IrresponsibleModule)
13
14
  [3]:Dirty#awful has 4 parameters (LongParameterList)
14
15
  [3]:Dirty#awful has boolean parameter 'log' (BooleanParameter)
16
+ [3]:Dirty#awful has the parameter name 'x' (UncommunicativeParameterName)
15
17
  [5]:Dirty#awful has the variable name 'w' (UncommunicativeVariableName)
16
18
  [3]:Dirty#awful has unused parameter 'log' (UnusedParameters)
17
19
  [3]:Dirty#awful has unused parameter 'offset' (UnusedParameters)
18
- [3]:Dirty#awful has unused parameter 'x' (UnusedParameters)
19
20
  [3]:Dirty#awful has unused parameter 'y' (UnusedParameters)
20
21
  """
@@ -39,6 +39,7 @@ Feature: Reek can be controlled using command-line options
39
39
  text (default)
40
40
  yaml
41
41
  json
42
+ xml
42
43
 
43
44
  Text format options:
44
45
  --[no-]color Use colors for the output (default: true)
@@ -4,15 +4,11 @@ Feature: Smell selection
4
4
  I want to be able to selectively activate smell detectors
5
5
 
6
6
  Scenario: --smell selects a smell to detect
7
- When I run reek --no-line-numbers --smell DuplicateMethodCall spec/samples/two_smelly_files
7
+ Given a smelly file called 'smelly.rb'
8
+ When I run reek --no-line-numbers --smell UncommunicativeMethodName smelly.rb
8
9
  Then the exit status indicates smells
9
10
  And it reports:
10
11
  """
11
- spec/samples/two_smelly_files/dirty_one.rb -- 2 warnings:
12
- Dirty#a calls @s.title 2 times (DuplicateMethodCall)
13
- Dirty#a calls puts(@s.title) 2 times (DuplicateMethodCall)
14
- spec/samples/two_smelly_files/dirty_two.rb -- 2 warnings:
15
- Dirty#a calls @s.title 2 times (DuplicateMethodCall)
16
- Dirty#a calls puts(@s.title) 2 times (DuplicateMethodCall)
17
- 4 total warnings
12
+ smelly.rb -- 1 warning:
13
+ Smelly#m has the name 'm' (UncommunicativeMethodName)
18
14
  """