rubocop 1.13.0 → 1.17.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/config/default.yml +68 -8
  4. data/lib/rubocop.rb +9 -0
  5. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -3
  6. data/lib/rubocop/cop/bundler/gem_version.rb +99 -0
  7. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  8. data/lib/rubocop/cop/layout/argument_alignment.rb +29 -11
  9. data/lib/rubocop/cop/layout/case_indentation.rb +57 -9
  10. data/lib/rubocop/cop/layout/dot_position.rb +7 -1
  11. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
  12. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +12 -0
  13. data/lib/rubocop/cop/layout/hash_alignment.rb +34 -9
  14. data/lib/rubocop/cop/layout/indentation_width.rb +13 -2
  15. data/lib/rubocop/cop/layout/redundant_line_break.rb +24 -10
  16. data/lib/rubocop/cop/layout/single_line_block_chain.rb +53 -0
  17. data/lib/rubocop/cop/layout/space_around_keyword.rb +28 -0
  18. data/lib/rubocop/cop/layout/space_around_operators.rb +6 -0
  19. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +83 -39
  20. data/lib/rubocop/cop/lint/empty_block.rb +18 -2
  21. data/lib/rubocop/cop/lint/empty_in_pattern.rb +62 -0
  22. data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
  23. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
  24. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  25. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +105 -74
  26. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
  27. data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -12
  28. data/lib/rubocop/cop/lint/unreachable_loop.rb +12 -2
  29. data/lib/rubocop/cop/lint/unused_block_argument.rb +7 -1
  30. data/lib/rubocop/cop/lint/void.rb +1 -1
  31. data/lib/rubocop/cop/migration/department_name.rb +3 -1
  32. data/lib/rubocop/cop/mixin/check_line_breakable.rb +19 -3
  33. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
  34. data/lib/rubocop/cop/mixin/gem_declaration.rb +13 -0
  35. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +14 -3
  36. data/lib/rubocop/cop/mixin/string_literals_help.rb +3 -5
  37. data/lib/rubocop/cop/mixin/symbol_help.rb +13 -0
  38. data/lib/rubocop/cop/style/class_and_module_children.rb +17 -5
  39. data/lib/rubocop/cop/style/empty_literal.rb +8 -1
  40. data/lib/rubocop/cop/style/hash_each_methods.rb +18 -1
  41. data/lib/rubocop/cop/style/identical_conditional_branches.rb +58 -8
  42. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -4
  43. data/lib/rubocop/cop/style/in_pattern_then.rb +56 -0
  44. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -1
  45. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +62 -0
  46. data/lib/rubocop/cop/style/multiline_when_then.rb +2 -11
  47. data/lib/rubocop/cop/style/negated_if_else_condition.rb +17 -9
  48. data/lib/rubocop/cop/style/nil_lambda.rb +29 -12
  49. data/lib/rubocop/cop/style/quoted_symbols.rb +110 -0
  50. data/lib/rubocop/cop/style/raise_args.rb +2 -0
  51. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  52. data/lib/rubocop/cop/style/redundant_self.rb +24 -2
  53. data/lib/rubocop/cop/style/regexp_literal.rb +9 -1
  54. data/lib/rubocop/cop/style/single_line_methods.rb +8 -3
  55. data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
  56. data/lib/rubocop/cop/style/string_literals.rb +1 -0
  57. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +1 -0
  58. data/lib/rubocop/cop/style/top_level_method_definition.rb +83 -0
  59. data/lib/rubocop/cop/style/trivial_accessors.rb +65 -0
  60. data/lib/rubocop/cop/style/when_then.rb +6 -2
  61. data/lib/rubocop/cop/variable_force/branch.rb +15 -0
  62. data/lib/rubocop/directive_comment.rb +58 -6
  63. data/lib/rubocop/formatter/junit_formatter.rb +21 -6
  64. data/lib/rubocop/options.rb +14 -20
  65. data/lib/rubocop/rake_task.rb +1 -1
  66. data/lib/rubocop/remote_config.rb +10 -2
  67. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  68. data/lib/rubocop/target_finder.rb +9 -2
  69. data/lib/rubocop/target_ruby.rb +1 -1
  70. data/lib/rubocop/version.rb +1 -1
  71. metadata +18 -9
@@ -3,10 +3,10 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # This cop checks how the ``when``s of a `case` expression
6
+ # This cop checks how the `when` and `in`s of a `case` expression
7
7
  # are indented in relation to its `case` or `end` keyword.
8
8
  #
9
- # It will register a separate offense for each misaligned `when`.
9
+ # It will register a separate offense for each misaligned `when` and `in`.
10
10
  #
11
11
  # @example
12
12
  # # If Layout/EndAlignment is set to keyword style (default)
@@ -22,6 +22,13 @@ module RuboCop
22
22
  # y / 3
23
23
  # end
24
24
  #
25
+ # case n
26
+ # in pattern
27
+ # x * 2
28
+ # else
29
+ # y / 3
30
+ # end
31
+ #
25
32
  # # good for all styles
26
33
  # case n
27
34
  # when 0
@@ -30,6 +37,13 @@ module RuboCop
30
37
  # y / 3
31
38
  # end
32
39
  #
40
+ # case n
41
+ # in pattern
42
+ # x * 2
43
+ # else
44
+ # y / 3
45
+ # end
46
+ #
33
47
  # @example EnforcedStyle: case (default)
34
48
  # # if EndAlignment is set to other style such as
35
49
  # # start_of_line (as shown below), then *when* alignment
@@ -43,6 +57,13 @@ module RuboCop
43
57
  # y / 3
44
58
  # end
45
59
  #
60
+ # a = case n
61
+ # in pattern
62
+ # x * 2
63
+ # else
64
+ # y / 3
65
+ # end
66
+ #
46
67
  # # good
47
68
  # a = case n
48
69
  # when 0
@@ -51,6 +72,13 @@ module RuboCop
51
72
  # y / 3
52
73
  # end
53
74
  #
75
+ # a = case n
76
+ # in pattern
77
+ # x * 2
78
+ # else
79
+ # y / 3
80
+ # end
81
+ #
54
82
  # @example EnforcedStyle: end
55
83
  # # bad
56
84
  # a = case n
@@ -60,6 +88,13 @@ module RuboCop
60
88
  # y / 3
61
89
  # end
62
90
  #
91
+ # a = case n
92
+ # in pattern
93
+ # x * 2
94
+ # else
95
+ # y / 3
96
+ # end
97
+ #
63
98
  # # good
64
99
  # a = case n
65
100
  # when 0
@@ -67,30 +102,43 @@ module RuboCop
67
102
  # else
68
103
  # y / 3
69
104
  # end
105
+ #
106
+ # a = case n
107
+ # in pattern
108
+ # x * 2
109
+ # else
110
+ # y / 3
111
+ # end
70
112
  class CaseIndentation < Base
71
113
  include Alignment
72
114
  include ConfigurableEnforcedStyle
73
115
  include RangeHelp
74
116
  extend AutoCorrector
75
117
 
76
- MSG = 'Indent `when` %<depth>s `%<base>s`.'
118
+ MSG = 'Indent `%<branch_type>s` %<depth>s `%<base>s`.'
77
119
 
78
120
  def on_case(case_node)
79
121
  return if case_node.single_line?
80
122
 
81
- case_node.each_when { |when_node| check_when(when_node) }
123
+ case_node.each_when { |when_node| check_when(when_node, 'when') }
124
+ end
125
+
126
+ def on_case_match(case_match_node)
127
+ return if case_match_node.single_line?
128
+
129
+ case_match_node.each_in_pattern { |in_pattern_node| check_when(in_pattern_node, 'in') }
82
130
  end
83
131
 
84
132
  private
85
133
 
86
- def check_when(when_node)
134
+ def check_when(when_node, branch_type)
87
135
  when_column = when_node.loc.keyword.column
88
136
  base_column = base_column(when_node.parent, style)
89
137
 
90
138
  if when_column == base_column + indentation_width
91
139
  correct_style_detected
92
140
  else
93
- incorrect_style(when_node)
141
+ incorrect_style(when_node, branch_type)
94
142
  end
95
143
  end
96
144
 
@@ -102,9 +150,9 @@ module RuboCop
102
150
  indent_one_step? ? configured_indentation_width : 0
103
151
  end
104
152
 
105
- def incorrect_style(when_node)
153
+ def incorrect_style(when_node, branch_type)
106
154
  depth = indent_one_step? ? 'one step more than' : 'as deep as'
107
- message = format(MSG, depth: depth, base: style)
155
+ message = format(MSG, branch_type: branch_type, depth: depth, base: style)
108
156
 
109
157
  add_offense(when_node.loc.keyword, message: message) do |corrector|
110
158
  detect_incorrect_style(when_node)
@@ -141,7 +189,7 @@ module RuboCop
141
189
  end
142
190
 
143
191
  def replacement(node)
144
- case_node = node.each_ancestor(:case).first
192
+ case_node = node.each_ancestor(:case, :case_match).first
145
193
  base_type = cop_config[style_parameter_name] == 'end' ? :end : :case
146
194
 
147
195
  column = base_column(case_node, base_type)
@@ -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
@@ -91,6 +91,8 @@ module RuboCop
91
91
  end
92
92
 
93
93
  def on_send(node)
94
+ return if enforce_first_argument_with_fixed_indentation?
95
+
94
96
  each_argument_node(node, :hash) do |hash_node, left_parenthesis|
95
97
  check(hash_node, left_parenthesis)
96
98
  end
@@ -182,6 +184,16 @@ module RuboCop
182
184
  'where the left brace is.'
183
185
  end
184
186
  end
187
+
188
+ def enforce_first_argument_with_fixed_indentation?
189
+ return false unless argument_alignment_config['Enabled']
190
+
191
+ argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
192
+ end
193
+
194
+ def argument_alignment_config
195
+ config.for_cop('Layout/ArgumentAlignment')
196
+ end
185
197
  end
186
198
  end
187
199
  end
@@ -185,7 +185,9 @@ module RuboCop
185
185
  SeparatorAlignment => 'Align the separators of a hash ' \
186
186
  'literal if they span more than one line.',
187
187
  TableAlignment => 'Align the keys and values of a hash ' \
188
- 'literal if they span more than one line.' }.freeze
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
189
191
 
190
192
  def on_send(node)
191
193
  return if double_splat?(node)
@@ -200,14 +202,12 @@ module RuboCop
200
202
  alias on_super on_send
201
203
  alias on_yield on_send
202
204
 
203
- def on_hash(node) # rubocop:todo Metrics/CyclomaticComplexity
204
- return if ignored_node?(node)
205
- return if node.pairs.empty? || node.single_line?
205
+ def on_hash(node)
206
+ return if autocorrect_incompatible_with_other_cops?(node) || ignored_node?(node) ||
207
+ node.pairs.empty? || node.single_line?
206
208
 
207
- return unless alignment_for_hash_rockets
208
- .any? { |a| a.checkable_layout?(node) } &&
209
- alignment_for_colons
210
- .any? { |a| a.checkable_layout?(node) }
209
+ proc = ->(a) { a.checkable_layout?(node) }
210
+ return unless alignment_for_hash_rockets.any?(proc) && alignment_for_colons.any?(proc)
211
211
 
212
212
  check_pairs(node)
213
213
  end
@@ -216,6 +216,12 @@ module RuboCop
216
216
 
217
217
  private
218
218
 
219
+ def autocorrect_incompatible_with_other_cops?(node)
220
+ enforce_first_argument_with_fixed_indentation? &&
221
+ node.pairs.any? &&
222
+ node.parent&.call_type? && node.parent.loc.line == node.pairs.first.loc.line
223
+ end
224
+
219
225
  def reset!
220
226
  self.offences_by = {}
221
227
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
@@ -245,7 +251,14 @@ module RuboCop
245
251
  end
246
252
 
247
253
  def add_offences
254
+ kwsplat_offences = offences_by.delete(KeywordSplatAlignment)
255
+ register_offences_with_format(kwsplat_offences, KeywordSplatAlignment)
256
+
248
257
  format, offences = offences_by.min_by { |_, v| v.length }
258
+ register_offences_with_format(offences, format)
259
+ end
260
+
261
+ def register_offences_with_format(offences, format)
249
262
  (offences || []).each do |offence|
250
263
  add_offense(offence, message: MESSAGES[format]) do |corrector|
251
264
  delta = column_deltas[alignment_for(offence).first.class][offence]
@@ -273,7 +286,9 @@ module RuboCop
273
286
  end
274
287
 
275
288
  def alignment_for(pair)
276
- if pair.hash_rocket?
289
+ if pair.kwsplat_type?
290
+ [KeywordSplatAlignment.new]
291
+ elsif pair.hash_rocket?
277
292
  alignment_for_hash_rockets
278
293
  else
279
294
  alignment_for_colons
@@ -353,6 +368,16 @@ module RuboCop
353
368
  def good_alignment?(column_deltas)
354
369
  column_deltas.values.all?(&:zero?)
355
370
  end
371
+
372
+ def enforce_first_argument_with_fixed_indentation?
373
+ return false unless argument_alignment_config['Enabled']
374
+
375
+ argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
376
+ end
377
+
378
+ def argument_alignment_config
379
+ config.for_cop('Layout/ArgumentAlignment')
380
+ end
356
381
  end
357
382
  end
358
383
  end
@@ -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?
@@ -313,9 +321,12 @@ module RuboCop
313
321
  check_rescue?(body_node)
314
322
  elsif body_node.ensure_type?
315
323
  block_body, = *body_node
316
- return unless block_body
317
324
 
318
- check_rescue?(block_body) if block_body.rescue_type?
325
+ if block_body&.rescue_type?
326
+ check_rescue?(block_body)
327
+ else
328
+ !block_body.nil?
329
+ end
319
330
  else
320
331
  true
321
332
  end
@@ -42,8 +42,9 @@ module RuboCop
42
42
  # # good
43
43
  # foo(a) { |x| puts x }
44
44
  #
45
- class RedundantLineBreak < Cop
45
+ class RedundantLineBreak < Base
46
46
  include CheckAssignment
47
+ extend AutoCorrector
47
48
 
48
49
  MSG = 'Redundant line break detected.'
49
50
 
@@ -55,23 +56,24 @@ module RuboCop
55
56
 
56
57
  return unless offense?(node) && !part_of_ignored_node?(node)
57
58
 
58
- add_offense(node)
59
- ignore_node(node)
59
+ register_offense(node)
60
60
  end
61
61
 
62
+ private
63
+
62
64
  def check_assignment(node, _rhs)
63
65
  return unless offense?(node)
64
66
 
65
- add_offense(node)
66
- ignore_node(node)
67
+ register_offense(node)
67
68
  end
68
69
 
69
- def autocorrect(node)
70
- ->(corrector) { corrector.replace(node.source_range, to_single_line(node.source).strip) }
70
+ def register_offense(node)
71
+ add_offense(node) do |corrector|
72
+ corrector.replace(node.source_range, to_single_line(node.source).strip)
73
+ end
74
+ ignore_node(node)
71
75
  end
72
76
 
73
- private
74
-
75
77
  def offense?(node)
76
78
  return false if configured_to_not_be_inspected?(node)
77
79
 
@@ -79,8 +81,20 @@ module RuboCop
79
81
  end
80
82
 
81
83
  def configured_to_not_be_inspected?(node)
84
+ return true if other_cop_takes_precedence?(node)
85
+
82
86
  !cop_config['InspectBlocks'] && (node.block_type? ||
83
- node.each_child_node(:block).any?(&:multiline?))
87
+ node.each_descendant(:block).any?(&:multiline?))
88
+ end
89
+
90
+ def other_cop_takes_precedence?(node)
91
+ single_line_block_chain_enabled? && node.each_descendant(:block).any? do |block_node|
92
+ block_node.parent.send_type? && block_node.parent.loc.dot && !block_node.multiline?
93
+ end
94
+ end
95
+
96
+ def single_line_block_chain_enabled?
97
+ @config.for_cop('Layout/SingleLineBlockChain')['Enabled']
84
98
  end
85
99
 
86
100
  def suitable_as_single_line?(node)
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Layout
6
+ # This cop checks if method calls are chained onto single line blocks. It considers that a
7
+ # line break before the dot improves the readability of the code.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # example.select { |item| item.cond? }.join('-')
12
+ #
13
+ # # good
14
+ # example.select { |item| item.cond? }
15
+ # .join('-')
16
+ #
17
+ # # good (not a concern for this cop)
18
+ # example.select do |item|
19
+ # item.cond?
20
+ # end.join('-')
21
+ #
22
+ class SingleLineBlockChain < Base
23
+ include RangeHelp
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Put method call on a separate line if chained to a single line block.'
27
+
28
+ def on_send(node)
29
+ range = offending_range(node)
30
+ add_offense(range) { |corrector| corrector.insert_before(range, "\n") } if range
31
+ end
32
+
33
+ private
34
+
35
+ def offending_range(node)
36
+ receiver = node.receiver
37
+ return unless receiver&.block_type?
38
+
39
+ receiver_location = receiver.loc
40
+ closing_block_delimiter_line_number = receiver_location.end.line
41
+ return if receiver_location.begin.line < closing_block_delimiter_line_number
42
+
43
+ node_location = node.loc
44
+ dot_range = node_location.dot
45
+ return unless dot_range
46
+ return if dot_range.line > closing_block_delimiter_line_number
47
+
48
+ range_between(dot_range.begin_pos, node_location.selector.end_pos)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end