rubocop 1.34.0 → 1.35.1

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +22 -0
  4. data/lib/rubocop/cli/command/{auto_genenerate_config.rb → auto_generate_config.rb} +0 -0
  5. data/lib/rubocop/config.rb +1 -1
  6. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +32 -2
  7. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  8. data/lib/rubocop/cop/generator/require_file_injector.rb +2 -2
  9. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +69 -0
  10. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  11. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  12. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  13. data/lib/rubocop/cop/layout/block_end_newline.rb +2 -0
  14. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +5 -2
  15. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +2 -0
  16. data/lib/rubocop/cop/layout/end_of_line.rb +4 -4
  17. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  18. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  19. data/lib/rubocop/cop/layout/indentation_width.rb +2 -0
  20. data/lib/rubocop/cop/layout/line_length.rb +4 -1
  21. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  22. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  23. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  24. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  25. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  26. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  27. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  28. data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -9
  29. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -0
  30. data/lib/rubocop/cop/lint/next_without_accumulator.rb +25 -6
  31. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +6 -6
  32. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +12 -0
  33. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +9 -3
  34. data/lib/rubocop/cop/lint/redundant_with_index.rb +13 -10
  35. data/lib/rubocop/cop/lint/redundant_with_object.rb +12 -11
  36. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -0
  37. data/lib/rubocop/cop/lint/unreachable_loop.rb +7 -1
  38. data/lib/rubocop/cop/lint/useless_access_modifier.rb +6 -4
  39. data/lib/rubocop/cop/lint/void.rb +2 -0
  40. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  41. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +76 -1
  42. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  43. data/lib/rubocop/cop/mixin/method_complexity.rb +4 -4
  44. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  45. data/lib/rubocop/cop/mixin/range_help.rb +2 -3
  46. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  47. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  48. data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
  49. data/lib/rubocop/cop/style/class_methods_definitions.rb +2 -1
  50. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  51. data/lib/rubocop/cop/style/combinable_loops.rb +3 -1
  52. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  53. data/lib/rubocop/cop/style/each_with_object.rb +39 -8
  54. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  55. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  56. data/lib/rubocop/cop/style/for.rb +2 -0
  57. data/lib/rubocop/cop/style/guard_clause.rb +27 -16
  58. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -1
  59. data/lib/rubocop/cop/style/hash_syntax.rb +17 -0
  60. data/lib/rubocop/cop/style/inverse_methods.rb +8 -6
  61. data/lib/rubocop/cop/style/magic_comment_format.rb +307 -0
  62. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
  63. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
  64. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -1
  65. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  66. data/lib/rubocop/cop/style/next.rb +3 -5
  67. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  68. data/lib/rubocop/cop/style/object_then.rb +2 -0
  69. data/lib/rubocop/cop/style/proc.rb +4 -1
  70. data/lib/rubocop/cop/style/redundant_begin.rb +2 -0
  71. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  72. data/lib/rubocop/cop/style/redundant_self.rb +2 -0
  73. data/lib/rubocop/cop/style/redundant_sort_by.rb +24 -8
  74. data/lib/rubocop/cop/style/safe_navigation.rb +4 -2
  75. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  76. data/lib/rubocop/cop/style/sole_nested_conditional.rb +0 -2
  77. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  78. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -1
  79. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  80. data/lib/rubocop/cop/style/word_array.rb +1 -1
  81. data/lib/rubocop/cop/util.rb +1 -1
  82. data/lib/rubocop/feature_loader.rb +9 -3
  83. data/lib/rubocop/formatter/html_formatter.rb +2 -2
  84. data/lib/rubocop/server/cache.rb +11 -8
  85. data/lib/rubocop/version.rb +1 -1
  86. data/lib/rubocop.rb +3 -2
  87. metadata +9 -7
@@ -7,6 +7,11 @@ module RuboCop
7
7
  # `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods
8
8
  # are checked by default. These are customizable with `AllowedMethods` option.
9
9
  #
10
+ # The `AllowedMethods` option specifies nil-safe methods,
11
+ # in other words, it is a method that is allowed to skip safe navigation.
12
+ # Note that the `AllowedMethod` option is not an option that specifies methods
13
+ # for which to suppress (allow) this cop's check.
14
+ #
10
15
  # In the example below, the safe navigation operator (`&.`) is unnecessary
11
16
  # because `NilClass` has methods like `respond_to?` and `is_a?`.
12
17
  #
@@ -35,12 +40,13 @@ module RuboCop
35
40
  # # good - without `&.` this will always return `true`
36
41
  # foo&.respond_to?(:to_a)
37
42
  #
38
- # @example AllowedMethods: [foo?]
43
+ # @example AllowedMethods: [nil_safe_method]
39
44
  # # bad
40
- # do_something if attrs&.foo?(:[])
45
+ # do_something if attrs&.nil_safe_method(:[])
41
46
  #
42
47
  # # good
43
- # do_something if attrs&.bar?(:[])
48
+ # do_something if attrs.nil_safe_method(:[])
49
+ # do_something if attrs&.not_nil_safe_method(:[])
44
50
  #
45
51
  class RedundantSafeNavigation < Base
46
52
  include AllowedMethods
@@ -33,16 +33,6 @@ module RuboCop
33
33
  MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.'
34
34
  MSG_WITH_INDEX = 'Remove redundant `with_index`.'
35
35
 
36
- # @!method redundant_with_index?(node)
37
- def_node_matcher :redundant_with_index?, <<~PATTERN
38
- (block
39
- $(send
40
- _ {:each_with_index :with_index} ...)
41
- (args
42
- (arg _))
43
- ...)
44
- PATTERN
45
-
46
36
  def on_block(node)
47
37
  return unless (send = redundant_with_index?(node))
48
38
 
@@ -58,8 +48,21 @@ module RuboCop
58
48
  end
59
49
  end
60
50
 
51
+ alias on_numblock on_block
52
+
61
53
  private
62
54
 
55
+ # @!method redundant_with_index?(node)
56
+ def_node_matcher :redundant_with_index?, <<~PATTERN
57
+ {
58
+ (block
59
+ $(send _ {:each_with_index :with_index} ...)
60
+ (args (arg _)) ...)
61
+ (numblock
62
+ $(send _ {:each_with_index :with_index} ...) 1 ...)
63
+ }
64
+ PATTERN
65
+
63
66
  def message(node)
64
67
  if node.method?(:each_with_index)
65
68
  MSG_EACH_WITH_INDEX
@@ -31,19 +31,8 @@ module RuboCop
31
31
  extend AutoCorrector
32
32
 
33
33
  MSG_EACH_WITH_OBJECT = 'Use `each` instead of `each_with_object`.'
34
-
35
34
  MSG_WITH_OBJECT = 'Remove redundant `with_object`.'
36
35
 
37
- # @!method redundant_with_object?(node)
38
- def_node_matcher :redundant_with_object?, <<~PATTERN
39
- (block
40
- $(send _ {:each_with_object :with_object}
41
- _)
42
- (args
43
- (arg _))
44
- ...)
45
- PATTERN
46
-
47
36
  def on_block(node)
48
37
  return unless (send = redundant_with_object?(node))
49
38
 
@@ -59,8 +48,20 @@ module RuboCop
59
48
  end
60
49
  end
61
50
 
51
+ alias on_numblock on_block
52
+
62
53
  private
63
54
 
55
+ # @!method redundant_with_object?(node)
56
+ def_node_matcher :redundant_with_object?, <<~PATTERN
57
+ {
58
+ (block
59
+ $(send _ {:each_with_object :with_object} _) (args (arg _)) ...)
60
+ (numblock
61
+ $(send _ {:each_with_object :with_object} _) 1 ...)
62
+ }
63
+ PATTERN
64
+
64
65
  def message(node)
65
66
  if node.method?(:each_with_object)
66
67
  MSG_EACH_WITH_OBJECT
@@ -69,6 +69,7 @@ module RuboCop
69
69
 
70
70
  outer_local_variable_node =
71
71
  find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
72
+ return true unless outer_local_variable_node
72
73
 
73
74
  outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
74
75
  end
@@ -101,10 +101,14 @@ module RuboCop
101
101
  check(node) if loop_method?(node)
102
102
  end
103
103
 
104
+ def on_numblock(node)
105
+ check(node) if loop_method?(node)
106
+ end
107
+
104
108
  private
105
109
 
106
110
  def loop_method?(node)
107
- return false unless node.block_type?
111
+ return false unless node.block_type? || node.numblock_type?
108
112
 
109
113
  send_node = node.send_node
110
114
  return false if matches_allowed_pattern?(send_node.source)
@@ -179,6 +183,8 @@ module RuboCop
179
183
 
180
184
  def preceded_by_continue_statement?(break_statement)
181
185
  break_statement.left_siblings.any? do |sibling|
186
+ # Numblocks have the arguments count as a number in the AST.
187
+ next if sibling.is_a?(Integer)
182
188
  next if sibling.loop_keyword? || loop_method?(sibling)
183
189
 
184
190
  sibling.each_descendant(*CONTINUE_KEYWORDS).any?
@@ -142,6 +142,8 @@ module RuboCop
142
142
  check_node(node.body)
143
143
  end
144
144
 
145
+ alias on_numblock on_block
146
+
145
147
  private
146
148
 
147
149
  def autocorrect(corrector, node)
@@ -157,17 +159,17 @@ module RuboCop
157
159
 
158
160
  # @!method dynamic_method_definition?(node)
159
161
  def_node_matcher :dynamic_method_definition?, <<~PATTERN
160
- {(send nil? :define_method ...) (block (send nil? :define_method ...) ...)}
162
+ {(send nil? :define_method ...) ({block numblock} (send nil? :define_method ...) ...)}
161
163
  PATTERN
162
164
 
163
165
  # @!method class_or_instance_eval?(node)
164
166
  def_node_matcher :class_or_instance_eval?, <<~PATTERN
165
- (block (send _ {:class_eval :instance_eval}) ...)
167
+ ({block numblock} (send _ {:class_eval :instance_eval}) ...)
166
168
  PATTERN
167
169
 
168
170
  # @!method class_or_module_or_struct_new_call?(node)
169
171
  def_node_matcher :class_or_module_or_struct_new_call?, <<~PATTERN
170
- (block (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
172
+ ({block numblock} (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
171
173
  PATTERN
172
174
 
173
175
  def check_node(node)
@@ -277,7 +279,7 @@ module RuboCop
277
279
  matcher_name = "#{m}_block?".to_sym
278
280
  unless respond_to?(matcher_name)
279
281
  self.class.def_node_matcher matcher_name, <<~PATTERN
280
- (block (send {nil? const} {:#{m}} ...) ...)
282
+ ({block numblock} (send {nil? const} {:#{m}} ...) ...)
281
283
  PATTERN
282
284
  end
283
285
 
@@ -67,6 +67,8 @@ module RuboCop
67
67
  check_expression(node.body)
68
68
  end
69
69
 
70
+ alias on_numblock on_block
71
+
70
72
  def on_begin(node)
71
73
  check_begin(node)
72
74
  end
@@ -220,7 +220,7 @@ module RuboCop
220
220
  def already_on_multiple_lines?(node)
221
221
  return node.first_line != node.arguments.last.last_line if node.def_type?
222
222
 
223
- node.first_line != node.last_line
223
+ !node.single_line?
224
224
  end
225
225
  end
226
226
  end
@@ -5,7 +5,22 @@ module RuboCop
5
5
  # This module checks for Ruby 3.1's hash value omission syntax.
6
6
  module HashShorthandSyntax
7
7
  OMIT_HASH_VALUE_MSG = 'Omit the hash value.'
8
- EXPLICIT_HASH_VALUE_MSG = 'Explicit the hash value.'
8
+ EXPLICIT_HASH_VALUE_MSG = 'Include the hash value.'
9
+ DO_NOT_MIX_MSG_PREFIX = 'Do not mix explicit and implicit hash values.'
10
+ DO_NOT_MIX_OMIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{OMIT_HASH_VALUE_MSG}"
11
+ DO_NOT_MIX_EXPLICIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{EXPLICIT_HASH_VALUE_MSG}"
12
+
13
+ def on_hash_for_mixed_shorthand(hash_node)
14
+ return if ignore_mixed_hash_shorthand_syntax?(hash_node)
15
+
16
+ hash_value_type_breakdown = breakdown_value_types_of_hash(hash_node)
17
+
18
+ if hash_with_mixed_shorthand_syntax?(hash_value_type_breakdown)
19
+ mixed_shorthand_syntax_check(hash_value_type_breakdown)
20
+ else
21
+ no_mixed_shorthand_syntax_check(hash_value_type_breakdown)
22
+ end
23
+ end
9
24
 
10
25
  def on_pair(node)
11
26
  return if ignore_hash_shorthand_syntax?(node)
@@ -36,8 +51,14 @@ module RuboCop
36
51
  end
37
52
  end
38
53
 
54
+ def ignore_mixed_hash_shorthand_syntax?(hash_node)
55
+ target_ruby_version <= 3.0 || enforced_shorthand_syntax != 'consistent' ||
56
+ !hash_node.hash_type?
57
+ end
58
+
39
59
  def ignore_hash_shorthand_syntax?(pair_node)
40
60
  target_ruby_version <= 3.0 || enforced_shorthand_syntax == 'either' ||
61
+ enforced_shorthand_syntax == 'consistent' ||
41
62
  !pair_node.parent.hash_type?
42
63
  end
43
64
 
@@ -81,6 +102,60 @@ module RuboCop
81
102
 
82
103
  ancestor.respond_to?(:parenthesized?) && !ancestor.parenthesized? && !!right_sibling
83
104
  end
105
+
106
+ def breakdown_value_types_of_hash(hash_node)
107
+ hash_node.pairs.group_by do |pair_node|
108
+ if pair_node.value_omission?
109
+ :value_omitted
110
+ elsif require_hash_value?(pair_node.key.source, pair_node)
111
+ :value_needed
112
+ else
113
+ :value_omittable
114
+ end
115
+ end
116
+ end
117
+
118
+ def hash_with_mixed_shorthand_syntax?(hash_value_type_breakdown)
119
+ hash_value_type_breakdown.keys.size > 1
120
+ end
121
+
122
+ def hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
123
+ hash_value_type_breakdown[:value_needed]&.any?
124
+ end
125
+
126
+ def each_omitted_value_pair(hash_value_type_breakdown, &block)
127
+ hash_value_type_breakdown[:value_omitted]&.each(&block)
128
+ end
129
+
130
+ def each_omittable_value_pair(hash_value_type_breakdown, &block)
131
+ hash_value_type_breakdown[:value_omittable]&.each(&block)
132
+ end
133
+
134
+ def mixed_shorthand_syntax_check(hash_value_type_breakdown)
135
+ if hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
136
+ each_omitted_value_pair(hash_value_type_breakdown) do |pair_node|
137
+ hash_key_source = pair_node.key.source
138
+ replacement = "#{hash_key_source}: #{hash_key_source}"
139
+ register_offense(pair_node, DO_NOT_MIX_EXPLICIT_VALUE_MSG, replacement)
140
+ end
141
+ else
142
+ each_omittable_value_pair(hash_value_type_breakdown) do |pair_node|
143
+ hash_key_source = pair_node.key.source
144
+ replacement = "#{hash_key_source}:"
145
+ register_offense(pair_node, DO_NOT_MIX_OMIT_VALUE_MSG, replacement)
146
+ end
147
+ end
148
+ end
149
+
150
+ def no_mixed_shorthand_syntax_check(hash_value_type_breakdown)
151
+ return if hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
152
+
153
+ each_omittable_value_pair(hash_value_type_breakdown) do |pair_node|
154
+ hash_key_source = pair_node.key.source
155
+ replacement = "#{hash_key_source}:"
156
+ register_offense(pair_node, OMIT_HASH_VALUE_MSG, replacement)
157
+ end
158
+ end
84
159
  end
85
160
  end
86
161
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  {(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)}
15
15
  PATTERN
16
16
 
17
- def on_block(node)
17
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
18
18
  on_bad_each_with_object(node) do |*match|
19
19
  handle_possible_offense(node, match, 'each_with_object')
20
20
  end
@@ -29,14 +29,14 @@ module RuboCop
29
29
  end
30
30
  end
31
31
 
32
+ alias on_numblock on_block
33
+
32
34
  private
33
35
 
34
36
  # @!method define_method?(node)
35
37
  def_node_matcher :define_method?, <<~PATTERN
36
- (block
37
- (send nil? :define_method ({sym str} $_))
38
- args
39
- _)
38
+ ({block numblock}
39
+ (send nil? :define_method ({sym str} $_)) _ _)
40
40
  PATTERN
41
41
 
42
42
  def check_complexity(node, method_name)
@@ -57,7 +57,7 @@ module RuboCop
57
57
  end
58
58
 
59
59
  if left_parenthesis && style == :special_inside_parentheses
60
- return [left_parenthesis.column + 1, :first_colmn_after_left_parenthesis]
60
+ return [left_parenthesis.column + 1, :first_column_after_left_parenthesis]
61
61
  end
62
62
 
63
63
  [left_brace.source_line =~ /\S/, :start_of_line]
@@ -70,9 +70,8 @@ module RuboCop
70
70
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
71
71
  end
72
72
 
73
- def range_by_whole_lines(range, include_final_newline: false)
74
- buffer = @processed_source.buffer
75
-
73
+ def range_by_whole_lines(range, include_final_newline: false,
74
+ buffer: @processed_source.buffer)
76
75
  last_line = buffer.source_line(range.last_line)
77
76
  end_offset = last_line.length - range.last_column
78
77
  end_offset += 1 if include_final_newline
@@ -38,7 +38,7 @@ module RuboCop
38
38
  class BlockParameterName < Base
39
39
  include UncommunicativeName
40
40
 
41
- def on_block(node)
41
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
42
42
  return unless node.arguments?
43
43
 
44
44
  check(node, node.arguments)
@@ -72,10 +72,10 @@ module RuboCop
72
72
  PATTERN
73
73
 
74
74
  def allowed_conditional_expression_on_rhs?(node)
75
- node&.if_type? && contains_contant?(node)
75
+ node&.if_type? && contains_constant?(node)
76
76
  end
77
77
 
78
- def contains_contant?(node)
78
+ def contains_constant?(node)
79
79
  node.branches.any?(&:const_type?)
80
80
  end
81
81
  end
@@ -73,11 +73,11 @@ module RuboCop
73
73
  {
74
74
  (send _ _
75
75
  (splat (lvar %1))
76
- (block-pass (lvar %2)))
76
+ (block-pass {(lvar %2) nil?}))
77
77
  (send _ _
78
78
  (splat (lvar %1))
79
79
  (hash (kwsplat (lvar %3)))
80
- (block-pass (lvar %2)))
80
+ (block-pass {(lvar %2) nil?}))
81
81
  }
82
82
  PATTERN
83
83
 
@@ -70,7 +70,7 @@ module RuboCop
70
70
 
71
71
  def on_sclass(node)
72
72
  return unless def_self_style?
73
- return unless node.identifier.source == 'self'
73
+ return unless node.identifier.self_type?
74
74
  return unless all_methods_public?(node)
75
75
 
76
76
  add_offense(node, message: MSG_SCLASS) do |corrector|
@@ -80,6 +80,7 @@ module RuboCop
80
80
 
81
81
  def on_defs(node)
82
82
  return if def_self_style?
83
+ return unless node.receiver.self_type?
83
84
 
84
85
  message = format(MSG, preferred: 'class << self')
85
86
  add_offense(node, message: message)
@@ -48,6 +48,8 @@ module RuboCop
48
48
  check_method_node(node.send_node)
49
49
  end
50
50
 
51
+ alias on_numblock on_block
52
+
51
53
  def on_send(node)
52
54
  return unless implicit_block?(node)
53
55
 
@@ -66,6 +66,8 @@ module RuboCop
66
66
  add_offense(node) if same_collection_looping?(node, node.left_sibling)
67
67
  end
68
68
 
69
+ alias on_numblock on_block
70
+
69
71
  def on_for(node)
70
72
  return unless node.parent&.begin_type?
71
73
 
@@ -82,7 +84,7 @@ module RuboCop
82
84
  end
83
85
 
84
86
  def same_collection_looping?(node, sibling)
85
- sibling&.block_type? &&
87
+ (sibling&.block_type? || sibling&.numblock_type?) &&
86
88
  sibling.send_node.method?(node.method_name) &&
87
89
  sibling.receiver == node.receiver &&
88
90
  sibling.send_node.arguments == node.send_node.arguments
@@ -27,7 +27,7 @@ module RuboCop
27
27
 
28
28
  MSG = 'Use `Integer#times` for a simple loop which iterates a fixed number of times.'
29
29
 
30
- def on_block(node)
30
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
31
31
  return unless offending_each_range(node)
32
32
 
33
33
  send_node = node.send_node
@@ -23,13 +23,8 @@ module RuboCop
23
23
  MSG = 'Use `each_with_object` instead of `%<method>s`.'
24
24
  METHODS = %i[inject reduce].freeze
25
25
 
26
- # @!method each_with_object_candidate?(node)
27
- def_node_matcher :each_with_object_candidate?, <<~PATTERN
28
- (block $(send _ {:inject :reduce} _) $_ $_)
29
- PATTERN
30
-
31
26
  def on_block(node)
32
- each_with_object_candidate?(node) do |method, args, body|
27
+ each_with_object_block_candidate?(node) do |method, args, body|
33
28
  _, method_name, method_arg = *method
34
29
  return if simple_method_arg?(method_arg)
35
30
 
@@ -40,14 +35,38 @@ module RuboCop
40
35
 
41
36
  message = format(MSG, method: method_name)
42
37
  add_offense(method.loc.selector, message: message) do |corrector|
43
- autocorrect(corrector, node, return_value)
38
+ autocorrect_block(corrector, node, return_value)
39
+ end
40
+ end
41
+ end
42
+
43
+ def on_numblock(node)
44
+ each_with_object_numblock_candidate?(node) do |method, body|
45
+ _, method_name, method_arg = *method
46
+ return if simple_method_arg?(method_arg)
47
+
48
+ return unless return_value(body)&.source == '_1'
49
+
50
+ message = format(MSG, method: method_name)
51
+ add_offense(method.loc.selector, message: message) do |corrector|
52
+ autocorrect_numblock(corrector, node)
44
53
  end
45
54
  end
46
55
  end
47
56
 
48
57
  private
49
58
 
50
- def autocorrect(corrector, node, return_value)
59
+ # @!method each_with_object_block_candidate?(node)
60
+ def_node_matcher :each_with_object_block_candidate?, <<~PATTERN
61
+ (block $(send _ {:inject :reduce} _) $_ $_)
62
+ PATTERN
63
+
64
+ # @!method each_with_object_numblock_candidate?(node)
65
+ def_node_matcher :each_with_object_numblock_candidate?, <<~PATTERN
66
+ (numblock $(send _ {:inject :reduce} _) 2 $_)
67
+ PATTERN
68
+
69
+ def autocorrect_block(corrector, node, return_value)
51
70
  corrector.replace(node.send_node.loc.selector, 'each_with_object')
52
71
 
53
72
  first_arg, second_arg = *node.arguments
@@ -62,6 +81,18 @@ module RuboCop
62
81
  end
63
82
  end
64
83
 
84
+ def autocorrect_numblock(corrector, node)
85
+ corrector.replace(node.send_node.loc.selector, 'each_with_object')
86
+
87
+ # We don't remove the return value to avoid a clobbering error.
88
+ node.body.each_descendant do |var|
89
+ next unless var.lvar_type?
90
+
91
+ corrector.replace(var, '_2') if var.source == '_1'
92
+ corrector.replace(var, '_1') if var.source == '_2'
93
+ end
94
+ end
95
+
65
96
  def simple_method_arg?(method_arg)
66
97
  method_arg&.basic_literal?
67
98
  end
@@ -28,7 +28,7 @@ module RuboCop
28
28
 
29
29
  MSG = 'Omit pipes for the empty block parameters.'
30
30
 
31
- def on_block(node)
31
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
32
32
  send_node = node.send_node
33
33
  check(node) unless send_node.send_type? && send_node.lambda_literal?
34
34
  end
@@ -23,7 +23,7 @@ module RuboCop
23
23
 
24
24
  MSG = 'Omit parentheses for the empty lambda parameters.'
25
25
 
26
- def on_block(node)
26
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
27
27
  send_node = node.send_node
28
28
  return unless send_node.send_type?
29
29
 
@@ -75,6 +75,8 @@ module RuboCop
75
75
  end
76
76
  end
77
77
 
78
+ alias on_numblock on_block
79
+
78
80
  private
79
81
 
80
82
  def suspect_enumerable?(node)
@@ -6,6 +6,10 @@ module RuboCop
6
6
  # Use a guard clause instead of wrapping the code inside a conditional
7
7
  # expression
8
8
  #
9
+ # A condition with an `elsif` or `else` branch is allowed unless
10
+ # one of `return`, `break`, `next`, `raise`, or `fail` is used
11
+ # in the body of the conditional expression.
12
+ #
9
13
  # @example
10
14
  # # bad
11
15
  # def test
@@ -50,34 +54,41 @@ module RuboCop
50
54
  #
51
55
  # @example AllowConsecutiveConditionals: false (default)
52
56
  # # bad
53
- # if foo?
54
- # work
55
- # end
57
+ # def test
58
+ # if foo?
59
+ # work
60
+ # end
56
61
  #
57
- # if bar? # <- reports an offense
58
- # work
62
+ # if bar? # <- reports an offense
63
+ # work
64
+ # end
59
65
  # end
60
66
  #
61
67
  # @example AllowConsecutiveConditionals: true
62
68
  # # good
63
- # if foo?
64
- # work
65
- # end
69
+ # def test
70
+ # if foo?
71
+ # work
72
+ # end
66
73
  #
67
- # if bar?
68
- # work
74
+ # if bar?
75
+ # work
76
+ # end
69
77
  # end
70
78
  #
71
79
  # # bad
72
- # if foo?
73
- # work
74
- # end
80
+ # def test
81
+ # if foo?
82
+ # work
83
+ # end
75
84
  #
76
- # do_something
85
+ # do_something
77
86
  #
78
- # if bar? # <- reports an offense
79
- # work
87
+ # if bar? # <- reports an offense
88
+ # work
89
+ # end
80
90
  # end
91
+ #
81
92
  class GuardClause < Base
82
93
  include MinBodyLength
83
94
  include StatementModifier
@@ -35,13 +35,15 @@ module RuboCop
35
35
 
36
36
  # @!method kv_each(node)
37
37
  def_node_matcher :kv_each, <<~PATTERN
38
- (block $(send (send _ ${:keys :values}) :each) ...)
38
+ ({block numblock} $(send (send _ ${:keys :values}) :each) ...)
39
39
  PATTERN
40
40
 
41
41
  def on_block(node)
42
42
  register_kv_offense(node)
43
43
  end
44
44
 
45
+ alias on_numblock on_block
46
+
45
47
  private
46
48
 
47
49
  def register_kv_offense(node)