reek 3.9.1 → 3.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +7 -0
- data/.dockerignore +26 -0
- data/CHANGELOG.md +6 -0
- data/Dockerfile +28 -0
- data/bin/code_climate_reek +57 -0
- data/engine.json +11 -0
- data/lib/reek/report/code_climate/code_climate_configuration.yml +664 -0
- data/lib/reek/report/{code_climate_formatter.rb → code_climate/code_climate_formatter.rb} +20 -3
- data/lib/reek/report/formatter.rb +2 -2
- data/lib/reek/report/report.rb +3 -1
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +1 -1
- data/spec/reek/report/code_climate_formatter_spec.rb +26 -45
- data/spec/reek/report/code_climate_report_spec.rb +23 -37
- metadata +13 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb34a3d020ec6d9c214ba0601080f6f3f1be9f62
|
4
|
+
data.tar.gz: 7f9ce71ca71ef44adad6fc79f99abeef88f72a02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1f7e66b52c231fe72f07e209ca06bd3abe9f65af64e9b886d1137b744f244cd93de634769da9598f6bd403d82bfce674d4ace97118b77d19c5d19da974f6496
|
7
|
+
data.tar.gz: d43adf2de2ffb4ec3a4351afed0ddd1be460b1d1dbfcd10afd3a04a15e747d54da7132c56f5cc324e44c39ad167546204195f96ef6b35e024af142d41852fd10
|
data/.codeclimate.yml
ADDED
data/.dockerignore
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Folders
|
2
|
+
|
3
|
+
.git
|
4
|
+
.idea
|
5
|
+
docs
|
6
|
+
features
|
7
|
+
logo
|
8
|
+
pkg
|
9
|
+
spec
|
10
|
+
tasks
|
11
|
+
tmp
|
12
|
+
|
13
|
+
# Files
|
14
|
+
|
15
|
+
.dockerignore
|
16
|
+
.gitignore
|
17
|
+
.rubocop.yml
|
18
|
+
.travis.yml
|
19
|
+
.yardopts
|
20
|
+
ataru_setup.rb
|
21
|
+
CHANGELOG.md
|
22
|
+
CONTRIBUTING.md
|
23
|
+
defaults.reek
|
24
|
+
Dockerfile
|
25
|
+
Rakefile
|
26
|
+
README.md
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 3.10.0 (2016-01-27)
|
6
|
+
|
7
|
+
* Add CodeClimate Docker integration. This will allow users to deduct their own docker image
|
8
|
+
from the existing one and use it for their own CI set up in whatever ways they see fit.
|
9
|
+
Furthermore this will enable users to run `Reek` locally in combination with `codeclimate cli`.
|
10
|
+
|
5
11
|
## 3.9.1 (2016-01-24)
|
6
12
|
|
7
13
|
* (troessner) Actually use the corresponding parser for Ruby 2.3
|
data/Dockerfile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# CodeClimate specification: https://github.com/codeclimate/spec/blob/master/SPEC.md
|
2
|
+
#
|
3
|
+
# Build and run via:
|
4
|
+
# docker build -t codeclimate/codeclimate-reek . && docker run codeclimate/codeclimate-reek
|
5
|
+
|
6
|
+
FROM codeclimate/alpine-ruby:b38
|
7
|
+
|
8
|
+
MAINTAINER The Reek core team
|
9
|
+
|
10
|
+
ENV code_dir /code
|
11
|
+
ENV app_dir /usr/src/app
|
12
|
+
ENV user app
|
13
|
+
|
14
|
+
RUN apk --update add git
|
15
|
+
|
16
|
+
ADD . ${app_dir}
|
17
|
+
|
18
|
+
WORKDIR ${app_dir}
|
19
|
+
|
20
|
+
RUN bundle install --without debugging development
|
21
|
+
RUN adduser -u 9000 -D ${user}
|
22
|
+
RUN chown -R ${user}:${user} ${app_dir}
|
23
|
+
|
24
|
+
VOLUME ${code_dir}
|
25
|
+
WORKDIR ${code_dir}
|
26
|
+
USER ${user}
|
27
|
+
|
28
|
+
CMD [ "/usr/src/app/bin/code_climate_reek" ]
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Wrapper for the CodeClimate integration.
|
4
|
+
|
5
|
+
require_relative '../lib/reek'
|
6
|
+
require_relative '../lib/reek/cli/application'
|
7
|
+
|
8
|
+
# Map input coming from CodeClimate to Reek.
|
9
|
+
class CodeClimateToReek
|
10
|
+
# Following the spec (https://github.com/codeclimate/spec/blob/master/SPEC.md)
|
11
|
+
# we have to exit with a zero for both failure and success.
|
12
|
+
ENGINE_CONFIGURATION = [
|
13
|
+
'-f', 'code_climate',
|
14
|
+
'--failure-exit-code', '0',
|
15
|
+
'--success-exit-code', '0'
|
16
|
+
]
|
17
|
+
|
18
|
+
attr_reader :configuration_file_path, :include_paths_key, :include_paths_default
|
19
|
+
|
20
|
+
def initialize(configuration_file_path: '/config.json',
|
21
|
+
include_paths_key: 'include_paths',
|
22
|
+
include_paths_default: [])
|
23
|
+
@configuration_file_path = configuration_file_path
|
24
|
+
@include_paths_key = include_paths_key
|
25
|
+
@include_paths_default = include_paths_default
|
26
|
+
end
|
27
|
+
|
28
|
+
def cli_arguments
|
29
|
+
include_paths + ENGINE_CONFIGURATION
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def configuration_file_exists?
|
35
|
+
Pathname.new(configuration_file_path).exist?
|
36
|
+
end
|
37
|
+
|
38
|
+
# The config.json file we try to read below might look like this:
|
39
|
+
# {
|
40
|
+
# "include_paths":[
|
41
|
+
# "lib",
|
42
|
+
# "spec"
|
43
|
+
# ]
|
44
|
+
# }
|
45
|
+
def include_paths
|
46
|
+
if configuration_file_exists?
|
47
|
+
config = JSON.parse File.read(configuration_file_path)
|
48
|
+
config.fetch include_paths_key, include_paths_default
|
49
|
+
else
|
50
|
+
include_paths_default
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
application = Reek::CLI::Application.new(CodeClimateToReek.new.cli_arguments)
|
56
|
+
|
57
|
+
exit application.execute
|
data/engine.json
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
{
|
2
|
+
"name": "Reek",
|
3
|
+
"description": "Reek is a tool that examines Ruby classes, modules and methods and reports any code smells it finds.",
|
4
|
+
"maintainer": {
|
5
|
+
"name": "Matijs van Zuijlen, Piotr Szotkowski, Timo Rößner",
|
6
|
+
"email": "timo.roessner@googlemail.com"
|
7
|
+
},
|
8
|
+
"languages" : ["Ruby"],
|
9
|
+
"version": "0.1",
|
10
|
+
"spec_version": "0.0.1"
|
11
|
+
}
|
@@ -0,0 +1,664 @@
|
|
1
|
+
---
|
2
|
+
Attribute:
|
3
|
+
remediation_points: 250_000
|
4
|
+
content: |
|
5
|
+
A class that publishes a setter for an instance variable invites client classes to become too intimate with its inner workings, and in particular with its representation of state.
|
6
|
+
|
7
|
+
The same holds to a lesser extent for getters, but Reek doesn't flag those.
|
8
|
+
|
9
|
+
## Example
|
10
|
+
|
11
|
+
Given:
|
12
|
+
|
13
|
+
```Ruby
|
14
|
+
class Klass
|
15
|
+
attr_accessor :dummy
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
Reek would emit the following warning:
|
20
|
+
|
21
|
+
```
|
22
|
+
reek test.rb
|
23
|
+
|
24
|
+
test.rb -- 1 warning:
|
25
|
+
[2]:Klass declares the writable attribute dummy (Attribute)
|
26
|
+
```
|
27
|
+
BooleanParameter:
|
28
|
+
remediation_points: 500_000
|
29
|
+
content: |
|
30
|
+
`Boolean Parameter` is a special case of `Control Couple`, where a method parameter is defaulted to true or false. A _Boolean Parameter_ effectively permits a method's caller to decide which execution path to take. This is a case of bad cohesion. You're creating a dependency between methods that is not really necessary, thus increasing coupling.
|
31
|
+
|
32
|
+
## Example
|
33
|
+
|
34
|
+
Given
|
35
|
+
|
36
|
+
```Ruby
|
37
|
+
class Dummy
|
38
|
+
def hit_the_switch(switch = true)
|
39
|
+
if switch
|
40
|
+
puts 'Hitting the switch'
|
41
|
+
# do other things...
|
42
|
+
else
|
43
|
+
puts 'Not hitting the switch'
|
44
|
+
# do other things...
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Reek would emit the following warning:
|
51
|
+
|
52
|
+
```
|
53
|
+
test.rb -- 3 warnings:
|
54
|
+
[1]:Dummy#hit_the_switch has boolean parameter 'switch' (BooleanParameter)
|
55
|
+
[2]:Dummy#hit_the_switch is controlled by argument switch (ControlParameter)
|
56
|
+
```
|
57
|
+
|
58
|
+
Note that both smells are reported, `Boolean Parameter` and `Control Parameter`.
|
59
|
+
|
60
|
+
## Getting rid of the smell
|
61
|
+
|
62
|
+
This is highly dependant on your exact architecture, but looking at the example above what you could do is:
|
63
|
+
|
64
|
+
* Move everything in the `if` branch into a separate method
|
65
|
+
* Move everything in the `else` branch into a separate method
|
66
|
+
* Get rid of the `hit_the_switch` method alltogether
|
67
|
+
* Make the decision what method to call in the initial caller of `hit_the_switch`
|
68
|
+
ClassVariable:
|
69
|
+
remediation_points: 350_000
|
70
|
+
content: |
|
71
|
+
Class variables form part of the global runtime state, and as such make it easy for one part of the system to accidentally or inadvertently depend on another part of the system. So the system becomes more prone to problems where changing something over here breaks something over there. In particular, class variables can make it hard to set up tests (because the context of the test includes all global state).
|
72
|
+
|
73
|
+
For a detailed explanation, check out [this article](http://4thmouse.com/index.php/2011/03/20/why-class-variables-in-ruby-are-a-bad-idea/)
|
74
|
+
|
75
|
+
## Example
|
76
|
+
|
77
|
+
Given
|
78
|
+
|
79
|
+
```Ruby
|
80
|
+
class Dummy
|
81
|
+
@@class_variable = :whatever
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
Reek would emit the following warning:
|
86
|
+
|
87
|
+
```
|
88
|
+
reek test.rb
|
89
|
+
|
90
|
+
test.rb -- 1 warning:
|
91
|
+
[2]:Dummy declares the class variable @@class_variable (ClassVariable)
|
92
|
+
```
|
93
|
+
|
94
|
+
## Getting rid of the smell
|
95
|
+
|
96
|
+
You can use class-instance variable to mitigate the problem (as also suggested in the linked article above):
|
97
|
+
|
98
|
+
```Ruby
|
99
|
+
class Dummy
|
100
|
+
@class_variable = :whatever
|
101
|
+
end
|
102
|
+
```
|
103
|
+
ControlParameter:
|
104
|
+
remediation_points: 500_000
|
105
|
+
content: |
|
106
|
+
`Control Parameter` is a special case of `Control Couple`
|
107
|
+
|
108
|
+
## Example
|
109
|
+
|
110
|
+
A simple example would be the "quoted" parameter in the following method:
|
111
|
+
|
112
|
+
```Ruby
|
113
|
+
def write(quoted)
|
114
|
+
if quoted
|
115
|
+
write_quoted @value
|
116
|
+
else
|
117
|
+
write_unquoted @value
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
Fixing those problems is out of the scope of this document but an easy solution could be to remove the "write" method alltogether and to move the calls to "write_quoted" / "write_unquoted" in the initial caller of "write".
|
123
|
+
DataClump:
|
124
|
+
remediation_points: 250_000
|
125
|
+
content: |
|
126
|
+
In general, a `Data Clump` occurs when the same two or three items frequently appear together in classes and parameter lists, or when a group of instance variable names start or end with similar substrings.
|
127
|
+
|
128
|
+
The recurrence of the items often means there is duplicate code spread around to handle them. There may be an abstraction missing from the code, making the system harder to understand.
|
129
|
+
|
130
|
+
## Example
|
131
|
+
|
132
|
+
Given
|
133
|
+
|
134
|
+
```Ruby
|
135
|
+
class Dummy
|
136
|
+
def x(y1,y2); end
|
137
|
+
def y(y1,y2); end
|
138
|
+
def z(y1,y2); end
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
Reek would emit the following warning:
|
143
|
+
|
144
|
+
```
|
145
|
+
test.rb -- 1 warning:
|
146
|
+
[2, 3, 4]:Dummy takes parameters [y1, y2] to 3 methods (DataClump)
|
147
|
+
```
|
148
|
+
|
149
|
+
A possible way to fix this problem (quoting from [Martin Fowler](http://martinfowler.com/bliki/DataClump.html)):
|
150
|
+
|
151
|
+
> The first step is to replace data clumps with objects and use the objects whenever you see them. An immediate benefit is that you'll shrink some parameter lists. The interesting stuff happens as you begin to look for behavior to move into the new objects.
|
152
|
+
DuplicateMethodCall:
|
153
|
+
remediation_points: 350_000
|
154
|
+
content: |
|
155
|
+
Duplication occurs when two fragments of code look nearly identical, or when two fragments of code have nearly identical effects at some conceptual level.
|
156
|
+
|
157
|
+
Reek implements a check for _Duplicate Method Call_.
|
158
|
+
|
159
|
+
## Example
|
160
|
+
|
161
|
+
Here's a very much simplified and contrived example. The following method will report a warning:
|
162
|
+
|
163
|
+
```Ruby
|
164
|
+
def double_thing()
|
165
|
+
@other.thing + @other.thing
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
One quick approach to silence Reek would be to refactor the code thus:
|
170
|
+
|
171
|
+
```Ruby
|
172
|
+
def double_thing()
|
173
|
+
thing = @other.thing
|
174
|
+
thing + thing
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
178
|
+
A slightly different approach would be to replace all calls of `double_thing` by calls to `@other.double_thing`:
|
179
|
+
|
180
|
+
```Ruby
|
181
|
+
class Other
|
182
|
+
def double_thing()
|
183
|
+
thing + thing
|
184
|
+
end
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
The approach you take will depend on balancing other factors in your code.
|
189
|
+
FeatureEnvy:
|
190
|
+
remediation_points: 500_000
|
191
|
+
content: |
|
192
|
+
_Feature Envy_ occurs when a code fragment references another object more often than it references itself, or when several clients do the same series of manipulations on a particular type of object.
|
193
|
+
|
194
|
+
_Feature Envy_ reduces the code's ability to communicate intent: code that "belongs" on one class but which is located in another can be hard to find, and may upset the "System of Names" in the host class.
|
195
|
+
|
196
|
+
_Feature Envy_ also affects the design's flexibility: A code fragment that is in the wrong class creates couplings that may not be natural within the application's domain, and creates a loss of cohesion in the unwilling host class.
|
197
|
+
|
198
|
+
_Feature Envy_ often arises because it must manipulate other objects (usually its arguments) to get them into a useful form, and one force preventing them (the arguments) doing this themselves is that the common knowledge lives outside the arguments, or the arguments are of too basic a type to justify extending that type. Therefore there must be something which 'knows' about the contents or purposes of the arguments. That thing would have to be more than just a basic type, because the basic types are either containers which don't know about their contents, or they are single objects which can't capture their relationship with their fellows of the same type. So, this thing with the extra knowledge should be reified into a class, and the utility method will most likely belong there.
|
199
|
+
|
200
|
+
## Example
|
201
|
+
|
202
|
+
Running Reek on:
|
203
|
+
|
204
|
+
```Ruby
|
205
|
+
class Warehouse
|
206
|
+
def sale_price(item)
|
207
|
+
(item.price - item.rebate) * @vat
|
208
|
+
end
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
would report:
|
213
|
+
|
214
|
+
```Bash
|
215
|
+
Warehouse#total_price refers to item more than self (FeatureEnvy)
|
216
|
+
```
|
217
|
+
|
218
|
+
since this:
|
219
|
+
|
220
|
+
```Ruby
|
221
|
+
(item.price - item.rebate)
|
222
|
+
```
|
223
|
+
|
224
|
+
belongs to the Item class, not the Warehouse.
|
225
|
+
IrresponsibleModule:
|
226
|
+
remediation_points: 350_000
|
227
|
+
content: |
|
228
|
+
Classes and modules are the units of reuse and release. It is therefore considered good practice to annotate every class and module with a brief comment outlining its responsibilities.
|
229
|
+
|
230
|
+
## Example
|
231
|
+
|
232
|
+
Given
|
233
|
+
|
234
|
+
```Ruby
|
235
|
+
class Dummy
|
236
|
+
# Do things...
|
237
|
+
end
|
238
|
+
```
|
239
|
+
|
240
|
+
Reek would emit the following warning:
|
241
|
+
|
242
|
+
```
|
243
|
+
test.rb -- 1 warning:
|
244
|
+
[1]:Dummy has no descriptive comment (IrresponsibleModule)
|
245
|
+
```
|
246
|
+
|
247
|
+
Fixing this is simple - just an explaining comment:
|
248
|
+
|
249
|
+
```Ruby
|
250
|
+
# The Dummy class is responsible for ...
|
251
|
+
class Dummy
|
252
|
+
# Do things...
|
253
|
+
end
|
254
|
+
```
|
255
|
+
LongParameterList:
|
256
|
+
remediation_points: 500_000
|
257
|
+
content: |
|
258
|
+
A `Long Parameter List` occurs when a method has a lot of parameters.
|
259
|
+
|
260
|
+
## Example
|
261
|
+
|
262
|
+
Given
|
263
|
+
|
264
|
+
```Ruby
|
265
|
+
class Dummy
|
266
|
+
def long_list(foo,bar,baz,fling,flung)
|
267
|
+
puts foo,bar,baz,fling,flung
|
268
|
+
end
|
269
|
+
end
|
270
|
+
```
|
271
|
+
|
272
|
+
Reek would report the following warning:
|
273
|
+
|
274
|
+
```
|
275
|
+
test.rb -- 1 warning:
|
276
|
+
[2]:Dummy#long_list has 5 parameters (LongParameterList)
|
277
|
+
```
|
278
|
+
|
279
|
+
A common solution to this problem would be the introduction of parameter objects.
|
280
|
+
LongYieldList:
|
281
|
+
remediation_points: 500_000
|
282
|
+
content: |
|
283
|
+
A _Long Yield List_ occurs when a method yields a lot of arguments to the block it gets passed.
|
284
|
+
|
285
|
+
## Example
|
286
|
+
|
287
|
+
```Ruby
|
288
|
+
class Dummy
|
289
|
+
def yields_a_lot(foo,bar,baz,fling,flung)
|
290
|
+
yield foo,bar,baz,fling,flung
|
291
|
+
end
|
292
|
+
end
|
293
|
+
```
|
294
|
+
|
295
|
+
Reek would report the following warning:
|
296
|
+
|
297
|
+
```
|
298
|
+
test.rb -- 1 warning:
|
299
|
+
[4]:Dummy#yields_a_lot yields 5 parameters (LongYieldList)
|
300
|
+
```
|
301
|
+
|
302
|
+
A common solution to this problem would be the introduction of parameter objects.
|
303
|
+
ModuleInitialize:
|
304
|
+
remediation_points: 350_000
|
305
|
+
content: |
|
306
|
+
A module is usually a mixin, so when an `#initialize` method is present it is
|
307
|
+
hard to tell initialization order and parameters so having `#initialize`
|
308
|
+
in a module is usually a bad idea.
|
309
|
+
|
310
|
+
## Example
|
311
|
+
|
312
|
+
The `Foo` module below contains a method `initialize`. Although class `B` inherits from `A`, the inclusion of `Foo` stops `A#initialize` from being called.
|
313
|
+
|
314
|
+
```Ruby
|
315
|
+
class A
|
316
|
+
def initialize(a)
|
317
|
+
@a = a
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
module Foo
|
322
|
+
def initialize(foo)
|
323
|
+
@foo = foo
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class B < A
|
328
|
+
include Foo
|
329
|
+
|
330
|
+
def initialize(b)
|
331
|
+
super('bar')
|
332
|
+
@b = b
|
333
|
+
end
|
334
|
+
end
|
335
|
+
```
|
336
|
+
|
337
|
+
A simple solution is to rename `Foo#initialize` and call that method by name:
|
338
|
+
|
339
|
+
```Ruby
|
340
|
+
module Foo
|
341
|
+
def setup_foo_module(foo)
|
342
|
+
@foo = foo
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
class B < A
|
347
|
+
include Foo
|
348
|
+
|
349
|
+
def initialize(b)
|
350
|
+
super 'bar'
|
351
|
+
setup_foo_module('foo')
|
352
|
+
@b = b
|
353
|
+
end
|
354
|
+
end
|
355
|
+
```
|
356
|
+
NestedIterators:
|
357
|
+
remediation_points: 500_000
|
358
|
+
content: |
|
359
|
+
A `Nested Iterator` occurs when a block contains another block.
|
360
|
+
|
361
|
+
## Example
|
362
|
+
|
363
|
+
Given
|
364
|
+
|
365
|
+
```Ruby
|
366
|
+
class Duck
|
367
|
+
class << self
|
368
|
+
def duck_names
|
369
|
+
%i!tick trick track!.each do |surname|
|
370
|
+
%i!duck!.each do |last_name|
|
371
|
+
puts "full name is #{surname} #{last_name}"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
```
|
378
|
+
|
379
|
+
Reek would report the following warning:
|
380
|
+
|
381
|
+
```
|
382
|
+
test.rb -- 1 warning:
|
383
|
+
[5]:Duck#duck_names contains iterators nested 2 deep (NestedIterators)
|
384
|
+
```
|
385
|
+
NilCheck:
|
386
|
+
remediation_points: 250_000
|
387
|
+
content: |
|
388
|
+
A `NilCheck` is a type check. Failures of `NilCheck` violate the ["tell, don't ask"](http://robots.thoughtbot.com/tell-dont-ask) principle.
|
389
|
+
|
390
|
+
Additionally, type checks often mask bigger problems in your source code like not using OOP and / or polymorphism when you should.
|
391
|
+
|
392
|
+
## Example
|
393
|
+
|
394
|
+
Given
|
395
|
+
|
396
|
+
```Ruby
|
397
|
+
class Klass
|
398
|
+
def nil_checker(argument)
|
399
|
+
if argument.nil?
|
400
|
+
puts "argument isn't nil!"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
```
|
405
|
+
|
406
|
+
Reek would emit the following warning:
|
407
|
+
|
408
|
+
```
|
409
|
+
test.rb -- 1 warning:
|
410
|
+
[3]:Klass#nil_checker performs a nil-check. (NilCheck)
|
411
|
+
```
|
412
|
+
PrimaDonnaMethod:
|
413
|
+
remediation_points: 250_000
|
414
|
+
content: |
|
415
|
+
A candidate method for the `Prima Donna Method` smell are methods whose names end with an exclamation mark.
|
416
|
+
|
417
|
+
An exclamation mark in method names means (the explanation below is taken from [here](http://dablog.rubypal.com/2007/8/15/bang-methods-or-danger-will-rubyist) ):
|
418
|
+
|
419
|
+
>>
|
420
|
+
The ! in method names that end with ! means, “This method is dangerous”—or, more precisely, this method is the “dangerous” version of an otherwise equivalent method, with the same name minus the !. “Danger” is relative; the ! doesn’t mean anything at all unless the method name it’s in corresponds to a similar but bang-less method name.
|
421
|
+
So, for example, gsub! is the dangerous version of gsub. exit! is the dangerous version of exit. flatten! is the dangerous version of flatten. And so forth.
|
422
|
+
|
423
|
+
Such a method is called `Prima Donna Method` if and only if her non-bang version does not exist and this method is reported as a smell.
|
424
|
+
|
425
|
+
## Example
|
426
|
+
|
427
|
+
Given
|
428
|
+
|
429
|
+
```Ruby
|
430
|
+
class C
|
431
|
+
def foo; end
|
432
|
+
def foo!; end
|
433
|
+
def bar!; end
|
434
|
+
end
|
435
|
+
```
|
436
|
+
|
437
|
+
Reek would report `bar!` as `prima donna method` smell but not `foo!`.
|
438
|
+
|
439
|
+
Reek reports this smell only in a class context, not in a module context in order to allow perfectly legit code like this:
|
440
|
+
|
441
|
+
|
442
|
+
```Ruby
|
443
|
+
class Parent
|
444
|
+
def foo; end
|
445
|
+
end
|
446
|
+
|
447
|
+
module Dangerous
|
448
|
+
def foo!; end
|
449
|
+
end
|
450
|
+
|
451
|
+
class Son < Parent
|
452
|
+
include Dangerous
|
453
|
+
end
|
454
|
+
|
455
|
+
class Daughter < Parent
|
456
|
+
end
|
457
|
+
```
|
458
|
+
|
459
|
+
In this example, Reek would not report the `prima donna method` smell for the method `foo` of the `Dangerous` module.
|
460
|
+
RepeatedConditional:
|
461
|
+
remediation_points: 400_000
|
462
|
+
content: |
|
463
|
+
`Repeated Conditional` is a special case of `Simulated Polymorphism`. Basically it means you are checking the same value throughout a single class and take decisions based on this.
|
464
|
+
|
465
|
+
## Example
|
466
|
+
|
467
|
+
Given
|
468
|
+
|
469
|
+
```Ruby
|
470
|
+
class RepeatedConditionals
|
471
|
+
attr_accessor :switch
|
472
|
+
|
473
|
+
def repeat_1
|
474
|
+
puts "Repeat 1!" if switch
|
475
|
+
end
|
476
|
+
|
477
|
+
def repeat_2
|
478
|
+
puts "Repeat 2!" if switch
|
479
|
+
end
|
480
|
+
|
481
|
+
def repeat_3
|
482
|
+
puts "Repeat 3!" if switch
|
483
|
+
end
|
484
|
+
end
|
485
|
+
```
|
486
|
+
|
487
|
+
Reek would emit the following warning:
|
488
|
+
|
489
|
+
```
|
490
|
+
test.rb -- 4 warnings:
|
491
|
+
[5, 9, 13]:RepeatedConditionals tests switch at least 3 times (RepeatedConditional)
|
492
|
+
```
|
493
|
+
|
494
|
+
If you get this warning then you are probably not using the right abstraction or even more probable, missing an additional abstraction.
|
495
|
+
TooManyInstanceVariables:
|
496
|
+
remediation_points: 500_000
|
497
|
+
content: |
|
498
|
+
`Too Many Instance Variables` is a special case of `LargeClass`.
|
499
|
+
|
500
|
+
## Example
|
501
|
+
|
502
|
+
Given this configuration
|
503
|
+
|
504
|
+
```yaml
|
505
|
+
TooManyInstanceVariables:
|
506
|
+
max_instance_variables: 3
|
507
|
+
```
|
508
|
+
|
509
|
+
and this code:
|
510
|
+
|
511
|
+
```Ruby
|
512
|
+
class TooManyInstanceVariables
|
513
|
+
def initialize
|
514
|
+
@arg_1 = :dummy
|
515
|
+
@arg_2 = :dummy
|
516
|
+
@arg_3 = :dummy
|
517
|
+
@arg_4 = :dummy
|
518
|
+
end
|
519
|
+
end
|
520
|
+
```
|
521
|
+
|
522
|
+
Reek would emit the following warning:
|
523
|
+
|
524
|
+
```
|
525
|
+
test.rb -- 5 warnings:
|
526
|
+
[1]:TooManyInstanceVariables has at least 4 instance variables (TooManyInstanceVariables)
|
527
|
+
```
|
528
|
+
TooManyMethods:
|
529
|
+
remediation_points: 500_000
|
530
|
+
content: |
|
531
|
+
`Too Many Methods` is a special case of `LargeClass`.
|
532
|
+
|
533
|
+
## Example
|
534
|
+
|
535
|
+
Given this configuration
|
536
|
+
|
537
|
+
```yaml
|
538
|
+
TooManyMethods:
|
539
|
+
max_methods: 3
|
540
|
+
```
|
541
|
+
|
542
|
+
and this code:
|
543
|
+
|
544
|
+
```Ruby
|
545
|
+
class TooManyMethods
|
546
|
+
def one; end
|
547
|
+
def two; end
|
548
|
+
def three; end
|
549
|
+
def four; end
|
550
|
+
end
|
551
|
+
```
|
552
|
+
|
553
|
+
Reek would emit the following warning:
|
554
|
+
|
555
|
+
```
|
556
|
+
test.rb -- 1 warning:
|
557
|
+
[1]:TooManyMethods has at least 4 methods (TooManyMethods)
|
558
|
+
```
|
559
|
+
TooManyStatements:
|
560
|
+
remediation_points: 500_000
|
561
|
+
content: |
|
562
|
+
A method with `Too Many Statements` is any method that has a large number of lines.
|
563
|
+
|
564
|
+
`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.
|
565
|
+
|
566
|
+
So the following method would score +6 in Reek's statement-counting algorithm:
|
567
|
+
|
568
|
+
```Ruby
|
569
|
+
def parse(arg, argv, &error)
|
570
|
+
if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
|
571
|
+
return nil, block, nil # +1
|
572
|
+
end
|
573
|
+
opt = (val = parse_arg(val, &error))[1] # +2
|
574
|
+
val = conv_arg(*val) # +3
|
575
|
+
if opt and !arg
|
576
|
+
argv.shift # +4
|
577
|
+
else
|
578
|
+
val[0] = nil # +5
|
579
|
+
end
|
580
|
+
val # +6
|
581
|
+
end
|
582
|
+
```
|
583
|
+
|
584
|
+
(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.)
|
585
|
+
UncommunicativeMethodName:
|
586
|
+
remediation_points: 150_000
|
587
|
+
content: |
|
588
|
+
An `Uncommunicative Method Name` is a method name that doesn't communicate its intent well enough.
|
589
|
+
|
590
|
+
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.
|
591
|
+
UncommunicativeModuleName:
|
592
|
+
remediation_points: 150_000
|
593
|
+
content: |
|
594
|
+
An `Uncommunicative Module Name` is a module name that doesn't communicate its intent well enough.
|
595
|
+
|
596
|
+
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.
|
597
|
+
UncommunicativeParameterName:
|
598
|
+
remediation_points: 150_000
|
599
|
+
content: |
|
600
|
+
An `Uncommunicative Parameter Name` is a parameter name that doesn't communicate its intent well enough.
|
601
|
+
|
602
|
+
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.
|
603
|
+
UncommunicativeVariableName:
|
604
|
+
remediation_points: 150_000
|
605
|
+
content: |
|
606
|
+
An `Uncommunicative Variable Name` is a variable name that doesn't communicate its intent well enough.
|
607
|
+
|
608
|
+
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.
|
609
|
+
UnusedParameters:
|
610
|
+
remediation_points: 200_000
|
611
|
+
content: |
|
612
|
+
`Unused Parameter` refers to methods with parameters that are unused in scope of the method.
|
613
|
+
|
614
|
+
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.
|
615
|
+
|
616
|
+
## Example
|
617
|
+
|
618
|
+
Given:
|
619
|
+
|
620
|
+
```Ruby
|
621
|
+
class Klass
|
622
|
+
def unused_parameters(x,y,z)
|
623
|
+
puts x,y # but not z
|
624
|
+
end
|
625
|
+
end
|
626
|
+
```
|
627
|
+
|
628
|
+
Reek would emit the following warning:
|
629
|
+
|
630
|
+
```
|
631
|
+
[2]:Klass#unused_parameters has unused parameter 'z' (UnusedParameters)
|
632
|
+
```
|
633
|
+
UnusedPrivateMethod:
|
634
|
+
remediation_points: 200_000
|
635
|
+
content: |
|
636
|
+
Classes should use their private methods. Otherwise this is dead
|
637
|
+
code which is confusing and bad for maintenance.
|
638
|
+
|
639
|
+
The `Unused Private Method` detector reports unused private instance
|
640
|
+
methods and instance methods only - class methods are ignored.
|
641
|
+
|
642
|
+
## Example
|
643
|
+
|
644
|
+
Given:
|
645
|
+
|
646
|
+
```Ruby
|
647
|
+
class Car
|
648
|
+
private
|
649
|
+
def drive; end
|
650
|
+
def start; end
|
651
|
+
end
|
652
|
+
```
|
653
|
+
|
654
|
+
`Reek` would emit the following warning:
|
655
|
+
|
656
|
+
```
|
657
|
+
2 warnings:
|
658
|
+
[3]:Car has the unused private instance method `drive` (UnusedPrivateMethod)
|
659
|
+
[4]:Car has the unused private instance method `start` (UnusedPrivateMethod)
|
660
|
+
```
|
661
|
+
UtilityFunction:
|
662
|
+
remediation_points: 250_000
|
663
|
+
content: |
|
664
|
+
A _Utility Function_ is any instance method that has no dependency on the state of the instance.
|
@@ -11,12 +11,14 @@ module Reek
|
|
11
11
|
@warning = warning
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def render
|
15
15
|
CCEngine::Issue.new(check_name: check_name,
|
16
16
|
description: description,
|
17
17
|
categories: categories,
|
18
|
-
location: location
|
19
|
-
|
18
|
+
location: location,
|
19
|
+
remediation_points: remediation_points,
|
20
|
+
content: content
|
21
|
+
).render
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
@@ -41,6 +43,21 @@ module Reek
|
|
41
43
|
line_range: warning_lines.first..warning_lines.last
|
42
44
|
)
|
43
45
|
end
|
46
|
+
|
47
|
+
def remediation_points
|
48
|
+
configuration[warning.smell_type].fetch('remediation_points')
|
49
|
+
end
|
50
|
+
|
51
|
+
def content
|
52
|
+
configuration[warning.smell_type].fetch('content')
|
53
|
+
end
|
54
|
+
|
55
|
+
def configuration
|
56
|
+
@configuration ||= begin
|
57
|
+
config_file = File.expand_path('../code_climate_configuration.yml', __FILE__)
|
58
|
+
YAML.load_file config_file
|
59
|
+
end
|
60
|
+
end
|
44
61
|
end
|
45
62
|
end
|
46
63
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'private_attr/everywhere'
|
2
2
|
require_relative 'location_formatter'
|
3
|
-
require_relative '
|
3
|
+
require_relative 'code_climate/code_climate_formatter'
|
4
4
|
|
5
5
|
module Reek
|
6
6
|
module Report
|
@@ -45,7 +45,7 @@ module Reek
|
|
45
45
|
|
46
46
|
# :reek:UtilityFunction
|
47
47
|
def format_code_climate_hash(warning)
|
48
|
-
CodeClimateFormatter.new(warning).
|
48
|
+
CodeClimateFormatter.new(warning).render
|
49
49
|
end
|
50
50
|
|
51
51
|
private_attr_reader :location_formatter
|
data/lib/reek/report/report.rb
CHANGED
@@ -151,7 +151,9 @@ module Reek
|
|
151
151
|
class CodeClimateReport < Base
|
152
152
|
# @public
|
153
153
|
def show(out = $stdout)
|
154
|
-
|
154
|
+
smells.map do |smell|
|
155
|
+
out.print warning_formatter.format_code_climate_hash(smell)
|
156
|
+
end
|
155
157
|
end
|
156
158
|
end
|
157
159
|
|
data/lib/reek/version.rb
CHANGED
data/reek.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.required_ruby_version = '>= 2.0.0'
|
23
23
|
s.summary = 'Code smell detector for Ruby'
|
24
24
|
|
25
|
-
s.add_runtime_dependency 'codeclimate-engine-rb', '~> 0.1
|
25
|
+
s.add_runtime_dependency 'codeclimate-engine-rb', '~> 0.3.1'
|
26
26
|
s.add_runtime_dependency 'parser', '~> 2.3'
|
27
27
|
s.add_runtime_dependency 'private_attr', '~> 1.1'
|
28
28
|
s.add_runtime_dependency 'rainbow', '~> 2.0'
|
@@ -1,63 +1,44 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
require_lib 'reek/report/code_climate_formatter'
|
2
|
+
require_lib 'reek/report/code_climate/code_climate_formatter'
|
3
|
+
|
4
|
+
RSpec.describe Reek::Report::CodeClimateFormatter, '#render' do
|
5
|
+
let(:warning) do
|
6
|
+
FactoryGirl.build(:smell_warning,
|
7
|
+
smell_detector: Reek::Smells::UtilityFunction.new,
|
8
|
+
context: 'context foo',
|
9
|
+
message: 'message bar',
|
10
|
+
lines: [1, 2],
|
11
|
+
source: 'a/ruby/source/file.rb')
|
12
|
+
end
|
13
|
+
let(:rendered) { Reek::Report::CodeClimateFormatter.new(warning).render }
|
3
14
|
|
4
|
-
RSpec.describe Reek::Report::CodeClimateFormatter, '#to_hash' do
|
5
15
|
it "sets the type as 'issue'" do
|
6
|
-
|
7
|
-
issue = Reek::Report::CodeClimateFormatter.new(warning)
|
8
|
-
|
9
|
-
result = issue.to_hash
|
10
|
-
|
11
|
-
expect(result).to include(type: 'issue')
|
16
|
+
expect(rendered).to match(/\"type\":\"issue\"/)
|
12
17
|
end
|
13
18
|
|
14
19
|
it 'sets the category' do
|
15
|
-
|
16
|
-
issue = Reek::Report::CodeClimateFormatter.new(warning)
|
17
|
-
|
18
|
-
result = issue.to_hash
|
19
|
-
|
20
|
-
expect(result).to include(categories: ['Complexity'])
|
20
|
+
expect(rendered).to match(/\"categories\":\[\"Complexity\"\]/)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'constructs a description based on the context and message' do
|
24
|
-
|
25
|
-
context: 'context foo',
|
26
|
-
message: 'message bar')
|
27
|
-
issue = Reek::Report::CodeClimateFormatter.new(warning)
|
28
|
-
|
29
|
-
result = issue.to_hash
|
30
|
-
|
31
|
-
expect(result).to include(
|
32
|
-
description: 'context foo message bar')
|
24
|
+
expect(rendered).to match(/\"description\":\"context foo message bar\"/)
|
33
25
|
end
|
34
26
|
|
35
27
|
it 'sets a check name based on the smell detector' do
|
36
|
-
|
37
|
-
smell_detector: Reek::Smells::UtilityFunction.new)
|
38
|
-
issue = Reek::Report::CodeClimateFormatter.new(warning)
|
39
|
-
|
40
|
-
result = issue.to_hash
|
41
|
-
|
42
|
-
expect(result).to include(check_name: 'LowCohesion/UtilityFunction')
|
28
|
+
expect(rendered).to match(%r{\"check_name\":\"LowCohesion\/UtilityFunction\"})
|
43
29
|
end
|
44
30
|
|
45
31
|
it 'sets the location' do
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
expect(result).to include(
|
54
|
-
location: {
|
55
|
-
path: 'a/ruby/source/file.rb',
|
56
|
-
lines: {
|
57
|
-
begin: 1,
|
58
|
-
end: 2
|
59
|
-
}
|
60
|
-
}
|
32
|
+
expect(rendered).to match(%r{\"location\":{\"path\":\"a/ruby/source/file.rb\",\"lines\":{\"begin\":1,\"end\":2}}})
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'sets a content based on the smell detector' do
|
36
|
+
expect(rendered).to match(
|
37
|
+
/\"body\":\"A _Utility Function_ is any instance method that has no dependency on the state of the instance.\\n\"/
|
61
38
|
)
|
62
39
|
end
|
40
|
+
|
41
|
+
it 'sets remediation points based on the smell detector' do
|
42
|
+
expect(rendered).to match(/\"remediation_points\":250000/)
|
43
|
+
end
|
63
44
|
end
|
@@ -18,8 +18,8 @@ RSpec.describe Reek::Report::CodeClimateReport do
|
|
18
18
|
context 'with empty source' do
|
19
19
|
let(:source) { '' }
|
20
20
|
|
21
|
-
it 'prints empty
|
22
|
-
expect { instance.show }.to output(
|
21
|
+
it 'prints an empty string' do
|
22
|
+
expect { instance.show }.to output('').to_stdout
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -27,42 +27,28 @@ RSpec.describe Reek::Report::CodeClimateReport do
|
|
27
27
|
let(:source) { 'def simple(a) a[3] end' }
|
28
28
|
|
29
29
|
it 'prints smells as json' do
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
"type": "issue",
|
51
|
-
"check_name": "LowCohesion/UtilityFunction",
|
52
|
-
"description": "simple doesn't depend on instance state (maybe move it to another class?)",
|
53
|
-
"categories": ["Complexity"],
|
54
|
-
"location": {
|
55
|
-
"path": "string",
|
56
|
-
"lines": {
|
57
|
-
"begin": 1,
|
58
|
-
"end": 1
|
59
|
-
}
|
60
|
-
}
|
61
|
-
}
|
62
|
-
]
|
30
|
+
expected = <<-EOS.delete("\n")
|
31
|
+
{\"type\":\"issue\",
|
32
|
+
\"check_name\":\"UncommunicativeName/UncommunicativeParameterName\",
|
33
|
+
\"description\":\"simple has the parameter name 'a'\",
|
34
|
+
\"categories\":[\"Complexity\"],
|
35
|
+
\"location\":{\"path\":\"string\",\"lines\":{\"begin\":1,\"end\":1}},
|
36
|
+
\"remediation_points\":150000,
|
37
|
+
\"content\":{\"body\":\"An `Uncommunicative Parameter Name` is a parameter name that
|
38
|
+
doesn't communicate its intent well enough.\\n\\nPoor names make it hard for the reader
|
39
|
+
to build a mental picture of what's going on in the code. They can also be
|
40
|
+
mis-interpreted; and they hurt the flow of reading, because the reader must slow down
|
41
|
+
to interpret the names.\\n\"}}\u0000
|
42
|
+
{\"type\":\"issue\",
|
43
|
+
\"check_name\":\"LowCohesion/UtilityFunction\",
|
44
|
+
\"description\":\"simple doesn't depend on instance state (maybe move it to another class?)\",
|
45
|
+
\"categories\":[\"Complexity\"],
|
46
|
+
\"location\":{\"path\":\"string\",\"lines\":{\"begin\":1,\"end\":1}},
|
47
|
+
\"remediation_points\":250000,
|
48
|
+
\"content\":{\"body\":\"A _Utility Function_ is any instance method that has no
|
49
|
+
dependency on the state of the instance.\\n\"}}\u0000
|
63
50
|
EOS
|
64
|
-
|
65
|
-
expect(result).to eq expected
|
51
|
+
expect { instance.show }.to output(expected).to_stdout
|
66
52
|
end
|
67
53
|
end
|
68
54
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reek
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Rutherford
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2016-01-
|
14
|
+
date: 2016-01-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: codeclimate-engine-rb
|
@@ -19,14 +19,14 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.1
|
22
|
+
version: 0.3.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.1
|
29
|
+
version: 0.3.1
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: parser
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,23 +75,28 @@ description: |2
|
|
75
75
|
email:
|
76
76
|
- timo.roessner@googlemail.com
|
77
77
|
executables:
|
78
|
+
- code_climate_reek
|
78
79
|
- reek
|
79
80
|
extensions: []
|
80
81
|
extra_rdoc_files:
|
81
82
|
- CHANGELOG.md
|
82
83
|
- License.txt
|
83
84
|
files:
|
85
|
+
- ".codeclimate.yml"
|
86
|
+
- ".dockerignore"
|
84
87
|
- ".gitignore"
|
85
88
|
- ".rubocop.yml"
|
86
89
|
- ".travis.yml"
|
87
90
|
- ".yardopts"
|
88
91
|
- CHANGELOG.md
|
89
92
|
- CONTRIBUTING.md
|
93
|
+
- Dockerfile
|
90
94
|
- Gemfile
|
91
95
|
- License.txt
|
92
96
|
- README.md
|
93
97
|
- Rakefile
|
94
98
|
- ataru_setup.rb
|
99
|
+
- bin/code_climate_reek
|
95
100
|
- bin/reek
|
96
101
|
- defaults.reek
|
97
102
|
- docs/API.md
|
@@ -139,6 +144,7 @@ files:
|
|
139
144
|
- docs/templates/default/docstring/setup.rb
|
140
145
|
- docs/templates/default/fulldoc/html/css/common.css
|
141
146
|
- docs/yard_plugin.rb
|
147
|
+
- engine.json
|
142
148
|
- features/command_line_interface/basic_usage.feature
|
143
149
|
- features/command_line_interface/options.feature
|
144
150
|
- features/command_line_interface/smell_selection.feature
|
@@ -212,7 +218,8 @@ files:
|
|
212
218
|
- lib/reek/examiner.rb
|
213
219
|
- lib/reek/rake/task.rb
|
214
220
|
- lib/reek/report.rb
|
215
|
-
- lib/reek/report/
|
221
|
+
- lib/reek/report/code_climate/code_climate_configuration.yml
|
222
|
+
- lib/reek/report/code_climate/code_climate_formatter.rb
|
216
223
|
- lib/reek/report/formatter.rb
|
217
224
|
- lib/reek/report/heading_formatter.rb
|
218
225
|
- lib/reek/report/html_report.html.erb
|
@@ -394,7 +401,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
394
401
|
version: '0'
|
395
402
|
requirements: []
|
396
403
|
rubyforge_project:
|
397
|
-
rubygems_version: 2.
|
404
|
+
rubygems_version: 2.5.1
|
398
405
|
signing_key:
|
399
406
|
specification_version: 4
|
400
407
|
summary: Code smell detector for Ruby
|