snoot 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE +21 -0
- data/README.md +49 -0
- data/data/reek_docs/API.md +174 -0
- data/data/reek_docs/Attribute.md +39 -0
- data/data/reek_docs/Basic-Smell-Options.md +85 -0
- data/data/reek_docs/Boolean-Parameter.md +54 -0
- data/data/reek_docs/Class-Variable.md +40 -0
- data/data/reek_docs/Code-Smells.md +39 -0
- data/data/reek_docs/Command-Line-Options.md +119 -0
- data/data/reek_docs/Control-Couple.md +26 -0
- data/data/reek_docs/Control-Parameter.md +32 -0
- data/data/reek_docs/Data-Clump.md +46 -0
- data/data/reek_docs/Duplicate-Method-Call.md +264 -0
- data/data/reek_docs/Feature-Envy.md +93 -0
- data/data/reek_docs/How-To-Write-New-Detectors.md +144 -0
- data/data/reek_docs/How-reek-works-internally.md +114 -0
- data/data/reek_docs/Instance-Variable-Assumption.md +163 -0
- data/data/reek_docs/Irresponsible-Module.md +47 -0
- data/data/reek_docs/LICENSE +20 -0
- data/data/reek_docs/Large-Class.md +16 -0
- data/data/reek_docs/Long-Parameter-List.md +39 -0
- data/data/reek_docs/Long-Yield-List.md +37 -0
- data/data/reek_docs/Manual-Dispatch.md +30 -0
- data/data/reek_docs/Missing-Safe-Method.md +92 -0
- data/data/reek_docs/Module-Initialize.md +62 -0
- data/data/reek_docs/Nested-Iterators.md +59 -0
- data/data/reek_docs/Nil-Check.md +47 -0
- data/data/reek_docs/RSpec-matchers.md +129 -0
- data/data/reek_docs/Rake-Task.md +66 -0
- data/data/reek_docs/Reek-4-to-Reek-5-migration.md +188 -0
- data/data/reek_docs/Reek-Driven-Development.md +46 -0
- data/data/reek_docs/Repeated-Conditional.md +47 -0
- data/data/reek_docs/Simulated-Polymorphism.md +16 -0
- data/data/reek_docs/Smell-Suppression.md +96 -0
- data/data/reek_docs/Style-Guide.md +19 -0
- data/data/reek_docs/Subclassed-From-Core-Class.md +79 -0
- data/data/reek_docs/Too-Many-Constants.md +37 -0
- data/data/reek_docs/Too-Many-Instance-Variables.md +43 -0
- data/data/reek_docs/Too-Many-Methods.md +56 -0
- data/data/reek_docs/Too-Many-Statements.md +54 -0
- data/data/reek_docs/Uncommunicative-Method-Name.md +94 -0
- data/data/reek_docs/Uncommunicative-Module-Name.md +92 -0
- data/data/reek_docs/Uncommunicative-Name.md +18 -0
- data/data/reek_docs/Uncommunicative-Parameter-Name.md +90 -0
- data/data/reek_docs/Uncommunicative-Variable-Name.md +96 -0
- data/data/reek_docs/Unused-Parameters.md +28 -0
- data/data/reek_docs/Unused-Private-Method.md +101 -0
- data/data/reek_docs/Utility-Function.md +57 -0
- data/data/reek_docs/Versioning-Policy.md +7 -0
- data/data/reek_docs/YAML-Reports.md +93 -0
- data/exe/snoot +5 -0
- data/lib/snoot/analyse_run/decision.rb +62 -0
- data/lib/snoot/analyse_run/result.rb +12 -0
- data/lib/snoot/analyse_run.rb +70 -0
- data/lib/snoot/analyser_orchestration/default.rb +149 -0
- data/lib/snoot/analyser_orchestration/result_mapping.rb +52 -0
- data/lib/snoot/analyser_orchestration.rb +21 -0
- data/lib/snoot/analyser_result.rb +14 -0
- data/lib/snoot/cli/event.rb +13 -0
- data/lib/snoot/cli/pipeline.rb +14 -0
- data/lib/snoot/cli.rb +147 -0
- data/lib/snoot/findings.rb +23 -0
- data/lib/snoot/render_report.rb +82 -0
- data/lib/snoot/run.rb +35 -0
- data/lib/snoot/state_error.rb +9 -0
- data/lib/snoot/value_types.rb +20 -0
- data/lib/snoot/version.rb +5 -0
- data/lib/snoot.rb +21 -0
- data/snoot.allium +482 -0
- metadata +160 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Instance Variable Assumption
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Classes should not assume that instance variables are set or present outside of the current class definition.
|
|
6
|
+
|
|
7
|
+
Good:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
class Foo
|
|
11
|
+
def initialize
|
|
12
|
+
@bar = :foo
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def foo?
|
|
16
|
+
@bar == :foo
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Good as well:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
class Foo
|
|
25
|
+
def foo?
|
|
26
|
+
bar == :foo
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def bar
|
|
30
|
+
@bar ||= :foo
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Bad:
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
class Foo
|
|
39
|
+
def go_foo!
|
|
40
|
+
@bar = :foo
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def foo?
|
|
44
|
+
@bar == :foo
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Example
|
|
50
|
+
|
|
51
|
+
Running Reek on:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
class Dummy
|
|
55
|
+
def test
|
|
56
|
+
@ivar
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
would report:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
[1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Note that this example would trigger this smell warning as well:
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
class Parent
|
|
71
|
+
def initialize(omg)
|
|
72
|
+
@omg = omg
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class Child < Parent
|
|
77
|
+
def foo
|
|
78
|
+
@omg
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The way to address the smell warning is that you should create an `attr_reader` to use `@omg` in the subclass and not access `@omg` directly like this:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
class Parent
|
|
87
|
+
attr_reader :omg
|
|
88
|
+
|
|
89
|
+
def initialize(omg)
|
|
90
|
+
@omg = omg
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class Child < Parent
|
|
95
|
+
def foo
|
|
96
|
+
omg
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Directly accessing instance variables is considered a smell because it [breaks encapsulation](https://www.designisrefactoring.com/2015/03/30/organizing-data-self-encapsulation/) and makes it harder to reason about code.
|
|
102
|
+
|
|
103
|
+
If you don't want to expose those methods as public API just make them private like this:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
class Parent
|
|
107
|
+
def initialize(omg)
|
|
108
|
+
@omg = omg
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
attr_reader :omg
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
class Child < Parent
|
|
116
|
+
def foo
|
|
117
|
+
omg
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
## Current Support in Reek
|
|
124
|
+
|
|
125
|
+
An instance variable must:
|
|
126
|
+
|
|
127
|
+
* be set in the constructor
|
|
128
|
+
* or be accessed through a method with lazy initialization / memoization.
|
|
129
|
+
|
|
130
|
+
If not, _Instance Variable Assumption_ will be reported.
|
|
131
|
+
|
|
132
|
+
## Using Instance Variable Assumption in a Rails context
|
|
133
|
+
|
|
134
|
+
In ActiveRecord it seems common to use callbacks like `after_initialize` to initialize instance variables as
|
|
135
|
+
outlined [here](https://stackoverflow.com/questions/41165520/overriding-applicationrecord-initialize-bad-idea)
|
|
136
|
+
or [here](http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html)
|
|
137
|
+
instead of overriding the `initialize` method.
|
|
138
|
+
If an instance variable is initialized in such a callback Reek will report it correspondingly.
|
|
139
|
+
|
|
140
|
+
This would smell for instance:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
class Sample < ApplicationRecord
|
|
144
|
+
after_initialize do
|
|
145
|
+
@my_var = false
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Since Reek cannot reliably detect that is used in a Rails context we recommend to disable this detector
|
|
151
|
+
for "app/models" like this:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
directories:
|
|
155
|
+
# Your other configuration....
|
|
156
|
+
"app/models":
|
|
157
|
+
InstanceVariableAssumption:
|
|
158
|
+
enabled: false
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Configuration
|
|
162
|
+
|
|
163
|
+
_Instance Variable Assumption_ supports the [Basic Smell Options](Basic-Smell-Options.md).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Irresponsible Module
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Classes and modules are the units of reuse and release. It is therefore
|
|
6
|
+
considered good practice to annotate every class and module with a brief
|
|
7
|
+
comment outlining its responsibilities.
|
|
8
|
+
|
|
9
|
+
For further guideline on how to write good documentation in Ruby, see these
|
|
10
|
+
links:
|
|
11
|
+
- [Rails API documentation guidelines](http://edgeguides.rubyonrails.org/api_documentation_guidelines.html)
|
|
12
|
+
- [Comments tell you why](https://blog.codinghorror.com/code-tells-you-how-comments-tell-you-why/)
|
|
13
|
+
|
|
14
|
+
## Example
|
|
15
|
+
|
|
16
|
+
Given
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
class Dummy
|
|
20
|
+
# Do things...
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Reek would emit the following warning:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
test.rb -- 1 warning:
|
|
28
|
+
[1]:IrresponsibleModule: Dummy has no descriptive comment
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Fixing this is simple - just an explaining comment:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
# The Dummy class is responsible for ...
|
|
35
|
+
class Dummy
|
|
36
|
+
# Do things...
|
|
37
|
+
end
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Current Support in Reek
|
|
41
|
+
|
|
42
|
+
_Irresponsible Module_ checks classes and modules, including those
|
|
43
|
+
created through `Struct.new` and `Class.new` and directly assigned to a constant.
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
_Irresponsible Module_ supports only the [Basic Smell Options](Basic-Smell-Options.md).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2008,2009 Kevin Rutherford
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Large Class
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A _Large Class_ is a class or module that has a large number of instance
|
|
6
|
+
variables, methods or lines of code in any one piece of its specification.
|
|
7
|
+
(That is, this smell relates to pieces of the class's specification, not to the
|
|
8
|
+
size of the corresponding instance of `Class`.)
|
|
9
|
+
|
|
10
|
+
## Current Support in Reek
|
|
11
|
+
|
|
12
|
+
Reek offers three checks in this category.
|
|
13
|
+
|
|
14
|
+
* [Too Many Constants](Too-Many-Constants.md)
|
|
15
|
+
* [Too Many Instance Variables](Too-Many-Instance-Variables.md)
|
|
16
|
+
* [Too Many Methods](Too-Many-Methods.md)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Long Parameter List
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A _Long Parameter List_ occurs when a method has a lot of parameters.
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
Given
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
class Dummy
|
|
13
|
+
def long_list(foo,bar,baz,fling,flung)
|
|
14
|
+
puts foo,bar,baz,fling,flung
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Reek would report the following warning:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
test.rb -- 1 warning:
|
|
23
|
+
[2]:Dummy#long_list has 5 parameters (LongParameterList)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A common solution to this problem would be the introduction of parameter objects.
|
|
27
|
+
|
|
28
|
+
## Current Support in Reek
|
|
29
|
+
|
|
30
|
+
_Long Parameter List_ reports any method or block with more than 3 parameters.
|
|
31
|
+
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
Reek's _Long Parameter List_ detector supports the
|
|
35
|
+
[Basic Smell Options](Basic-Smell-Options.md), plus:
|
|
36
|
+
|
|
37
|
+
| Option | Value | Effect |
|
|
38
|
+
| -------------|---------|---------|
|
|
39
|
+
| `max_params` | integer | The maximum number of parameters allowed in a method or block before a warning is issued. Defaults to 3. |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Long Yield List
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A _Long Yield List_ occurs when a method yields a lot of arguments to the block
|
|
6
|
+
it gets passed. It is a special case of [Long Parameter List](Long-Parameter-List.md).
|
|
7
|
+
|
|
8
|
+
## Example
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
class Dummy
|
|
12
|
+
def yields_a_lot(foo,bar,baz,fling,flung)
|
|
13
|
+
yield foo,bar,baz,fling,flung
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Reek would report the following warning:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
test.rb -- 1 warning:
|
|
22
|
+
[4]:Dummy#yields_a_lot yields 5 parameters (LongYieldList)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
A common solution to this problem would be the introduction of parameter objects.
|
|
26
|
+
|
|
27
|
+
## Current Support in Reek
|
|
28
|
+
|
|
29
|
+
Currently _Long Yield List_ reports any method or block with more than 3 parameters.
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
Reek's _Long Yield List_ detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
|
|
34
|
+
|
|
35
|
+
| Option | Value | Effect |
|
|
36
|
+
| -------------|---------|---------|
|
|
37
|
+
| `max_params` | integer | The maximum number of parameters allowed in a method or block before a warning is issued. Defaults to 3. |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
## Introduction
|
|
2
|
+
|
|
3
|
+
Reek reports a _Manual Dispatch_ smell if it finds source code that manually checks whether an object responds to a method before that method is called. Manual dispatch is a type of [Simulated Polymorphism](Simulated-Polymorphism.md) which leads to code that is harder to reason about, debug, and refactor.
|
|
4
|
+
|
|
5
|
+
## Example
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
class MyManualDispatcher
|
|
9
|
+
attr_reader :foo
|
|
10
|
+
|
|
11
|
+
def initialize(foo)
|
|
12
|
+
@foo = foo
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
foo.bar if foo.respond_to?(:bar)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Reek would emit the following warning:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
test.rb -- 1 warning:
|
|
25
|
+
[9]: MyManualDispatcher manually dispatches method call (ManualDispatch)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
_Manual Dispatch_ offers the [Basic Smell Options](Basic-Smell-Options.md).
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Missing Safe Method
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Candidate methods for the _Missing Safe Method_ smell are methods whose names
|
|
6
|
+
end with an exclamation mark.
|
|
7
|
+
|
|
8
|
+
An exclamation mark in method names means (the explanation below is taken from
|
|
9
|
+
[here](http://dablog.rubypal.com/2007/8/15/bang-methods-or-danger-will-rubyist)):
|
|
10
|
+
|
|
11
|
+
> The ! in method names that end with ! means, “This method is dangerous”—or,
|
|
12
|
+
> more precisely, this method is the “dangerous” version of an otherwise
|
|
13
|
+
> equivalent method, with the same name minus the !. “Danger” is relative; the
|
|
14
|
+
> ! doesn’t mean anything at all unless the method name it’s in corresponds to
|
|
15
|
+
> a similar but bang-less method name.
|
|
16
|
+
>
|
|
17
|
+
> So, for example, gsub! is the dangerous version of gsub. exit! is the
|
|
18
|
+
> dangerous version of exit. flatten! is the dangerous version of flatten. And
|
|
19
|
+
> so forth.
|
|
20
|
+
|
|
21
|
+
Such a method is called _Missing Safe Method_ if and only if the non-bang
|
|
22
|
+
version does not exist and this method is reported as a smell.
|
|
23
|
+
|
|
24
|
+
Missing Safe Method was formerly known as Prima Donna Method.
|
|
25
|
+
|
|
26
|
+
## Example
|
|
27
|
+
|
|
28
|
+
Given
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
class C
|
|
32
|
+
def foo; end
|
|
33
|
+
def foo!; end
|
|
34
|
+
def bar!; end
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Reek would report the _Missing Safe Method_ smell for `bar!`, but not for `foo!`.
|
|
39
|
+
|
|
40
|
+
Reek reports this smell only in a class context, not in a module context in order to allow perfectly legit code like this:
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
class Parent
|
|
45
|
+
def foo; end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module Dangerous
|
|
49
|
+
def foo!; end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Son < Parent
|
|
53
|
+
include Dangerous
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Daughter < Parent
|
|
57
|
+
end
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
In this example, Reek would not report the _Missing Safe Method_ smell for the
|
|
61
|
+
method `foo` of the `Dangerous` module.
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
_Missing Safe Method_ offers the [Basic Smell Options](Basic-Smell-Options.md).
|
|
66
|
+
|
|
67
|
+
## Example configuration via source comment
|
|
68
|
+
|
|
69
|
+
Imagine code like this:
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
class Alfa
|
|
73
|
+
def bravo!
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This would report:
|
|
79
|
+
|
|
80
|
+
>>
|
|
81
|
+
ruby.rb -- 1 warning:
|
|
82
|
+
[1]:MissingSafeMethod: Alfa has missing safe method 'bravo!'
|
|
83
|
+
|
|
84
|
+
If you want to suppress this warning you can do this via source comment like this:
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
# :reek:MissingSafeMethod { exclude: [ bravo! ] }
|
|
88
|
+
class Alfa
|
|
89
|
+
def bravo!
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Module Initialize
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A module is usually a mixin, so when an `#initialize` method is present it is
|
|
6
|
+
hard to tell initialization order and parameters so having `#initialize`
|
|
7
|
+
in a module is usually a bad idea.
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
The `Foo` module below contains a method `initialize`. Although class `B` inherits from `A`, the inclusion of `Foo` stops `A#initialize` from being called.
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
class A
|
|
15
|
+
def initialize(a)
|
|
16
|
+
@a = a
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module Foo
|
|
21
|
+
def initialize(foo)
|
|
22
|
+
@foo = foo
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class B < A
|
|
27
|
+
include Foo
|
|
28
|
+
|
|
29
|
+
def initialize(b)
|
|
30
|
+
super('bar')
|
|
31
|
+
@b = b
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
A simple solution is to rename `Foo#initialize` and call that method by name:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
module Foo
|
|
40
|
+
def setup_foo_module(foo)
|
|
41
|
+
@foo = foo
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class B < A
|
|
46
|
+
include Foo
|
|
47
|
+
|
|
48
|
+
def initialize(b)
|
|
49
|
+
super 'bar'
|
|
50
|
+
setup_foo_module('foo')
|
|
51
|
+
@b = b
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Current Support in Reek
|
|
57
|
+
|
|
58
|
+
Reek warns about module initialize when an instance method named `initialize` is present in a module.
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
Module Initialize supports the [Basic Smell Options](Basic-Smell-Options.md).
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Nested Iterators
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A _Nested Iterator_ occurs when a block contains another block.
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
Given
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
class Duck
|
|
13
|
+
class << self
|
|
14
|
+
def duck_names
|
|
15
|
+
%i!tick trick track!.each do |surname|
|
|
16
|
+
%i!duck!.each do |last_name|
|
|
17
|
+
puts "full name is #{surname} #{last_name}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Reek would report the following warning:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
test.rb -- 1 warning:
|
|
29
|
+
[5]:Duck#duck_names contains iterators nested 2 deep (NestedIterators)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Current Support in Reek
|
|
33
|
+
|
|
34
|
+
_Nested Iterators_ reports failing methods only once.
|
|
35
|
+
`Object#tap` is ignored by default and thus does not count as iterator.
|
|
36
|
+
Furthermore iterators without block arguments are not counted, e.g.:
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
def foo
|
|
41
|
+
before do
|
|
42
|
+
item.each do |part|
|
|
43
|
+
puts part
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
would not smell of NestedIterators (given a maximum allowed nesting of 1) since the
|
|
50
|
+
`before` would not be counted (because it doesn't pass any arguments to the block).
|
|
51
|
+
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
_Nested Iterators_ offers the [Basic Smell Options](Basic-Smell-Options.md), plus:
|
|
55
|
+
|
|
56
|
+
| Option | Value | Effect |
|
|
57
|
+
| ----------------------|---------|---------|
|
|
58
|
+
| `max_allowed_nesting` | integer | The maximum depth of nested iterators. Defaults to 1 |
|
|
59
|
+
| `ignore_iterators` | Array | List of iterators to be excluded from the smell check. Includes only `tap` at the moment|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Nil Check
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
A _Nil Check_ is a type check. Failures of _Nil Check_ violate the
|
|
6
|
+
["tell, don't ask"](http://robots.thoughtbot.com/tell-dont-ask) principle.
|
|
7
|
+
Additionally to that, type checks often mask bigger problems in your source
|
|
8
|
+
code like not using OOP and / or polymorphism when you should.
|
|
9
|
+
|
|
10
|
+
The _Nil Check_ code smell is a case of [Simulated Polymorphism](Simulated-Polymorphism.md).
|
|
11
|
+
|
|
12
|
+
## Example
|
|
13
|
+
|
|
14
|
+
Given
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
class Klass
|
|
18
|
+
def nil_checker(argument)
|
|
19
|
+
if argument.nil?
|
|
20
|
+
puts "argument is nil!"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Reek would emit the following warning:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
test.rb -- 1 warning:
|
|
30
|
+
[3]:Klass#nil_checker performs a nil-check. (NilCheck)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Current Support in Reek
|
|
34
|
+
|
|
35
|
+
_Nil Check_ reports use of
|
|
36
|
+
|
|
37
|
+
* <code>.nil?</code> method
|
|
38
|
+
* <code>==</code> and <code>===</code> operators when checking vs. <code>nil</code>
|
|
39
|
+
* case statements that use syntax like <code>when nil</code>
|
|
40
|
+
|
|
41
|
+
_Nil Check_ allows use of
|
|
42
|
+
|
|
43
|
+
* the safe navigation operator like `foo&.bar`
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
_Nil Check_ offers the [Basic Smell Options](Basic-Smell-Options.md).
|