reek 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -21
- data/.travis.yml +1 -0
- data/.yardopts +3 -6
- data/CHANGELOG +6 -0
- data/CONTRIBUTING.md +8 -3
- data/README.md +94 -42
- data/config/defaults.reek +0 -1
- data/docs/API.md +50 -0
- data/docs/Attribute.md +43 -0
- data/docs/Basic-Smell-Options.md +44 -0
- data/docs/Boolean-Parameter.md +52 -0
- data/docs/Class-Variable.md +40 -0
- data/docs/Code-Smells.md +34 -0
- data/docs/Command-Line-Options.md +84 -0
- data/docs/Configuration-Files.md +38 -0
- data/docs/Control-Couple.md +22 -0
- data/docs/Control-Parameter.md +29 -0
- data/docs/Data-Clump.md +44 -0
- data/docs/Duplicate-Method-Call.md +49 -0
- data/docs/Feature-Envy.md +29 -0
- data/docs/How-reek-works-internally.md +44 -0
- data/docs/Irresponsible-Module.md +39 -0
- data/docs/Large-Class.md +20 -0
- data/docs/Long-Parameter-List.md +38 -0
- data/docs/Long-Yield-List.md +36 -0
- data/docs/Module-Initialize.md +62 -0
- data/docs/Nested-Iterators.md +38 -0
- data/docs/Nil-Check.md +39 -0
- data/docs/Prima-Donna-Method.md +53 -0
- data/docs/RSpec-matchers.md +133 -0
- data/docs/Rake-Task.md +58 -0
- data/docs/Reek-Driven-Development.md +45 -0
- data/docs/Repeated-Conditional.md +44 -0
- data/docs/Simulated-Polymorphism.md +16 -0
- data/docs/Smell-Suppression.md +32 -0
- data/docs/Too-Many-Instance-Variables.md +43 -0
- data/docs/Too-Many-Methods.md +55 -0
- data/docs/Too-Many-Statements.md +50 -0
- data/docs/Uncommunicative-Method-Name.md +24 -0
- data/docs/Uncommunicative-Module-Name.md +23 -0
- data/docs/Uncommunicative-Name.md +16 -0
- data/docs/Uncommunicative-Parameter-Name.md +24 -0
- data/docs/Uncommunicative-Variable-Name.md +24 -0
- data/docs/Unused-Parameters.md +27 -0
- data/docs/Utility-Function.md +46 -0
- data/docs/Versioning-Policy.md +7 -0
- data/docs/YAML-Reports.md +111 -0
- data/docs/yard_plugin.rb +14 -0
- data/features/command_line_interface/options.feature +1 -0
- data/features/programmatic_access.feature +1 -1
- data/features/samples.feature +3 -3
- data/lib/reek.rb +2 -2
- data/lib/reek/cli/input.rb +2 -2
- data/lib/reek/cli/option_interpreter.rb +2 -0
- data/lib/reek/cli/options.rb +10 -4
- data/lib/reek/cli/reek_command.rb +2 -2
- data/lib/reek/cli/report/report.rb +60 -0
- data/lib/reek/cli/silencer.rb +13 -0
- data/lib/reek/{source → core}/ast_node.rb +1 -1
- data/lib/reek/{source → core}/ast_node_class_map.rb +10 -11
- data/lib/reek/{source → core}/code_comment.rb +1 -1
- data/lib/reek/core/code_context.rb +1 -1
- data/lib/reek/core/examiner.rb +85 -0
- data/lib/reek/core/method_context.rb +1 -1
- data/lib/reek/core/module_context.rb +2 -2
- data/lib/reek/core/reference_collector.rb +31 -0
- data/lib/reek/core/singleton_method_context.rb +0 -4
- data/lib/reek/core/smell_repository.rb +4 -2
- data/lib/reek/{source → core}/tree_dresser.rb +1 -1
- data/lib/reek/{source → sexp}/sexp_extensions.rb +5 -5
- data/lib/reek/sexp/sexp_formatter.rb +29 -0
- data/lib/reek/sexp/sexp_node.rb +91 -0
- data/lib/reek/smells.rb +4 -2
- data/lib/reek/smells/attribute.rb +35 -7
- data/lib/reek/smells/boolean_parameter.rb +1 -1
- data/lib/reek/smells/class_variable.rb +1 -1
- data/lib/reek/smells/control_parameter.rb +1 -1
- data/lib/reek/smells/data_clump.rb +1 -1
- data/lib/reek/smells/duplicate_method_call.rb +12 -4
- data/lib/reek/smells/feature_envy.rb +1 -1
- data/lib/reek/smells/irresponsible_module.rb +3 -3
- data/lib/reek/smells/long_parameter_list.rb +1 -1
- data/lib/reek/smells/long_yield_list.rb +1 -1
- data/lib/reek/smells/module_initialize.rb +1 -1
- data/lib/reek/smells/nested_iterators.rb +1 -1
- data/lib/reek/smells/nil_check.rb +3 -2
- data/lib/reek/smells/prima_donna_method.rb +18 -11
- data/lib/reek/smells/repeated_conditional.rb +3 -3
- data/lib/reek/smells/smell_detector.rb +5 -1
- data/lib/reek/smells/smell_warning.rb +99 -0
- data/lib/reek/smells/too_many_instance_variables.rb +1 -1
- data/lib/reek/smells/too_many_methods.rb +1 -1
- data/lib/reek/smells/too_many_statements.rb +1 -1
- data/lib/reek/smells/uncommunicative_method_name.rb +1 -1
- data/lib/reek/smells/uncommunicative_module_name.rb +1 -1
- data/lib/reek/smells/uncommunicative_parameter_name.rb +1 -1
- data/lib/reek/smells/uncommunicative_variable_name.rb +1 -1
- data/lib/reek/smells/unused_parameters.rb +1 -1
- data/lib/reek/smells/utility_function.rb +3 -16
- data/lib/reek/source/source_code.rb +31 -13
- data/lib/reek/source/source_locator.rb +16 -17
- data/lib/reek/source/source_repository.rb +10 -11
- data/lib/reek/spec/should_reek.rb +2 -2
- data/lib/reek/spec/should_reek_of.rb +2 -2
- data/lib/reek/spec/should_reek_only_of.rb +2 -2
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +3 -4
- data/spec/factories/factories.rb +1 -1
- data/spec/gem/yard_spec.rb +1 -1
- data/spec/quality/reek_source_spec.rb +2 -2
- data/spec/reek/cli/html_report_spec.rb +3 -3
- data/spec/reek/cli/json_report_spec.rb +3 -3
- data/spec/reek/cli/{option_interperter_spec.rb → option_interpreter_spec.rb} +1 -1
- data/spec/reek/cli/options_spec.rb +19 -0
- data/spec/reek/cli/text_report_spec.rb +7 -7
- data/spec/reek/cli/xml_report_spec.rb +34 -0
- data/spec/reek/cli/yaml_report_spec.rb +3 -3
- data/spec/reek/configuration/app_configuration_spec.rb +1 -1
- data/spec/reek/configuration/configuration_file_finder_spec.rb +22 -1
- data/spec/reek/{source → core}/code_comment_spec.rb +14 -14
- data/spec/reek/core/code_context_spec.rb +1 -1
- data/spec/reek/{examiner_spec.rb → core/examiner_spec.rb} +12 -12
- data/spec/reek/core/method_context_spec.rb +27 -22
- data/spec/reek/core/module_context_spec.rb +2 -2
- data/spec/reek/core/object_refs_spec.rb +1 -1
- data/spec/reek/{source → core}/object_source_spec.rb +1 -1
- data/spec/reek/{source → core}/reference_collector_spec.rb +25 -16
- data/spec/reek/core/singleton_method_context_spec.rb +12 -2
- data/spec/reek/core/smell_configuration_spec.rb +1 -1
- data/spec/reek/core/smell_repository_spec.rb +12 -1
- data/spec/reek/core/stop_context_spec.rb +1 -1
- data/spec/reek/core/tree_dresser_spec.rb +16 -0
- data/spec/reek/core/tree_walker_spec.rb +3 -3
- data/spec/reek/core/warning_collector_spec.rb +6 -6
- data/spec/reek/{source → sexp}/sexp_extensions_spec.rb +8 -8
- data/spec/reek/{source → sexp}/sexp_formatter_spec.rb +11 -5
- data/spec/reek/{source → sexp}/sexp_node_spec.rb +3 -3
- data/spec/reek/smells/attribute_spec.rb +89 -85
- data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
- data/spec/reek/smells/boolean_parameter_spec.rb +1 -1
- data/spec/reek/smells/class_variable_spec.rb +1 -1
- data/spec/reek/smells/control_parameter_spec.rb +1 -1
- data/spec/reek/smells/data_clump_spec.rb +2 -2
- data/spec/reek/smells/duplicate_method_call_spec.rb +1 -1
- data/spec/reek/smells/feature_envy_spec.rb +2 -2
- data/spec/reek/smells/irresponsible_module_spec.rb +1 -1
- data/spec/reek/smells/long_parameter_list_spec.rb +2 -2
- data/spec/reek/smells/long_yield_list_spec.rb +1 -1
- data/spec/reek/smells/module_initialize_spec.rb +1 -1
- data/spec/reek/smells/nested_iterators_spec.rb +2 -2
- data/spec/reek/smells/nil_check_spec.rb +1 -1
- data/spec/reek/smells/prima_donna_method_spec.rb +1 -1
- data/spec/reek/smells/repeated_conditional_spec.rb +1 -1
- data/spec/reek/smells/smell_detector_shared.rb +2 -2
- data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -7
- data/spec/reek/smells/too_many_instance_variables_spec.rb +1 -1
- data/spec/reek/smells/too_many_methods_spec.rb +1 -1
- data/spec/reek/smells/too_many_statements_spec.rb +4 -4
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +1 -1
- data/spec/reek/smells/unused_parameters_spec.rb +1 -1
- data/spec/reek/smells/utility_function_spec.rb +1 -1
- data/spec/reek/source/source_code_spec.rb +1 -1
- data/spec/reek/spec/should_reek_of_spec.rb +1 -1
- data/spec/reek/spec/should_reek_only_of_spec.rb +1 -1
- data/spec/reek/spec/should_reek_spec.rb +1 -1
- data/spec/samples/checkstyle.xml +2 -0
- data/spec/spec_helper.rb +15 -3
- metadata +68 -38
- data/.ruby-gemset +0 -1
- data/lib/reek/examiner.rb +0 -79
- data/lib/reek/smell_warning.rb +0 -87
- data/lib/reek/source/reference_collector.rb +0 -27
- data/lib/reek/source/sexp_formatter.rb +0 -22
- data/lib/reek/source/sexp_node.rb +0 -79
- 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.
|