rubocop 1.4.1 → 1.6.0

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +54 -11
  4. data/config/obsoletion.yml +196 -0
  5. data/lib/rubocop.rb +14 -0
  6. data/lib/rubocop/cli.rb +5 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +80 -0
  8. data/lib/rubocop/config_loader.rb +1 -1
  9. data/lib/rubocop/config_loader_resolver.rb +5 -1
  10. data/lib/rubocop/config_obsoletion.rb +65 -247
  11. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  12. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  13. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  14. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  16. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  17. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  18. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  20. data/lib/rubocop/config_validator.rb +18 -4
  21. data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
  22. data/lib/rubocop/cop/base.rb +17 -15
  23. data/lib/rubocop/cop/cop.rb +2 -2
  24. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  25. data/lib/rubocop/cop/generator.rb +1 -1
  26. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +3 -3
  27. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  28. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  29. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  30. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  31. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +12 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  33. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  34. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  35. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +1 -1
  36. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  37. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  38. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +7 -2
  39. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  40. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  41. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  42. data/lib/rubocop/cop/metrics/parameter_lists.rb +64 -1
  43. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  44. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  45. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  46. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  47. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -2
  48. data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
  49. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  50. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  51. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  52. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  53. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  54. data/lib/rubocop/cop/style/and_or.rb +10 -0
  55. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  56. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  57. data/lib/rubocop/cop/style/float_division.rb +44 -1
  58. data/lib/rubocop/cop/style/format_string.rb +8 -3
  59. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  60. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  61. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  62. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  63. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  64. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  65. data/lib/rubocop/cop/style/redundant_argument.rb +17 -2
  66. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  67. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  68. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  69. data/lib/rubocop/cop/style/sole_nested_conditional.rb +65 -3
  70. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  71. data/lib/rubocop/cop/style/string_concatenation.rb +26 -1
  72. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  73. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  74. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  75. data/lib/rubocop/core_ext/hash.rb +20 -0
  76. data/lib/rubocop/ext/regexp_node.rb +29 -12
  77. data/lib/rubocop/ext/regexp_parser.rb +20 -9
  78. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  79. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  80. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  81. data/lib/rubocop/lockfile.rb +40 -0
  82. data/lib/rubocop/version.rb +1 -1
  83. metadata +32 -5
@@ -11,6 +11,12 @@ module RuboCop
11
11
  include Metrics::Utils::RepeatedCsendDiscount
12
12
  extend NodePattern::Macros
13
13
 
14
+ # Ensure cops that include `MethodComplexity` have the config
15
+ # `attr_accessor`s that `ignored_method?` needs.
16
+ def self.included(base)
17
+ base.extend(IgnoredMethods::Config)
18
+ end
19
+
14
20
  def on_def(node)
15
21
  return if ignored_method?(node.method_name)
16
22
 
@@ -14,7 +14,10 @@ module RuboCop
14
14
  return if part_of_ignored_node?(node)
15
15
 
16
16
  if offense?(node)
17
- add_offense(node) { opposite_style_detected }
17
+ add_offense(node) do |corrector|
18
+ opposite_style_detected
19
+ autocorrect(corrector, node) if respond_to?(:autocorrect, true)
20
+ end
18
21
  else
19
22
  correct_style_detected
20
23
  end
@@ -3,7 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # This cop makes sure that accessor methods are named properly.
6
+ # This cop makes sure that accessor methods are named properly. Applies
7
+ # to both instance and class methods.
8
+ #
9
+ # NOTE: Offenses are only registered for methods with the expected
10
+ # arity. Getters (`get_attribute`) must have no arguments to be
11
+ # registered, and setters (`set_attribute(value)`) must have exactly
12
+ # one.
7
13
  #
8
14
  # @example
9
15
  # # bad
@@ -21,6 +27,14 @@ module RuboCop
21
27
  # # good
22
28
  # def attribute
23
29
  # end
30
+ #
31
+ # # accepted, incorrect arity for getter
32
+ # def get_value(attr)
33
+ # end
34
+ #
35
+ # # accepted, incorrect arity for setter
36
+ # def set_value
37
+ # end
24
38
  class AccessorMethodName < Base
25
39
  MSG_READER = 'Do not prefix reader method names with `get_`.'
26
40
  MSG_WRITER = 'Do not prefix writer method names with `set_`.'
@@ -104,6 +104,8 @@ module RuboCop
104
104
  def on_arg(node)
105
105
  @node = node
106
106
  name, = *node
107
+ return if allowed_identifier?(name)
108
+
107
109
  check_name(node, name, node.loc.name)
108
110
  end
109
111
  alias on_lvasgn on_arg
@@ -139,7 +141,7 @@ module RuboCop
139
141
  end
140
142
 
141
143
  def allowed_identifier?(name)
142
- allowed_identifiers.include?(name.to_s)
144
+ allowed_identifiers.include?(name.to_s.delete('@'))
143
145
  end
144
146
 
145
147
  def allowed_identifiers
@@ -72,6 +72,8 @@ module RuboCop
72
72
  end
73
73
 
74
74
  corrector.replace(node.loc.operator, node.alternate_operator)
75
+
76
+ keep_operator_precedence(corrector, node)
75
77
  end
76
78
  end
77
79
 
@@ -123,6 +125,14 @@ module RuboCop
123
125
  corrector.wrap(node, '(', ')')
124
126
  end
125
127
 
128
+ def keep_operator_precedence(corrector, node)
129
+ if node.or_type? && node.parent&.and_type?
130
+ corrector.wrap(node, '(', ')')
131
+ elsif node.and_type? && node.rhs.or_type?
132
+ corrector.wrap(node.rhs, '(', ')')
133
+ end
134
+ end
135
+
126
136
  def correctable_send?(node)
127
137
  !node.parenthesized? && node.arguments? && !node.method?(:[])
128
138
  end
@@ -14,8 +14,9 @@ module RuboCop
14
14
  #
15
15
  # # good
16
16
  # ?\C-\M-d
17
- class CharacterLiteral < Cop
17
+ class CharacterLiteral < Base
18
18
  include StringHelp
19
+ extend AutoCorrector
19
20
 
20
21
  MSG = 'Do not use the character literal - ' \
21
22
  'use string literal instead.'
@@ -26,17 +27,15 @@ module RuboCop
26
27
  node.source.size.between?(2, 3)
27
28
  end
28
29
 
29
- def autocorrect(node)
30
- lambda do |corrector|
31
- string = node.source[1..-1]
30
+ def autocorrect(corrector, node)
31
+ string = node.source[1..-1]
32
32
 
33
- # special character like \n
34
- # or ' which needs to use "" or be escaped.
35
- if string.length == 2 || string == "'"
36
- corrector.replace(node, %("#{string}"))
37
- elsif string.length == 1 # normal character
38
- corrector.replace(node, "'#{string}'")
39
- end
33
+ # special character like \n
34
+ # or ' which needs to use "" or be escaped.
35
+ if string.length == 2 || string == "'"
36
+ corrector.replace(node, %("#{string}"))
37
+ elsif string.length == 1 # normal character
38
+ corrector.replace(node, "'#{string}'")
40
39
  end
41
40
  end
42
41
 
@@ -55,13 +55,18 @@ module RuboCop
55
55
  padding = ((' ' * indent_width) + leading_spaces(node)).to_s
56
56
  padding_for_trailing_end = padding.sub(' ' * node.loc.end.column, '')
57
57
 
58
- replace_keyword_with_module(corrector, node)
58
+ replace_namespace_keyword(corrector, node)
59
59
  split_on_double_colon(corrector, node, padding)
60
60
  add_trailing_end(corrector, node, padding_for_trailing_end)
61
61
  end
62
62
 
63
- def replace_keyword_with_module(corrector, node)
64
- corrector.replace(node.loc.keyword, 'module')
63
+ def replace_namespace_keyword(corrector, node)
64
+ class_definition = node.left_sibling&.each_node(:class)&.find do |class_node|
65
+ class_node.identifier == node.identifier.namespace
66
+ end
67
+ namespace_keyword = class_definition ? 'class' : 'module'
68
+
69
+ corrector.replace(node.loc.keyword, namespace_keyword)
65
70
  end
66
71
 
67
72
  def split_on_double_colon(corrector, node, padding)
@@ -41,6 +41,8 @@ module RuboCop
41
41
  # a.fdiv(b)
42
42
  class FloatDivision < Base
43
43
  include ConfigurableEnforcedStyle
44
+ extend AutoCorrector
45
+
44
46
  MESSAGES = {
45
47
  left_coerce: 'Prefer using `.to_f` on the left side.',
46
48
  right_coerce: 'Prefer using `.to_f` on the right side.',
@@ -64,7 +66,20 @@ module RuboCop
64
66
  PATTERN
65
67
 
66
68
  def on_send(node)
67
- add_offense(node) if offense_condition?(node)
69
+ return unless offense_condition?(node)
70
+
71
+ add_offense(node) do |corrector|
72
+ case style
73
+ when :left_coerce, :single_coerce
74
+ add_to_f_method(corrector, node.receiver)
75
+ remove_to_f_method(corrector, node.first_argument)
76
+ when :right_coerce
77
+ remove_to_f_method(corrector, node.receiver)
78
+ add_to_f_method(corrector, node.first_argument)
79
+ when :fdiv
80
+ correct_from_slash_to_fdiv(corrector, node, node.receiver, node.first_argument)
81
+ end
82
+ end
68
83
  end
69
84
 
70
85
  private
@@ -87,6 +102,34 @@ module RuboCop
87
102
  def message(_node)
88
103
  MESSAGES[style]
89
104
  end
105
+
106
+ def add_to_f_method(corrector, node)
107
+ corrector.insert_after(node, '.to_f') unless node.send_type? && node.method?(:to_f)
108
+ end
109
+
110
+ def remove_to_f_method(corrector, send_node)
111
+ corrector.remove(send_node.loc.dot)
112
+ corrector.remove(send_node.loc.selector)
113
+ end
114
+
115
+ def correct_from_slash_to_fdiv(corrector, node, receiver, argument)
116
+ receiver_source = extract_receiver_source(receiver)
117
+ argument_source = extract_receiver_source(argument)
118
+
119
+ if argument.respond_to?(:parenthesized?) && !argument.parenthesized?
120
+ argument_source = "(#{argument_source})"
121
+ end
122
+
123
+ corrector.replace(node, "#{receiver_source}.fdiv#{argument_source}")
124
+ end
125
+
126
+ def extract_receiver_source(node)
127
+ if node.send_type? && node.method?(:to_f)
128
+ node.receiver.source
129
+ else
130
+ node.source
131
+ end
132
+ end
90
133
  end
91
134
  end
92
135
  end
@@ -111,15 +111,20 @@ module RuboCop
111
111
  format = format_arg.source
112
112
 
113
113
  args = if param_args.one?
114
- arg = param_args.last
115
-
116
- arg.hash_type? ? "{ #{arg.source} }" : arg.source
114
+ format_single_parameter(param_args.last)
117
115
  else
118
116
  "[#{param_args.map(&:source).join(', ')}]"
119
117
  end
120
118
 
121
119
  corrector.replace(node, "#{format} % #{args}")
122
120
  end
121
+
122
+ def format_single_parameter(arg)
123
+ source = arg.source
124
+ return "{ #{source} }" if arg.hash_type?
125
+
126
+ arg.send_type? && arg.operator_method? && !arg.parenthesized? ? "(#{source})" : source
127
+ end
123
128
  end
124
129
  end
125
130
  end
@@ -46,6 +46,10 @@ module RuboCop
46
46
  MSG_USE_NORMAL =
47
47
  'Modifier form of `%<keyword>s` makes the line too long.'
48
48
 
49
+ def self.autocorrect_incompatible_with
50
+ [Style::SoleNestedConditional]
51
+ end
52
+
49
53
  def on_if(node)
50
54
  msg = if single_line_as_modifier?(node) && !named_capture_in_condition?(node)
51
55
  MSG_USE_MODIFIER
@@ -17,26 +17,61 @@ module RuboCop
17
17
  include OnNormalIfUnless
18
18
  extend AutoCorrector
19
19
 
20
- MSG = 'Do not use if x; Use the ternary operator instead.'
20
+ MSG_IF_ELSE = 'Do not use `if %<expr>s;` - use `if/else` instead.'
21
+ MSG_TERNARY = 'Do not use `if %<expr>s;` - use a ternary operator instead.'
21
22
 
22
23
  def on_normal_if_unless(node)
23
24
  return unless node.else_branch
25
+ return if node.parent&.if_type?
24
26
 
25
27
  beginning = node.loc.begin
26
28
  return unless beginning&.is?(';')
27
29
 
28
- add_offense(node) do |corrector|
29
- corrector.replace(node, correct_to_ternary(node))
30
+ message = node.else_branch.if_type? ? MSG_IF_ELSE : MSG_TERNARY
31
+
32
+ add_offense(node, message: format(message, expr: node.condition.source)) do |corrector|
33
+ corrector.replace(node, autocorrect(node))
30
34
  end
31
35
  end
32
36
 
33
37
  private
34
38
 
35
- def correct_to_ternary(node)
39
+ def autocorrect(node)
40
+ return correct_elsif(node) if node.else_branch.if_type?
41
+
36
42
  else_code = node.else_branch ? node.else_branch.source : 'nil'
37
43
 
38
44
  "#{node.condition.source} ? #{node.if_branch.source} : #{else_code}"
39
45
  end
46
+
47
+ def correct_elsif(node)
48
+ <<~RUBY.chop
49
+ if #{node.condition.source}
50
+ #{node.if_branch.source}
51
+ #{build_else_branch(node.else_branch).chop}
52
+ end
53
+ RUBY
54
+ end
55
+
56
+ def build_else_branch(second_condition)
57
+ result = <<~RUBY
58
+ elsif #{second_condition.condition.source}
59
+ #{second_condition.if_branch.source}
60
+ RUBY
61
+
62
+ if second_condition.else_branch
63
+ result += if second_condition.else_branch.if_type?
64
+ build_else_branch(second_condition.else_branch)
65
+ else
66
+ <<~RUBY
67
+ else
68
+ #{second_condition.else_branch.source}
69
+ RUBY
70
+ end
71
+ end
72
+
73
+ result
74
+ end
40
75
  end
41
76
  end
42
77
  end
@@ -18,7 +18,7 @@ module RuboCop
18
18
  #
19
19
  # # good
20
20
  # ip_address = ENV['DEPLOYMENT_IP_ADDRESS']
21
- class IpAddresses < Cop
21
+ class IpAddresses < Base
22
22
  include StringHelp
23
23
 
24
24
  IPV6_MAX_SIZE = 45 # IPv4-mapped IPv6 is the longest
@@ -21,21 +21,30 @@ module RuboCop
21
21
  def on_send(node)
22
22
  return unless !node.arguments? && node.parenthesized?
23
23
  return if ineligible_node?(node)
24
+ return if default_argument?(node)
24
25
  return if ignored_method?(node.method_name)
25
26
  return if same_name_assignment?(node)
26
27
 
28
+ register_offense(node)
29
+ end
30
+
31
+ private
32
+
33
+ def register_offense(node)
27
34
  add_offense(offense_range(node)) do |corrector|
28
35
  corrector.remove(node.loc.begin)
29
36
  corrector.remove(node.loc.end)
30
37
  end
31
38
  end
32
39
 
33
- private
34
-
35
40
  def ineligible_node?(node)
36
41
  node.camel_case_method? || node.implicit_call? || node.prefix_not?
37
42
  end
38
43
 
44
+ def default_argument?(node)
45
+ node.parent&.optarg_type?
46
+ end
47
+
39
48
  def same_name_assignment?(node)
40
49
  any_assignment?(node) do |asgn_node|
41
50
  next variable_in_mass_assignment?(node.method_name, asgn_node) if asgn_node.masgn_type?
@@ -27,12 +27,13 @@ module RuboCop
27
27
  # # bad
28
28
  # 10_000_00 # typical representation of $10,000 in cents
29
29
  #
30
- class NumericLiterals < Cop
30
+ class NumericLiterals < Base
31
31
  # The parameter is called MinDigits (meaning the minimum number of
32
32
  # digits for which an offense can be registered), but essentially it's
33
33
  # a Max parameter (the maximum number of something that's allowed).
34
34
  include ConfigurableMax
35
35
  include IntegerNode
36
+ extend AutoCorrector
36
37
 
37
38
  MSG = 'Use underscores(_) as thousands separator and ' \
38
39
  'separate every 3 digits with them.'
@@ -46,12 +47,6 @@ module RuboCop
46
47
  check(node)
47
48
  end
48
49
 
49
- def autocorrect(node)
50
- lambda do |corrector|
51
- corrector.replace(node, format_number(node))
52
- end
53
- end
54
-
55
50
  private
56
51
 
57
52
  def max_parameter_name
@@ -67,11 +62,19 @@ module RuboCop
67
62
 
68
63
  case int
69
64
  when /^\d+$/
70
- add_offense(node) { self.max = int.size + 1 }
65
+ return unless (self.max = int.size + 1)
66
+
67
+ register_offense(node)
71
68
  when /\d{4}/, short_group_regex
72
- add_offense(node) do
73
- self.config_to_allow_offenses = { 'Enabled' => false }
74
- end
69
+ return unless (self.config_to_allow_offenses = { 'Enabled' => false })
70
+
71
+ register_offense(node)
72
+ end
73
+ end
74
+
75
+ def register_offense(node)
76
+ add_offense(node) do |corrector|
77
+ corrector.replace(node, format_number(node))
75
78
  end
76
79
  end
77
80
 
@@ -4,7 +4,8 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # This cop looks for uses of Perl-style regexp match
7
- # backreferences like $1, $2, etc.
7
+ # backreferences and their English versions like
8
+ # $1, $2, $&, &+, $MATCH, $PREMATCH, etc.
8
9
  #
9
10
  # @example
10
11
  # # bad
@@ -15,19 +16,95 @@ module RuboCop
15
16
  class PerlBackrefs < Base
16
17
  extend AutoCorrector
17
18
 
18
- MSG = 'Avoid the use of Perl-style backrefs.'
19
+ MESSAGE_FORMAT = 'Prefer `%<preferred_expression>s` over `%<original_expression>s`.'
20
+
21
+ def on_back_ref(node)
22
+ on_back_ref_or_gvar_or_nth_ref(node)
23
+ end
24
+
25
+ def on_gvar(node)
26
+ on_back_ref_or_gvar_or_nth_ref(node)
27
+ end
19
28
 
20
29
  def on_nth_ref(node)
21
- add_offense(node) do |corrector|
22
- backref, = *node
23
- parent_type = node.parent ? node.parent.type : nil
30
+ on_back_ref_or_gvar_or_nth_ref(node)
31
+ end
24
32
 
25
- if %i[dstr xstr regexp].include?(parent_type)
26
- corrector.replace(node, "{Regexp.last_match(#{backref})}")
33
+ private
34
+
35
+ # @private
36
+ # @param [RuboCop::AST::Node] node
37
+ # @return [Boolean]
38
+ def derived_from_braceless_interpolation?(node)
39
+ %i[
40
+ dstr
41
+ regexp
42
+ xstr
43
+ ].include?(node.parent&.type)
44
+ end
45
+
46
+ # @private
47
+ # @param [RuboCop::AST::Node] node
48
+ # @param [String] preferred_expression
49
+ # @return [String]
50
+ def format_message(node:, preferred_expression:)
51
+ original_expression = original_expression_of(node)
52
+ format(
53
+ MESSAGE_FORMAT,
54
+ original_expression: original_expression,
55
+ preferred_expression: preferred_expression
56
+ )
57
+ end
27
58
 
28
- else
29
- corrector.replace(node, "Regexp.last_match(#{backref})")
59
+ # @private
60
+ # @param [RuboCop::AST::Node] node
61
+ # @return [String]
62
+ def original_expression_of(node)
63
+ first = node.to_a.first
64
+ if first.is_a?(::Integer)
65
+ "$#{first}"
66
+ else
67
+ first.to_s
68
+ end
69
+ end
70
+
71
+ # @private
72
+ # @param [RuboCop::AST::Node] node
73
+ # @return [String, nil]
74
+ def preferred_expression_to(node)
75
+ first = node.to_a.first
76
+ case first
77
+ when ::Integer
78
+ "Regexp.last_match(#{first})"
79
+ when :$&, :$MATCH
80
+ 'Regexp.last_match(0)'
81
+ when :$`, :$PREMATCH
82
+ 'Regexp.last_match.pre_match'
83
+ when :$', :$POSTMATCH
84
+ 'Regexp.last_match.post_match'
85
+ when :$+, :$LAST_PAREN_MATCH
86
+ 'Regexp.last_match(-1)'
87
+ end
88
+ end
89
+
90
+ # @private
91
+ # @param [RuboCop::AST::Node] node
92
+ def on_back_ref_or_gvar_or_nth_ref(node)
93
+ preferred_expression = preferred_expression_to(node)
94
+ return unless preferred_expression
95
+
96
+ add_offense(
97
+ node,
98
+ message: format_message(
99
+ node: node,
100
+ preferred_expression: preferred_expression
101
+ )
102
+ ) do |corrector|
103
+ if derived_from_braceless_interpolation?(node)
104
+ preferred_expression = "{#{preferred_expression}}"
30
105
  end
106
+
107
+ corrector.replace(node, preferred_expression)
31
108
  end
32
109
  end
33
110
  end