rubocop 0.73.0 → 0.74.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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/console +1 -0
  4. data/config/default.yml +2 -1
  5. data/lib/rubocop.rb +3 -0
  6. data/lib/rubocop/ast/node.rb +1 -7
  7. data/lib/rubocop/config.rb +17 -537
  8. data/lib/rubocop/config_obsoletion.rb +201 -0
  9. data/lib/rubocop/config_validator.rb +239 -0
  10. data/lib/rubocop/cop/layout/extra_spacing.rb +14 -53
  11. data/lib/rubocop/cop/layout/indentation_width.rb +19 -5
  12. data/lib/rubocop/cop/layout/space_around_operators.rb +42 -23
  13. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +22 -40
  14. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  15. data/lib/rubocop/cop/lint/empty_interpolation.rb +4 -4
  16. data/lib/rubocop/cop/lint/erb_new_arguments.rb +56 -0
  17. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -8
  18. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +6 -6
  19. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +6 -1
  20. data/lib/rubocop/cop/metrics/line_length.rb +6 -0
  21. data/lib/rubocop/cop/mixin/documentation_comment.rb +0 -2
  22. data/lib/rubocop/cop/mixin/interpolation.rb +27 -0
  23. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +87 -0
  24. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -5
  25. data/lib/rubocop/cop/style/commented_keyword.rb +8 -28
  26. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -3
  27. data/lib/rubocop/cop/style/constant_visibility.rb +13 -2
  28. data/lib/rubocop/cop/style/guard_clause.rb +39 -10
  29. data/lib/rubocop/cop/style/lambda.rb +0 -2
  30. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +4 -6
  31. data/lib/rubocop/cop/style/variable_interpolation.rb +6 -16
  32. data/lib/rubocop/path_util.rb +1 -1
  33. data/lib/rubocop/processed_source.rb +4 -0
  34. data/lib/rubocop/rspec/expect_offense.rb +4 -1
  35. data/lib/rubocop/version.rb +1 -1
  36. metadata +5 -2
@@ -158,11 +158,7 @@ module RuboCop
158
158
  if indentation_consistency_style == 'indented_internal_methods'
159
159
  check_members_for_indented_internal_methods_style(members)
160
160
  else
161
- members.first.children.each do |member|
162
- next if member.send_type? && member.access_modifier?
163
-
164
- check_indentation(base, member)
165
- end
161
+ check_members_for_normal_style(base, members)
166
162
  end
167
163
  end
168
164
 
@@ -170,6 +166,8 @@ module RuboCop
170
166
  return unless member
171
167
 
172
168
  if access_modifier?(member.children.first)
169
+ return if access_modifier_indentation_style == 'outdent'
170
+
173
171
  member.children.first
174
172
  else
175
173
  member
@@ -183,6 +181,14 @@ module RuboCop
183
181
  end
184
182
  end
185
183
 
184
+ def check_members_for_normal_style(base, members)
185
+ members.first.children.each do |member|
186
+ next if member.send_type? && member.access_modifier?
187
+
188
+ check_indentation(base, member)
189
+ end
190
+ end
191
+
186
192
  def each_member(members)
187
193
  previous_modifier = nil
188
194
  members.first.children.each do |member|
@@ -199,6 +205,14 @@ module RuboCop
199
205
  indentation_consistency_style == 'indented_internal_methods'
200
206
  end
201
207
 
208
+ def special_modifier?(node)
209
+ node.bare_access_modifier? && SPECIAL_MODIFIERS.include?(node.source)
210
+ end
211
+
212
+ def access_modifier_indentation_style
213
+ config.for_cop('Layout/AccessModifierIndentation')['EnforcedStyle']
214
+ end
215
+
202
216
  def indentation_consistency_style
203
217
  config.for_cop('Layout/IndentationConsistency')['EnforcedStyle']
204
218
  end
@@ -34,14 +34,14 @@ module RuboCop
34
34
 
35
35
  return if hash_table_style? && !node.parent.pairs_on_same_line?
36
36
 
37
- check_operator(node.loc.operator, node.source_range)
37
+ check_operator(:pair, node.loc.operator, node.source_range)
38
38
  end
39
39
 
40
40
  def on_if(node)
41
41
  return unless node.ternary?
42
42
 
43
- check_operator(node.loc.question, node.if_branch.source_range)
44
- check_operator(node.loc.colon, node.else_branch.source_range)
43
+ check_operator(:if, node.loc.question, node.if_branch.source_range)
44
+ check_operator(:if, node.loc.colon, node.else_branch.source_range)
45
45
  end
46
46
 
47
47
  def on_resbody(node)
@@ -49,23 +49,33 @@ module RuboCop
49
49
 
50
50
  _, variable, = *node
51
51
 
52
- check_operator(node.loc.assoc, variable.source_range)
52
+ check_operator(:resbody, node.loc.assoc, variable.source_range)
53
53
  end
54
54
 
55
55
  def on_send(node)
56
56
  if node.setter_method?
57
57
  on_special_asgn(node)
58
58
  elsif regular_operator?(node)
59
- check_operator(node.loc.selector, node.first_argument.source_range)
59
+ check_operator(:send,
60
+ node.loc.selector,
61
+ node.first_argument.source_range)
60
62
  end
61
63
  end
62
64
 
65
+ def on_assignment(node)
66
+ _, rhs, = *node
67
+
68
+ return unless rhs
69
+
70
+ check_operator(:assignment, node.loc.operator, rhs.source_range)
71
+ end
72
+
63
73
  def on_binary(node)
64
74
  _, rhs, = *node
65
75
 
66
76
  return unless rhs
67
77
 
68
- check_operator(node.loc.operator, rhs.source_range)
78
+ check_operator(:binary, node.loc.operator, rhs.source_range)
69
79
  end
70
80
 
71
81
  def on_special_asgn(node)
@@ -73,20 +83,20 @@ module RuboCop
73
83
 
74
84
  return unless right
75
85
 
76
- check_operator(node.loc.operator, right.source_range)
86
+ check_operator(:special_asgn, node.loc.operator, right.source_range)
77
87
  end
78
88
 
79
89
  alias on_or on_binary
80
90
  alias on_and on_binary
81
- alias on_lvasgn on_binary
82
- alias on_masgn on_binary
91
+ alias on_lvasgn on_assignment
92
+ alias on_masgn on_assignment
83
93
  alias on_casgn on_special_asgn
84
- alias on_ivasgn on_binary
85
- alias on_cvasgn on_binary
86
- alias on_gvasgn on_binary
94
+ alias on_ivasgn on_assignment
95
+ alias on_cvasgn on_assignment
96
+ alias on_gvasgn on_assignment
87
97
  alias on_class on_binary
88
- alias on_or_asgn on_binary
89
- alias on_and_asgn on_binary
98
+ alias on_or_asgn on_assignment
99
+ alias on_and_asgn on_assignment
90
100
  alias on_op_asgn on_special_asgn
91
101
 
92
102
  def autocorrect(range)
@@ -113,35 +123,44 @@ module RuboCop
113
123
  !IRREGULAR_METHODS.include?(send_node.method_name)
114
124
  end
115
125
 
116
- def check_operator(operator, right_operand)
126
+ def check_operator(type, operator, right_operand)
117
127
  with_space = range_with_surrounding_space(range: operator)
118
128
  return if with_space.source.start_with?("\n")
119
129
 
120
- offense(operator, with_space, right_operand) do |msg|
130
+ offense(type, operator, with_space, right_operand) do |msg|
121
131
  add_offense(with_space, location: operator, message: msg)
122
132
  end
123
133
  end
124
134
 
125
- def offense(operator, with_space, right_operand)
126
- msg = offense_message(operator, with_space, right_operand)
135
+ def offense(type, operator, with_space, right_operand)
136
+ msg = offense_message(type, operator, with_space, right_operand)
127
137
  yield msg if msg
128
138
  end
129
139
 
130
- def offense_message(operator, with_space, right_operand)
140
+ def offense_message(type, operator, with_space, right_operand)
131
141
  if operator.is?('**')
132
142
  'Space around operator `**` detected.' unless with_space.is?('**')
133
143
  elsif with_space.source !~ /^\s.*\s$/
134
144
  "Surrounding space missing for operator `#{operator.source}`."
135
- elsif excess_leading_space?(operator, with_space) ||
145
+ elsif excess_leading_space?(type, operator, with_space) ||
136
146
  excess_trailing_space?(right_operand, with_space)
137
147
  "Operator `#{operator.source}` should be surrounded " \
138
148
  'by a single space.'
139
149
  end
140
150
  end
141
151
 
142
- def excess_leading_space?(operator, with_space)
143
- with_space.source.start_with?(EXCESSIVE_SPACE) &&
144
- (!allow_for_alignment? || !aligned_with_operator?(operator))
152
+ def excess_leading_space?(type, operator, with_space)
153
+ return false unless allow_for_alignment?
154
+ return false unless with_space.source.start_with?(EXCESSIVE_SPACE)
155
+
156
+ return !aligned_with_operator?(operator) unless type == :assignment
157
+
158
+ token = Token.new(operator, nil, operator.source)
159
+ align_preceding = aligned_with_preceding_assignment(token)
160
+
161
+ return align_preceding == :no unless align_preceding == :none
162
+
163
+ aligned_with_subsequent_assignment(token) != :yes
145
164
  end
146
165
 
147
166
  def excess_trailing_space?(right_operand, with_space)
@@ -19,61 +19,43 @@ module RuboCop
19
19
  # # good
20
20
  # var = "This is the #{ space } example"
21
21
  class SpaceInsideStringInterpolation < Cop
22
+ include Interpolation
23
+ include SurroundingSpace
22
24
  include ConfigurableEnforcedStyle
23
25
  include RangeHelp
24
26
 
25
27
  NO_SPACE_MSG = 'Space inside string interpolation detected.'
26
- SPACE_MSG = 'Missing space around string interpolation detected.'
28
+ SPACE_MSG = 'Missing space inside string interpolation detected.'
27
29
 
28
- def on_dstr(node)
29
- each_style_violation(node) do |final_node|
30
- add_offense(final_node)
31
- end
32
- end
30
+ def on_interpolation(begin_node)
31
+ delims = delimiters(begin_node)
32
+ return if empty_brackets?(*delims)
33
33
 
34
- def autocorrect(node)
35
- new_source = style == :no_space ? node.source : " #{node.source} "
36
- lambda do |corrector|
37
- corrector.replace(
38
- range_with_surrounding_space(range: node.source_range),
39
- new_source
40
- )
34
+ if style == :no_space
35
+ no_space_offenses(begin_node, *delims, NO_SPACE_MSG)
36
+ else
37
+ space_offenses(begin_node, *delims, SPACE_MSG)
41
38
  end
42
39
  end
43
40
 
44
- private
45
-
46
- def each_style_violation(node)
47
- node.each_child_node(:begin) do |begin_node|
48
- final_node = begin_node.children.last
49
- next unless final_node
41
+ def autocorrect(begin_node)
42
+ lambda do |corrector|
43
+ delims = delimiters(begin_node)
50
44
 
51
- if style == :no_space && space_on_any_side?(final_node)
52
- yield final_node
53
- elsif style == :space && !space_on_each_side?(final_node)
54
- yield final_node
45
+ if style == :no_space
46
+ SpaceCorrector.remove_space(processed_source, corrector, *delims)
47
+ else
48
+ SpaceCorrector.add_space(processed_source, corrector, *delims)
55
49
  end
56
50
  end
57
51
  end
58
52
 
59
- def message(_node)
60
- style == :no_space ? NO_SPACE_MSG : SPACE_MSG
61
- end
62
-
63
- def space_on_any_side?(node)
64
- interp = node.source_range
65
- interp_with_surrounding_space =
66
- range_with_surrounding_space(range: interp)
67
-
68
- interp_with_surrounding_space != interp
69
- end
70
-
71
- def space_on_each_side?(node)
72
- interp = node.source_range
73
- interp_with_surrounding_space =
74
- range_with_surrounding_space(range: interp)
53
+ private
75
54
 
76
- interp_with_surrounding_space.source == " #{interp.source} "
55
+ def delimiters(begin_node)
56
+ left = processed_source.tokens[index_of_first_token(begin_node)]
57
+ right = processed_source.tokens[index_of_last_token(begin_node)]
58
+ [left, right]
77
59
  end
78
60
  end
79
61
  end
@@ -56,8 +56,6 @@ module RuboCop
56
56
  (send (send {#kernel? nil?} :binding) :irb ...)
57
57
  PATTERN
58
58
 
59
- def_node_matcher :pry_rescue?, '(send (const nil? :Pry) :rescue ...)'
60
-
61
59
  def on_send(node)
62
60
  return unless debugger_call?(node) || binding_irb?(node)
63
61
 
@@ -17,12 +17,12 @@ module RuboCop
17
17
  #
18
18
  # "result is #{some_result}"
19
19
  class EmptyInterpolation < Cop
20
+ include Interpolation
21
+
20
22
  MSG = 'Empty interpolation detected.'
21
23
 
22
- def on_dstr(node)
23
- node.each_child_node(:begin) do |begin_node|
24
- add_offense(begin_node) if begin_node.children.empty?
25
- end
24
+ def on_interpolation(begin_node)
25
+ add_offense(begin_node) if begin_node.children.empty?
26
26
  end
27
27
 
28
28
  def autocorrect(node)
@@ -61,6 +61,7 @@ module RuboCop
61
61
  #
62
62
  class ErbNewArguments < Cop
63
63
  extend TargetRubyVersion
64
+ include RangeHelp
64
65
 
65
66
  minimum_target_ruby_version 2.6
66
67
 
@@ -97,10 +98,65 @@ module RuboCop
97
98
  end
98
99
  end
99
100
 
101
+ def autocorrect(node)
102
+ str_arg = node.arguments[0].source
103
+
104
+ kwargs = build_kwargs(node)
105
+ overridden_kwargs = override_by_legacy_args(kwargs, node)
106
+
107
+ good_arguments = [
108
+ str_arg, overridden_kwargs
109
+ ].flatten.compact.join(', ')
110
+
111
+ lambda do |corrector|
112
+ corrector.replace(arguments_range(node), good_arguments)
113
+ end
114
+ end
115
+
116
+ private
117
+
100
118
  def correct_arguments?(arguments)
101
119
  arguments.size == 1 ||
102
120
  arguments.size == 2 && arguments[1].hash_type?
103
121
  end
122
+
123
+ def build_kwargs(node)
124
+ return [nil, nil] unless node.arguments.last.hash_type?
125
+
126
+ trim_mode_arg, eoutvar_arg = nil
127
+
128
+ node.arguments.last.pairs.each do |pair|
129
+ case pair.key.source
130
+ when 'trim_mode'
131
+ trim_mode_arg = "trim_mode: #{pair.value.source}"
132
+ when 'eoutvar'
133
+ eoutvar_arg = "eoutvar: #{pair.value.source}"
134
+ end
135
+ end
136
+
137
+ [trim_mode_arg, eoutvar_arg]
138
+ end
139
+
140
+ def override_by_legacy_args(kwargs, node)
141
+ overridden_kwargs = kwargs.dup
142
+
143
+ if node.arguments[2]
144
+ overridden_kwargs[0] = "trim_mode: #{node.arguments[2].source}"
145
+ end
146
+
147
+ if node.arguments[3] && !node.arguments[3].hash_type?
148
+ overridden_kwargs[1] = "eoutvar: #{node.arguments[3].source}"
149
+ end
150
+
151
+ overridden_kwargs
152
+ end
153
+
154
+ def arguments_range(node)
155
+ arguments = node.arguments
156
+
157
+ range_between(arguments.first.source_range.begin_pos,
158
+ arguments.last.source_range.end_pos)
159
+ end
104
160
  end
105
161
  end
106
162
  end
@@ -17,21 +17,20 @@ module RuboCop
17
17
  #
18
18
  # "result is 10"
19
19
  class LiteralInInterpolation < Cop
20
+ include Interpolation
20
21
  include RangeHelp
21
22
  include PercentLiteral
22
23
 
23
24
  MSG = 'Literal interpolation detected.'
24
25
  COMPOSITE = %i[array hash pair irange erange].freeze
25
26
 
26
- def on_dstr(node)
27
- node.each_child_node(:begin) do |begin_node|
28
- final_node = begin_node.children.last
29
- next unless final_node
30
- next if special_keyword?(final_node)
31
- next unless prints_as_self?(final_node)
27
+ def on_interpolation(begin_node)
28
+ final_node = begin_node.children.last
29
+ return unless final_node
30
+ return if special_keyword?(final_node)
31
+ return unless prints_as_self?(final_node)
32
32
 
33
- add_offense(final_node)
34
- end
33
+ add_offense(final_node)
35
34
  end
36
35
 
37
36
  def autocorrect(node)
@@ -18,20 +18,20 @@ module RuboCop
18
18
  #
19
19
  # "result is #{something}"
20
20
  class StringConversionInInterpolation < Cop
21
+ include Interpolation
22
+
21
23
  MSG_DEFAULT = 'Redundant use of `Object#to_s` in interpolation.'
22
24
  MSG_SELF = 'Use `self` instead of `Object#to_s` in ' \
23
25
  'interpolation.'
24
26
 
25
27
  def_node_matcher :to_s_without_args?, '(send _ :to_s)'
26
28
 
27
- def on_dstr(node)
28
- node.each_child_node(:begin) do |begin_node|
29
- final_node = begin_node.children.last
29
+ def on_interpolation(begin_node)
30
+ final_node = begin_node.children.last
30
31
 
31
- next unless to_s_without_args?(final_node)
32
+ return unless to_s_without_args?(final_node)
32
33
 
33
- add_offense(final_node, location: :selector)
34
- end
34
+ add_offense(final_node, location: :selector)
35
35
  end
36
36
 
37
37
  def autocorrect(node)
@@ -58,7 +58,12 @@ module RuboCop
58
58
  PERCENT_CAPITAL_I = '%I'
59
59
  ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn].freeze
60
60
 
61
- def_node_matcher :array_new?, '$(send (const nil? :Array) :new ...)'
61
+ def_node_matcher :array_new?, <<~PATTERN
62
+ {
63
+ $(send (const nil? :Array) :new ...)
64
+ $(block (send (const nil? :Array) :new ...) ...)
65
+ }
66
+ PATTERN
62
67
 
63
68
  def_node_matcher :literal_expansion, <<~PATTERN
64
69
  (splat {$({str dstr int float array} ...) (block $#array_new? ...) $#array_new?} ...)
@@ -10,6 +10,7 @@ module RuboCop
10
10
  # The maximum length is configurable.
11
11
  # The tab size is configured in the `IndentationWidth`
12
12
  # of the `Layout/Tab` cop.
13
+ # It also ignores a shebang line by default.
13
14
  #
14
15
  # This cop has some autocorrection capabilities.
15
16
  # It can programmatically shorten certain long lines by
@@ -138,9 +139,14 @@ module RuboCop
138
139
 
139
140
  def ignored_line?(line, line_index)
140
141
  matches_ignored_pattern?(line) ||
142
+ shebang?(line, line_index) ||
141
143
  heredocs && line_in_permitted_heredoc?(line_index.succ)
142
144
  end
143
145
 
146
+ def shebang?(line, line_index)
147
+ line_index.zero? && line.start_with?('#!')
148
+ end
149
+
144
150
  def register_offense(loc, line, line_index)
145
151
  message = format(MSG, length: line_length(line), max: max)
146
152