reek 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -21
  3. data/.travis.yml +1 -0
  4. data/.yardopts +3 -6
  5. data/CHANGELOG +6 -0
  6. data/CONTRIBUTING.md +8 -3
  7. data/README.md +94 -42
  8. data/config/defaults.reek +0 -1
  9. data/docs/API.md +50 -0
  10. data/docs/Attribute.md +43 -0
  11. data/docs/Basic-Smell-Options.md +44 -0
  12. data/docs/Boolean-Parameter.md +52 -0
  13. data/docs/Class-Variable.md +40 -0
  14. data/docs/Code-Smells.md +34 -0
  15. data/docs/Command-Line-Options.md +84 -0
  16. data/docs/Configuration-Files.md +38 -0
  17. data/docs/Control-Couple.md +22 -0
  18. data/docs/Control-Parameter.md +29 -0
  19. data/docs/Data-Clump.md +44 -0
  20. data/docs/Duplicate-Method-Call.md +49 -0
  21. data/docs/Feature-Envy.md +29 -0
  22. data/docs/How-reek-works-internally.md +44 -0
  23. data/docs/Irresponsible-Module.md +39 -0
  24. data/docs/Large-Class.md +20 -0
  25. data/docs/Long-Parameter-List.md +38 -0
  26. data/docs/Long-Yield-List.md +36 -0
  27. data/docs/Module-Initialize.md +62 -0
  28. data/docs/Nested-Iterators.md +38 -0
  29. data/docs/Nil-Check.md +39 -0
  30. data/docs/Prima-Donna-Method.md +53 -0
  31. data/docs/RSpec-matchers.md +133 -0
  32. data/docs/Rake-Task.md +58 -0
  33. data/docs/Reek-Driven-Development.md +45 -0
  34. data/docs/Repeated-Conditional.md +44 -0
  35. data/docs/Simulated-Polymorphism.md +16 -0
  36. data/docs/Smell-Suppression.md +32 -0
  37. data/docs/Too-Many-Instance-Variables.md +43 -0
  38. data/docs/Too-Many-Methods.md +55 -0
  39. data/docs/Too-Many-Statements.md +50 -0
  40. data/docs/Uncommunicative-Method-Name.md +24 -0
  41. data/docs/Uncommunicative-Module-Name.md +23 -0
  42. data/docs/Uncommunicative-Name.md +16 -0
  43. data/docs/Uncommunicative-Parameter-Name.md +24 -0
  44. data/docs/Uncommunicative-Variable-Name.md +24 -0
  45. data/docs/Unused-Parameters.md +27 -0
  46. data/docs/Utility-Function.md +46 -0
  47. data/docs/Versioning-Policy.md +7 -0
  48. data/docs/YAML-Reports.md +111 -0
  49. data/docs/yard_plugin.rb +14 -0
  50. data/features/command_line_interface/options.feature +1 -0
  51. data/features/programmatic_access.feature +1 -1
  52. data/features/samples.feature +3 -3
  53. data/lib/reek.rb +2 -2
  54. data/lib/reek/cli/input.rb +2 -2
  55. data/lib/reek/cli/option_interpreter.rb +2 -0
  56. data/lib/reek/cli/options.rb +10 -4
  57. data/lib/reek/cli/reek_command.rb +2 -2
  58. data/lib/reek/cli/report/report.rb +60 -0
  59. data/lib/reek/cli/silencer.rb +13 -0
  60. data/lib/reek/{source → core}/ast_node.rb +1 -1
  61. data/lib/reek/{source → core}/ast_node_class_map.rb +10 -11
  62. data/lib/reek/{source → core}/code_comment.rb +1 -1
  63. data/lib/reek/core/code_context.rb +1 -1
  64. data/lib/reek/core/examiner.rb +85 -0
  65. data/lib/reek/core/method_context.rb +1 -1
  66. data/lib/reek/core/module_context.rb +2 -2
  67. data/lib/reek/core/reference_collector.rb +31 -0
  68. data/lib/reek/core/singleton_method_context.rb +0 -4
  69. data/lib/reek/core/smell_repository.rb +4 -2
  70. data/lib/reek/{source → core}/tree_dresser.rb +1 -1
  71. data/lib/reek/{source → sexp}/sexp_extensions.rb +5 -5
  72. data/lib/reek/sexp/sexp_formatter.rb +29 -0
  73. data/lib/reek/sexp/sexp_node.rb +91 -0
  74. data/lib/reek/smells.rb +4 -2
  75. data/lib/reek/smells/attribute.rb +35 -7
  76. data/lib/reek/smells/boolean_parameter.rb +1 -1
  77. data/lib/reek/smells/class_variable.rb +1 -1
  78. data/lib/reek/smells/control_parameter.rb +1 -1
  79. data/lib/reek/smells/data_clump.rb +1 -1
  80. data/lib/reek/smells/duplicate_method_call.rb +12 -4
  81. data/lib/reek/smells/feature_envy.rb +1 -1
  82. data/lib/reek/smells/irresponsible_module.rb +3 -3
  83. data/lib/reek/smells/long_parameter_list.rb +1 -1
  84. data/lib/reek/smells/long_yield_list.rb +1 -1
  85. data/lib/reek/smells/module_initialize.rb +1 -1
  86. data/lib/reek/smells/nested_iterators.rb +1 -1
  87. data/lib/reek/smells/nil_check.rb +3 -2
  88. data/lib/reek/smells/prima_donna_method.rb +18 -11
  89. data/lib/reek/smells/repeated_conditional.rb +3 -3
  90. data/lib/reek/smells/smell_detector.rb +5 -1
  91. data/lib/reek/smells/smell_warning.rb +99 -0
  92. data/lib/reek/smells/too_many_instance_variables.rb +1 -1
  93. data/lib/reek/smells/too_many_methods.rb +1 -1
  94. data/lib/reek/smells/too_many_statements.rb +1 -1
  95. data/lib/reek/smells/uncommunicative_method_name.rb +1 -1
  96. data/lib/reek/smells/uncommunicative_module_name.rb +1 -1
  97. data/lib/reek/smells/uncommunicative_parameter_name.rb +1 -1
  98. data/lib/reek/smells/uncommunicative_variable_name.rb +1 -1
  99. data/lib/reek/smells/unused_parameters.rb +1 -1
  100. data/lib/reek/smells/utility_function.rb +3 -16
  101. data/lib/reek/source/source_code.rb +31 -13
  102. data/lib/reek/source/source_locator.rb +16 -17
  103. data/lib/reek/source/source_repository.rb +10 -11
  104. data/lib/reek/spec/should_reek.rb +2 -2
  105. data/lib/reek/spec/should_reek_of.rb +2 -2
  106. data/lib/reek/spec/should_reek_only_of.rb +2 -2
  107. data/lib/reek/version.rb +1 -1
  108. data/reek.gemspec +3 -4
  109. data/spec/factories/factories.rb +1 -1
  110. data/spec/gem/yard_spec.rb +1 -1
  111. data/spec/quality/reek_source_spec.rb +2 -2
  112. data/spec/reek/cli/html_report_spec.rb +3 -3
  113. data/spec/reek/cli/json_report_spec.rb +3 -3
  114. data/spec/reek/cli/{option_interperter_spec.rb → option_interpreter_spec.rb} +1 -1
  115. data/spec/reek/cli/options_spec.rb +19 -0
  116. data/spec/reek/cli/text_report_spec.rb +7 -7
  117. data/spec/reek/cli/xml_report_spec.rb +34 -0
  118. data/spec/reek/cli/yaml_report_spec.rb +3 -3
  119. data/spec/reek/configuration/app_configuration_spec.rb +1 -1
  120. data/spec/reek/configuration/configuration_file_finder_spec.rb +22 -1
  121. data/spec/reek/{source → core}/code_comment_spec.rb +14 -14
  122. data/spec/reek/core/code_context_spec.rb +1 -1
  123. data/spec/reek/{examiner_spec.rb → core/examiner_spec.rb} +12 -12
  124. data/spec/reek/core/method_context_spec.rb +27 -22
  125. data/spec/reek/core/module_context_spec.rb +2 -2
  126. data/spec/reek/core/object_refs_spec.rb +1 -1
  127. data/spec/reek/{source → core}/object_source_spec.rb +1 -1
  128. data/spec/reek/{source → core}/reference_collector_spec.rb +25 -16
  129. data/spec/reek/core/singleton_method_context_spec.rb +12 -2
  130. data/spec/reek/core/smell_configuration_spec.rb +1 -1
  131. data/spec/reek/core/smell_repository_spec.rb +12 -1
  132. data/spec/reek/core/stop_context_spec.rb +1 -1
  133. data/spec/reek/core/tree_dresser_spec.rb +16 -0
  134. data/spec/reek/core/tree_walker_spec.rb +3 -3
  135. data/spec/reek/core/warning_collector_spec.rb +6 -6
  136. data/spec/reek/{source → sexp}/sexp_extensions_spec.rb +8 -8
  137. data/spec/reek/{source → sexp}/sexp_formatter_spec.rb +11 -5
  138. data/spec/reek/{source → sexp}/sexp_node_spec.rb +3 -3
  139. data/spec/reek/smells/attribute_spec.rb +89 -85
  140. data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
  141. data/spec/reek/smells/boolean_parameter_spec.rb +1 -1
  142. data/spec/reek/smells/class_variable_spec.rb +1 -1
  143. data/spec/reek/smells/control_parameter_spec.rb +1 -1
  144. data/spec/reek/smells/data_clump_spec.rb +2 -2
  145. data/spec/reek/smells/duplicate_method_call_spec.rb +1 -1
  146. data/spec/reek/smells/feature_envy_spec.rb +2 -2
  147. data/spec/reek/smells/irresponsible_module_spec.rb +1 -1
  148. data/spec/reek/smells/long_parameter_list_spec.rb +2 -2
  149. data/spec/reek/smells/long_yield_list_spec.rb +1 -1
  150. data/spec/reek/smells/module_initialize_spec.rb +1 -1
  151. data/spec/reek/smells/nested_iterators_spec.rb +2 -2
  152. data/spec/reek/smells/nil_check_spec.rb +1 -1
  153. data/spec/reek/smells/prima_donna_method_spec.rb +1 -1
  154. data/spec/reek/smells/repeated_conditional_spec.rb +1 -1
  155. data/spec/reek/smells/smell_detector_shared.rb +2 -2
  156. data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -7
  157. data/spec/reek/smells/too_many_instance_variables_spec.rb +1 -1
  158. data/spec/reek/smells/too_many_methods_spec.rb +1 -1
  159. data/spec/reek/smells/too_many_statements_spec.rb +4 -4
  160. data/spec/reek/smells/uncommunicative_method_name_spec.rb +1 -1
  161. data/spec/reek/smells/uncommunicative_module_name_spec.rb +1 -1
  162. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +1 -1
  163. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +1 -1
  164. data/spec/reek/smells/unused_parameters_spec.rb +1 -1
  165. data/spec/reek/smells/utility_function_spec.rb +1 -1
  166. data/spec/reek/source/source_code_spec.rb +1 -1
  167. data/spec/reek/spec/should_reek_of_spec.rb +1 -1
  168. data/spec/reek/spec/should_reek_only_of_spec.rb +1 -1
  169. data/spec/reek/spec/should_reek_spec.rb +1 -1
  170. data/spec/samples/checkstyle.xml +2 -0
  171. data/spec/spec_helper.rb +15 -3
  172. metadata +68 -38
  173. data/.ruby-gemset +0 -1
  174. data/lib/reek/examiner.rb +0 -79
  175. data/lib/reek/smell_warning.rb +0 -87
  176. data/lib/reek/source/reference_collector.rb +0 -27
  177. data/lib/reek/source/sexp_formatter.rb +0 -22
  178. data/lib/reek/source/sexp_node.rb +0 -79
  179. data/spec/reek/source/tree_dresser_spec.rb +0 -16
@@ -0,0 +1,133 @@
1
+ # RSpec matchers
2
+
3
+ ## Introduction
4
+
5
+ `reek` offers matchers for RSpec you can easily include into your project.
6
+
7
+ There are 3 matchers available:
8
+
9
+ - `reek`
10
+ - `reek_of`
11
+ - `reek_only_of`
12
+
13
+ ## Quickstart
14
+
15
+ Let's install the dependencies:
16
+
17
+ ```
18
+ gem install reek
19
+ gem install rspec
20
+ ```
21
+
22
+ And then use it like that in your spec file:
23
+
24
+ ```Ruby
25
+ require 'reek'
26
+ require 'reek/spec'
27
+ require 'rspec'
28
+
29
+ RSpec.describe 'Reek Integration' do
30
+ it 'works with reek' do
31
+ smelly_class = 'class C; def m; end; end'
32
+ expect(smelly_class).not_to reek
33
+ end
34
+ end
35
+ ```
36
+
37
+ Running this via
38
+
39
+ ```
40
+ rspec reek-integration-spec.rb
41
+ ```
42
+
43
+ would give you:
44
+
45
+ ```
46
+ Failures:
47
+
48
+ 1) Reek Integration works with reek
49
+ Failure/Error: expect(smelly_class).not_to reek
50
+ Expected no smells, but got:
51
+ C has no descriptive comment (IrresponsibleModule)
52
+ C has the name 'C' (UncommunicativeModuleName)
53
+ C#m has the name 'm' (UncommunicativeMethodName)
54
+ # ./reek-integration-spec.rb:8:in `block (2 levels) in <top (required)>'
55
+
56
+ Finished in 0.00284 seconds (files took 0.28815 seconds to load)
57
+ 1 example, 1 failure
58
+
59
+ Failed examples:
60
+
61
+ rspec ./reek-integration-spec.rb:6 # Reek Integration works with reek
62
+ ```
63
+
64
+ ## The matchers explained
65
+
66
+ ### `reek`
67
+
68
+ A very generic matcher that basically just tells you if something reeks, but not after what exactly.
69
+ See the "Quickstart" example from above.
70
+
71
+ ### `reek_of`
72
+
73
+ Checks the target source code for instances of "smell category"
74
+ and returns true only if it can find one of them that matches.
75
+
76
+ Remember that this includes our "smell types" as well. So it could be the
77
+ "smell type" UtilityFunction, which is represented as a concrete class
78
+ in reek but it could also be "Duplication" which is a "smell categgory".
79
+
80
+ In theory you could pass many different types of input here:
81
+ - :UtilityFunction
82
+ - "UtilityFunction"
83
+ - UtilityFunction (this works in our specs because we tend to do "include Reek:Smells")
84
+ - Reek::Smells::UtilityFunction (the right way if you really want to pass a class)
85
+ - "Duplication" or :Duplication which is an abstract "smell category"
86
+
87
+ It is recommended to pass this as a symbol like :UtilityFunction. However we don't
88
+ enforce this.
89
+
90
+ Additionally you can be more specific and pass in "smell_details" you
91
+ want to check for as well e.g. "name" or "count" (see the examples below).
92
+ The parameters you can check for are depending on the smell you are checking for.
93
+ For instance "count" doesn't make sense everywhere whereas "name" does in most cases.
94
+ If you pass in a parameter that doesn't exist (e.g. you make a typo like "namme") reek will
95
+ raise an ArgumentError to give you a hint that you passed something that doesn't make
96
+ much sense.
97
+
98
+ So in a nutshell `reek_of` takes the following two arguments:
99
+
100
+ - smell_category - The "smell category" or "smell_type" we check for.
101
+ - smells_details - A hash containing "smell warning" parameters
102
+
103
+ **Examples**
104
+
105
+ Without smell_details:
106
+
107
+ ```Ruby
108
+ reek_of(:FeatureEnvy)
109
+ reek_of(Reek::Smells::UtilityFunction)
110
+ ```
111
+
112
+ With smell_details:
113
+
114
+ ```Ruby
115
+ reek_of(UncommunicativeParameterName, name: 'x2')
116
+ reek_of(DataClump, count: 3)
117
+ ```
118
+
119
+ **Examples from a real spec**
120
+
121
+ ```Ruby
122
+ expect(src).to reek_of(Reek::Smells::DuplicateMethodCall, name: '@other.thing')
123
+ ```
124
+
125
+ ### reek_only_of
126
+
127
+ See the documentaton for `reek_of`.
128
+
129
+ **Notable differences to reek_of:**
130
+
131
+ 1.) `reek_of` doesn't mind if there are other smells of a different category. "reek_only_of" will fail in that case.
132
+
133
+ 2.) `reek_only_of` doesn't support the additional smell_details hash.
data/docs/Rake-Task.md ADDED
@@ -0,0 +1,58 @@
1
+ # Rake Task
2
+
3
+ ## Introduction
4
+
5
+ `reek` provides a Rake task that runs `reek` on a set of source files. In its most simple form you just include something like that in your Rakefile:
6
+
7
+ ```Ruby
8
+ require 'reek/rake/task'
9
+
10
+ Reek::Rake::Task.new do |t|
11
+ t.fail_on_error = false
12
+ end
13
+ ```
14
+
15
+ In its most simple form, that's it.
16
+
17
+ When you now run:
18
+
19
+ ```Bash
20
+ rake -T
21
+ ```
22
+
23
+ you should see
24
+
25
+ ```Bash
26
+ rake reek # Check for code smells
27
+ ```
28
+
29
+ ## Configuration via task
30
+
31
+ An more sophisticated rake task that would make use of all available configuration options could look like this:
32
+
33
+ ```Ruby
34
+ Reek::Rake::Task.new do |t|
35
+ t.name = 'custom_rake' # Whatever name you want. Defaults to "reek".
36
+ t.config_file = 'config/config.reek' # Defaults to nothing.
37
+ t.source_files = 'vendor/**/*.rb' # Glob pattern to match source files. Defaults to lib/**/*.rb
38
+ t.reek_opts = '-U' # Defaults to ''. You can pass all the options here in that are shown by "reek -h"
39
+ t.fail_on_error = false # Defaults to true
40
+ t.verbose = true # Defaults to false
41
+ end
42
+ ```
43
+
44
+ ## Configuration via environment variables
45
+
46
+ You can overwrite the following attributes by environment variables:
47
+
48
+ - "reek_opts" by using REEK_OPTS
49
+ - "config_file" by using REEK_CFG
50
+ - "source_files" by using REEK_SRC
51
+
52
+ An example rake call using environment variables could look like this:
53
+
54
+ ```Bash
55
+ REEK_CFG="config/custom.reek" REEK_OPTS="-s" rake reek
56
+ ```
57
+
58
+ See also: [Reek-Driven-Development](Reek-Driven-Development.md)
@@ -0,0 +1,45 @@
1
+ # Reek Driven Development
2
+
3
+ ## rake
4
+
5
+ One way to drive quality into your code from the very beginning of a project is to run `reek` as a part of your testing process. For example, you could do that by adding a [Rake Task](Rake-Task.md) to your rakefile, which will make it easy to run `reek` on all your source files whenever you need to.
6
+
7
+ ```Ruby
8
+ require 'reek/rake/task'
9
+
10
+ Reek::Rake::Task.new do |t|
11
+ t.fail_on_error = true
12
+ t.verbose = false
13
+ t.source_files = 'lib/**/*.rb'
14
+ end
15
+ ```
16
+
17
+ Now the command `reek` will run `reek` on your source code (and in this case, it fails if it finds any smells). For more detailed information about `reek`'s integration with Rake, see [Rake Task](Rake-Task.md) in this wiki.
18
+
19
+ ## reek/spec
20
+
21
+ But there's another way; a much more effective "Reek-driven" approach: add `reek` expectations directly into your Rspec specs. Here's an example taken directly from `reek`'s own source code:
22
+
23
+ ```Ruby
24
+ it 'contains no code smells' do
25
+ Dir['lib/**/*.rb'].should_not reek
26
+ end
27
+ ```
28
+
29
+ By requiring "reek/spec":http://reek.rubyforge.org/rdoc/classes/Reek/Spec.html you gain access to the `reek` matcher, which returns true if and only if `reek` finds smells in your code. And if the test fails, the matcher produces an error message that includes details of all the smells it found.
30
+
31
+ Note: if you're on ruby 1.9 and RSpec2 you should include Reek::Spec in the configuration block like so,
32
+
33
+ ```Ruby
34
+ RSpec.configure do |c|
35
+ c.include(Reek::Spec)
36
+ end
37
+ ```
38
+
39
+ ## assert
40
+
41
+ If you're not yet into BDD with Rspec, you can still gain the benefits of Reek-driven development using assertions:
42
+
43
+ ```Ruby
44
+ assert !Dir['lib/**/*.rb'].to_source.smelly?
45
+ ```
@@ -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.