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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: baf611107a9ba063fb9882a312ae27c556f4a4f6
4
- data.tar.gz: f56386a2775e1a178a1df9af568055c5ac63c80f
3
+ metadata.gz: a57753b0b855d7182054e7551940eac44cf57f60
4
+ data.tar.gz: 245074bd6e150589a1bc7a69830a34e3db600a83
5
5
  SHA512:
6
- metadata.gz: d108db6dd4064eced4dfe277238771246120f73874f89ae3800e7bbef91b101d946861cb1793b7a138ce761bf4b26e854ee05b13ca5d39287c46b7c64027436a
7
- data.tar.gz: 2005c56063bdc5a62f3ec3fe53b73d99158b8b124bdbbb45a3d8ff5ab64ab35e2863afdace05d05b5538855fdc80ed4ca138e073b415ac38f7d9dab95ccbc382
6
+ metadata.gz: 4c422c0a25421d8d0abc337766f7b2defae5f7044137c3e5fb7c34fffea7ee409d165f56922f433565fa8643d716cdbb3e9a3c7cec568bfa50bf15b2eed8b254
7
+ data.tar.gz: d4b77922d2745ab3d7f6f053931193b543f646e605a0b3a7f7a444ddf24d3462df4bf7732a248f14fd49f9253925afbf441d3fda578df736b130bfbf80db5096
@@ -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(r)
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 'r' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
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(r)
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 'r' [https://github.com/troessner/reek/blob/master/docs/Unused-Parameters.md]
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
 
@@ -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(context, exp, send_expression)
14
+ def initialize(exp, send_expression)
15
15
  @visibility = :public
16
16
  @send_expression = send_expression
17
- super context, exp
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(context, exp)
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.to_sym }
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.plain_name)
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
@@ -13,9 +13,8 @@ module Reek
13
13
  class ModuleContext < CodeContext
14
14
  attr_reader :visibility_tracker
15
15
 
16
- def initialize(context, exp)
16
+ def initialize(exp)
17
17
  super
18
-
19
18
  @visibility_tracker = VisibilityTracker.new
20
19
  end
21
20
 
@@ -9,10 +9,6 @@ module Reek
9
9
  # A context wrapper representing the root of an abstract syntax tree.
10
10
  #
11
11
  class RootContext < CodeContext
12
- def initialize(exp)
13
- super(nil, exp)
14
- end
15
-
16
12
  def type
17
13
  :root
18
14
  end
@@ -10,9 +10,9 @@ module Reek
10
10
  class SendContext < CodeContext
11
11
  attr_reader :name
12
12
 
13
- def initialize(context, exp, name)
13
+ def initialize(exp, name)
14
14
  @name = name
15
- super context, exp
15
+ super exp
16
16
  end
17
17
  end
18
18
  end
@@ -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(&method(:build))
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 exp - current expression
486
+ # @param args - arguments for the class initializer
486
487
  # @yield block
487
488
  #
488
- def inside_new_context(klass, exp)
489
- new_context = append_new_context(klass, exp)
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
- # Append a new child context to the current context but does not change the
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(current_context, *args).tap do |new_context|
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 |detector|
43
- detector.run_for(context)
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, :detectors
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
- enabled_detectors.select do |detector|
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(config = {})
32
- @config = SmellConfiguration.new self.class.default_config.merge(config)
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 contexts
40
- self.class.contexts
41
- end
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
- def enabled_for?(context)
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
- expression.parameter_names.select do |name|
44
- sanitized_name = sanitize name
45
- uncommunicative_parameter_name?(name: sanitized_name, context: context)
46
- end.map do |name|
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 uncommunicative_parameter_name?(name:, context:)
58
- !acceptable_name?(name: name, context: context) && context.uses_param?(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?(name:, context:)
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
@@ -75,6 +75,7 @@ module Reek
75
75
 
76
76
  #
77
77
  # @param ctx [Context::ClassContext]
78
+ # @param method [Context::MethodContext]
78
79
  # @return [Boolean]
79
80
  #
80
81
  # :reek:FeatureEnvy
@@ -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, parent: nil)
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, parent: sexp) }
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, parent: parent)
48
+ location: sexp.loc, comments: comments)
49
49
  end
50
50
 
51
51
  private
@@ -8,6 +8,6 @@ module Reek
8
8
  # @public
9
9
  module Version
10
10
  # @public
11
- STRING = '4.7.1'.freeze
11
+ STRING = '4.7.2'.freeze
12
12
  end
13
13
  end
@@ -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(nil, exp) }
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(outer, exp) }
46
+ let(:ctx) { described_class.new(exp) }
47
47
  let(:outer_name) { 'another_random sting' }
48
- let(:outer) { described_class.new(nil, instance_double('Reek::AST::Node')) }
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(nil, ast)
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(nil, ast)
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(nil, ast)
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(outer, expression) }
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(nil, instance_double('Reek::AST::Node')) }
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(nil, instance_double('Reek::AST::Node')) }
200
- let(:first_child) { described_class.new(context, instance_double('Reek::AST::Node')) }
201
- let(:second_child) { described_class.new(context, instance_double('Reek::AST::Node')) }
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(nil, instance_double('Reek::AST::Node')) }
213
- let(:first_child) { described_class.new(context, instance_double('Reek::AST::Node')) }
214
- let(:second_child) { described_class.new(context, instance_double('Reek::AST::Node')) }
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(nil, exp) }
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(parent, nil)
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(parent, nil) }
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(ghost, sexp(:foo))
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(ghost, sexp(:foo))
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(ghost, sexp(:foo))
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(ghost, nil) }
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(child_ghost, sexp(:foo))
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(nil, exp) }
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(nil, exp)
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(nil, main_exp) }
36
- let(:first_child) { Reek::Context::MethodContext.new(context, first_def) }
37
- let(:second_child) { Reek::Context::MethodContext.new(context, second_def) }
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.1
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-06-12 00:00:00.000000000 Z
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.5.1
446
+ rubygems_version: 2.6.12
447
447
  signing_key:
448
448
  specification_version: 4
449
449
  summary: Code smell detector for Ruby