rubocop 1.63.0 → 1.64.1

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/config/default.yml +18 -3
  4. data/lib/rubocop/cached_data.rb +11 -3
  5. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  6. data/lib/rubocop/cli.rb +4 -0
  7. data/lib/rubocop/config.rb +2 -3
  8. data/lib/rubocop/cop/base.rb +9 -14
  9. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  10. data/lib/rubocop/cop/documentation.rb +16 -6
  11. data/lib/rubocop/cop/force.rb +12 -0
  12. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  13. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  14. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  15. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  16. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -0
  17. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  18. data/lib/rubocop/cop/lint/assignment_in_condition.rb +3 -1
  19. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  20. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  21. data/lib/rubocop/cop/lint/erb_new_arguments.rb +21 -14
  22. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  23. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  24. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
  25. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  26. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
  27. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
  28. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  29. data/lib/rubocop/cop/style/access_modifier_declarations.rb +50 -0
  30. data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -2
  31. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  32. data/lib/rubocop/cop/style/copyright.rb +15 -10
  33. data/lib/rubocop/cop/style/documentation.rb +24 -24
  34. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  35. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  36. data/lib/rubocop/cop/style/hash_syntax.rb +18 -0
  37. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
  38. data/lib/rubocop/cop/style/map_into_array.rb +3 -3
  39. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  40. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  41. data/lib/rubocop/cop/style/redundant_line_continuation.rb +4 -1
  42. data/lib/rubocop/cop/style/require_order.rb +1 -1
  43. data/lib/rubocop/cop/style/send.rb +4 -4
  44. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +90 -0
  45. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  46. data/lib/rubocop/cop/style/super_arguments.rb +156 -0
  47. data/lib/rubocop/cop/style/symbol_proc.rb +32 -5
  48. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  49. data/lib/rubocop/cop/team.rb +2 -0
  50. data/lib/rubocop/formatter/disabled_config_formatter.rb +13 -9
  51. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  52. data/lib/rubocop/lockfile.rb +25 -6
  53. data/lib/rubocop/lsp/routes.rb +10 -13
  54. data/lib/rubocop/lsp/server.rb +2 -0
  55. data/lib/rubocop/lsp.rb +9 -2
  56. data/lib/rubocop/options.rb +3 -3
  57. data/lib/rubocop/rake_task.rb +1 -1
  58. data/lib/rubocop/runner.rb +5 -4
  59. data/lib/rubocop/version.rb +4 -4
  60. data/lib/rubocop.rb +2 -0
  61. metadata +10 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8eadae0a09b33bf6a4ae3621ad1b86ba4eff0e7601d3ceb89dcf115759e9c022
4
- data.tar.gz: ae113bb4d3eab63b4a551e36541f14d4e3bf3aae3354b853fb45960e80b90bbb
3
+ metadata.gz: cc79c69246529843a3d6179458d5563867515189cca9f68d34e6cba9f103a032
4
+ data.tar.gz: 2b71ef0f55a63904b93e1315417ab4bd9701c1d91f3f87087fda9046243a4176
5
5
  SHA512:
6
- metadata.gz: 6343643a7515b53e3e880a6cb92e256f37a3c1ee42c757af0506bf6457d900d36ea95b48bef2c6e008b5a96ba957f28b448a8e62da10ef1c27e6fe88dfbc1935
7
- data.tar.gz: c67f434f594eb5b3f609d1e36140c04a6c79ce784b2d614c0e57ed4d22f7bea437a4edf89de0b976c425c7a2fcaf54b46ce66391eb9e1b61f60fa03bd46fdebc
6
+ metadata.gz: 4ea1aa79a49f5a9c7331286e58563b5b92c5c8b11bc1d81dbddee107595a9588e84c7888a8fe6338b29e856740d35d56df47e8d7b485db5cc4cd6cd0f45a8406
7
+ data.tar.gz: f5bc4fb8153c6277534bc4acd22da3bb3e41ef0ca5eef2639817893fa2312b5291ca80b308151c2e315db993ea086f32f618f9ef65146b69e4b99fc50782c165
data/README.md CHANGED
@@ -5,7 +5,6 @@
5
5
  ----------
6
6
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
7
7
  [![Gem Version](https://badge.fury.io/rb/rubocop.svg)](https://badge.fury.io/rb/rubocop)
8
- [![CircleCI Status](https://circleci.com/gh/rubocop/rubocop/tree/master.svg?style=svg)](https://circleci.com/gh/rubocop/rubocop/tree/master)
9
8
  [![Actions Status](https://github.com/rubocop/rubocop/workflows/CI/badge.svg?branch=master)](https://github.com/rubocop/rubocop/actions?query=workflow%3ACI)
10
9
  [![Test Coverage](https://api.codeclimate.com/v1/badges/d2d67f728e88ea84ac69/test_coverage)](https://codeclimate.com/github/rubocop/rubocop/test_coverage)
11
10
  [![Maintainability](https://api.codeclimate.com/v1/badges/d2d67f728e88ea84ac69/maintainability)](https://codeclimate.com/github/rubocop/rubocop/maintainability)
@@ -53,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
52
  in your `Gemfile`:
54
53
 
55
54
  ```rb
56
- gem 'rubocop', '~> 1.63', require: false
55
+ gem 'rubocop', '~> 1.64', require: false
57
56
  ```
58
57
 
59
58
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -156,7 +156,7 @@ AllCops:
156
156
  # included.
157
157
  SuggestExtensions:
158
158
  rubocop-rails: [rails]
159
- rubocop-rspec: [rspec]
159
+ rubocop-rspec: [rspec, rspec-rails]
160
160
  rubocop-minitest: [minitest]
161
161
  rubocop-sequel: [sequel]
162
162
  rubocop-rake: [rake]
@@ -1703,7 +1703,6 @@ Lint/Debugger:
1703
1703
  DebuggerRequires:
1704
1704
  debug.rb:
1705
1705
  - debug/open
1706
- - debug/open_nonstop
1707
1706
  - debug/start
1708
1707
 
1709
1708
  Lint/DeprecatedClassMethods:
@@ -3091,6 +3090,7 @@ Style/AccessModifierDeclarations:
3091
3090
  - inline
3092
3091
  - group
3093
3092
  AllowModifiersOnSymbols: true
3093
+ AllowModifiersOnAttrs: true
3094
3094
  SafeAutoCorrect: false
3095
3095
 
3096
3096
  Style/AccessorGrouping:
@@ -3688,6 +3688,7 @@ Style/DocumentationMethod:
3688
3688
  Description: 'Checks for missing documentation comment for public methods.'
3689
3689
  Enabled: false
3690
3690
  VersionAdded: '0.43'
3691
+ AllowedMethods: []
3691
3692
  Exclude:
3692
3693
  - 'spec/**/*'
3693
3694
  - 'test/**/*'
@@ -4069,6 +4070,8 @@ Style/HashSyntax:
4069
4070
  - either
4070
4071
  # forces use of the 3.1 syntax only if all values can be omitted in the hash.
4071
4072
  - consistent
4073
+ # allow either (implicit or explicit) syntax but enforce consistency within a single hash
4074
+ - either_consistent
4072
4075
  # Force hashes that have a symbol value to use hash rockets
4073
4076
  UseHashRocketsWithSymbolValues: false
4074
4077
  # Do not suggest { a?: 1 } over { :a? => 1 } in ruby19 style
@@ -5241,6 +5244,13 @@ Style/Send:
5241
5244
  Enabled: false
5242
5245
  VersionAdded: '0.33'
5243
5246
 
5247
+ Style/SendWithLiteralMethodName:
5248
+ Description: 'Detects the use of the `public_send` method with a static method name argument.'
5249
+ Enabled: pending
5250
+ Safe: false
5251
+ AllowSend: true
5252
+ VersionAdded: '1.64'
5253
+
5244
5254
  Style/SignalException:
5245
5255
  Description: 'Checks for proper usage of fail and raise.'
5246
5256
  StyleGuide: '#prefer-raise-over-fail'
@@ -5415,6 +5425,11 @@ Style/StructInheritance:
5415
5425
  VersionAdded: '0.29'
5416
5426
  VersionChanged: '1.20'
5417
5427
 
5428
+ Style/SuperArguments:
5429
+ Description: 'Call `super` without arguments and parentheses when the signature is identical.'
5430
+ Enabled: pending
5431
+ VersionAdded: '1.64'
5432
+
5418
5433
  Style/SuperWithArgsParentheses:
5419
5434
  Description: 'Use parentheses for `super` with arguments.'
5420
5435
  StyleGuide: '#super-with-args'
@@ -5450,7 +5465,7 @@ Style/SymbolProc:
5450
5465
  Enabled: true
5451
5466
  Safe: false
5452
5467
  VersionAdded: '0.26'
5453
- VersionChanged: '1.40'
5468
+ VersionChanged: '1.64'
5454
5469
  AllowMethodsWithArguments: false
5455
5470
  # A list of method names to be always allowed by the check.
5456
5471
  # The names should be fairly unique, otherwise you'll end up ignoring lots of code.
@@ -48,11 +48,19 @@ module RuboCop
48
48
  source_buffer = Parser::Source::Buffer.new(@filename)
49
49
  source_buffer.source = File.read(@filename, encoding: Encoding::UTF_8)
50
50
  offenses.map! do |o|
51
- location = Parser::Source::Range.new(source_buffer,
52
- o['location']['begin_pos'],
53
- o['location']['end_pos'])
51
+ location = location_from_source_buffer(o, source_buffer)
54
52
  Cop::Offense.new(o['severity'], location, o['message'], o['cop_name'], o['status'].to_sym)
55
53
  end
56
54
  end
55
+
56
+ def location_from_source_buffer(offense, source_buffer)
57
+ begin_pos = offense['location']['begin_pos']
58
+ end_pos = offense['location']['end_pos']
59
+ if begin_pos.zero? && end_pos.zero?
60
+ Cop::Offense::NO_LOCATION
61
+ else
62
+ Parser::Source::Range.new(source_buffer, begin_pos, end_pos)
63
+ end
64
+ end
57
65
  end
58
66
  end
@@ -26,10 +26,10 @@ module RuboCop
26
26
 
27
27
  cops_array.each do |cop_name|
28
28
  cop = registry_hash[cop_name]
29
-
30
29
  next if cop.empty?
31
30
 
32
- puts Cop::Documentation.url_for(cop.first, @config)
31
+ url = Cop::Documentation.url_for(cop.first, @config)
32
+ puts url if url
33
33
  end
34
34
 
35
35
  puts
data/lib/rubocop/cli.rb CHANGED
@@ -57,6 +57,10 @@ module RuboCop
57
57
  rescue RuboCop::Error => e
58
58
  warn Rainbow("Error: #{e.message}").red
59
59
  STATUS_ERROR
60
+ rescue Interrupt
61
+ warn ''
62
+ warn 'Exiting...'
63
+ STATUS_INTERRUPTED
60
64
  rescue Finished
61
65
  STATUS_SUCCESS
62
66
  rescue OptionParser::InvalidOption => e
@@ -319,9 +319,8 @@ module RuboCop
319
319
  # @param [Gem::Version] gem_version an object like `Gem::Version.new("7.1.2.3")`
320
320
  # @return [Float] The major and minor version, like `7.1`
321
321
  def gem_version_to_major_minor_float(gem_version)
322
- segments = gem_version.canonical_segments
323
- # segments.fetch(0).to_f + (segments.fetch(1, 0.0).to_f / 10)
324
- Float("#{segments.fetch(0)}.#{segments.fetch(1, 0)}")
322
+ segments = gem_version.segments
323
+ Float("#{segments[0]}.#{segments[1]}")
325
324
  end
326
325
 
327
326
  # @returns [Hash{String => Gem::Version}] The locked gem versions, keyed by the gems' names.
@@ -60,12 +60,15 @@ module RuboCop
60
60
  []
61
61
  end
62
62
 
63
- # Cops (other than builtin) are encouraged to implement this
63
+ # Returns an url to view this cops documentation online.
64
+ # Requires 'DocumentationBaseURL' to be set for your department.
65
+ # Will follow the convention of RuboCops own documentation structure,
66
+ # overwrite this method to accommodate your custom layout.
64
67
  # @return [String, nil]
65
68
  #
66
69
  # @api public
67
- def self.documentation_url
68
- Documentation.url_for(self) if builtin?
70
+ def self.documentation_url(config = nil)
71
+ Documentation.url_for(self, config)
69
72
  end
70
73
 
71
74
  def self.inherited(subclass)
@@ -186,7 +189,9 @@ module RuboCop
186
189
  def add_global_offense(message = nil, severity: nil)
187
190
  severity = find_severity(nil, severity)
188
191
  message = find_message(nil, message)
189
- current_offenses << Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported)
192
+ range = Offense::NO_LOCATION
193
+ status = enabled_line?(range.line) ? :unsupported : :disabled
194
+ current_offenses << Offense.new(severity, range, message, name, status)
190
195
  end
191
196
 
192
197
  # Adds an offense on the specified range (or node with an expression)
@@ -396,16 +401,6 @@ module RuboCop
396
401
 
397
402
  ### Actually private methods
398
403
 
399
- # rubocop:disable Layout/ClassStructure
400
- def self.builtin?
401
- return false unless (m = instance_methods(false).first) # any custom method will do
402
-
403
- path, _line = instance_method(m).source_location
404
- path.start_with?(__dir__)
405
- end
406
- private_class_method :builtin?
407
- # rubocop:enable Layout/ClassStructure
408
-
409
404
  def reset_investigation
410
405
  @currently_disabled_lines = @current_offenses = @processed_source = @current_corrector = nil
411
406
  end
@@ -90,13 +90,11 @@ module RuboCop
90
90
  Array(cop_config['AllowedGems'])
91
91
  end
92
92
 
93
- def message(range)
94
- gem_specification = range.source
95
-
93
+ def message(_range)
96
94
  if required_style?
97
- format(REQUIRED_MSG, gem_specification: gem_specification)
95
+ REQUIRED_MSG
98
96
  elsif forbidden_style?
99
- format(FORBIDDEN_MSG, gem_specification: gem_specification)
97
+ FORBIDDEN_MSG
100
98
  end
101
99
  end
102
100
 
@@ -17,23 +17,33 @@ module RuboCop
17
17
  fragment = cop_class.cop_name.downcase.gsub(/[^a-z]/, '')
18
18
  base_url = base_url_for(cop_class, config)
19
19
 
20
- "#{base_url}/#{base}.html##{fragment}"
20
+ "#{base_url}/#{base}.html##{fragment}" if base_url
21
21
  end
22
22
 
23
23
  # @api private
24
24
  def base_url_for(cop_class, config)
25
- return default_base_url unless config
25
+ if config
26
+ department_name = cop_class.department.to_s
27
+ url = config.for_department(department_name)['DocumentationBaseURL']
28
+ return url if url
29
+ end
26
30
 
27
- department_name = cop_class.department.to_s
28
-
29
- config.for_department(department_name)['DocumentationBaseURL'] ||
30
- config.for_all_cops['DocumentationBaseURL']
31
+ default_base_url if builtin?(cop_class)
31
32
  end
32
33
 
33
34
  # @api private
34
35
  def default_base_url
35
36
  'https://docs.rubocop.org/rubocop'
36
37
  end
38
+
39
+ # @api private
40
+ def builtin?(cop_class)
41
+ # any custom method will do
42
+ return false unless (m = cop_class.instance_methods(false).first)
43
+
44
+ path, _line = cop_class.instance_method(m).source_location
45
+ path.start_with?(__dir__)
46
+ end
37
47
  end
38
48
  end
39
49
  end
@@ -4,6 +4,16 @@ module RuboCop
4
4
  module Cop
5
5
  # A scaffold for concrete forces.
6
6
  class Force
7
+ # @api private
8
+ class HookError < StandardError
9
+ attr_reader :joining_cop
10
+
11
+ def initialize(joining_cop)
12
+ super
13
+ @joining_cop = joining_cop
14
+ end
15
+ end
16
+
7
17
  attr_reader :cops
8
18
 
9
19
  def self.all
@@ -32,6 +42,8 @@ module RuboCop
32
42
  next unless cop.respond_to?(method_name)
33
43
 
34
44
  cop.public_send(method_name, *args)
45
+ rescue StandardError
46
+ raise HookError, cop
35
47
  end
36
48
  end
37
49
 
@@ -101,13 +101,11 @@ module RuboCop
101
101
  Array(cop_config['AllowedGems'])
102
102
  end
103
103
 
104
- def message(range)
105
- gem_specification = range.source
106
-
104
+ def message(_range)
107
105
  if required_style?
108
- format(REQUIRED_MSG, gem_specification: gem_specification)
106
+ REQUIRED_MSG
109
107
  elsif forbidden_style?
110
- format(FORBIDDEN_MSG, gem_specification: gem_specification)
108
+ FORBIDDEN_MSG
111
109
  end
112
110
  end
113
111
 
@@ -46,7 +46,7 @@ module RuboCop
46
46
  /\A(does not|doesn't) (register|find|flag|report)/ => 'registers',
47
47
  /\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense',
48
48
  /\Aregisters no offense/ => 'registers an offense',
49
- /\Aaccepts\b/ => 'registers'
49
+ /\A(accepts|register)\b/ => 'registers'
50
50
  }.freeze
51
51
 
52
52
  EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
@@ -160,7 +160,7 @@ module RuboCop
160
160
  end
161
161
 
162
162
  def two_alternatives?(line)
163
- /^\s*(else|elsif|when|rescue|ensure)\b/.match?(line)
163
+ /^\s*(else|elsif|when|in|rescue|ensure)\b/.match?(line)
164
164
  end
165
165
  end
166
166
  end
@@ -106,7 +106,9 @@ module RuboCop
106
106
  end
107
107
 
108
108
  def concat_consecutive_comments(comments)
109
- consecutive_comments = comments.chunk_while { |i, j| i.loc.line.succ == j.loc.line }
109
+ consecutive_comments = comments.chunk_while do |i, j|
110
+ i.loc.line.succ == j.loc.line && i.loc.column == j.loc.column
111
+ end
110
112
 
111
113
  consecutive_comments.map do |chunk|
112
114
  joined_text = chunk.map { |c| comment_text(c) }.join
@@ -92,6 +92,8 @@ module RuboCop
92
92
  'in an array, relative to %<base_description>s.'
93
93
 
94
94
  def on_array(node)
95
+ return if style != :consistent && enforce_first_argument_with_fixed_indentation?
96
+
95
97
  check(node, nil) if node.loc.begin
96
98
  end
97
99
 
@@ -25,8 +25,7 @@ module RuboCop
25
25
  include RangeHelp
26
26
  extend AutoCorrector
27
27
 
28
- NO_SPACE_MSG = 'Space inside string interpolation detected.'
29
- SPACE_MSG = 'Missing space inside string interpolation detected.'
28
+ MSG = '%<command>s space inside string interpolation.'
30
29
 
31
30
  def on_interpolation(begin_node)
32
31
  return if begin_node.multiline?
@@ -36,9 +35,9 @@ module RuboCop
36
35
  return if empty_brackets?(left, right, tokens: tokens)
37
36
 
38
37
  if style == :no_space
39
- no_space_offenses(begin_node, left, right, NO_SPACE_MSG)
38
+ no_space_offenses(begin_node, left, right, MSG)
40
39
  else
41
- space_offenses(begin_node, left, right, SPACE_MSG)
40
+ space_offenses(begin_node, left, right, MSG)
42
41
  end
43
42
  end
44
43
 
@@ -88,7 +88,9 @@ module RuboCop
88
88
  end
89
89
 
90
90
  def skip_children?(asgn_node)
91
- empty_condition?(asgn_node) || (safe_assignment_allowed? && safe_assignment?(asgn_node))
91
+ (asgn_node.call_type? && !asgn_node.assignment_method?) ||
92
+ empty_condition?(asgn_node) ||
93
+ (safe_assignment_allowed? && safe_assignment?(asgn_node))
92
94
  end
93
95
 
94
96
  def traverse_node(node, &block)
@@ -52,7 +52,7 @@ module RuboCop
52
52
  # @!method deprecated_class_method?(node)
53
53
  def_node_matcher :deprecated_class_method?, <<~PATTERN
54
54
  {
55
- (send (const {cbase nil?} {:ENV}) {:clone :dup :freeze})
55
+ (send (const {cbase nil?} :ENV) {:clone :dup :freeze})
56
56
  (send (const {cbase nil?} {:File :Dir}) :exists? _)
57
57
  (send (const {cbase nil?} :Socket) {:gethostbyaddr :gethostbyname} ...)
58
58
  (send nil? :attr _ boolean)
@@ -146,7 +146,7 @@ module RuboCop
146
146
  node.source_range.with(end_pos: node.condition.source_range.end_pos)
147
147
  elsif all_branches_body_missing?(node)
148
148
  if_node = node.ancestors.detect(&:if?)
149
- node.source_range.with(end_pos: if_node.loc.end.end_pos)
149
+ node.source_range.join(if_node.loc.end.end)
150
150
  else
151
151
  node.source_range
152
152
  end
@@ -65,17 +65,15 @@ module RuboCop
65
65
 
66
66
  minimum_target_ruby_version 2.6
67
67
 
68
- MESSAGES = [
69
- 'Passing safe_level with the 2nd argument of `ERB.new` is ' \
70
- 'deprecated. Do not use it, and specify other arguments as ' \
71
- 'keyword arguments.',
72
- 'Passing trim_mode with the 3rd argument of `ERB.new` is ' \
73
- 'deprecated. Use keyword argument like ' \
74
- '`ERB.new(str, trim_mode: %<arg_value>s)` instead.',
75
- 'Passing eoutvar with the 4th argument of `ERB.new` is ' \
76
- 'deprecated. Use keyword argument like ' \
77
- '`ERB.new(str, eoutvar: %<arg_value>s)` instead.'
78
- ].freeze
68
+ MESSAGE_SAFE_LEVEL = 'Passing safe_level with the 2nd argument of `ERB.new` is ' \
69
+ 'deprecated. Do not use it, and specify other arguments as ' \
70
+ 'keyword arguments.'
71
+ MESSAGE_TRIM_MODE = 'Passing trim_mode with the 3rd argument of `ERB.new` is ' \
72
+ 'deprecated. Use keyword argument like ' \
73
+ '`ERB.new(str, trim_mode: %<arg_value>s)` instead.'
74
+ MESSAGE_EOUTVAR = 'Passing eoutvar with the 4th argument of `ERB.new` is ' \
75
+ 'deprecated. Use keyword argument like ' \
76
+ '`ERB.new(str, eoutvar: %<arg_value>s)` instead.'
79
77
 
80
78
  RESTRICT_ON_SEND = %i[new].freeze
81
79
 
@@ -92,10 +90,8 @@ module RuboCop
92
90
  arguments[1..3].each_with_index do |argument, i|
93
91
  next if !argument || argument.hash_type?
94
92
 
95
- message = format(MESSAGES[i], arg_value: argument.source)
96
-
97
93
  add_offense(
98
- argument.source_range, message: message
94
+ argument.source_range, message: message(i, argument.source)
99
95
  ) do |corrector|
100
96
  autocorrect(corrector, node)
101
97
  end
@@ -105,6 +101,17 @@ module RuboCop
105
101
 
106
102
  private
107
103
 
104
+ def message(positional_argument_index, arg_value)
105
+ case positional_argument_index
106
+ when 0
107
+ MESSAGE_SAFE_LEVEL
108
+ when 1
109
+ format(MESSAGE_TRIM_MODE, arg_value: arg_value)
110
+ when 2
111
+ format(MESSAGE_EOUTVAR, arg_value: arg_value)
112
+ end
113
+ end
114
+
108
115
  def autocorrect(corrector, node)
109
116
  str_arg = node.first_argument.source
110
117
 
@@ -47,8 +47,10 @@ module RuboCop
47
47
 
48
48
  def on_regexp(node)
49
49
  each_unsafe_regexp_range(node) do |loc|
50
+ next unless (replacement = regexp_range(loc.source))
51
+
50
52
  add_offense(loc) do |corrector|
51
- corrector.replace(loc, rewrite_regexp_range(loc.source))
53
+ corrector.replace(loc, replacement)
52
54
  end
53
55
  end
54
56
  end
@@ -99,10 +101,13 @@ module RuboCop
99
101
  end
100
102
  end
101
103
 
102
- def rewrite_regexp_range(source)
104
+ def regexp_range(source)
103
105
  open, close = source.split('-')
104
- first = [open, range_for(open).end]
105
- second = [range_for(close).begin, close]
106
+ return unless (open_range = range_for(open))
107
+ return unless (close_range = range_for(close))
108
+
109
+ first = [open, open_range.end]
110
+ second = [close_range.begin, close]
106
111
  "#{first.uniq.join('-')}#{second.uniq.join('-')}"
107
112
  end
108
113
  end
@@ -130,7 +130,7 @@ module RuboCop
130
130
  # @return [Parser::Source::Range]
131
131
  #
132
132
  def last_arg_range(node)
133
- node.last_argument.source_range.with(begin_pos: node.arguments[-2].source_range.end_pos)
133
+ node.last_argument.source_range.join(node.arguments[-2].source_range.end)
134
134
  end
135
135
 
136
136
  def unsorted_dir_loop?(node)
@@ -71,7 +71,7 @@ module RuboCop
71
71
  expressions.any? { |expr| flow_expression?(expr) }
72
72
  when :if
73
73
  check_if(node)
74
- when :case
74
+ when :case, :case_match
75
75
  check_case(node)
76
76
  else
77
77
  false
@@ -89,7 +89,9 @@ module RuboCop
89
89
  return false unless else_branch
90
90
  return false unless flow_expression?(else_branch)
91
91
 
92
- node.when_branches.all? { |branch| branch.body && flow_expression?(branch.body) }
92
+ branches = node.case_type? ? node.when_branches : node.in_pattern_branches
93
+
94
+ branches.all? { |branch| branch.body && flow_expression?(branch.body) }
93
95
  end
94
96
  end
95
97
  end
@@ -160,7 +160,7 @@ module RuboCop
160
160
  break_statement && !preceded_by_continue_statement?(break_statement)
161
161
  when :if
162
162
  check_if(node)
163
- when :case
163
+ when :case, :case_match
164
164
  check_case(node)
165
165
  else
166
166
  false
@@ -178,7 +178,13 @@ module RuboCop
178
178
  return false unless else_branch
179
179
  return false unless break_statement?(else_branch)
180
180
 
181
- node.when_branches.all? { |branch| branch.body && break_statement?(branch.body) }
181
+ branches = if node.case_type?
182
+ node.when_branches
183
+ else
184
+ node.in_pattern_branches
185
+ end
186
+
187
+ branches.all? { |branch| branch.body && break_statement?(branch.body) }
182
188
  end
183
189
 
184
190
  def preceded_by_continue_statement?(break_statement)
@@ -43,16 +43,16 @@ module RuboCop
43
43
  types.map do |type|
44
44
  case type
45
45
  when :array
46
- ->(node) { node.array_type? }
46
+ lambda(&:array_type?)
47
47
  when :hash
48
- ->(node) { node.hash_type? }
48
+ lambda(&:hash_type?)
49
49
  when :heredoc
50
50
  ->(node) { heredoc_node?(node) }
51
51
  when :method_call
52
- ->(node) { node.call_type? }
52
+ lambda(&:call_type?)
53
53
  else
54
- raise ArgumentError, "Unknown foldable type: #{type.inspect}. " \
55
- "Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}."
54
+ raise Warning, "Unknown foldable type: #{type.inspect}. " \
55
+ "Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}."
56
56
  end
57
57
  end
58
58
  end
@@ -67,13 +67,14 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def ignore_mixed_hash_shorthand_syntax?(hash_node)
70
- target_ruby_version <= 3.0 || enforced_shorthand_syntax != 'consistent' ||
70
+ target_ruby_version <= 3.0 ||
71
+ !%w[consistent either_consistent].include?(enforced_shorthand_syntax) ||
71
72
  !hash_node.hash_type?
72
73
  end
73
74
 
74
75
  def ignore_hash_shorthand_syntax?(pair_node)
75
76
  target_ruby_version <= 3.0 || enforced_shorthand_syntax == 'either' ||
76
- enforced_shorthand_syntax == 'consistent' ||
77
+ %w[consistent either_consistent].include?(enforced_shorthand_syntax) ||
77
78
  !pair_node.parent.hash_type?
78
79
  end
79
80
 
@@ -172,6 +173,11 @@ module RuboCop
172
173
  hash_value_type_breakdown[:value_needed]&.any?
173
174
  end
174
175
 
176
+ def ignore_explicit_omissible_hash_shorthand_syntax?(hash_value_type_breakdown)
177
+ hash_value_type_breakdown.keys == [:value_omittable] &&
178
+ enforced_shorthand_syntax == 'either_consistent'
179
+ end
180
+
175
181
  def each_omitted_value_pair(hash_value_type_breakdown, &block)
176
182
  hash_value_type_breakdown[:value_omitted]&.each(&block)
177
183
  end
@@ -198,6 +204,7 @@ module RuboCop
198
204
 
199
205
  def no_mixed_shorthand_syntax_check(hash_value_type_breakdown)
200
206
  return if hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
207
+ return if ignore_explicit_omissible_hash_shorthand_syntax?(hash_value_type_breakdown)
201
208
 
202
209
  each_omittable_value_pair(hash_value_type_breakdown) do |pair_node|
203
210
  hash_key_source = pair_node.key.source
@@ -30,8 +30,8 @@ module RuboCop
30
30
  class CompoundHash < Base
31
31
  COMBINATOR_IN_HASH_MSG = 'Use `[...].hash` instead of combining hash values manually.'
32
32
  MONUPLE_HASH_MSG =
33
- 'Delegate hash directly without wrapping in an array when only using a single value'
34
- REDUNDANT_HASH_MSG = 'Calling .hash on elements of a hashed array is redundant'
33
+ 'Delegate hash directly without wrapping in an array when only using a single value.'
34
+ REDUNDANT_HASH_MSG = 'Calling .hash on elements of a hashed array is redundant.'
35
35
 
36
36
  # @!method hash_method_definition?(node)
37
37
  def_node_matcher :hash_method_definition?, <<~PATTERN