rubocop 1.34.1 → 1.36.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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +33 -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 +16 -12
  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 +5 -1
  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/layout/space_inside_block_braces.rb +25 -9
  27. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  28. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  29. data/lib/rubocop/cop/lint/duplicate_require.rb +1 -1
  30. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  31. data/lib/rubocop/cop/lint/empty_conditional_body.rb +31 -1
  32. data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -9
  33. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -0
  34. data/lib/rubocop/cop/lint/next_without_accumulator.rb +25 -6
  35. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +6 -6
  36. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +12 -0
  37. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +9 -3
  38. data/lib/rubocop/cop/lint/redundant_with_index.rb +13 -10
  39. data/lib/rubocop/cop/lint/redundant_with_object.rb +12 -11
  40. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  41. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +15 -2
  42. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  43. data/lib/rubocop/cop/lint/useless_access_modifier.rb +8 -6
  44. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  45. data/lib/rubocop/cop/lint/void.rb +2 -0
  46. data/lib/rubocop/cop/mixin/allowed_methods.rb +10 -5
  47. data/lib/rubocop/cop/mixin/allowed_pattern.rb +13 -5
  48. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  49. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +76 -1
  50. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -6
  51. data/lib/rubocop/cop/mixin/method_complexity.rb +4 -4
  52. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  53. data/lib/rubocop/cop/mixin/range_help.rb +2 -3
  54. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  55. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  56. data/lib/rubocop/cop/style/access_modifier_declarations.rb +77 -1
  57. data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
  58. data/lib/rubocop/cop/style/case_equality.rb +40 -10
  59. data/lib/rubocop/cop/style/class_methods_definitions.rb +2 -1
  60. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  61. data/lib/rubocop/cop/style/combinable_loops.rb +3 -1
  62. data/lib/rubocop/cop/style/each_for_simple_loop.rb +41 -6
  63. data/lib/rubocop/cop/style/each_with_object.rb +39 -8
  64. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  65. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  66. data/lib/rubocop/cop/style/for.rb +2 -0
  67. data/lib/rubocop/cop/style/guard_clause.rb +27 -16
  68. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -1
  69. data/lib/rubocop/cop/style/hash_syntax.rb +17 -0
  70. data/lib/rubocop/cop/style/inverse_methods.rb +8 -6
  71. data/lib/rubocop/cop/style/magic_comment_format.rb +307 -0
  72. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
  73. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
  74. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -1
  75. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  76. data/lib/rubocop/cop/style/next.rb +3 -5
  77. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  78. data/lib/rubocop/cop/style/object_then.rb +2 -0
  79. data/lib/rubocop/cop/style/perl_backrefs.rb +22 -1
  80. data/lib/rubocop/cop/style/proc.rb +4 -1
  81. data/lib/rubocop/cop/style/redundant_begin.rb +2 -0
  82. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  83. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  84. data/lib/rubocop/cop/style/redundant_self.rb +2 -0
  85. data/lib/rubocop/cop/style/redundant_sort_by.rb +24 -8
  86. data/lib/rubocop/cop/style/safe_navigation.rb +4 -2
  87. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  88. data/lib/rubocop/cop/style/sole_nested_conditional.rb +0 -2
  89. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  90. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  91. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -1
  92. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  93. data/lib/rubocop/cop/style/word_array.rb +1 -1
  94. data/lib/rubocop/cop/util.rb +1 -1
  95. data/lib/rubocop/feature_loader.rb +6 -2
  96. data/lib/rubocop/formatter/html_formatter.rb +2 -2
  97. data/lib/rubocop/runner.rb +4 -0
  98. data/lib/rubocop/server/cache.rb +11 -8
  99. data/lib/rubocop/version.rb +3 -2
  100. data/lib/rubocop.rb +3 -2
  101. metadata +9 -7
@@ -63,7 +63,7 @@ module RuboCop
63
63
  class EmptyBlock < Base
64
64
  MSG = 'Empty block detected.'
65
65
 
66
- def on_block(node)
66
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
67
67
  return if node.body
68
68
  return if allow_empty_lambdas? && lambda_or_proc?(node)
69
69
  return if cop_config['AllowComments'] && allow_comment?(node)
@@ -96,7 +96,7 @@ module RuboCop
96
96
  end
97
97
 
98
98
  def correct_other_branches(corrector, node)
99
- return unless (node.if? || node.unless?) && node.else_branch
99
+ return unless require_other_branches_correction?(node)
100
100
 
101
101
  if node.else_branch.if_type?
102
102
  # Replace an orphaned `elsif` with `if`
@@ -107,13 +107,43 @@ module RuboCop
107
107
  end
108
108
  end
109
109
 
110
+ def require_other_branches_correction?(node)
111
+ return false unless node.if_type? && node.else_branch
112
+ return false if !empty_if_branch?(node) && node.elsif?
113
+
114
+ !empty_else_branch?(node)
115
+ end
116
+
117
+ def empty_if_branch?(node)
118
+ return false unless (parent = node.parent)
119
+ return true unless parent.if_type?
120
+ return true unless (if_branch = parent.if_branch)
121
+
122
+ if_branch.if_type? && !if_branch.body
123
+ end
124
+
125
+ def empty_else_branch?(node)
126
+ node.else_branch.if_type? && !node.else_branch.body
127
+ end
128
+
129
+ # rubocop:disable Metrics/AbcSize
110
130
  def branch_range(node)
111
131
  if node.loc.else
112
132
  node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
133
+ elsif all_branches_body_missing?(node)
134
+ if_node = node.ancestors.detect(&:if?)
135
+ node.source_range.with(end_pos: if_node.loc.end.end_pos)
113
136
  else
114
137
  node.source_range
115
138
  end
116
139
  end
140
+ # rubocop:enable Metrics/AbcSize
141
+
142
+ def all_branches_body_missing?(node)
143
+ return false unless node.parent&.if_type?
144
+
145
+ node.parent.branches.compact.empty?
146
+ end
117
147
 
118
148
  def deletion_range(range)
119
149
  # Collect a range between the start of the `if` node and the next relevant node,
@@ -6,18 +6,18 @@ module RuboCop
6
6
  #
7
7
  # This cop emulates the following Ruby warnings in Ruby 2.6.
8
8
  #
9
+ # [source,console]
10
+ # ----
9
11
  # % cat example.rb
10
12
  # ERB.new('hi', nil, '-', '@output_buffer')
11
13
  # % ruby -rerb example.rb
12
- # example.rb:1: warning: Passing safe_level with the 2nd argument of
13
- # ERB.new is deprecated. Do not use it, and specify other arguments as
14
- # keyword arguments.
15
- # example.rb:1: warning: Passing trim_mode with the 3rd argument of
16
- # ERB.new is deprecated. Use keyword argument like
17
- # ERB.new(str, trim_mode:...) instead.
18
- # example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new
19
- # is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...)
20
- # instead.
14
+ # example.rb:1: warning: Passing safe_level with the 2nd argument of ERB.new is
15
+ # deprecated. Do not use it, and specify other arguments as keyword arguments.
16
+ # example.rb:1: warning: Passing trim_mode with the 3rd argument of ERB.new is
17
+ # deprecated. Use keyword argument like ERB.new(str, trim_mode:...) instead.
18
+ # example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new is
19
+ # deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.
20
+ # ----
21
21
  #
22
22
  # Now non-keyword arguments other than first one are softly deprecated
23
23
  # and will be removed when Ruby 2.5 becomes EOL.
@@ -58,6 +58,7 @@ module RuboCop
58
58
  (node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
59
59
  end
60
60
 
61
+ # rubocop:disable Metrics/MethodLength
61
62
  def autocorrected_value(node)
62
63
  case node.type
63
64
  when :int
@@ -70,10 +71,13 @@ module RuboCop
70
71
  autocorrected_value_for_symbol(node)
71
72
  when :array
72
73
  autocorrected_value_for_array(node)
74
+ when :nil
75
+ ''
73
76
  else
74
77
  node.source.gsub('"', '\"')
75
78
  end
76
79
  end
80
+ # rubocop:enable Metrics/MethodLength
77
81
 
78
82
  def autocorrected_value_for_string(node)
79
83
  if node.source.start_with?("'", '%q')
@@ -25,13 +25,8 @@ module RuboCop
25
25
  class NextWithoutAccumulator < Base
26
26
  MSG = 'Use `next` with an accumulator argument in a `reduce`.'
27
27
 
28
- # @!method on_body_of_reduce(node)
29
- def_node_matcher :on_body_of_reduce, <<~PATTERN
30
- (block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...))
31
- PATTERN
32
-
33
28
  def on_block(node)
34
- on_body_of_reduce(node) do |body|
29
+ on_block_body_of_reduce(node) do |body|
35
30
  void_next = body.each_node(:next).find do |n|
36
31
  n.children.empty? && parent_block_node(n) == node
37
32
  end
@@ -40,11 +35,35 @@ module RuboCop
40
35
  end
41
36
  end
42
37
 
38
+ def on_numblock(node)
39
+ on_numblock_body_of_reduce(node) do |body|
40
+ void_next = body.each_node(:next).find do |n|
41
+ n.children.empty? && parent_numblock_node(n) == node
42
+ end
43
+
44
+ add_offense(void_next) if void_next
45
+ end
46
+ end
47
+
43
48
  private
44
49
 
50
+ # @!method on_block_body_of_reduce(node)
51
+ def_node_matcher :on_block_body_of_reduce, <<~PATTERN
52
+ (block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...))
53
+ PATTERN
54
+
55
+ # @!method on_numblock_body_of_reduce(node)
56
+ def_node_matcher :on_numblock_body_of_reduce, <<~PATTERN
57
+ (numblock (send _recv {:reduce :inject} !sym) _argscount $(begin ...))
58
+ PATTERN
59
+
45
60
  def parent_block_node(node)
46
61
  node.each_ancestor(:block).first
47
62
  end
63
+
64
+ def parent_numblock_node(node)
65
+ node.each_ancestor(:numblock).first
66
+ end
48
67
  end
49
68
  end
50
69
  end
@@ -99,19 +99,19 @@ module RuboCop
99
99
  end
100
100
 
101
101
  def register_offense(node, exist_node)
102
- unless force_method?(node)
103
- add_offense(node,
104
- message: format(MSG_CHANGE_FORCE_METHOD,
105
- method_name: replacement_method(node)))
106
- end
102
+ add_offense(node, message: message_change_force_method(node)) unless force_method?(node)
107
103
 
108
104
  range = range_between(node.parent.loc.keyword.begin_pos,
109
105
  exist_node.loc.expression.end_pos)
110
106
  add_offense(range, message: message_remove_file_exist_check(exist_node)) do |corrector|
111
- autocorrect(corrector, node, range)
107
+ autocorrect(corrector, node, range) unless node.parent.elsif?
112
108
  end
113
109
  end
114
110
 
111
+ def message_change_force_method(node)
112
+ format(MSG_CHANGE_FORCE_METHOD, method_name: replacement_method(node))
113
+ end
114
+
115
115
  def message_remove_file_exist_check(node)
116
116
  receiver, method_name = receiver_and_method_name(node)
117
117
  format(MSG_REMOVE_FILE_EXIST_CHECK, receiver: receiver, method_name: method_name)
@@ -74,6 +74,18 @@ module RuboCop
74
74
  end
75
75
  end
76
76
 
77
+ def on_numblock(node)
78
+ return if target_ruby_version >= 3.0
79
+ return unless node.body
80
+ return unless unsorted_dir_loop?(node.send_node)
81
+
82
+ node.argument_list
83
+ .filter { |argument| var_is_required?(node.body, argument.name) }
84
+ .each do
85
+ add_offense(node.send_node) { |corrector| correct_block(corrector, node.send_node) }
86
+ end
87
+ end
88
+
77
89
  def on_block_pass(node)
78
90
  return if target_ruby_version >= 3.0
79
91
  return unless method_require?(node)
@@ -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
@@ -12,7 +12,7 @@ module RuboCop
12
12
  # same `rescue` statement. In both cases, the more specific rescue is
13
13
  # unnecessary because it is covered by rescuing the less specific
14
14
  # exception. (ie. `rescue Exception, StandardError` has the same behavior
15
- # whether `StandardError` is included or not, because all `StandardError`s
15
+ # whether `StandardError` is included or not, because all ``StandardError``s
16
16
  # are rescued by `rescue Exception`).
17
17
  #
18
18
  # @example
@@ -64,13 +64,26 @@ module RuboCop
64
64
  end
65
65
 
66
66
  def same_conditions_node_different_branch?(variable, outer_local_variable)
67
- variable_node = variable.scope.node.parent
67
+ variable_node = variable_node(variable)
68
68
  return false unless variable_node.conditional?
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
- outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
74
+ outer_local_variable_node.conditional? &&
75
+ (variable_node == outer_local_variable_node ||
76
+ variable_node == outer_local_variable_node.else_branch)
77
+ end
78
+
79
+ def variable_node(variable)
80
+ parent_node = variable.scope.node.parent
81
+
82
+ if parent_node.when_type?
83
+ parent_node.parent
84
+ else
85
+ parent_node
86
+ end
74
87
  end
75
88
 
76
89
  def find_conditional_node_from_ascendant(node)
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # In rare cases where only one iteration (or at most one iteration) is intended behavior,
10
10
  # the code should be refactored to use `if` conditionals.
11
11
  #
12
- # NOTE: Block methods that are used with `Enumerable`s are considered to be loops.
12
+ # NOTE: Block methods that are used with ``Enumerable``s are considered to be loops.
13
13
  #
14
14
  # `AllowedPatterns` can be used to match against the block receiver in order to allow
15
15
  # code that would otherwise be registered as an offense (eg. `times` used not in an
@@ -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?
@@ -31,8 +31,8 @@ module RuboCop
31
31
  # # bad
32
32
  # class Foo
33
33
  # # The following is redundant (methods defined on the class'
34
- # # singleton class are not affected by the public modifier)
35
- # public
34
+ # # singleton class are not affected by the private modifier)
35
+ # private
36
36
  #
37
37
  # def self.method3
38
38
  # end
@@ -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
 
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Looks for `ruby2_keywords` calls for methods that do not need it.
7
7
  #
8
8
  # `ruby2_keywords` should only be called on methods that accept an argument splat
9
- # (`*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
9
+ # (`\*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
10
10
  # a keyword splat (`**kwargs`).
11
11
  #
12
12
  # @example
@@ -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
@@ -17,16 +17,21 @@ module RuboCop
17
17
 
18
18
  # @api public
19
19
  def allowed_methods
20
- deprecated_values = cop_config_deprecated_values
21
- if deprecated_values.any?(Regexp)
22
- cop_config.fetch('AllowedMethods', [])
20
+ if cop_config_deprecated_values.any?(Regexp)
21
+ cop_config_allowed_methods
23
22
  else
24
- Array(cop_config['AllowedMethods']).concat(deprecated_values)
23
+ cop_config_allowed_methods + cop_config_deprecated_values
25
24
  end
26
25
  end
27
26
 
27
+ def cop_config_allowed_methods
28
+ @cop_config_allowed_methods ||= Array(cop_config.fetch('AllowedMethods', []))
29
+ end
30
+
28
31
  def cop_config_deprecated_values
29
- Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
32
+ @cop_config_deprecated_values ||=
33
+ Array(cop_config.fetch('IgnoredMethods', [])) +
34
+ Array(cop_config.fetch('ExcludedMethods', []))
30
35
  end
31
36
  end
32
37
  # @deprecated IgnoredMethods class has been replaced with AllowedMethods.
@@ -30,15 +30,23 @@ module RuboCop
30
30
  def allowed_patterns
31
31
  # Since there could be a pattern specified in the default config, merge the two
32
32
  # arrays together.
33
- patterns = Array(cop_config['AllowedPatterns']).concat(Array(cop_config['IgnoredPatterns']))
34
- deprecated_values = cop_config_deprecated_methods_values
35
- return patterns unless deprecated_values.any?(Regexp)
33
+ if cop_config_deprecated_methods_values.any?(Regexp)
34
+ cop_config_patterns_values + cop_config_deprecated_methods_values
35
+ else
36
+ cop_config_patterns_values
37
+ end
38
+ end
36
39
 
37
- Array(patterns.concat(deprecated_values))
40
+ def cop_config_patterns_values
41
+ @cop_config_patterns_values ||=
42
+ Array(cop_config.fetch('AllowedPatterns', [])) +
43
+ Array(cop_config.fetch('IgnoredPatterns', []))
38
44
  end
39
45
 
40
46
  def cop_config_deprecated_methods_values
41
- Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
47
+ @cop_config_deprecated_methods_values ||=
48
+ Array(cop_config.fetch('IgnoredMethods', [])) +
49
+ Array(cop_config.fetch('ExcludedMethods', []))
42
50
  end
43
51
  end
44
52
 
@@ -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