rubocop 1.17.0 → 1.18.4

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +70 -29
  4. data/lib/rubocop.rb +2 -0
  5. data/lib/rubocop/cli/command/suggest_extensions.rb +3 -3
  6. data/lib/rubocop/config_loader.rb +1 -1
  7. data/lib/rubocop/config_loader_resolver.rb +1 -1
  8. data/lib/rubocop/config_validator.rb +23 -10
  9. data/lib/rubocop/cop/base.rb +2 -2
  10. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  11. data/lib/rubocop/cop/bundler/gem_version.rb +38 -4
  12. data/lib/rubocop/cop/corrector.rb +4 -4
  13. data/lib/rubocop/cop/generator.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  15. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  16. data/lib/rubocop/cop/layout/array_alignment.rb +2 -2
  17. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  18. data/lib/rubocop/cop/layout/class_structure.rb +5 -1
  19. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +7 -1
  20. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  21. data/lib/rubocop/cop/layout/end_alignment.rb +8 -1
  22. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  23. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  24. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  25. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  26. data/lib/rubocop/cop/layout/hash_alignment.rb +25 -24
  27. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  28. data/lib/rubocop/cop/layout/indentation_style.rb +2 -2
  29. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +122 -0
  30. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +6 -6
  31. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +2 -2
  32. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +6 -6
  33. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -6
  34. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +6 -6
  35. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +3 -3
  36. data/lib/rubocop/cop/layout/parameter_alignment.rb +2 -2
  37. data/lib/rubocop/cop/layout/space_around_operators.rb +5 -1
  38. data/lib/rubocop/cop/lint/duplicate_branch.rb +2 -1
  39. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  40. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  41. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  42. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  43. data/lib/rubocop/cop/lint/unused_block_argument.rb +1 -1
  44. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  45. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  46. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  47. data/lib/rubocop/cop/mixin/check_line_breakable.rb +12 -3
  48. data/lib/rubocop/cop/mixin/hash_transform_method.rb +6 -1
  49. data/lib/rubocop/cop/naming/inclusive_language.rb +249 -0
  50. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -2
  51. data/lib/rubocop/cop/style/block_delimiters.rb +15 -0
  52. data/lib/rubocop/cop/style/class_and_module_children.rb +14 -0
  53. data/lib/rubocop/cop/style/comment_annotation.rb +50 -6
  54. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -7
  55. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  56. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +8 -2
  57. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  58. data/lib/rubocop/cop/style/multiple_comparison.rb +1 -1
  59. data/lib/rubocop/cop/style/mutable_constant.rb +6 -8
  60. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  61. data/lib/rubocop/cop/style/quoted_symbols.rb +2 -2
  62. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  63. data/lib/rubocop/cop/style/regexp_literal.rb +3 -2
  64. data/lib/rubocop/cop/style/single_line_methods.rb +25 -15
  65. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  66. data/lib/rubocop/cop/style/string_concatenation.rb +32 -5
  67. data/lib/rubocop/cop/style/string_literals.rb +2 -2
  68. data/lib/rubocop/cop/style/swap_values.rb +1 -1
  69. data/lib/rubocop/cop/style/unpack_first.rb +1 -1
  70. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  71. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -1
  72. data/lib/rubocop/options.rb +4 -4
  73. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  74. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  75. data/lib/rubocop/version.rb +1 -1
  76. metadata +11 -9
@@ -32,7 +32,7 @@ module RuboCop
32
32
 
33
33
  # Removes `size` characters prior to the source range.
34
34
  #
35
- # @param [Parser::Source::Range, Rubocop::AST::Node] range or node
35
+ # @param [Parser::Source::Range, RuboCop::AST::Node] range or node
36
36
  # @param [Integer] size
37
37
  def remove_preceding(node_or_range, size)
38
38
  range = to_range(node_or_range)
@@ -44,7 +44,7 @@ module RuboCop
44
44
  # If `size` is greater than the size of `range`, the removed region can
45
45
  # overrun the end of `range`.
46
46
  #
47
- # @param [Parser::Source::Range, Rubocop::AST::Node] range or node
47
+ # @param [Parser::Source::Range, RuboCop::AST::Node] range or node
48
48
  # @param [Integer] size
49
49
  def remove_leading(node_or_range, size)
50
50
  range = to_range(node_or_range)
@@ -56,7 +56,7 @@ module RuboCop
56
56
  # If `size` is greater than the size of `range`, the removed region can
57
57
  # overrun the beginning of `range`.
58
58
  #
59
- # @param [Parser::Source::Range, Rubocop::AST::Node] range or node
59
+ # @param [Parser::Source::Range, RuboCop::AST::Node] range or node
60
60
  # @param [Integer] size
61
61
  def remove_trailing(node_or_range, size)
62
62
  range = to_range(node_or_range)
@@ -90,7 +90,7 @@ module RuboCop
90
90
  else
91
91
  raise TypeError,
92
92
  'Expected a Parser::Source::Range, Comment or ' \
93
- "Rubocop::AST::Node, got #{node_or_range.class}"
93
+ "RuboCop::AST::Node, got #{node_or_range.class}"
94
94
  end
95
95
  validate_buffer(range.source_buffer)
96
96
  range
@@ -104,7 +104,7 @@ module RuboCop
104
104
 
105
105
  CONFIGURATION_ADDED_MESSAGE =
106
106
  '[modify] A configuration for the cop is added into ' \
107
- '%<configuration_file_path>s.'
107
+ '%<configuration_file_path>s.'
108
108
 
109
109
  def initialize(name, github_user, output: $stdout)
110
110
  @badge = Badge.parse(name)
@@ -25,7 +25,7 @@ module RuboCop
25
25
 
26
26
  MSG = 'Preceed `%<method>s` with a `@!method` YARD directive.'
27
27
  MSG_WRONG_NAME = '`@!method` YARD directive has invalid method name, ' \
28
- 'use `%<expected>s` instead of `%<actual>s`.'
28
+ 'use `%<expected>s` instead of `%<actual>s`.'
29
29
  MSG_TOO_MANY = 'Multiple `@!method` YARD directives found for this matcher.'
30
30
 
31
31
  RESTRICT_ON_SEND = %i[def_node_matcher def_node_search].to_set.freeze
@@ -50,7 +50,7 @@ module RuboCop
50
50
  ALIGN_PARAMS_MSG = 'Align the arguments of a method call if they span more than one line.'
51
51
 
52
52
  FIXED_INDENT_MSG = 'Use one level of indentation for arguments ' \
53
- 'following the first line of a multi-line method call.'
53
+ 'following the first line of a multi-line method call.'
54
54
 
55
55
  def on_send(node)
56
56
  first_arg = node.first_argument
@@ -38,10 +38,10 @@ module RuboCop
38
38
  extend AutoCorrector
39
39
 
40
40
  ALIGN_ELEMENTS_MSG = 'Align the elements of an array literal ' \
41
- 'if they span more than one line.'
41
+ 'if they span more than one line.'
42
42
 
43
43
  FIXED_INDENT_MSG = 'Use one level of indentation for elements ' \
44
- 'following the first line of a multi-line array.'
44
+ 'following the first line of a multi-line array.'
45
45
 
46
46
  def on_array(node)
47
47
  return if node.children.size < 2
@@ -210,7 +210,7 @@ module RuboCop
210
210
 
211
211
  def format_source_line_column(source_line_column)
212
212
  "`#{source_line_column[:source]}` at #{source_line_column[:line]}, " \
213
- "#{source_line_column[:column]}"
213
+ "#{source_line_column[:column]}"
214
214
  end
215
215
 
216
216
  def compute_start_col(ancestor_node, node)
@@ -289,12 +289,16 @@ module RuboCop
289
289
  (node.first_line - 1).downto(1) do |annotation_line|
290
290
  break unless (comment = processed_source.comment_at_line(annotation_line))
291
291
 
292
- first_comment = comment
292
+ first_comment = comment if whole_line_comment_at_line?(annotation_line)
293
293
  end
294
294
 
295
295
  start_line_position(first_comment || node)
296
296
  end
297
297
 
298
+ def whole_line_comment_at_line?(line)
299
+ /\A\s*#/.match?(processed_source.lines[line - 1])
300
+ end
301
+
298
302
  def start_line_position(node)
299
303
  buffer.line_range(node.loc.line).begin_pos - 1
300
304
  end
@@ -155,7 +155,13 @@ module RuboCop
155
155
  end
156
156
 
157
157
  def all_elements_aligned?(elements)
158
- elements.map { |e| e.loc.column }.uniq.count == 1
158
+ elements.flat_map do |e|
159
+ if e.hash_type?
160
+ e.each_pair.map { |pair| pair.loc.column }
161
+ else
162
+ e.loc.column
163
+ end
164
+ end.uniq.count == 1
159
165
  end
160
166
 
161
167
  def first_argument_line(elements)
@@ -37,7 +37,7 @@ module RuboCop
37
37
  extend AutoCorrector
38
38
 
39
39
  MSG = 'Incorrect indentation detected (column %<column>d ' \
40
- 'instead of %<correct_comment_indentation>d).'
40
+ 'instead of %<correct_comment_indentation>d).'
41
41
 
42
42
  def on_new_investigation
43
43
  processed_source.comments.each { |comment| check(comment) }
@@ -167,7 +167,8 @@ module RuboCop
167
167
  def alignment_node_for_variable_style(node)
168
168
  return node.parent if node.case_type? && node.argument?
169
169
 
170
- assignment = node.ancestors.find(&:assignment_or_similar?)
170
+ assignment = assignment_or_operator_method(node)
171
+
171
172
  if assignment && !line_break_before_keyword?(assignment.source_range, node)
172
173
  assignment
173
174
  else
@@ -177,6 +178,12 @@ module RuboCop
177
178
  node
178
179
  end
179
180
  end
181
+
182
+ def assignment_or_operator_method(node)
183
+ node.ancestors.find do |ancestor|
184
+ ancestor.assignment_or_similar? || ancestor.send_type? && ancestor.operator_method?
185
+ end
186
+ end
180
187
  end
181
188
  end
182
189
  end
@@ -154,7 +154,7 @@ module RuboCop
154
154
 
155
155
  def on_send(node)
156
156
  return if style != :consistent && enforce_first_argument_with_fixed_indentation?
157
- return if !node.arguments? || bare_operator?(node)
157
+ return if !node.arguments? || bare_operator?(node) || node.setter_method?
158
158
 
159
159
  indent = base_indentation(node) + configured_indentation_width
160
160
 
@@ -161,10 +161,10 @@ module RuboCop
161
161
  'Indent the right bracket the same as the left bracket.'
162
162
  elsif style == :special_inside_parentheses && left_parenthesis
163
163
  'Indent the right bracket the same as the first position ' \
164
- 'after the preceding left parenthesis.'
164
+ 'after the preceding left parenthesis.'
165
165
  else
166
166
  'Indent the right bracket the same as the start of the line' \
167
- ' where the left bracket is.'
167
+ ' where the left bracket is.'
168
168
  end
169
169
  end
170
170
  end
@@ -178,10 +178,10 @@ module RuboCop
178
178
  'Indent the right brace the same as the left brace.'
179
179
  elsif style == :special_inside_parentheses && left_parenthesis
180
180
  'Indent the right brace the same as the first position ' \
181
- 'after the preceding left parenthesis.'
181
+ 'after the preceding left parenthesis.'
182
182
  else
183
183
  'Indent the right brace the same as the start of the line ' \
184
- 'where the left brace is.'
184
+ 'where the left brace is.'
185
185
  end
186
186
  end
187
187
 
@@ -48,7 +48,7 @@ module RuboCop
48
48
  extend AutoCorrector
49
49
 
50
50
  MSG = 'Use %<configured_indentation_width>d spaces for indentation ' \
51
- 'in method args, relative to %<base_description>s.'
51
+ 'in method args, relative to %<base_description>s.'
52
52
 
53
53
  def on_def(node)
54
54
  return if node.arguments.empty?
@@ -180,14 +180,15 @@ module RuboCop
180
180
  include RangeHelp
181
181
  extend AutoCorrector
182
182
 
183
- MESSAGES = { KeyAlignment => 'Align the keys of a hash literal if ' \
184
- 'they span more than one line.',
185
- SeparatorAlignment => 'Align the separators of a hash ' \
186
- 'literal if they span more than one line.',
187
- TableAlignment => 'Align the keys and values of a hash ' \
188
- 'literal if they span more than one line.',
189
- KeywordSplatAlignment => 'Align keyword splats with the ' \
190
- 'rest of the hash if it spans more than one line.' }.freeze
183
+ MESSAGES = {
184
+ KeyAlignment => 'Align the keys of a hash literal if they span more than one line.',
185
+ SeparatorAlignment => 'Align the separators of a hash literal if they span more than ' \
186
+ 'one line.',
187
+ TableAlignment => 'Align the keys and values of a hash literal if they span more than ' \
188
+ 'one line.',
189
+ KeywordSplatAlignment => 'Align keyword splats with the rest of the hash if it spans ' \
190
+ 'more than one line.'
191
+ }.freeze
191
192
 
192
193
  def on_send(node)
193
194
  return if double_splat?(node)
@@ -212,18 +213,18 @@ module RuboCop
212
213
  check_pairs(node)
213
214
  end
214
215
 
215
- attr_accessor :offences_by, :column_deltas
216
+ attr_accessor :offenses_by, :column_deltas
216
217
 
217
218
  private
218
219
 
219
220
  def autocorrect_incompatible_with_other_cops?(node)
220
221
  enforce_first_argument_with_fixed_indentation? &&
221
222
  node.pairs.any? &&
222
- node.parent&.call_type? && node.parent.loc.line == node.pairs.first.loc.line
223
+ node.parent&.call_type? && node.parent.loc.selector&.line == node.pairs.first.loc.line
223
224
  end
224
225
 
225
226
  def reset!
226
- self.offences_by = {}
227
+ self.offenses_by = {}
227
228
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
228
229
  end
229
230
 
@@ -247,33 +248,33 @@ module RuboCop
247
248
  end
248
249
  end
249
250
 
250
- add_offences
251
+ add_offenses
251
252
  end
252
253
 
253
- def add_offences
254
- kwsplat_offences = offences_by.delete(KeywordSplatAlignment)
255
- register_offences_with_format(kwsplat_offences, KeywordSplatAlignment)
254
+ def add_offenses
255
+ kwsplat_offenses = offenses_by.delete(KeywordSplatAlignment)
256
+ register_offenses_with_format(kwsplat_offenses, KeywordSplatAlignment)
256
257
 
257
- format, offences = offences_by.min_by { |_, v| v.length }
258
- register_offences_with_format(offences, format)
258
+ format, offenses = offenses_by.min_by { |_, v| v.length }
259
+ register_offenses_with_format(offenses, format)
259
260
  end
260
261
 
261
- def register_offences_with_format(offences, format)
262
- (offences || []).each do |offence|
263
- add_offense(offence, message: MESSAGES[format]) do |corrector|
264
- delta = column_deltas[alignment_for(offence).first.class][offence]
262
+ def register_offenses_with_format(offenses, format)
263
+ (offenses || []).each do |offense|
264
+ add_offense(offense, message: MESSAGES[format]) do |corrector|
265
+ delta = column_deltas[alignment_for(offense).first.class][offense]
265
266
 
266
- correct_node(corrector, offence, delta) unless delta.nil?
267
+ correct_node(corrector, offense, delta) unless delta.nil?
267
268
  end
268
269
  end
269
270
  end
270
271
 
271
272
  def check_delta(delta, node:, alignment:)
272
- offences_by[alignment.class] ||= []
273
+ offenses_by[alignment.class] ||= []
273
274
  return if good_alignment? delta
274
275
 
275
276
  column_deltas[alignment.class][node] = delta
276
- offences_by[alignment.class].push(node)
277
+ offenses_by[alignment.class].push(node)
277
278
  end
278
279
 
279
280
  def ignore_hash_argument?(node)
@@ -55,7 +55,7 @@ module RuboCop
55
55
  extend AutoCorrector
56
56
 
57
57
  MSG = 'Put the closing parenthesis for a method call with a ' \
58
- 'HEREDOC parameter on the same line as the HEREDOC opening.'
58
+ 'HEREDOC parameter on the same line as the HEREDOC opening.'
59
59
 
60
60
  def self.autocorrect_incompatible_with
61
61
  [Style::TrailingCommaInArguments]
@@ -43,7 +43,7 @@ module RuboCop
43
43
  str_ranges = string_literal_ranges(processed_source.ast)
44
44
 
45
45
  processed_source.lines.each.with_index(1) do |line, lineno|
46
- next unless (range = find_offence(line, lineno))
46
+ next unless (range = find_offense(line, lineno))
47
47
  next if in_string_literal?(str_ranges, range)
48
48
 
49
49
  add_offense(range) { |corrector| autocorrect(corrector, range) }
@@ -60,7 +60,7 @@ module RuboCop
60
60
  end
61
61
  end
62
62
 
63
- def find_offence(line, lineno)
63
+ def find_offense(line, lineno)
64
64
  match = if style == :spaces
65
65
  line.match(/\A\s*\t+/)
66
66
  else
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Layout
6
+ # This cop checks the indentation of the next line after a line that ends with a string
7
+ # literal and a backslash.
8
+ #
9
+ # If `EnforcedStyle: aligned` is set, the concatenated string parts shall be aligned with the
10
+ # first part. There are some exceptions, such as implicit return values, where the
11
+ # concatenated string parts shall be indented regardless of `EnforcedStyle` configuration.
12
+ #
13
+ # If `EnforcedStyle: indented` is set, it's the second line that shall be indented one step
14
+ # more than the first line. Lines 3 and forward shall be aligned with line 2. Here too there
15
+ # are exceptions. Values in a hash literal are always aligned.
16
+ #
17
+ # @example
18
+ # # bad
19
+ # def some_method
20
+ # 'x' \
21
+ # 'y' \
22
+ # 'z'
23
+ # end
24
+ #
25
+ # my_hash = {
26
+ # first: 'a message' \
27
+ # 'in two parts'
28
+ # }
29
+ #
30
+ # # good
31
+ # def some_method
32
+ # 'x' \
33
+ # 'y' \
34
+ # 'z'
35
+ # end
36
+ #
37
+ # my_hash = {
38
+ # first: 'a message' \
39
+ # 'in two parts'
40
+ # }
41
+ #
42
+ # @example EnforcedStyle: aligned (default)
43
+ # # bad
44
+ # puts 'x' \
45
+ # 'y'
46
+ #
47
+ # # good
48
+ # puts 'x' \
49
+ # 'y'
50
+ #
51
+ # @example EnforcedStyle: indented
52
+ # # bad
53
+ # result = 'x' \
54
+ # 'y'
55
+ #
56
+ # # good
57
+ # result = 'x' \
58
+ # 'y'
59
+ #
60
+ class LineEndStringConcatenationIndentation < Base
61
+ include ConfigurableEnforcedStyle
62
+ include Alignment
63
+ extend AutoCorrector
64
+
65
+ MSG_ALIGN = 'Align parts of a string concatenated with backslash.'
66
+ MSG_INDENT = 'Indent the first part of a string concatenated with backslash.'
67
+ PARENT_TYPES_FOR_INDENTED = [nil, :block, :begin, :def, :defs, :if].freeze
68
+
69
+ def on_dstr(node)
70
+ return unless strings_concatenated_with_backslash?(node)
71
+
72
+ children = node.children
73
+ if style == :aligned && !always_indented?(node) || always_aligned?(node)
74
+ check_aligned(children, 1)
75
+ else
76
+ check_indented(children)
77
+ check_aligned(children, 2)
78
+ end
79
+ end
80
+
81
+ def autocorrect(corrector, node)
82
+ AlignmentCorrector.correct(corrector, processed_source, node, @column_delta)
83
+ end
84
+
85
+ private
86
+
87
+ def strings_concatenated_with_backslash?(dstr_node)
88
+ dstr_node.multiline? &&
89
+ dstr_node.children.all? { |c| c.str_type? || c.dstr_type? } &&
90
+ dstr_node.children.none?(&:multiline?)
91
+ end
92
+
93
+ def always_indented?(dstr_node)
94
+ PARENT_TYPES_FOR_INDENTED.include?(dstr_node.parent&.type)
95
+ end
96
+
97
+ def always_aligned?(dstr_node)
98
+ dstr_node.parent&.pair_type?
99
+ end
100
+
101
+ def check_aligned(children, start_index)
102
+ base_column = children[start_index - 1].loc.column
103
+ children[start_index..-1].each do |child|
104
+ @column_delta = base_column - child.loc.column
105
+ add_offense_and_correction(child, MSG_ALIGN) if @column_delta != 0
106
+ base_column = child.loc.column
107
+ end
108
+ end
109
+
110
+ def check_indented(children)
111
+ base_column = children[0].source_range.source_line =~ /\S/
112
+ @column_delta = base_column + configured_indentation_width - children[1].loc.column
113
+ add_offense_and_correction(children[1], MSG_INDENT) if @column_delta != 0
114
+ end
115
+
116
+ def add_offense_and_correction(node, message)
117
+ add_offense(node, message: message) { |corrector| autocorrect(corrector, node) }
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end