reek 4.7.1 → 4.7.2
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/features/configuration_files/directory_specific_directives.feature +4 -4
- data/lib/reek/ast/node.rb +0 -3
- data/lib/reek/context/attribute_context.rb +2 -2
- data/lib/reek/context/code_context.rb +39 -32
- data/lib/reek/context/method_context.rb +16 -4
- data/lib/reek/context/module_context.rb +1 -2
- data/lib/reek/context/root_context.rb +0 -4
- data/lib/reek/context/send_context.rb +2 -2
- data/lib/reek/context_builder.rb +34 -33
- data/lib/reek/detector_repository.rb +5 -11
- data/lib/reek/smell_detectors/base_detector.rb +13 -14
- data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +11 -12
- data/lib/reek/smell_detectors/unused_private_method.rb +1 -0
- data/lib/reek/tree_dresser.rb +3 -3
- data/lib/reek/version.rb +1 -1
- data/spec/reek/context/code_context_spec.rb +14 -14
- data/spec/reek/context/ghost_context_spec.rb +8 -8
- data/spec/reek/context/method_context_spec.rb +2 -2
- data/spec/reek/context/module_context_spec.rb +3 -3
- data/spec/reek/context_builder_spec.rb +20 -0
- data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -11
- data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +30 -11
- data/spec/reek/smell_detectors/unused_private_method_spec.rb +11 -0
- data/spec/reek/smell_detectors/utility_function_spec.rb +52 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a57753b0b855d7182054e7551940eac44cf57f60
|
|
4
|
+
data.tar.gz: 245074bd6e150589a1bc7a69830a34e3db600a83
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c422c0a25421d8d0abc337766f7b2defae5f7044137c3e5fb7c34fffea7ee409d165f56922f433565fa8643d716cdbb3e9a3c7cec568bfa50bf15b2eed8b254
|
|
7
|
+
data.tar.gz: d4b77922d2745ab3d7f6f053931193b543f646e605a0b3a7f7a444ddf24d3462df4bf7732a248f14fd49f9253925afbf441d3fda578df736b130bfbf80db5096
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Change log
|
|
2
2
|
|
|
3
|
+
## 4.7.2 (2017-07-24)
|
|
4
|
+
|
|
5
|
+
* (mvz) Also report unused uncommunicative parameter names
|
|
6
|
+
* (mvz) Track visibility correctly when using method definition visibility modifiers
|
|
7
|
+
* (mvz) Handle method comments when using method definition visibility modifiers
|
|
8
|
+
|
|
3
9
|
## 4.7.1 (2017-06-12)
|
|
4
10
|
|
|
5
11
|
* (mvz) Improve IrresponsibleModule and fix some bugs along
|
|
@@ -41,7 +41,7 @@ Feature: Directory directives
|
|
|
41
41
|
And a file named "web_app/app/models/user.rb" with:
|
|
42
42
|
"""
|
|
43
43
|
class User < ActiveRecord::Base
|
|
44
|
-
def logged_in_with_role(
|
|
44
|
+
def logged_in_with_role(role)
|
|
45
45
|
true
|
|
46
46
|
end
|
|
47
47
|
end
|
|
@@ -53,7 +53,7 @@ Feature: Directory directives
|
|
|
53
53
|
[1]:InstanceVariableAssumption: UsersController assumes too much for instance variable '@user' [https://github.com/troessner/reek/blob/master/docs/Instance-Variable-Assumption.md]
|
|
54
54
|
web_app/app/models/user.rb -- 2 warnings:
|
|
55
55
|
[1]:IrresponsibleModule: User has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
|
|
56
|
-
[2]:UnusedParameters: User#logged_in_with_role has unused parameter '
|
|
56
|
+
[2]:UnusedParameters: User#logged_in_with_role has unused parameter 'role' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
|
|
57
57
|
3 total warnings
|
|
58
58
|
"""
|
|
59
59
|
|
|
@@ -112,7 +112,7 @@ Feature: Directory directives
|
|
|
112
112
|
And a file named "web_app/app/models/user.rb" with:
|
|
113
113
|
"""
|
|
114
114
|
class User < ActiveRecord::Base
|
|
115
|
-
def logged_in_with_role(
|
|
115
|
+
def logged_in_with_role(role)
|
|
116
116
|
true
|
|
117
117
|
end
|
|
118
118
|
end
|
|
@@ -125,7 +125,7 @@ Feature: Directory directives
|
|
|
125
125
|
[1]:IrresponsibleModule: UsersController has no descriptive comment [https://github.com/troessner/reek/blob/master/docs/Irresponsible-Module.md]
|
|
126
126
|
[4]:NestedIterators: UsersController#show contains iterators nested 2 deep [https://github.com/troessner/reek/blob/master/docs/Nested-Iterators.md]
|
|
127
127
|
web_app/app/models/user.rb -- 1 warning:
|
|
128
|
-
[2]:UnusedParameters: User#logged_in_with_role has unused parameter '
|
|
128
|
+
[2]:UnusedParameters: User#logged_in_with_role has unused parameter 'role' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
|
|
129
129
|
4 total warnings
|
|
130
130
|
"""
|
|
131
131
|
|
data/lib/reek/ast/node.rb
CHANGED
|
@@ -12,11 +12,8 @@ module Reek
|
|
|
12
12
|
# methods to ease the transition from Sexp to AST::Node.
|
|
13
13
|
#
|
|
14
14
|
class Node < ::Parser::AST::Node
|
|
15
|
-
attr_reader :parent
|
|
16
|
-
|
|
17
15
|
def initialize(type, children = [], options = {})
|
|
18
16
|
@comments = options.fetch(:comments, [])
|
|
19
|
-
@parent = options.fetch(:parent, nil)
|
|
20
17
|
super
|
|
21
18
|
end
|
|
22
19
|
|
|
@@ -11,10 +11,10 @@ module Reek
|
|
|
11
11
|
class AttributeContext < CodeContext
|
|
12
12
|
attr_accessor :visibility
|
|
13
13
|
|
|
14
|
-
def initialize(
|
|
14
|
+
def initialize(exp, send_expression)
|
|
15
15
|
@visibility = :public
|
|
16
16
|
@send_expression = send_expression
|
|
17
|
-
super
|
|
17
|
+
super exp
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def full_comment
|
|
@@ -26,39 +26,8 @@ module Reek
|
|
|
26
26
|
|
|
27
27
|
# Initializes a new CodeContext.
|
|
28
28
|
#
|
|
29
|
-
# @param _parent [CodeContext, nil] The parent context
|
|
30
29
|
# @param exp [Reek::AST::Node] The code described by this context
|
|
31
|
-
|
|
32
|
-
# For example, given the following code:
|
|
33
|
-
#
|
|
34
|
-
# class Omg
|
|
35
|
-
# def foo(x)
|
|
36
|
-
# puts x
|
|
37
|
-
# end
|
|
38
|
-
# end
|
|
39
|
-
#
|
|
40
|
-
# The {ContextBuilder} object first instantiates a {RootContext}, which has no parent.
|
|
41
|
-
#
|
|
42
|
-
# Next, it instantiates a {ModuleContext}, with +parent+ being the
|
|
43
|
-
# {RootContext} just created, and +exp+ looking like this:
|
|
44
|
-
#
|
|
45
|
-
# (class
|
|
46
|
-
# (const nil :Omg) nil
|
|
47
|
-
# (def :foo
|
|
48
|
-
# (args
|
|
49
|
-
# (arg :x))
|
|
50
|
-
# (send nil :puts
|
|
51
|
-
# (lvar :x))))
|
|
52
|
-
#
|
|
53
|
-
# Finally, {ContextBuilder} will instantiate a {MethodContext}. This time,
|
|
54
|
-
# +parent+ is the {ModuleContext} created above, and +exp+ is:
|
|
55
|
-
#
|
|
56
|
-
# (def :foo
|
|
57
|
-
# (args
|
|
58
|
-
# (arg :x))
|
|
59
|
-
# (send nil :puts
|
|
60
|
-
# (lvar :x)))
|
|
61
|
-
def initialize(_parent, exp)
|
|
30
|
+
def initialize(exp)
|
|
62
31
|
@exp = exp
|
|
63
32
|
@children = []
|
|
64
33
|
@statement_counter = StatementCounter.new
|
|
@@ -91,6 +60,44 @@ module Reek
|
|
|
91
60
|
end
|
|
92
61
|
end
|
|
93
62
|
|
|
63
|
+
# Link the present context to its parent.
|
|
64
|
+
#
|
|
65
|
+
# @param parent [Reek::AST::Node] The parent context of the code described by this context
|
|
66
|
+
#
|
|
67
|
+
# For example, given the following code:
|
|
68
|
+
#
|
|
69
|
+
# class Omg
|
|
70
|
+
# def foo(x)
|
|
71
|
+
# puts x
|
|
72
|
+
# end
|
|
73
|
+
# end
|
|
74
|
+
#
|
|
75
|
+
# The {ContextBuilder} object first instantiates a {RootContext}, which has no parent.
|
|
76
|
+
#
|
|
77
|
+
# Next, it instantiates a {ModuleContext}, with +exp+ looking like this:
|
|
78
|
+
#
|
|
79
|
+
# (class
|
|
80
|
+
# (const nil :Omg) nil
|
|
81
|
+
# (def :foo
|
|
82
|
+
# (args
|
|
83
|
+
# (arg :x))
|
|
84
|
+
# (send nil :puts
|
|
85
|
+
# (lvar :x))))
|
|
86
|
+
#
|
|
87
|
+
# It will then call #register_with_parent on the {ModuleContext}, passing
|
|
88
|
+
# in the parent {RootContext}.
|
|
89
|
+
#
|
|
90
|
+
# Finally, {ContextBuilder} will instantiate a {MethodContext}. This time,
|
|
91
|
+
# +exp+ is:
|
|
92
|
+
#
|
|
93
|
+
# (def :foo
|
|
94
|
+
# (args
|
|
95
|
+
# (arg :x))
|
|
96
|
+
# (send nil :puts
|
|
97
|
+
# (lvar :x)))
|
|
98
|
+
#
|
|
99
|
+
# Then it will call #register_with_parent on the {MethodContext}, passing
|
|
100
|
+
# in the parent {ModuleContext}.
|
|
94
101
|
def register_with_parent(parent)
|
|
95
102
|
@parent = parent.append_child_context(self) if parent
|
|
96
103
|
end
|
|
@@ -12,9 +12,10 @@ module Reek
|
|
|
12
12
|
attr_accessor :visibility
|
|
13
13
|
attr_reader :refs
|
|
14
14
|
|
|
15
|
-
def initialize(
|
|
15
|
+
def initialize(exp, parent_exp)
|
|
16
|
+
@parent_exp = parent_exp
|
|
16
17
|
@visibility = :public
|
|
17
|
-
super
|
|
18
|
+
super exp
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def references_self?
|
|
@@ -36,7 +37,7 @@ module Reek
|
|
|
36
37
|
# stop at the `lvasgn` and not detect the contained `lvar`.
|
|
37
38
|
# Hence we first get all `lvar` nodes followed by all `lvasgn` nodes.
|
|
38
39
|
#
|
|
39
|
-
(local_nodes(:lvar) + local_nodes(:lvasgn)).find { |node| node.var_name == param.
|
|
40
|
+
(local_nodes(:lvar) + local_nodes(:lvasgn)).find { |node| node.var_name == param.name }
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
# :reek:FeatureEnvy
|
|
@@ -44,7 +45,7 @@ module Reek
|
|
|
44
45
|
exp.arguments.reject do |param|
|
|
45
46
|
param.anonymous_splat? ||
|
|
46
47
|
param.marked_unused? ||
|
|
47
|
-
uses_param?(param
|
|
48
|
+
uses_param?(param)
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
51
|
|
|
@@ -80,6 +81,17 @@ module Reek
|
|
|
80
81
|
def non_public_visibility?
|
|
81
82
|
visibility != :public
|
|
82
83
|
end
|
|
84
|
+
|
|
85
|
+
def full_comment
|
|
86
|
+
own = super
|
|
87
|
+
return own unless own.empty?
|
|
88
|
+
return parent_exp.full_comment if parent_exp
|
|
89
|
+
''
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
attr_reader :parent_exp
|
|
83
95
|
end
|
|
84
96
|
end
|
|
85
97
|
end
|
data/lib/reek/context_builder.rb
CHANGED
|
@@ -22,6 +22,7 @@ module Reek
|
|
|
22
22
|
#
|
|
23
23
|
# :reek:TooManyMethods: { max_methods: 31 }
|
|
24
24
|
# :reek:UnusedPrivateMethod: { exclude: [ !ruby/regexp /process_/ ] }
|
|
25
|
+
# :reek:DataClump
|
|
25
26
|
class ContextBuilder
|
|
26
27
|
attr_reader :context_tree
|
|
27
28
|
|
|
@@ -58,10 +59,10 @@ module Reek
|
|
|
58
59
|
# RootContext -> children: 1 ModuleContext -> children: 1 MethodContext
|
|
59
60
|
#
|
|
60
61
|
# @return [Reek::Context::RootContext] tree of nested contexts
|
|
61
|
-
def build(exp)
|
|
62
|
+
def build(exp, parent_exp = nil)
|
|
62
63
|
context_processor = "process_#{exp.type}"
|
|
63
64
|
if context_processor_exists?(context_processor)
|
|
64
|
-
send(context_processor, exp)
|
|
65
|
+
send(context_processor, exp, parent_exp)
|
|
65
66
|
else
|
|
66
67
|
process exp
|
|
67
68
|
end
|
|
@@ -71,12 +72,12 @@ module Reek
|
|
|
71
72
|
# Handles every node for which we have no context_processor.
|
|
72
73
|
#
|
|
73
74
|
def process(exp)
|
|
74
|
-
exp.children.grep(AST::Node).each(
|
|
75
|
+
exp.children.grep(AST::Node).each { |child| build(child, exp) }
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
# Handles `module` and `class` nodes.
|
|
78
79
|
#
|
|
79
|
-
def process_module(exp)
|
|
80
|
+
def process_module(exp, _parent)
|
|
80
81
|
inside_new_context(Context::ModuleContext, exp) do
|
|
81
82
|
process(exp)
|
|
82
83
|
end
|
|
@@ -91,7 +92,7 @@ module Reek
|
|
|
91
92
|
# class << self
|
|
92
93
|
# end
|
|
93
94
|
#
|
|
94
|
-
def process_sclass(exp)
|
|
95
|
+
def process_sclass(exp, _parent)
|
|
95
96
|
inside_new_context(Context::GhostContext, exp) do
|
|
96
97
|
process(exp)
|
|
97
98
|
end
|
|
@@ -103,9 +104,9 @@ module Reek
|
|
|
103
104
|
#
|
|
104
105
|
# Foo = Class.new Bar
|
|
105
106
|
#
|
|
106
|
-
def process_casgn(exp)
|
|
107
|
+
def process_casgn(exp, parent)
|
|
107
108
|
if exp.defines_module?
|
|
108
|
-
process_module(exp)
|
|
109
|
+
process_module(exp, parent)
|
|
109
110
|
else
|
|
110
111
|
process(exp)
|
|
111
112
|
end
|
|
@@ -119,8 +120,8 @@ module Reek
|
|
|
119
120
|
#
|
|
120
121
|
# Given the above example we would count 2 statements overall.
|
|
121
122
|
#
|
|
122
|
-
def process_def(exp)
|
|
123
|
-
inside_new_context(current_context.method_context_class, exp) do
|
|
123
|
+
def process_def(exp, parent)
|
|
124
|
+
inside_new_context(current_context.method_context_class, exp, parent) do
|
|
124
125
|
increase_statement_count_by(exp.body)
|
|
125
126
|
process(exp)
|
|
126
127
|
end
|
|
@@ -134,8 +135,8 @@ module Reek
|
|
|
134
135
|
#
|
|
135
136
|
# Given the above example we would count 2 statements overall.
|
|
136
137
|
#
|
|
137
|
-
def process_defs(exp)
|
|
138
|
-
inside_new_context(Context::SingletonMethodContext, exp) do
|
|
138
|
+
def process_defs(exp, parent)
|
|
139
|
+
inside_new_context(Context::SingletonMethodContext, exp, parent) do
|
|
139
140
|
increase_statement_count_by(exp.body)
|
|
140
141
|
process(exp)
|
|
141
142
|
end
|
|
@@ -151,14 +152,14 @@ module Reek
|
|
|
151
152
|
# we also record to what the method call is referring to
|
|
152
153
|
# which we later use for smell detectors like FeatureEnvy.
|
|
153
154
|
#
|
|
154
|
-
def process_send(exp)
|
|
155
|
+
def process_send(exp, _parent)
|
|
156
|
+
process(exp)
|
|
155
157
|
case current_context
|
|
156
158
|
when Context::ModuleContext
|
|
157
159
|
handle_send_for_modules exp
|
|
158
160
|
when Context::MethodContext
|
|
159
161
|
handle_send_for_methods exp
|
|
160
162
|
end
|
|
161
|
-
process(exp)
|
|
162
163
|
end
|
|
163
164
|
|
|
164
165
|
# Handles `op_asgn` nodes a.k.a. Ruby's assignment operators.
|
|
@@ -173,7 +174,7 @@ module Reek
|
|
|
173
174
|
#
|
|
174
175
|
# We record one reference to `x` given the example above.
|
|
175
176
|
#
|
|
176
|
-
def process_op_asgn(exp)
|
|
177
|
+
def process_op_asgn(exp, _parent)
|
|
177
178
|
current_context.record_call_to(exp)
|
|
178
179
|
process(exp)
|
|
179
180
|
end
|
|
@@ -192,7 +193,7 @@ module Reek
|
|
|
192
193
|
#
|
|
193
194
|
# We record one reference to `self`.
|
|
194
195
|
#
|
|
195
|
-
def process_ivar(exp)
|
|
196
|
+
def process_ivar(exp, _parent)
|
|
196
197
|
current_context.record_use_of_self
|
|
197
198
|
process(exp)
|
|
198
199
|
end
|
|
@@ -205,7 +206,7 @@ module Reek
|
|
|
205
206
|
#
|
|
206
207
|
# def self.foo; end
|
|
207
208
|
#
|
|
208
|
-
def process_self(_)
|
|
209
|
+
def process_self(_, _parent)
|
|
209
210
|
current_context.record_use_of_self
|
|
210
211
|
end
|
|
211
212
|
|
|
@@ -225,7 +226,7 @@ module Reek
|
|
|
225
226
|
#
|
|
226
227
|
# We record one reference to `self`.
|
|
227
228
|
#
|
|
228
|
-
def process_zsuper(_)
|
|
229
|
+
def process_zsuper(_, _parent)
|
|
229
230
|
current_context.record_use_of_self
|
|
230
231
|
end
|
|
231
232
|
|
|
@@ -249,7 +250,7 @@ module Reek
|
|
|
249
250
|
#
|
|
250
251
|
# We record one reference to `self`.
|
|
251
252
|
#
|
|
252
|
-
def process_super(exp)
|
|
253
|
+
def process_super(exp, _parent)
|
|
253
254
|
current_context.record_use_of_self
|
|
254
255
|
process(exp)
|
|
255
256
|
end
|
|
@@ -262,7 +263,7 @@ module Reek
|
|
|
262
263
|
#
|
|
263
264
|
# Counts non-empty blocks as one statement.
|
|
264
265
|
#
|
|
265
|
-
def process_block(exp)
|
|
266
|
+
def process_block(exp, _parent)
|
|
266
267
|
increase_statement_count_by(exp.block)
|
|
267
268
|
process(exp)
|
|
268
269
|
end
|
|
@@ -282,7 +283,7 @@ module Reek
|
|
|
282
283
|
# At the end we subtract one statement because the surrounding context was already counted
|
|
283
284
|
# as one (e.g. via `process_def`).
|
|
284
285
|
#
|
|
285
|
-
def process_begin(exp)
|
|
286
|
+
def process_begin(exp, _parent)
|
|
286
287
|
increase_statement_count_by(exp.children)
|
|
287
288
|
decrease_statement_count
|
|
288
289
|
process(exp)
|
|
@@ -308,7 +309,7 @@ module Reek
|
|
|
308
309
|
# `children[1]` refers to the `if` body (so `puts 'bingo'` from above) and
|
|
309
310
|
# `children[2]` to the `else` body (so `3` from above), which might be nil.
|
|
310
311
|
#
|
|
311
|
-
def process_if(exp)
|
|
312
|
+
def process_if(exp, _parent)
|
|
312
313
|
children = exp.children
|
|
313
314
|
increase_statement_count_by(children[1])
|
|
314
315
|
increase_statement_count_by(children[2])
|
|
@@ -331,7 +332,7 @@ module Reek
|
|
|
331
332
|
#
|
|
332
333
|
# `children[1]` below refers to the `while` body (so `puts 'bingo'` from above)
|
|
333
334
|
#
|
|
334
|
-
def process_while(exp)
|
|
335
|
+
def process_while(exp, _parent)
|
|
335
336
|
increase_statement_count_by(exp.children[1])
|
|
336
337
|
decrease_statement_count
|
|
337
338
|
process(exp)
|
|
@@ -354,7 +355,7 @@ module Reek
|
|
|
354
355
|
#
|
|
355
356
|
# `children[2]` below refers to the `while` body (so `puts i` from above)
|
|
356
357
|
#
|
|
357
|
-
def process_for(exp)
|
|
358
|
+
def process_for(exp, _parent)
|
|
358
359
|
increase_statement_count_by(exp.children[2])
|
|
359
360
|
decrease_statement_count
|
|
360
361
|
process(exp)
|
|
@@ -384,7 +385,7 @@ module Reek
|
|
|
384
385
|
# `exp` would be the whole method body wrapped under a `rescue` node.
|
|
385
386
|
# See `process_resbody` for additional reference.
|
|
386
387
|
#
|
|
387
|
-
def process_rescue(exp)
|
|
388
|
+
def process_rescue(exp, _parent)
|
|
388
389
|
increase_statement_count_by(exp.children.first)
|
|
389
390
|
decrease_statement_count
|
|
390
391
|
process(exp)
|
|
@@ -412,7 +413,7 @@ module Reek
|
|
|
412
413
|
# `exp` would be the whole `rescue` body.
|
|
413
414
|
# See `process_rescue` for additional reference.
|
|
414
415
|
#
|
|
415
|
-
def process_resbody(exp)
|
|
416
|
+
def process_resbody(exp, _parent)
|
|
416
417
|
increase_statement_count_by(exp.children[1..-1].compact)
|
|
417
418
|
process(exp)
|
|
418
419
|
end
|
|
@@ -434,7 +435,7 @@ module Reek
|
|
|
434
435
|
# At the end we subtract one statement because the surrounding context was already counted
|
|
435
436
|
# as one (e.g. via `process_def`).
|
|
436
437
|
#
|
|
437
|
-
def process_case(exp)
|
|
438
|
+
def process_case(exp, _parent)
|
|
438
439
|
increase_statement_count_by(exp.else_body)
|
|
439
440
|
decrease_statement_count
|
|
440
441
|
process(exp)
|
|
@@ -460,7 +461,7 @@ module Reek
|
|
|
460
461
|
#
|
|
461
462
|
# Counts the `when` body.
|
|
462
463
|
#
|
|
463
|
-
def process_when(exp)
|
|
464
|
+
def process_when(exp, _parent)
|
|
464
465
|
increase_statement_count_by(exp.body)
|
|
465
466
|
process(exp)
|
|
466
467
|
end
|
|
@@ -482,19 +483,19 @@ module Reek
|
|
|
482
483
|
# yields to the given block and then restores the previous context.
|
|
483
484
|
#
|
|
484
485
|
# @param klass [Context::*Context] - context class
|
|
485
|
-
# @param
|
|
486
|
+
# @param args - arguments for the class initializer
|
|
486
487
|
# @yield block
|
|
487
488
|
#
|
|
488
|
-
def inside_new_context(klass,
|
|
489
|
-
new_context = append_new_context(klass,
|
|
489
|
+
def inside_new_context(klass, *args)
|
|
490
|
+
new_context = append_new_context(klass, *args)
|
|
490
491
|
|
|
491
492
|
orig, self.current_context = current_context, new_context
|
|
492
493
|
yield
|
|
493
494
|
self.current_context = orig
|
|
494
495
|
end
|
|
495
496
|
|
|
496
|
-
#
|
|
497
|
-
# current context.
|
|
497
|
+
# Appends a new child context to the current context but does not change
|
|
498
|
+
# the current context.
|
|
498
499
|
#
|
|
499
500
|
# @param klass [Context::*Context] - context class
|
|
500
501
|
# @param args - arguments for the class initializer
|
|
@@ -502,7 +503,7 @@ module Reek
|
|
|
502
503
|
# @return [Context::*Context] - the context that was appended
|
|
503
504
|
#
|
|
504
505
|
def append_new_context(klass, *args)
|
|
505
|
-
klass.new(
|
|
506
|
+
klass.new(*args).tap do |new_context|
|
|
506
507
|
new_context.register_with_parent(current_context)
|
|
507
508
|
end
|
|
508
509
|
end
|
|
@@ -35,31 +35,25 @@ module Reek
|
|
|
35
35
|
configuration: {})
|
|
36
36
|
@configuration = configuration
|
|
37
37
|
@smell_types = smell_types
|
|
38
|
-
@detectors = smell_types.map { |klass| klass.new configuration_for(klass) }
|
|
39
38
|
end
|
|
40
39
|
|
|
41
40
|
def examine(context)
|
|
42
|
-
smell_detectors_for(context.type).flat_map do |
|
|
43
|
-
detector.
|
|
41
|
+
smell_detectors_for(context.type).flat_map do |klass|
|
|
42
|
+
detector = klass.new configuration: configuration_for(klass), context: context
|
|
43
|
+
detector.run
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
private
|
|
48
48
|
|
|
49
|
-
attr_reader :configuration, :smell_types
|
|
49
|
+
attr_reader :configuration, :smell_types
|
|
50
50
|
|
|
51
51
|
def configuration_for(klass)
|
|
52
52
|
configuration.fetch klass, {}
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def smell_detectors_for(type)
|
|
56
|
-
|
|
57
|
-
detector.contexts.include? type
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def enabled_detectors
|
|
62
|
-
detectors.select { |detector| detector.config.enabled? }
|
|
56
|
+
smell_types.select { |detector| detector.contexts.include? type }
|
|
63
57
|
end
|
|
64
58
|
end
|
|
65
59
|
end
|
|
@@ -28,29 +28,22 @@ module Reek
|
|
|
28
28
|
# in any configuration file.
|
|
29
29
|
DEFAULT_EXCLUDE_SET = [].freeze
|
|
30
30
|
|
|
31
|
-
def initialize(
|
|
32
|
-
@config = SmellConfiguration.new self.class.default_config.merge(
|
|
31
|
+
def initialize(configuration: {}, context: nil)
|
|
32
|
+
@config = SmellConfiguration.new self.class.default_config.merge(configuration)
|
|
33
|
+
@context = context
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
def smell_type
|
|
36
37
|
self.class.smell_type
|
|
37
38
|
end
|
|
38
39
|
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def run_for(context)
|
|
44
|
-
return [] unless enabled_for?(context)
|
|
45
|
-
return [] if exception?(context)
|
|
40
|
+
def run
|
|
41
|
+
return [] unless enabled?
|
|
42
|
+
return [] if exception?
|
|
46
43
|
|
|
47
44
|
sniff(context)
|
|
48
45
|
end
|
|
49
46
|
|
|
50
|
-
def exception?(context)
|
|
51
|
-
context.matches?(value(EXCLUDE_KEY, context))
|
|
52
|
-
end
|
|
53
|
-
|
|
54
47
|
def self.todo_configuration_for(smells)
|
|
55
48
|
default_exclusions = default_config.fetch 'exclude'
|
|
56
49
|
exclusions = default_exclusions + smells.map(&:context)
|
|
@@ -59,7 +52,13 @@ module Reek
|
|
|
59
52
|
|
|
60
53
|
private
|
|
61
54
|
|
|
62
|
-
|
|
55
|
+
attr_reader :context
|
|
56
|
+
|
|
57
|
+
def exception?
|
|
58
|
+
context.matches?(value(EXCLUDE_KEY, context))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def enabled?
|
|
63
62
|
config.enabled? && config_for(context)[SmellConfiguration::ENABLED_KEY] != false
|
|
64
63
|
end
|
|
65
64
|
|
|
@@ -40,10 +40,12 @@ module Reek
|
|
|
40
40
|
#
|
|
41
41
|
def sniff(context)
|
|
42
42
|
expression = context.exp
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
end
|
|
43
|
+
|
|
44
|
+
params = expression.parameters.select do |param|
|
|
45
|
+
uncommunicative_parameter?(parameter: param, context: context)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
params.map(&:name).map do |name|
|
|
47
49
|
smell_warning(
|
|
48
50
|
context: context,
|
|
49
51
|
lines: [expression.line],
|
|
@@ -54,11 +56,13 @@ module Reek
|
|
|
54
56
|
|
|
55
57
|
private
|
|
56
58
|
|
|
57
|
-
def
|
|
58
|
-
!acceptable_name?(
|
|
59
|
+
def uncommunicative_parameter?(parameter:, context:)
|
|
60
|
+
!acceptable_name?(parameter: parameter, context: context) &&
|
|
61
|
+
(context.uses_param?(parameter) || !parameter.marked_unused?)
|
|
59
62
|
end
|
|
60
63
|
|
|
61
|
-
def acceptable_name?(
|
|
64
|
+
def acceptable_name?(parameter:, context:)
|
|
65
|
+
name = parameter.plain_name
|
|
62
66
|
accept_patterns(context).any? { |accept_pattern| name.match accept_pattern } ||
|
|
63
67
|
reject_patterns(context).none? { |reject_pattern| name.match reject_pattern }
|
|
64
68
|
end
|
|
@@ -70,11 +74,6 @@ module Reek
|
|
|
70
74
|
def accept_patterns(context)
|
|
71
75
|
Array value(ACCEPT_KEY, context)
|
|
72
76
|
end
|
|
73
|
-
|
|
74
|
-
# :reek:UtilityFunction
|
|
75
|
-
def sanitize(name)
|
|
76
|
-
name.to_s.gsub(/^[@\*\&]*/, '')
|
|
77
|
-
end
|
|
78
77
|
end
|
|
79
78
|
end
|
|
80
79
|
end
|
data/lib/reek/tree_dresser.rb
CHANGED
|
@@ -39,13 +39,13 @@ module Reek
|
|
|
39
39
|
#
|
|
40
40
|
# :reek:FeatureEnvy
|
|
41
41
|
# :reek:TooManyStatements: { max_statements: 6 }
|
|
42
|
-
def dress(sexp, comment_map
|
|
42
|
+
def dress(sexp, comment_map)
|
|
43
43
|
return sexp unless sexp.is_a? ::Parser::AST::Node
|
|
44
44
|
type = sexp.type
|
|
45
|
-
children = sexp.children.map { |child| dress(child, comment_map
|
|
45
|
+
children = sexp.children.map { |child| dress(child, comment_map) }
|
|
46
46
|
comments = comment_map[sexp]
|
|
47
47
|
klass_map.klass_for(type).new(type, children,
|
|
48
|
-
location: sexp.loc, comments: comments
|
|
48
|
+
location: sexp.loc, comments: comments)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
private
|
data/lib/reek/version.rb
CHANGED
|
@@ -4,7 +4,7 @@ require_lib 'reek/context/module_context'
|
|
|
4
4
|
|
|
5
5
|
RSpec.describe Reek::Context::CodeContext do
|
|
6
6
|
context 'name recognition' do
|
|
7
|
-
let(:ctx) { described_class.new(
|
|
7
|
+
let(:ctx) { described_class.new(exp) }
|
|
8
8
|
let(:exp) { instance_double('Reek::AST::SexpExtensions::ModuleNode') }
|
|
9
9
|
let(:exp_name) { 'random_name' }
|
|
10
10
|
let(:full_name) { "::::::::::::::::::::#{exp_name}" }
|
|
@@ -43,9 +43,9 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
context 'when there is an outer' do
|
|
46
|
-
let(:ctx) { described_class.new(
|
|
46
|
+
let(:ctx) { described_class.new(exp) }
|
|
47
47
|
let(:outer_name) { 'another_random sting' }
|
|
48
|
-
let(:outer) { described_class.new(
|
|
48
|
+
let(:outer) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
49
49
|
|
|
50
50
|
before do
|
|
51
51
|
ctx.register_with_parent outer
|
|
@@ -71,7 +71,7 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
71
71
|
let(:ctx) do
|
|
72
72
|
src = 'module Emptiness; end'
|
|
73
73
|
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
|
74
|
-
described_class.new(
|
|
74
|
+
described_class.new(ast)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
it 'yields no calls' do
|
|
@@ -99,7 +99,7 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
99
99
|
let(:ctx) do
|
|
100
100
|
src = "module Loneliness; def calloo; puts('hello') end; end"
|
|
101
101
|
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
|
102
|
-
described_class.new(
|
|
102
|
+
described_class.new(ast)
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
it 'yields no ifs' do
|
|
@@ -149,7 +149,7 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
149
149
|
end
|
|
150
150
|
EOS
|
|
151
151
|
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
|
152
|
-
ctx = described_class.new(
|
|
152
|
+
ctx = described_class.new(ast)
|
|
153
153
|
expect(ctx.each_node(:if, []).length).to eq(3)
|
|
154
154
|
end
|
|
155
155
|
end
|
|
@@ -166,7 +166,7 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
166
166
|
end
|
|
167
167
|
let(:expression) { Reek::Source::SourceCode.from(src).syntax_tree }
|
|
168
168
|
let(:outer) { nil }
|
|
169
|
-
let(:context) { described_class.new(
|
|
169
|
+
let(:context) { described_class.new(expression) }
|
|
170
170
|
let(:sniffer) { class_double('Reek::SmellDetectors::BaseDetector') }
|
|
171
171
|
|
|
172
172
|
before do
|
|
@@ -181,7 +181,7 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
181
181
|
end
|
|
182
182
|
|
|
183
183
|
context 'when there is an outer context' do
|
|
184
|
-
let(:outer) { described_class.new(
|
|
184
|
+
let(:outer) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
185
185
|
|
|
186
186
|
before do
|
|
187
187
|
allow(outer).to receive(:config_for).with(sniffer).and_return(
|
|
@@ -196,9 +196,9 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
196
196
|
end
|
|
197
197
|
|
|
198
198
|
describe '#register_with_parent' do
|
|
199
|
-
let(:context) { described_class.new(
|
|
200
|
-
let(:first_child) { described_class.new(
|
|
201
|
-
let(:second_child) { described_class.new(
|
|
199
|
+
let(:context) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
200
|
+
let(:first_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
201
|
+
let(:second_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
202
202
|
|
|
203
203
|
it "appends the element to the parent context's list of children" do
|
|
204
204
|
first_child.register_with_parent context
|
|
@@ -209,9 +209,9 @@ RSpec.describe Reek::Context::CodeContext do
|
|
|
209
209
|
end
|
|
210
210
|
|
|
211
211
|
describe '#each' do
|
|
212
|
-
let(:context) { described_class.new(
|
|
213
|
-
let(:first_child) { described_class.new(
|
|
214
|
-
let(:second_child) { described_class.new(
|
|
212
|
+
let(:context) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
213
|
+
let(:first_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
214
|
+
let(:second_child) { described_class.new(instance_double('Reek::AST::Node')) }
|
|
215
215
|
|
|
216
216
|
it 'yields each child' do
|
|
217
217
|
first_child.register_with_parent context
|
|
@@ -4,53 +4,53 @@ require_lib 'reek/context/ghost_context'
|
|
|
4
4
|
|
|
5
5
|
RSpec.describe Reek::Context::GhostContext do
|
|
6
6
|
let(:exp) { instance_double('Reek::AST::Node') }
|
|
7
|
-
let(:parent) { Reek::Context::CodeContext.new(
|
|
7
|
+
let(:parent) { Reek::Context::CodeContext.new(exp) }
|
|
8
8
|
|
|
9
9
|
describe '#register_with_parent' do
|
|
10
10
|
it 'does not append itself to its parent' do
|
|
11
|
-
ghost = described_class.new(
|
|
11
|
+
ghost = described_class.new(nil)
|
|
12
12
|
ghost.register_with_parent(parent)
|
|
13
13
|
expect(parent.children).not_to include ghost
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
describe '#append_child_context' do
|
|
18
|
-
let(:ghost) { described_class.new(
|
|
18
|
+
let(:ghost) { described_class.new(nil) }
|
|
19
19
|
|
|
20
20
|
before do
|
|
21
21
|
ghost.register_with_parent(parent)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'appends the child to the grandparent context' do
|
|
25
|
-
child = Reek::Context::CodeContext.new(
|
|
25
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
26
26
|
child.register_with_parent(ghost)
|
|
27
27
|
|
|
28
28
|
expect(parent.children).to include child
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "sets the child's parent to the grandparent context" do
|
|
32
|
-
child = Reek::Context::CodeContext.new(
|
|
32
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
33
33
|
child.register_with_parent(ghost)
|
|
34
34
|
|
|
35
35
|
expect(child.parent).to eq parent
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
it 'appends the child to the list of children' do
|
|
39
|
-
child = Reek::Context::CodeContext.new(
|
|
39
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
40
40
|
child.register_with_parent(ghost)
|
|
41
41
|
|
|
42
42
|
expect(ghost.children).to include child
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
context 'if the grandparent is also a ghost' do
|
|
46
|
-
let(:child_ghost) { described_class.new(
|
|
46
|
+
let(:child_ghost) { described_class.new(nil) }
|
|
47
47
|
|
|
48
48
|
before do
|
|
49
49
|
child_ghost.register_with_parent(ghost)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
it 'sets the childs parent to its remote ancestor' do
|
|
53
|
-
child = Reek::Context::CodeContext.new(
|
|
53
|
+
child = Reek::Context::CodeContext.new(sexp(:foo))
|
|
54
54
|
child.register_with_parent(child_ghost)
|
|
55
55
|
|
|
56
56
|
expect(child.parent).to eq parent
|
|
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
|
|
|
2
2
|
require_lib 'reek/context/method_context'
|
|
3
3
|
|
|
4
4
|
RSpec.describe Reek::Context::MethodContext do
|
|
5
|
-
let(:method_context) { described_class.new(
|
|
5
|
+
let(:method_context) { described_class.new(exp, nil) }
|
|
6
6
|
|
|
7
7
|
describe '#matches?' do
|
|
8
8
|
let(:exp) { instance_double('Reek::AST::SexpExtensions::ModuleNode').as_null_object }
|
|
@@ -31,7 +31,7 @@ RSpec.describe Reek::Context::MethodContext do
|
|
|
31
31
|
describe '#default_assignments' do
|
|
32
32
|
def assignments_from(src)
|
|
33
33
|
exp = Reek::Source::SourceCode.from(src).syntax_tree
|
|
34
|
-
ctx = Reek::Context::MethodContext.new(
|
|
34
|
+
ctx = Reek::Context::MethodContext.new(exp, nil)
|
|
35
35
|
ctx.default_assignments
|
|
36
36
|
end
|
|
37
37
|
|
|
@@ -32,9 +32,9 @@ RSpec.describe Reek::Context::ModuleContext do
|
|
|
32
32
|
let(:first_def) { instance_double('Reek::AST::SexpExtensions::DefNode', name: :foo) }
|
|
33
33
|
let(:second_def) { instance_double('Reek::AST::SexpExtensions::DefNode') }
|
|
34
34
|
|
|
35
|
-
let(:context) { described_class.new(
|
|
36
|
-
let(:first_child) { Reek::Context::MethodContext.new(
|
|
37
|
-
let(:second_child) { Reek::Context::MethodContext.new(
|
|
35
|
+
let(:context) { described_class.new(main_exp) }
|
|
36
|
+
let(:first_child) { Reek::Context::MethodContext.new(first_def, main_exp) }
|
|
37
|
+
let(:second_child) { Reek::Context::MethodContext.new(second_def, main_exp) }
|
|
38
38
|
|
|
39
39
|
it 'sets visibility on subsequent child contexts' do
|
|
40
40
|
context.append_child_context first_child
|
|
@@ -220,6 +220,26 @@ RSpec.describe Reek::ContextBuilder do
|
|
|
220
220
|
described_class.new(syntax_tree(code)).context_tree
|
|
221
221
|
end
|
|
222
222
|
|
|
223
|
+
it 'marks instance methods when using a def modifier' do
|
|
224
|
+
code = <<-EOS
|
|
225
|
+
class Foo
|
|
226
|
+
private def bar
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def baz
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
EOS
|
|
233
|
+
|
|
234
|
+
root = context_tree_for(code)
|
|
235
|
+
module_context = root.children.first
|
|
236
|
+
method_contexts = module_context.children
|
|
237
|
+
aggregate_failures do
|
|
238
|
+
expect(method_contexts[0].visibility).to eq :private
|
|
239
|
+
expect(method_contexts[1].visibility).to eq :public
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
223
243
|
it 'does not mark class methods with instance visibility' do
|
|
224
244
|
code = <<-EOS
|
|
225
245
|
class Foo
|
|
@@ -49,17 +49,6 @@ RSpec.describe Reek::SmellDetectors::IrresponsibleModule do
|
|
|
49
49
|
expect(src).not_to reek_of(:IrresponsibleModule)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
it "does not report re-opened #{scope} in the same file" do
|
|
53
|
-
src = <<-EOS
|
|
54
|
-
# This comment describes Alfa
|
|
55
|
-
#{scope} Alfa; end
|
|
56
|
-
|
|
57
|
-
#{scope} Alfa; def bravo; end; end
|
|
58
|
-
EOS
|
|
59
|
-
|
|
60
|
-
expect(src).not_to reek_of(:IrresponsibleModule)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
52
|
it "reports a #{scope} with an empty comment" do
|
|
64
53
|
src = <<-EOS
|
|
65
54
|
#
|
|
@@ -32,15 +32,6 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
|
|
|
32
32
|
{ 'alfa.' => 'with a receiver',
|
|
33
33
|
'' => 'without a receiver' }.each do |host, description|
|
|
34
34
|
context "in a method definition #{description}" do
|
|
35
|
-
it 'does not recognise *' do
|
|
36
|
-
expect("def #{host}bravo(*); end").not_to reek_of(:UncommunicativeParameterName)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'does not report unused parameters' do
|
|
40
|
-
src = "def #{host}bravo(x); charlie; end"
|
|
41
|
-
expect(src).not_to reek_of(:UncommunicativeParameterName)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
35
|
it 'does not report two-letter parameter names' do
|
|
45
36
|
src = "def #{host}bravo(ab); charlie(ab); end"
|
|
46
37
|
expect(src).not_to reek_of(:UncommunicativeParameterName)
|
|
@@ -56,6 +47,26 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
|
|
|
56
47
|
expect(src).to reek_of(:UncommunicativeParameterName, name: 'param2')
|
|
57
48
|
end
|
|
58
49
|
|
|
50
|
+
it 'reports unused parameters' do
|
|
51
|
+
src = "def #{host}bravo(x); charlie; end"
|
|
52
|
+
expect(src).to reek_of(:UncommunicativeParameterName)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'reports splat parameters' do
|
|
56
|
+
expect("def #{host}bravo(*a); charlie(a); end").
|
|
57
|
+
to reek_of(:UncommunicativeParameterName, name: 'a')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'reports double splat parameters' do
|
|
61
|
+
expect("def #{host}bravo(**a); charlie(a); end").
|
|
62
|
+
to reek_of(:UncommunicativeParameterName, name: 'a')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'reports block parameters' do
|
|
66
|
+
expect("def #{host}bravo(&a); charlie(a); end").
|
|
67
|
+
to reek_of(:UncommunicativeParameterName, name: 'a')
|
|
68
|
+
end
|
|
69
|
+
|
|
59
70
|
it 'does not report unused anonymous parameter' do
|
|
60
71
|
src = "def #{host}bravo(_); charlie; end"
|
|
61
72
|
expect(src).not_to reek_of(:UncommunicativeParameterName)
|
|
@@ -63,12 +74,20 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeParameterName do
|
|
|
63
74
|
|
|
64
75
|
it 'reports used anonymous parameter' do
|
|
65
76
|
src = "def #{host}bravo(_); charlie(_) end"
|
|
66
|
-
expect(src).to reek_of(:UncommunicativeParameterName)
|
|
77
|
+
expect(src).to reek_of(:UncommunicativeParameterName, name: '_')
|
|
67
78
|
end
|
|
68
79
|
|
|
69
80
|
it 'reports used parameters marked as unused' do
|
|
70
81
|
src = "def #{host}bravo(_unused) charlie(_unused) end"
|
|
71
|
-
expect(src).to reek_of(:UncommunicativeParameterName)
|
|
82
|
+
expect(src).to reek_of(:UncommunicativeParameterName, name: '_unused')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'does not report anonymous splat' do
|
|
86
|
+
expect("def #{host}bravo(*); end").not_to reek_of(:UncommunicativeParameterName)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'does not report anonymous double splat' do
|
|
90
|
+
expect("def #{host}bravo(**); end").not_to reek_of(:UncommunicativeParameterName)
|
|
72
91
|
end
|
|
73
92
|
|
|
74
93
|
it 'reports names inside array decomposition' do
|
|
@@ -103,6 +103,17 @@ RSpec.describe Reek::SmellDetectors::UnusedPrivateMethod do
|
|
|
103
103
|
to reek_of(:UnusedPrivateMethod, name: 'bravo', lines: [3]).
|
|
104
104
|
and reek_of(:UnusedPrivateMethod, name: 'charlie', lines: [4])
|
|
105
105
|
end
|
|
106
|
+
|
|
107
|
+
it 'reports instance methods defined as private with a modifier' do
|
|
108
|
+
source = <<-EOF
|
|
109
|
+
class Alfa
|
|
110
|
+
private def bravo; end
|
|
111
|
+
end
|
|
112
|
+
EOF
|
|
113
|
+
|
|
114
|
+
expect(source).
|
|
115
|
+
to reek_of(:UnusedPrivateMethod, name: 'bravo')
|
|
116
|
+
end
|
|
106
117
|
end
|
|
107
118
|
|
|
108
119
|
describe 'configuring the detector via source code comment' do
|
|
@@ -221,6 +221,18 @@ RSpec.describe Reek::SmellDetectors::UtilityFunction do
|
|
|
221
221
|
|
|
222
222
|
expect(src).not_to reek_of(:UtilityFunction).with_config(config)
|
|
223
223
|
end
|
|
224
|
+
|
|
225
|
+
it 'does not report UtilityFunction when private is used as a def modifier' do
|
|
226
|
+
src = <<-EOS
|
|
227
|
+
class Alfa
|
|
228
|
+
private def bravo(charlie)
|
|
229
|
+
charlie.delta.echo
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
EOS
|
|
233
|
+
|
|
234
|
+
expect(src).not_to reek_of(:UtilityFunction).with_config(config)
|
|
235
|
+
end
|
|
224
236
|
end
|
|
225
237
|
|
|
226
238
|
context 'protected methods' do
|
|
@@ -236,6 +248,46 @@ RSpec.describe Reek::SmellDetectors::UtilityFunction do
|
|
|
236
248
|
|
|
237
249
|
expect(src).not_to reek_of(:UtilityFunction).with_config(config)
|
|
238
250
|
end
|
|
251
|
+
|
|
252
|
+
it 'does not report UtilityFunction when protected is used as a def modifier' do
|
|
253
|
+
src = <<-EOS
|
|
254
|
+
class Alfa
|
|
255
|
+
protected def bravo(charlie)
|
|
256
|
+
charlie.delta.echo
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
EOS
|
|
260
|
+
|
|
261
|
+
expect(src).not_to reek_of(:UtilityFunction).with_config(config)
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
describe 'disabling with a comment' do
|
|
267
|
+
it 'disables the method following the comment' do
|
|
268
|
+
src = <<-EOS
|
|
269
|
+
class Alfa
|
|
270
|
+
# :reek:UtilityFunction
|
|
271
|
+
def bravo(charlie)
|
|
272
|
+
charlie.delta.echo
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
EOS
|
|
276
|
+
|
|
277
|
+
expect(src).not_to reek_of(:UtilityFunction)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it 'disables a method when it has a visibility modifier' do
|
|
281
|
+
src = <<-EOS
|
|
282
|
+
class Alfa
|
|
283
|
+
# :reek:UtilityFunction
|
|
284
|
+
private def bravo(charlie)
|
|
285
|
+
charlie.delta.echo
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
EOS
|
|
289
|
+
|
|
290
|
+
expect(src).not_to reek_of(:UtilityFunction)
|
|
239
291
|
end
|
|
240
292
|
end
|
|
241
293
|
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: 4.7.
|
|
4
|
+
version: 4.7.2
|
|
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: 2017-
|
|
14
|
+
date: 2017-07-24 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: codeclimate-engine-rb
|
|
@@ -443,7 +443,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
443
443
|
version: '0'
|
|
444
444
|
requirements: []
|
|
445
445
|
rubyforge_project:
|
|
446
|
-
rubygems_version: 2.
|
|
446
|
+
rubygems_version: 2.6.12
|
|
447
447
|
signing_key:
|
|
448
448
|
specification_version: 4
|
|
449
449
|
summary: Code smell detector for Ruby
|