rubocop 1.55.1 → 1.56.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c1de4039df4f7edef2ab28f9623efa0f1d4d22e7f05d9cbd68bee76cb5216bf
4
- data.tar.gz: 3a0b84d52ba7fabd1980cfbb4d351a1d8ac2b5a1bd38608194529e34124ad603
3
+ metadata.gz: 76532b5c0c7ccf0baff454ad37e17c405e4f827a0c8323ce1a5aab0ee9e78c19
4
+ data.tar.gz: fe2f7d727d5addd930a762ebe7fb34a38845164fed801744a6802ab91e6ba779
5
5
  SHA512:
6
- metadata.gz: c4b5c017d22990f0f7627663d532d793cf193a97afc0de8dca538b86e35fa26210df1e871e705e3b4d9302ba0a46d5c1a7910368c083520ae62cd2facd21be0c
7
- data.tar.gz: 2e73d75f974b9f85a27e024e4c67bfc907a279f5fd07100996f04080361e9c1258b84eca28fe8352c594e5c815a6c748db786bbe67502bf887d86cfd201b8cc6
6
+ metadata.gz: ff206ac0d02084dd7014818da655f5f8d718ac1bb4bfc2f781d3c007839096a142236ded54d30084fa7b3e1689205ff7a8bc7ad7eee3ffea2d809e4610d6a1ae
7
+ data.tar.gz: aaa03f29b7669ffcf6fdcb16b7da4c38a6bc62187eb91d6347e3ada22f396370b6564177eb3a040fd5ddd3eeea9cf8b3ff51943e79c3d0ad410508a75bb3177b
data/README.md CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
53
  in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 1.55', require: false
56
+ gem 'rubocop', '~> 1.56', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -173,6 +173,16 @@ Bundler/DuplicatedGem:
173
173
  - '**/Gemfile'
174
174
  - '**/gems.rb'
175
175
 
176
+ Bundler/DuplicatedGroup:
177
+ Description: 'Checks for duplicate group entries in Gemfile.'
178
+ Enabled: true
179
+ Severity: warning
180
+ VersionAdded: '1.56'
181
+ Include:
182
+ - '**/*.gemfile'
183
+ - '**/Gemfile'
184
+ - '**/gems.rb'
185
+
176
186
  Bundler/GemComment:
177
187
  Description: 'Add a comment describing each gem.'
178
188
  Enabled: false
@@ -46,14 +46,14 @@ module RuboCop
46
46
 
47
47
  file = File.join(Dir.home, DOTFILE)
48
48
 
49
- return file if File.exist?(file)
49
+ file if File.exist?(file)
50
50
  end
51
51
 
52
52
  def find_user_xdg_config
53
53
  xdg_config_home = expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config'))
54
54
  xdg_config = File.join(xdg_config_home, 'rubocop', XDG_CONFIG)
55
55
 
56
- return xdg_config if File.exist?(xdg_config)
56
+ xdg_config if File.exist?(xdg_config)
57
57
  end
58
58
 
59
59
  def expand_path(path)
@@ -4,6 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Bundler
6
6
  # A Gem's requirements should be listed only once in a Gemfile.
7
+ #
7
8
  # @example
8
9
  # # bad
9
10
  # gem 'rubocop'
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Bundler
6
+ # A Gem group, or a set of groups, should be listed only once in a Gemfile.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # group :development do
11
+ # gem 'rubocop'
12
+ # end
13
+ #
14
+ # group :development do
15
+ # gem 'rubocop-rails'
16
+ # end
17
+ #
18
+ # # bad (same set of groups declared twice)
19
+ # group :development, :test do
20
+ # gem 'rubocop'
21
+ # end
22
+ #
23
+ # group :test, :development do
24
+ # gem 'rspec'
25
+ # end
26
+ #
27
+ # # good
28
+ # group :development do
29
+ # gem 'rubocop'
30
+ # end
31
+ #
32
+ # group :development, :test do
33
+ # gem 'rspec'
34
+ # end
35
+ #
36
+ # # good
37
+ # gem 'rubocop', groups: [:development, :test]
38
+ # gem 'rspec', groups: [:development, :test]
39
+ #
40
+ class DuplicatedGroup < Base
41
+ include RangeHelp
42
+
43
+ MSG = 'Gem group `%<group_name>s` already defined on line ' \
44
+ '%<line_of_first_occurrence>d of the Gemfile.'
45
+
46
+ def on_new_investigation
47
+ return if processed_source.blank?
48
+
49
+ duplicated_group_nodes.each do |nodes|
50
+ nodes[1..].each do |node|
51
+ register_offense(node, node.arguments.map(&:value).join(', '), nodes.first.first_line)
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ # @!method group_declarations(node)
59
+ def_node_search :group_declarations, '(send nil? :group ...)'
60
+
61
+ def duplicated_group_nodes
62
+ group_declarations(processed_source.ast)
63
+ .group_by { |node| node.arguments.map(&:value).map(&:to_s).sort }
64
+ .values
65
+ .select { |nodes| nodes.size > 1 }
66
+ end
67
+
68
+ def register_offense(node, group_name, line_of_first_occurrence)
69
+ line_range = node.loc.column...node.loc.last_column
70
+ offense_location = source_range(processed_source.buffer, node.first_line, line_range)
71
+ message = format(
72
+ MSG,
73
+ group_name: group_name,
74
+ line_of_first_occurrence: line_of_first_occurrence
75
+ )
76
+ add_offense(offense_location, message: message)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -137,7 +137,7 @@ module RuboCop
137
137
  return node if node
138
138
  end
139
139
 
140
- return last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
140
+ last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
141
141
  end
142
142
 
143
143
  def last_heredoc_argument_node(node)
@@ -354,7 +354,7 @@ module RuboCop
354
354
  # Don't check indentation if the line doesn't start with the body.
355
355
  # For example, lines like "else do_something".
356
356
  first_char_pos_on_line = body_node.source_range.source_line =~ /\S/
357
- return true unless body_node.loc.column == first_char_pos_on_line
357
+ true unless body_node.loc.column == first_char_pos_on_line
358
358
  end
359
359
 
360
360
  def offending_range(body_node, indentation)
@@ -168,7 +168,7 @@ module RuboCop
168
168
  # follows, and that the rules for space inside don't apply.
169
169
  return true if token2.comment?
170
170
 
171
- return true unless same_line?(token1, token2) && !token1.space_after?
171
+ true unless same_line?(token1, token2) && !token1.space_after?
172
172
  end
173
173
  end
174
174
  end
@@ -32,25 +32,25 @@ module RuboCop
32
32
  # @!method struct_new(node)
33
33
  def_node_matcher :struct_new, <<~PATTERN
34
34
  (send
35
- (const ${nil? cbase} :Struct) :new ...)
35
+ (const {nil? cbase} :Struct) :new ...)
36
36
  PATTERN
37
37
 
38
38
  def on_send(node)
39
- return unless struct_new(node) do
40
- node.arguments.each_with_index do |arg, index|
41
- # Ignore if the first argument is a class name
42
- next if index.zero? && arg.str_type?
39
+ return unless struct_new(node)
43
40
 
44
- # Ignore if the argument is not a member name
45
- next unless STRUCT_MEMBER_NAME_TYPES.include?(arg.type)
41
+ node.arguments.each_with_index do |arg, index|
42
+ # Ignore if the first argument is a class name
43
+ next if index.zero? && arg.str_type?
46
44
 
47
- member_name = arg.value
45
+ # Ignore if the argument is not a member name
46
+ next unless STRUCT_MEMBER_NAME_TYPES.include?(arg.type)
48
47
 
49
- next unless STRUCT_METHOD_NAMES.include?(member_name.to_sym)
48
+ member_name = arg.value
50
49
 
51
- message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s)
52
- add_offense(arg, message: message)
53
- end
50
+ next unless STRUCT_METHOD_NAMES.include?(member_name.to_sym)
51
+
52
+ message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s)
53
+ add_offense(arg, message: message)
54
54
  end
55
55
  end
56
56
  end
@@ -119,7 +119,7 @@ module RuboCop
119
119
  ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first
120
120
  return false unless ancestor
121
121
 
122
- end_line = ancestor.loc.end.line
122
+ end_line = ancestor.loc.end&.line || ancestor.loc.last_line
123
123
  processed_source[node.first_line...end_line].any? { |line| comment_line?(line) }
124
124
  end
125
125
 
@@ -30,8 +30,10 @@ module RuboCop
30
30
  private
31
31
 
32
32
  def inside_interpolation?(node)
33
- # A :begin node inside a :dstr or :dsym node is an interpolation.
34
- node.ancestors.drop_while { |a| !a.begin_type? }.any? { |a| a.dstr_type? || a.dsym_type? }
33
+ # A :begin node inside a :dstr, :dsym, or :regexp node is an interpolation.
34
+ node.ancestors
35
+ .drop_while { |a| !a.begin_type? }
36
+ .any? { |a| a.dstr_type? || a.dsym_type? || a.regexp_type? }
35
37
  end
36
38
  end
37
39
  end
@@ -122,7 +122,7 @@ module RuboCop
122
122
  end
123
123
 
124
124
  def bareword?(sym_node)
125
- !sym_node.source.start_with?(':')
125
+ !sym_node.source.start_with?(':') || sym_node.dsym_type?
126
126
  end
127
127
 
128
128
  def correct_alias_method_to_alias(corrector, send_node)
@@ -134,9 +134,7 @@ module RuboCop
134
134
 
135
135
  def correct_alias_to_alias_method(corrector, node)
136
136
  replacement =
137
- 'alias_method ' \
138
- ":#{identifier(node.new_identifier)}, " \
139
- ":#{identifier(node.old_identifier)}"
137
+ "alias_method #{identifier(node.new_identifier)}, #{identifier(node.old_identifier)}"
140
138
 
141
139
  corrector.replace(node, replacement)
142
140
  end
@@ -146,10 +144,13 @@ module RuboCop
146
144
  corrector.replace(node.old_identifier, node.old_identifier.source[1..])
147
145
  end
148
146
 
149
- # @!method identifier(node)
150
- def_node_matcher :identifier, <<~PATTERN
151
- (sym $_)
152
- PATTERN
147
+ def identifier(node)
148
+ if node.sym_type?
149
+ ":#{node.children.first}"
150
+ else
151
+ node.source
152
+ end
153
+ end
153
154
  end
154
155
  end
155
156
  end
@@ -100,7 +100,7 @@ module RuboCop
100
100
  return if send_classifications.empty?
101
101
 
102
102
  if only_forwards_all?(send_classifications)
103
- add_forward_all_offenses(node, send_classifications)
103
+ add_forward_all_offenses(node, send_classifications, forwardable_args)
104
104
  elsif target_ruby_version >= 3.2
105
105
  add_post_ruby_32_offenses(node, send_classifications, forwardable_args)
106
106
  end
@@ -118,12 +118,13 @@ module RuboCop
118
118
  send_classifications.each_value.all? { |c, _, _| c == :all }
119
119
  end
120
120
 
121
- def add_forward_all_offenses(node, send_classifications)
122
- send_classifications.each_key do |send_node|
123
- register_forward_all_offense_on_forwarding_method(send_node)
121
+ def add_forward_all_offenses(node, send_classifications, forwardable_args)
122
+ send_classifications.each do |send_node, (_c, forward_rest, _forward_kwrest)|
123
+ register_forward_all_offense(send_node, send_node, forward_rest)
124
124
  end
125
125
 
126
- register_forward_all_offense_on_method_def(node)
126
+ rest_arg, _kwrest_arg, _block_arg = *forwardable_args
127
+ register_forward_all_offense(node, node.arguments, rest_arg)
127
128
  end
128
129
 
129
130
  def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
@@ -186,9 +187,7 @@ module RuboCop
186
187
 
187
188
  def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
188
189
  add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
189
- unless parentheses?(def_arguments_or_send)
190
- add_parentheses(def_arguments_or_send, corrector)
191
- end
190
+ add_parens_if_missing(def_arguments_or_send, corrector)
192
191
 
193
192
  corrector.replace(rest_arg_or_splat, '*')
194
193
  end
@@ -196,36 +195,28 @@ module RuboCop
196
195
 
197
196
  def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat)
198
197
  add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector|
199
- if add_parens && !parentheses?(def_arguments_or_send)
200
- add_parentheses(def_arguments_or_send, corrector)
201
- end
198
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
202
199
 
203
200
  corrector.replace(kwrest_arg_or_splat, '**')
204
201
  end
205
202
  end
206
203
 
207
- def register_forward_all_offense_on_forwarding_method(forwarding_method)
208
- add_offense(arguments_range(forwarding_method), message: FORWARDING_MSG) do |corrector|
209
- begin_pos = forwarding_method.loc.selector&.end_pos || forwarding_method.loc.dot.end_pos
210
- range = range_between(begin_pos, forwarding_method.source_range.end_pos)
204
+ def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
205
+ arg_range = arguments_range(def_or_send, rest_or_splat)
211
206
 
212
- corrector.replace(range, '(...)')
213
- end
214
- end
207
+ add_offense(arg_range, message: FORWARDING_MSG) do |corrector|
208
+ add_parens_if_missing(send_or_arguments, corrector)
215
209
 
216
- def register_forward_all_offense_on_method_def(method_definition)
217
- add_offense(arguments_range(method_definition), message: FORWARDING_MSG) do |corrector|
218
- arguments_range = range_with_surrounding_space(
219
- method_definition.arguments.source_range, side: :left
220
- )
221
- corrector.replace(arguments_range, '(...)')
210
+ corrector.replace(arg_range, '...')
222
211
  end
223
212
  end
224
213
 
225
- def arguments_range(node)
214
+ def arguments_range(node, first_node)
226
215
  arguments = node.arguments
227
216
 
228
- range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
217
+ start_node = first_node || arguments.first
218
+
219
+ range_between(start_node.source_range.begin_pos, arguments.last.source_range.end_pos)
229
220
  end
230
221
 
231
222
  def allow_only_rest_arguments?
@@ -236,6 +227,12 @@ module RuboCop
236
227
  cop_config.fetch('UseAnonymousForwarding', false)
237
228
  end
238
229
 
230
+ def add_parens_if_missing(node, corrector)
231
+ return if parentheses?(node)
232
+
233
+ add_parentheses(node, corrector)
234
+ end
235
+
239
236
  # Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
240
237
  class SendNodeClassifier
241
238
  extend NodePattern::Macros
@@ -280,7 +277,7 @@ module RuboCop
280
277
  def classification
281
278
  return nil unless forwarded_rest_arg || forwarded_kwrest_arg
282
279
 
283
- if referenced_none? && (forwarded_exactly_all? || pre_ruby_32_allow_forward_all?)
280
+ if can_forward_all?
284
281
  :all
285
282
  elsif target_ruby_version >= 3.2
286
283
  :rest_or_kwrest
@@ -289,6 +286,27 @@ module RuboCop
289
286
 
290
287
  private
291
288
 
289
+ def can_forward_all?
290
+ return false if any_arg_referenced?
291
+ return false if ruby_32_missing_rest_or_kwest?
292
+ return false unless offensive_block_forwarding?
293
+ return false if forward_additional_kwargs?
294
+
295
+ no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
296
+ end
297
+
298
+ def ruby_32_missing_rest_or_kwest?
299
+ target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args
300
+ end
301
+
302
+ def offensive_block_forwarding?
303
+ @block_arg ? forwarded_block_arg : allow_offense_for_no_block?
304
+ end
305
+
306
+ def forwarded_rest_and_kwrest_args
307
+ forwarded_rest_arg && forwarded_kwrest_arg
308
+ end
309
+
292
310
  def arguments
293
311
  @send_node.arguments
294
312
  end
@@ -305,25 +323,36 @@ module RuboCop
305
323
  @referenced_lvars.include?(@block_arg_name)
306
324
  end
307
325
 
308
- def referenced_none?
309
- !(referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?)
310
- end
311
-
312
- def forwarded_exactly_all?
313
- @send_node.arguments.size == 3 &&
314
- forwarded_rest_arg &&
315
- forwarded_kwrest_arg &&
316
- forwarded_block_arg
326
+ def any_arg_referenced?
327
+ referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?
317
328
  end
318
329
 
319
330
  def target_ruby_version
320
331
  @config.fetch(:target_ruby_version)
321
332
  end
322
333
 
323
- def pre_ruby_32_allow_forward_all?
324
- target_ruby_version < 3.2 &&
325
- @def_node.arguments.none?(&:default?) &&
326
- (@block_arg ? forwarded_block_arg : !@config.fetch(:allow_only_rest_arguments))
334
+ def no_post_splat_args?
335
+ splat_index = arguments.index(forwarded_rest_arg)
336
+ arg_after_splat = arguments[splat_index + 1]
337
+
338
+ [nil, :hash, :block_pass].include?(arg_after_splat&.type)
339
+ end
340
+
341
+ def forward_additional_kwargs?
342
+ return false unless forwarded_kwrest_arg
343
+
344
+ !forwarded_kwrest_arg.parent.children.one?
345
+ end
346
+
347
+ def allow_offense_for_no_block?
348
+ !@config.fetch(:allow_only_rest_arguments)
349
+ end
350
+
351
+ def no_additional_args?
352
+ forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
353
+
354
+ @def_node.arguments.size == forwardable_count &&
355
+ @send_node.arguments.size == forwardable_count
327
356
  end
328
357
  end
329
358
  end
@@ -370,7 +370,8 @@ module RuboCop
370
370
  def special_method_proper_block_style?(node)
371
371
  method_name = node.method_name
372
372
  return true if allowed_method?(method_name) || matches_allowed_pattern?(method_name)
373
- return node.braces? if braces_required_method?(method_name)
373
+
374
+ node.braces? if braces_required_method?(method_name)
374
375
  end
375
376
 
376
377
  def braces_required_method?(method_name)
@@ -69,6 +69,8 @@ module RuboCop
69
69
  matches_allowed_pattern?(def_node.method_name))
70
70
 
71
71
  class_comparison_candidate?(node) do |receiver_node, class_node|
72
+ return if class_node.dstr_type?
73
+
72
74
  range = offense_range(receiver_node, node)
73
75
  class_argument = (class_name = class_name(class_node, node)) ? "(#{class_name})" : ''
74
76
 
@@ -20,6 +20,7 @@ module RuboCop
20
20
  # lambda.(x, y)
21
21
  class LambdaCall < Base
22
22
  include ConfigurableEnforcedStyle
23
+ include IgnoredNode
23
24
  extend AutoCorrector
24
25
 
25
26
  MSG = 'Prefer the use of `%<prefer>s` over `%<current>s`.'
@@ -33,8 +34,12 @@ module RuboCop
33
34
  current = node.source
34
35
 
35
36
  add_offense(node, message: format(MSG, prefer: prefer, current: current)) do |corrector|
37
+ next if part_of_ignored_node?(node)
38
+
36
39
  opposite_style_detected
37
40
  corrector.replace(node, prefer)
41
+
42
+ ignore_node(node)
38
43
  end
39
44
  else
40
45
  correct_style_detected
@@ -22,13 +22,18 @@ module RuboCop
22
22
  # return something
23
23
  # end
24
24
  #
25
- # # good
25
+ # # bad
26
26
  # def test
27
27
  # return something if something_else
28
28
  # end
29
29
  #
30
30
  # # good
31
31
  # def test
32
+ # something if something_else
33
+ # end
34
+ #
35
+ # # good
36
+ # def test
32
37
  # if x
33
38
  # elsif y
34
39
  # else
@@ -136,7 +141,7 @@ module RuboCop
136
141
  end
137
142
 
138
143
  def check_if_node(node)
139
- return if node.modifier_form? || node.ternary?
144
+ return if node.ternary?
140
145
 
141
146
  check_branch(node.if_branch)
142
147
  check_branch(node.else_branch)
@@ -3,22 +3,42 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks that quotes inside the string interpolation
6
+ # Checks that quotes inside string, symbol, and regexp interpolations
7
7
  # match the configured preference.
8
8
  #
9
9
  # @example EnforcedStyle: single_quotes (default)
10
10
  # # bad
11
- # result = "Tests #{success ? "PASS" : "FAIL"}"
11
+ # string = "Tests #{success ? "PASS" : "FAIL"}"
12
+ # symbol = :"Tests #{success ? "PASS" : "FAIL"}"
13
+ # heredoc = <<~TEXT
14
+ # Tests #{success ? "PASS" : "FAIL"}
15
+ # TEXT
16
+ # regexp = /Tests #{success ? "PASS" : "FAIL"}/
12
17
  #
13
18
  # # good
14
- # result = "Tests #{success ? 'PASS' : 'FAIL'}"
19
+ # string = "Tests #{success ? 'PASS' : 'FAIL'}"
20
+ # symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
21
+ # heredoc = <<~TEXT
22
+ # Tests #{success ? 'PASS' : 'FAIL'}
23
+ # TEXT
24
+ # regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
15
25
  #
16
26
  # @example EnforcedStyle: double_quotes
17
27
  # # bad
18
- # result = "Tests #{success ? 'PASS' : 'FAIL'}"
28
+ # string = "Tests #{success ? 'PASS' : 'FAIL'}"
29
+ # symbol = :"Tests #{success ? 'PASS' : 'FAIL'}"
30
+ # heredoc = <<~TEXT
31
+ # Tests #{success ? 'PASS' : 'FAIL'}
32
+ # TEXT
33
+ # regexp = /Tests #{success ? 'PASS' : 'FAIL'}/
19
34
  #
20
35
  # # good
21
- # result = "Tests #{success ? "PASS" : "FAIL"}"
36
+ # string = "Tests #{success ? "PASS" : "FAIL"}"
37
+ # symbol = :"Tests #{success ? "PASS" : "FAIL"}"
38
+ # heredoc = <<~TEXT
39
+ # Tests #{success ? "PASS" : "FAIL"}
40
+ # TEXT
41
+ # regexp = /Tests #{success ? "PASS" : "FAIL"}/
22
42
  class StringLiteralsInInterpolation < Base
23
43
  include ConfigurableEnforcedStyle
24
44
  include StringLiteralsHelp
@@ -29,6 +49,11 @@ module RuboCop
29
49
  StringLiteralCorrector.correct(corrector, node, style)
30
50
  end
31
51
 
52
+ # Cop classes that include the StringHelp module usually ignore regexp
53
+ # nodes. Not so for this cop, which is why we override the on_regexp
54
+ # definition with an empty one.
55
+ def on_regexp(node); end
56
+
32
57
  private
33
58
 
34
59
  def message(_node)
@@ -69,9 +69,9 @@ module RuboCop
69
69
 
70
70
  def complex_content?(node)
71
71
  node.children.any? do |sym|
72
- content, = *sym
73
- content = content.to_s
74
- content_without_delimiter_pairs = content.gsub(/(\[\])|(\(\))/, '')
72
+ content = *sym
73
+ content = content.map { |c| c.is_a?(AST::Node) ? c.source : c }.join
74
+ content_without_delimiter_pairs = content.gsub(/(\[[^\s\[\]]*\])|(\([^\s\(\)]*\))/, '')
75
75
 
76
76
  content.include?(' ') || DELIMITERS.any? do |delimiter|
77
77
  content_without_delimiter_pairs.include?(delimiter)
@@ -112,23 +112,29 @@ module RuboCop
112
112
  end
113
113
 
114
114
  handle 'workspace/executeCommand' do |request|
115
- if request[:params][:command] == 'rubocop.formatAutocorrects'
116
- uri = request[:params][:arguments][0][:uri]
117
- @server.write(
118
- id: request[:id],
119
- method: 'workspace/applyEdit',
120
- params: {
121
- label: 'Format with RuboCop autocorrects',
122
- edit: {
123
- changes: {
124
- uri => format_file(uri)
125
- }
126
- }
127
- }
128
- )
115
+ case (command = request[:params][:command])
116
+ when 'rubocop.formatAutocorrects'
117
+ label = 'Format with RuboCop autocorrects'
118
+ when 'rubocop.formatAutocorrectsAll'
119
+ label = 'Format all with RuboCop autocorrects'
129
120
  else
130
- handle_unsupported_method(request, request[:params][:command])
121
+ handle_unsupported_method(request, command)
122
+ return
131
123
  end
124
+
125
+ uri = request[:params][:arguments][0][:uri]
126
+ @server.write(
127
+ id: request[:id],
128
+ method: 'workspace/applyEdit',
129
+ params: {
130
+ label: label,
131
+ edit: {
132
+ changes: {
133
+ uri => format_file(uri, command: command)
134
+ }
135
+ }
136
+ }
137
+ )
132
138
  end
133
139
 
134
140
  handle 'textDocument/willSave' do |_request|
@@ -176,14 +182,14 @@ module RuboCop
176
182
  }
177
183
  end
178
184
 
179
- def format_file(file_uri)
185
+ def format_file(file_uri, command: nil)
180
186
  unless (text = @text_cache[file_uri])
181
187
  Logger.log("Format request arrived before text synchronized; skipping: `#{file_uri}'")
182
188
 
183
189
  return []
184
190
  end
185
191
 
186
- new_text = @server.format(remove_file_protocol_from(file_uri), text)
192
+ new_text = @server.format(remove_file_protocol_from(file_uri), text, command: command)
187
193
 
188
194
  return [] if new_text == text
189
195
 
@@ -35,9 +35,15 @@ module RuboCop
35
35
  # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cli/command/execute_runner.rb#L95
36
36
  # Setting `parallel: true` would break this here:
37
37
  # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/runner.rb#L72
38
- def format(path, text)
38
+ def format(path, text, command:)
39
+ safe_autocorrect = if command
40
+ command == 'rubocop.formatAutocorrects'
41
+ else
42
+ @safe_autocorrect
43
+ end
44
+
39
45
  formatting_options = {
40
- stdin: text, force_exclusion: true, autocorrect: true, safe_autocorrect: @safe_autocorrect
46
+ stdin: text, force_exclusion: true, autocorrect: true, safe_autocorrect: safe_autocorrect
41
47
  }
42
48
  formatting_options[:only] = config_only_options if @lint_mode || @layout_mode
43
49
 
@@ -45,8 +45,8 @@ module RuboCop
45
45
  @writer.write(response)
46
46
  end
47
47
 
48
- def format(path, text)
49
- @runtime.format(path, text)
48
+ def format(path, text, command:)
49
+ @runtime.format(path, text, command: command)
50
50
  end
51
51
 
52
52
  def offenses(path, text)
@@ -421,10 +421,10 @@ module RuboCop
421
421
  end
422
422
 
423
423
  def considered_failure?(offense)
424
- # For :autocorrect level, any offense - corrected or not - is a failure.
425
424
  return false if offense.disabled?
426
425
 
427
- return true if @options[:fail_level] == :autocorrect
426
+ # For :autocorrect level, any correctable offense is a failure, regardless of severity
427
+ return true if @options[:fail_level] == :autocorrect && offense.correctable?
428
428
 
429
429
  !offense.corrected? && offense.severity >= minimum_severity_to_fail
430
430
  end
@@ -461,7 +461,9 @@ module RuboCop
461
461
  @minimum_severity_to_fail ||= begin
462
462
  # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
463
463
  name = @options[:fail_level] || :refactor
464
- RuboCop::Cop::Severity.new(name)
464
+
465
+ # autocorrect is a fake level - use the default
466
+ RuboCop::Cop::Severity.new(name == :autocorrect ? :refactor : name)
465
467
  end
466
468
  end
467
469
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.55.1'
6
+ STRING = '1.56.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
data/lib/rubocop.rb CHANGED
@@ -162,6 +162,7 @@ require_relative 'rubocop/cop/correctors/string_literal_corrector'
162
162
  require_relative 'rubocop/cop/correctors/unused_arg_corrector'
163
163
 
164
164
  require_relative 'rubocop/cop/bundler/duplicated_gem'
165
+ require_relative 'rubocop/cop/bundler/duplicated_group'
165
166
  require_relative 'rubocop/cop/bundler/gem_comment'
166
167
  require_relative 'rubocop/cop/bundler/gem_filename'
167
168
  require_relative 'rubocop/cop/bundler/gem_version'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.55.1
4
+ version: 1.56.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,8 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2023-07-31 00:00:00.000000000 Z
13
+ date: 2023-08-09 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: base64
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: 0.1.1
15
29
  - !ruby/object:Gem::Dependency
16
30
  name: json
17
31
  requirement: !ruby/object:Gem::Requirement
@@ -240,6 +254,7 @@ files:
240
254
  - lib/rubocop/cop/badge.rb
241
255
  - lib/rubocop/cop/base.rb
242
256
  - lib/rubocop/cop/bundler/duplicated_gem.rb
257
+ - lib/rubocop/cop/bundler/duplicated_group.rb
243
258
  - lib/rubocop/cop/bundler/gem_comment.rb
244
259
  - lib/rubocop/cop/bundler/gem_filename.rb
245
260
  - lib/rubocop/cop/bundler/gem_version.rb
@@ -1023,7 +1038,7 @@ metadata:
1023
1038
  homepage_uri: https://rubocop.org/
1024
1039
  changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md
1025
1040
  source_code_uri: https://github.com/rubocop/rubocop/
1026
- documentation_uri: https://docs.rubocop.org/rubocop/1.55/
1041
+ documentation_uri: https://docs.rubocop.org/rubocop/1.56/
1027
1042
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues
1028
1043
  rubygems_mfa_required: 'true'
1029
1044
  post_install_message: