rubocop 0.73.0 → 0.74.0

Sign up to get free protection for your applications and to get access to all the features.
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