rubocop 1.16.1 → 1.18.3

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 (80) 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 +5 -5
  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/closing_parenthesis_indentation.rb +7 -1
  19. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  20. data/lib/rubocop/cop/layout/dot_position.rb +7 -1
  21. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
  22. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  23. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  24. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  25. data/lib/rubocop/cop/layout/hash_alignment.rb +11 -9
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  27. data/lib/rubocop/cop/layout/indentation_width.rb +8 -0
  28. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +122 -0
  29. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +6 -6
  30. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +2 -2
  31. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +6 -6
  32. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -6
  33. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +6 -6
  34. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +3 -3
  35. data/lib/rubocop/cop/layout/parameter_alignment.rb +2 -2
  36. data/lib/rubocop/cop/layout/redundant_line_break.rb +11 -9
  37. data/lib/rubocop/cop/layout/space_around_keyword.rb +12 -0
  38. data/lib/rubocop/cop/layout/space_around_operators.rb +11 -1
  39. data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
  40. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
  41. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  42. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  43. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  44. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +93 -65
  45. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
  46. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  47. data/lib/rubocop/cop/lint/unused_block_argument.rb +1 -1
  48. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  49. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  50. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  51. data/lib/rubocop/cop/migration/department_name.rb +3 -1
  52. data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -1
  53. data/lib/rubocop/cop/naming/inclusive_language.rb +249 -0
  54. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -2
  55. data/lib/rubocop/cop/style/block_delimiters.rb +15 -0
  56. data/lib/rubocop/cop/style/class_and_module_children.rb +14 -0
  57. data/lib/rubocop/cop/style/comment_annotation.rb +50 -6
  58. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +8 -2
  59. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  60. data/lib/rubocop/cop/style/identical_conditional_branches.rb +29 -0
  61. data/lib/rubocop/cop/style/multiple_comparison.rb +1 -1
  62. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  63. data/lib/rubocop/cop/style/quoted_symbols.rb +2 -2
  64. data/lib/rubocop/cop/style/raise_args.rb +2 -0
  65. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  66. data/lib/rubocop/cop/style/regexp_literal.rb +10 -1
  67. data/lib/rubocop/cop/style/single_line_methods.rb +11 -6
  68. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  69. data/lib/rubocop/cop/style/string_concatenation.rb +32 -5
  70. data/lib/rubocop/cop/style/string_literals.rb +2 -2
  71. data/lib/rubocop/cop/style/swap_values.rb +1 -1
  72. data/lib/rubocop/cop/style/unpack_first.rb +1 -1
  73. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  74. data/lib/rubocop/directive_comment.rb +53 -5
  75. data/lib/rubocop/options.rb +4 -4
  76. data/lib/rubocop/remote_config.rb +10 -2
  77. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  78. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  79. data/lib/rubocop/version.rb +1 -1
  80. metadata +5 -3
@@ -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)
@@ -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) }
@@ -24,6 +24,7 @@ module RuboCop
24
24
  # method
25
25
  class DotPosition < Base
26
26
  include ConfigurableEnforcedStyle
27
+ include RangeHelp
27
28
  extend AutoCorrector
28
29
 
29
30
  def on_send(node)
@@ -42,7 +43,12 @@ module RuboCop
42
43
  private
43
44
 
44
45
  def autocorrect(corrector, dot, node)
45
- corrector.remove(dot)
46
+ dot_range = if processed_source[dot.line - 1].strip == '.'
47
+ range_by_whole_lines(dot, include_final_newline: true)
48
+ else
49
+ dot
50
+ end
51
+ corrector.remove(dot_range)
46
52
  case style
47
53
  when :leading
48
54
  corrector.insert_before(selector_range(node), dot.source)
@@ -45,8 +45,7 @@ module RuboCop
45
45
  def on_if(node)
46
46
  return if correct_style?(node)
47
47
 
48
- if node.modifier_form? && last_argument_is_heredoc?(node)
49
- heredoc_node = last_heredoc_argument(node)
48
+ if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
50
49
  return if next_line_empty_or_enable_directive_comment?(heredoc_line(node, heredoc_node))
51
50
 
52
51
  add_offense(heredoc_node.loc.heredoc_end) do |corrector|
@@ -62,7 +61,7 @@ module RuboCop
62
61
  private
63
62
 
64
63
  def autocorrect(corrector, node)
65
- node_range = if node.respond_to?(:heredoc?) && node.heredoc?
64
+ node_range = if heredoc?(node)
66
65
  range_by_whole_lines(node.loc.heredoc_body)
67
66
  else
68
67
  range_by_whole_lines(node.source_range)
@@ -125,19 +124,8 @@ module RuboCop
125
124
  next_sibling.if_type? && contains_guard_clause?(next_sibling)
126
125
  end
127
126
 
128
- def last_argument_is_heredoc?(node)
129
- last_children = node.if_branch
130
- return false unless last_children&.send_type?
131
-
132
- heredoc?(last_heredoc_argument(node))
133
- end
134
-
135
127
  def last_heredoc_argument(node)
136
- n = if node.respond_to?(:if_branch)
137
- node.if_branch.children.last
138
- else
139
- node
140
- end
128
+ n = last_heredoc_argument_node(node)
141
129
 
142
130
  return n if heredoc?(n)
143
131
  return unless n.respond_to?(:arguments)
@@ -150,6 +138,16 @@ module RuboCop
150
138
  return last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
151
139
  end
152
140
 
141
+ def last_heredoc_argument_node(node)
142
+ return node unless node.respond_to?(:if_branch)
143
+
144
+ if node.if_branch.and_type?
145
+ node.if_branch.children.first
146
+ else
147
+ node.if_branch.children.last
148
+ end
149
+ end
150
+
153
151
  def heredoc_line(node, heredoc_node)
154
152
  heredoc_body = heredoc_node.loc.heredoc_body
155
153
  num_of_heredoc_lines = heredoc_body.last_line - heredoc_body.first_line
@@ -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)
@@ -218,7 +219,8 @@ module RuboCop
218
219
 
219
220
  def autocorrect_incompatible_with_other_cops?(node)
220
221
  enforce_first_argument_with_fixed_indentation? &&
221
- node.parent&.call_type? && node.parent.loc.line == node.pairs.first.loc.line
222
+ node.pairs.any? &&
223
+ node.parent&.call_type? && node.parent.loc.selector&.line == node.pairs.first.loc.line
222
224
  end
223
225
 
224
226
  def reset!
@@ -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]
@@ -138,6 +138,14 @@ module RuboCop
138
138
  check_indentation(case_node.when_branches.last.loc.keyword, case_node.else_branch)
139
139
  end
140
140
 
141
+ def on_case_match(case_match)
142
+ case_match.each_in_pattern do |in_pattern_node|
143
+ check_indentation(in_pattern_node.loc.keyword, in_pattern_node.body)
144
+ end
145
+
146
+ check_indentation(case_match.in_pattern_branches.last.loc.keyword, case_match.else_branch)
147
+ end
148
+
141
149
  def on_if(node, base = node)
142
150
  return if ignored_node?(node)
143
151
  return if node.ternary? || node.modifier_form?
@@ -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
@@ -93,18 +93,18 @@ module RuboCop
93
93
  extend AutoCorrector
94
94
 
95
95
  SAME_LINE_MESSAGE = 'The closing array brace must be on the same ' \
96
- 'line as the last array element when the opening brace is on the ' \
97
- 'same line as the first array element.'
96
+ 'line as the last array element when the opening brace is on the ' \
97
+ 'same line as the first array element.'
98
98
 
99
99
  NEW_LINE_MESSAGE = 'The closing array brace must be on the line ' \
100
- 'after the last array element when the opening brace is on a ' \
101
- 'separate line from the first array element.'
100
+ 'after the last array element when the opening brace is on a ' \
101
+ 'separate line from the first array element.'
102
102
 
103
103
  ALWAYS_NEW_LINE_MESSAGE = 'The closing array brace must be on the ' \
104
- 'line after the last array element.'
104
+ 'line after the last array element.'
105
105
 
106
106
  ALWAYS_SAME_LINE_MESSAGE = 'The closing array brace must be on the ' \
107
- 'same line as the last array element.'
107
+ 'same line as the last array element.'
108
108
 
109
109
  def on_array(node)
110
110
  check_brace_layout(node)
@@ -64,10 +64,10 @@ module RuboCop
64
64
  extend AutoCorrector
65
65
 
66
66
  NEW_LINE_OFFENSE = 'Right hand side of multi-line assignment is on ' \
67
- 'the same line as the assignment operator `=`.'
67
+ 'the same line as the assignment operator `=`.'
68
68
 
69
69
  SAME_LINE_OFFENSE = 'Right hand side of multi-line assignment is not ' \
70
- 'on the same line as the assignment operator `=`.'
70
+ 'on the same line as the assignment operator `=`.'
71
71
 
72
72
  def check_assignment(node, rhs)
73
73
  return if node.send_type? && node.loc.operator&.source != '='
@@ -93,18 +93,18 @@ module RuboCop
93
93
  extend AutoCorrector
94
94
 
95
95
  SAME_LINE_MESSAGE = 'Closing hash brace must be on the same line as ' \
96
- 'the last hash element when opening brace is on the same line as ' \
97
- 'the first hash element.'
96
+ 'the last hash element when opening brace is on the same line as ' \
97
+ 'the first hash element.'
98
98
 
99
99
  NEW_LINE_MESSAGE = 'Closing hash brace must be on the line after ' \
100
- 'the last hash element when opening brace is on a separate line ' \
101
- 'from the first hash element.'
100
+ 'the last hash element when opening brace is on a separate line ' \
101
+ 'from the first hash element.'
102
102
 
103
103
  ALWAYS_NEW_LINE_MESSAGE = 'Closing hash brace must be on the line ' \
104
- 'after the last hash element.'
104
+ 'after the last hash element.'
105
105
 
106
106
  ALWAYS_SAME_LINE_MESSAGE = 'Closing hash brace must be on the same ' \
107
- 'line as the last hash element.'
107
+ 'line as the last hash element.'
108
108
 
109
109
  def on_hash(node)
110
110
  check_brace_layout(node)