rubocop 1.75.6 → 1.76.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -13
  3. data/config/default.yml +48 -5
  4. data/config/obsoletion.yml +6 -3
  5. data/lib/rubocop/cop/autocorrect_logic.rb +18 -10
  6. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  7. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +50 -6
  8. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  9. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
  10. data/lib/rubocop/cop/layout/class_structure.rb +35 -0
  11. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -2
  12. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  13. data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -32
  14. data/lib/rubocop/cop/lint/duplicate_methods.rb +41 -1
  15. data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
  16. data/lib/rubocop/cop/lint/float_comparison.rb +27 -0
  17. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  18. data/lib/rubocop/cop/lint/literal_as_condition.rb +16 -24
  19. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  20. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +87 -0
  21. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  22. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  23. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  24. data/lib/rubocop/cop/naming/predicate_method.rb +216 -0
  25. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +2 -2
  26. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
  27. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  28. data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
  29. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  30. data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -4
  31. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
  32. data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
  33. data/lib/rubocop/cop/style/map_to_hash.rb +11 -0
  34. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
  35. data/lib/rubocop/cop/style/redundant_array_flatten.rb +48 -0
  36. data/lib/rubocop/cop/style/redundant_format.rb +6 -1
  37. data/lib/rubocop/cop/style/redundant_parentheses.rb +16 -5
  38. data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
  39. data/lib/rubocop/cop/style/safe_navigation.rb +10 -7
  40. data/lib/rubocop/cop/team.rb +1 -1
  41. data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
  42. data/lib/rubocop/version.rb +1 -1
  43. data/lib/rubocop.rb +6 -1
  44. metadata +12 -7
@@ -15,6 +15,14 @@ module RuboCop
15
15
  # x == 0.1
16
16
  # x != 0.1
17
17
  #
18
+ # # bad
19
+ # case value
20
+ # when 1.0
21
+ # foo
22
+ # when 2.0
23
+ # bar
24
+ # end
25
+ #
18
26
  # # good - using BigDecimal
19
27
  # x.to_d == 0.1.to_d
20
28
  #
@@ -32,12 +40,21 @@ module RuboCop
32
40
  # # good - comparing against nil
33
41
  # Float(x, exception: false) == nil
34
42
  #
43
+ # # good - using epsilon comparison in case expression
44
+ # case
45
+ # when (value - 1.0).abs < Float::EPSILON
46
+ # foo
47
+ # when (value - 2.0).abs < Float::EPSILON
48
+ # bar
49
+ # end
50
+ #
35
51
  # # Or some other epsilon based type of comparison:
36
52
  # # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
37
53
  #
38
54
  class FloatComparison < Base
39
55
  MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
40
56
  MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
57
+ MSG_CASE = 'Avoid float literal comparisons in case statements as they are unreliable.'
41
58
 
42
59
  EQUALITY_METHODS = %i[== != eql? equal?].freeze
43
60
  FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
@@ -58,6 +75,16 @@ module RuboCop
58
75
  end
59
76
  alias on_csend on_send
60
77
 
78
+ def on_case(node)
79
+ node.when_branches.each do |when_branch|
80
+ when_branch.each_condition do |condition|
81
+ next if !float?(condition) || literal_safe?(condition)
82
+
83
+ add_offense(condition, message: MSG_CASE)
84
+ end
85
+ end
86
+ end
87
+
61
88
  private
62
89
 
63
90
  def float?(node)
@@ -11,39 +11,43 @@ module RuboCop
11
11
  # @example
12
12
  # # bad
13
13
  # foo.object_id == bar.object_id
14
+ # foo.object_id != baz.object_id
14
15
  #
15
16
  # # good
16
17
  # foo.equal?(bar)
18
+ # !foo.equal?(baz)
17
19
  #
18
20
  class IdentityComparison < Base
19
21
  extend AutoCorrector
20
22
 
21
- MSG = 'Use `equal?` instead `==` when comparing `object_id`.'
22
- RESTRICT_ON_SEND = %i[==].freeze
23
+ MSG = 'Use `%<bang>sequal?` instead of `%<comparison_method>s` when comparing `object_id`.'
24
+ RESTRICT_ON_SEND = %i[== !=].freeze
25
+
26
+ # @!method object_id_comparison(node)
27
+ def_node_matcher :object_id_comparison, <<~PATTERN
28
+ (send
29
+ (send
30
+ _lhs_receiver :object_id) ${:== :!=}
31
+ (send
32
+ _rhs_receiver :object_id))
33
+ PATTERN
23
34
 
24
35
  def on_send(node)
25
- return unless compare_between_object_id_by_double_equal?(node)
36
+ return unless (comparison_method = object_id_comparison(node))
26
37
 
27
- add_offense(node) do |corrector|
38
+ bang = comparison_method == :== ? '' : '!'
39
+ add_offense(node,
40
+ message: format(MSG, comparison_method: comparison_method,
41
+ bang: bang)) do |corrector|
28
42
  receiver = node.receiver.receiver
29
43
  argument = node.first_argument.receiver
30
44
  return unless receiver && argument
31
45
 
32
- replacement = "#{receiver.source}.equal?(#{argument.source})"
46
+ replacement = "#{bang}#{receiver.source}.equal?(#{argument.source})"
33
47
 
34
48
  corrector.replace(node, replacement)
35
49
  end
36
50
  end
37
-
38
- private
39
-
40
- def compare_between_object_id_by_double_equal?(node)
41
- object_id_method?(node.receiver) && object_id_method?(node.first_argument)
42
- end
43
-
44
- def object_id_method?(node)
45
- node.send_type? && node.method?(:object_id)
46
- end
47
51
  end
48
52
  end
49
53
  end
@@ -240,30 +240,22 @@ module RuboCop
240
240
  def correct_if_node(node, cond)
241
241
  result = condition_evaluation(node, cond)
242
242
 
243
- if node.elsif? && result
244
- add_offense(cond) do |corrector|
245
- corrector.replace(node, "else\n #{node.if_branch.source}")
246
- end
247
- elsif node.elsif? && !result
248
- add_offense(cond) do |corrector|
249
- corrector.replace(node, "else\n #{node.else_branch.source}")
250
- end
251
- elsif node.if_branch && result
252
- add_offense(cond) do |corrector|
253
- corrector.replace(node, node.if_branch.source)
254
- end
255
- elsif node.elsif_conditional?
256
- add_offense(cond) do |corrector|
257
- corrector.replace(node, "#{node.else_branch.source.sub('elsif', 'if')}\nend")
258
- end
259
- elsif node.else? || node.ternary?
260
- add_offense(cond) do |corrector|
261
- corrector.replace(node, node.else_branch.source)
262
- end
263
- else
264
- add_offense(cond) do |corrector|
265
- corrector.remove(node)
266
- end
243
+ new_node = if node.elsif? && result
244
+ "else\n #{range_with_comments(node.if_branch).source}"
245
+ elsif node.elsif? && !result
246
+ "else\n #{node.else_branch.source}"
247
+ elsif node.if_branch && result
248
+ node.if_branch.source
249
+ elsif node.elsif_conditional?
250
+ "#{node.else_branch.source.sub('elsif', 'if')}\nend"
251
+ elsif node.else? || node.ternary?
252
+ node.else_branch.source
253
+ else
254
+ '' # Equivalent to removing the node
255
+ end
256
+
257
+ add_offense(cond) do |corrector|
258
+ corrector.replace(node, new_node)
267
259
  end
268
260
  end
269
261
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -8,6 +8,11 @@ module RuboCop
8
8
  # given by `ruby -cw` prior to Ruby 2.6:
9
9
  # "shadowing outer local variable - foo".
10
10
  #
11
+ # The cop is now disabled by default to match the upstream Ruby behavior.
12
+ # It's useful, however, if you'd like to avoid shadowing variables from outer
13
+ # scopes, which some people consider an anti-pattern that makes it harder
14
+ # to keep track of what's going on in a program.
15
+ #
11
16
  # NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
12
17
  # because `Ractor` should not access outer variables.
13
18
  # eg. following style is encouraged:
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for usage of method `fetch` or `Array.new` with default value argument
7
+ # and block. In such cases, block will always be used as default value.
8
+ #
9
+ # This cop emulates Ruby warning "block supersedes default value argument" which
10
+ # applies to `Array.new`, `Array#fetch`, `Hash#fetch`, `ENV.fetch` and
11
+ # `Thread#fetch`.
12
+ #
13
+ # @safety
14
+ # This cop is unsafe because the receiver could have nonstandard implementation
15
+ # of `fetch`, or be a class other than the one listed above.
16
+ #
17
+ # It is also unsafe because default value argument could have side effects:
18
+ #
19
+ # [source,ruby]
20
+ # ----
21
+ # def x(a) = puts "side effect"
22
+ # Array.new(5, x(1)) { 2 }
23
+ # ----
24
+ #
25
+ # so removing it would change behavior.
26
+ #
27
+ # @example
28
+ # # bad
29
+ # x.fetch(key, default_value) { block_value }
30
+ # Array.new(size, default_value) { block_value }
31
+ #
32
+ # # good
33
+ # x.fetch(key) { block_value }
34
+ # Array.new(size) { block_value }
35
+ #
36
+ # # also good - in case default value argument is desired instead
37
+ # x.fetch(key, default_value)
38
+ # Array.new(size, default_value)
39
+ #
40
+ # # good - keyword arguments aren't registered as offenses
41
+ # x.fetch(key, keyword: :arg) { block_value }
42
+ #
43
+ # @example AllowedReceivers: ['Rails.cache']
44
+ # # good
45
+ # Rails.cache.fetch(name, options) { block }
46
+ #
47
+ class UselessDefaultValueArgument < Base
48
+ include AllowedReceivers
49
+ extend AutoCorrector
50
+
51
+ MSG = 'Block supersedes default value argument.'
52
+
53
+ RESTRICT_ON_SEND = %i[fetch new].freeze
54
+
55
+ # @!method default_value_argument_and_block(node)
56
+ def_node_matcher :default_value_argument_and_block, <<~PATTERN
57
+ (any_block
58
+ {
59
+ (call _receiver :fetch $_key $_default_value)
60
+ (send (const _ :Array) :new $_size $_default_value)
61
+ }
62
+ _args
63
+ _block_body)
64
+ PATTERN
65
+
66
+ def on_send(node)
67
+ unless (prev_arg_node, default_value_node = default_value_argument_and_block(node.parent))
68
+ return
69
+ end
70
+ return if allowed_receiver?(node.receiver)
71
+ return if hash_without_braces?(default_value_node)
72
+
73
+ add_offense(default_value_node) do |corrector|
74
+ corrector.remove(prev_arg_node.source_range.end.join(default_value_node.source_range))
75
+ end
76
+ end
77
+ alias on_csend on_send
78
+
79
+ private
80
+
81
+ def hash_without_braces?(node)
82
+ node.hash_type? && !node.braces?
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for useless OR (`||` and `or`) expressions.
7
+ #
8
+ # Some methods always return a truthy value, even when called
9
+ # on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
10
+ # appended after these methods will never evaluate.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # x.to_a || fallback
16
+ # x.to_c || fallback
17
+ # x.to_d || fallback
18
+ # x.to_i || fallback
19
+ # x.to_f || fallback
20
+ # x.to_h || fallback
21
+ # x.to_r || fallback
22
+ # x.to_s || fallback
23
+ # x.to_sym || fallback
24
+ # x.intern || fallback
25
+ # x.inspect || fallback
26
+ # x.hash || fallback
27
+ # x.object_id || fallback
28
+ # x.__id__ || fallback
29
+ #
30
+ # x.to_s or fallback
31
+ #
32
+ # # good - if fallback is same as return value of method called on nil
33
+ # x.to_a # nil.to_a returns []
34
+ # x.to_c # nil.to_c returns (0+0i)
35
+ # x.to_d # nil.to_d returns 0.0
36
+ # x.to_i # nil.to_i returns 0
37
+ # x.to_f # nil.to_f returns 0.0
38
+ # x.to_h # nil.to_h returns {}
39
+ # x.to_r # nil.to_r returns (0/1)
40
+ # x.to_s # nil.to_s returns ''
41
+ # x.to_sym # nil.to_sym raises an error
42
+ # x.intern # nil.intern raises an error
43
+ # x.inspect # nil.inspect returns "nil"
44
+ # x.hash # nil.hash returns an Integer
45
+ # x.object_id # nil.object_id returns an Integer
46
+ # x.__id__ # nil.object_id returns an Integer
47
+ #
48
+ # # good - if the intention is not to call the method on nil
49
+ # x&.to_a || fallback
50
+ # x&.to_c || fallback
51
+ # x&.to_d || fallback
52
+ # x&.to_i || fallback
53
+ # x&.to_f || fallback
54
+ # x&.to_h || fallback
55
+ # x&.to_r || fallback
56
+ # x&.to_s || fallback
57
+ # x&.to_sym || fallback
58
+ # x&.intern || fallback
59
+ # x&.inspect || fallback
60
+ # x&.hash || fallback
61
+ # x&.object_id || fallback
62
+ # x&.__id__ || fallback
63
+ #
64
+ # x&.to_s or fallback
65
+ #
66
+ class UselessOr < Base
67
+ MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
68
+
69
+ TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
70
+ :to_s, :to_sym, :intern, :inspect, :hash, :object_id,
71
+ :__id__].freeze
72
+
73
+ # @!method truthy_return_value_method?(node)
74
+ def_node_matcher :truthy_return_value_method?, <<~PATTERN
75
+ (send _ %TRUTHY_RETURN_VALUE_METHODS)
76
+ PATTERN
77
+
78
+ def on_or(node)
79
+ if truthy_return_value_method?(node.lhs)
80
+ report_offense(node, node.lhs)
81
+ elsif truthy_return_value_method?(node.rhs)
82
+ parent = node.parent
83
+ parent = parent.parent if parent&.begin_type?
84
+
85
+ report_offense(parent, node.rhs) if parent&.or_type?
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def report_offense(or_node, truthy_node)
92
+ add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
93
+ message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -39,7 +39,7 @@ module RuboCop
39
39
  class AbcSize < Base
40
40
  include MethodComplexity
41
41
 
42
- MSG = 'Assignment Branch Condition size for %<method>s is too high. ' \
42
+ MSG = 'Assignment Branch Condition size for `%<method>s` is too high. ' \
43
43
  '[%<abc_vector>s %<complexity>.4g/%<max>.4g]'
44
44
 
45
45
  private
@@ -24,7 +24,7 @@ module RuboCop
24
24
  gem_canonical_name(string_a) < gem_canonical_name(string_b)
25
25
  end
26
26
 
27
- def consecutive_lines(previous, current)
27
+ def consecutive_lines?(previous, current)
28
28
  first_line = get_source_range(current, treat_comments_as_separators).first_line
29
29
  previous.source_range.last_line == first_line - 1
30
30
  end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Naming
6
+ # Checks that predicate methods end with `?` and non-predicate methods do not.
7
+ #
8
+ # The names of predicate methods (methods that return a boolean value) should end
9
+ # in a question mark. Methods that don’t return a boolean, shouldn’t
10
+ # end in a question mark.
11
+ #
12
+ # The cop assesses a predicate method as one that returns boolean values. Likewise,
13
+ # a method that only returns literal values is assessed as non-predicate. The cop does
14
+ # not make an assessment if the return type is unknown (method calls, variables, etc.).
15
+ #
16
+ # NOTE: Operator methods (`def ==`, etc.) are ignored.
17
+ #
18
+ # By default, the cop runs in `conservative` mode, which allows a method to be named
19
+ # with a question mark as long as at least one return value is boolean. In `aggressive`
20
+ # mode, methods with a question mark will register an offense if any known non-boolean
21
+ # return values are detected.
22
+ #
23
+ # The cop also has `AllowedMethods` configuration in order to prevent the cop from
24
+ # registering an offense from a method name that does not confirm to the naming
25
+ # guidelines. By default, `call` is allowed.
26
+ #
27
+ # @example Mode: conservative (default)
28
+ # # bad
29
+ # def foo
30
+ # bar == baz
31
+ # end
32
+ #
33
+ # # good
34
+ # def foo?
35
+ # bar == baz
36
+ # end
37
+ #
38
+ # # bad
39
+ # def foo?
40
+ # 5
41
+ # end
42
+ #
43
+ # # good
44
+ # def foo
45
+ # 5
46
+ # end
47
+ #
48
+ # # good - operator method
49
+ # def ==(other)
50
+ # hash == other.hash
51
+ # end
52
+ #
53
+ # # good - at least one return value is boolean
54
+ # def foo?
55
+ # return unless bar?
56
+ # true
57
+ # end
58
+ #
59
+ # # ok - return type is not known
60
+ # def foo?
61
+ # bar
62
+ # end
63
+ #
64
+ # # ok - return type is not known
65
+ # def foo
66
+ # bar?
67
+ # end
68
+ #
69
+ # @example Mode: aggressive
70
+ # # bad - the method returns nil in some cases
71
+ # def foo?
72
+ # return unless bar?
73
+ # true
74
+ # end
75
+ #
76
+ class PredicateMethod < Base
77
+ include AllowedMethods
78
+
79
+ MSG_PREDICATE = 'Predicate method names should end with `?`.'
80
+ MSG_NON_PREDICATE = 'Non-predicate method names should not end with `?`.'
81
+
82
+ def on_def(node)
83
+ return if allowed?(node)
84
+
85
+ return_values = return_values(node.body)
86
+ return if acceptable?(return_values)
87
+
88
+ if node.predicate_method? && potential_non_predicate?(return_values)
89
+ add_offense(node.loc.name, message: MSG_NON_PREDICATE)
90
+ elsif !node.predicate_method? && all_return_values_boolean?(return_values)
91
+ add_offense(node.loc.name, message: MSG_PREDICATE)
92
+ end
93
+ end
94
+ alias on_defs on_def
95
+
96
+ private
97
+
98
+ def allowed?(node)
99
+ allowed_method?(node.method_name) ||
100
+ node.operator_method? ||
101
+ node.body.nil?
102
+ end
103
+
104
+ def acceptable?(return_values)
105
+ # In `conservative` mode, if the method returns `super`, `zsuper`, or a
106
+ # non-comparison method call, the method name is acceptable.
107
+ return false unless conservative?
108
+
109
+ return_values.any? do |value|
110
+ value.type?(:super, :zsuper) || non_comparison_call?(value)
111
+ end
112
+ end
113
+
114
+ def non_comparison_call?(value)
115
+ value.call_type? && !value.comparison_method?
116
+ end
117
+
118
+ def return_values(node)
119
+ # Collect all the (implicit and explicit) return values of a node
120
+ return_values = Set.new(node.begin_type? ? [] : [extract_return_value(node)])
121
+
122
+ node.each_descendant(:return) do |return_node|
123
+ return_values << extract_return_value(return_node)
124
+ end
125
+
126
+ last_value = last_value(node)
127
+ return_values << last_value if last_value
128
+
129
+ process_return_values(return_values)
130
+ end
131
+
132
+ def all_return_values_boolean?(return_values)
133
+ values = return_values.reject { |value| value.type?(:super, :zsuper) }
134
+ return false if values.empty?
135
+
136
+ values.all? { |value| boolean_return?(value) }
137
+ end
138
+
139
+ def boolean_return?(value)
140
+ value.boolean_type? || (value.call_type? && value.comparison_method?)
141
+ end
142
+
143
+ def potential_non_predicate?(return_values)
144
+ # Assumes a method to be non-predicate if all return values are non-boolean literals.
145
+ #
146
+ # In `Mode: conservative`, if any of the return values is a boolean,
147
+ # the method name is acceptable.
148
+ # In `Mode: aggressive`, all return values must be booleans for a predicate
149
+ # method, or else an offense will be registered.
150
+ return false if conservative? && return_values.any? { |value| boolean_return?(value) }
151
+
152
+ return_values.any? do |value|
153
+ value.literal? && !value.boolean_type?
154
+ end
155
+ end
156
+
157
+ def extract_return_value(node)
158
+ return node unless node.return_type?
159
+
160
+ # `return` without a value is a `nil` return.
161
+ return s(:nil) if node.arguments.empty?
162
+
163
+ # When there's a multiple return, it cannot be a predicate
164
+ # so just return an `array` sexp for simplicity.
165
+ return s(:array) unless node.arguments.one?
166
+
167
+ node.first_argument
168
+ end
169
+
170
+ def last_value(node)
171
+ value = node.begin_type? ? node.children.last : node
172
+ value.return_type? ? extract_return_value(value) : value
173
+ end
174
+
175
+ def process_return_values(return_values)
176
+ return_values.flat_map do |value|
177
+ if value.conditional?
178
+ process_return_values(extract_conditional_branches(value))
179
+ elsif and_or?(value)
180
+ process_return_values(extract_and_or_clauses(value))
181
+ else
182
+ value
183
+ end
184
+ end
185
+ end
186
+
187
+ def and_or?(node)
188
+ node.type?(:and, :or)
189
+ end
190
+
191
+ def extract_and_or_clauses(node)
192
+ # Recursively traverse an `and` or `or` node to collect all clauses within
193
+ return node unless and_or?(node)
194
+
195
+ [extract_and_or_clauses(node.lhs), extract_and_or_clauses(node.rhs)].flatten
196
+ end
197
+
198
+ def extract_conditional_branches(node)
199
+ return node unless node.conditional?
200
+
201
+ if node.type?(:while, :until)
202
+ # If there is no body, act as implicit `nil`.
203
+ node.body ? [last_value(node.body)] : [s(:nil)]
204
+ else
205
+ # Branches with no value act as an implicit `nil`.
206
+ node.branches.filter_map { |branch| branch ? last_value(branch) : s(:nil) }
207
+ end
208
+ end
209
+
210
+ def conservative?
211
+ cop_config.fetch('Mode', :conservative).to_sym == :conservative
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
@@ -100,7 +100,7 @@ module RuboCop
100
100
  # # good
101
101
  # def_node_matcher(:even?) { |value| }
102
102
  #
103
- class PredicateName < Base
103
+ class PredicatePrefix < Base
104
104
  include AllowedMethods
105
105
 
106
106
  # @!method dynamic_method_define(node)
@@ -143,7 +143,7 @@ module RuboCop
143
143
  next if predicate_prefixes.include?(forbidden_prefix)
144
144
 
145
145
  raise ValidationError, <<~MSG.chomp
146
- The `Naming/PredicateName` cop is misconfigured. Prefix #{forbidden_prefix} must be included in NamePrefix because it is included in ForbiddenPrefixes.
146
+ The `Naming/PredicatePrefix` cop is misconfigured. Prefix #{forbidden_prefix} must be included in NamePrefix because it is included in ForbiddenPrefixes.
147
147
  MSG
148
148
  end
149
149
  end
@@ -195,15 +195,27 @@ module RuboCop
195
195
  def autocorrect(corrector, node)
196
196
  case style
197
197
  when :group
198
- def_nodes = find_corresponding_def_nodes(node)
199
- return unless def_nodes.any?
200
-
201
- replace_defs(corrector, node, def_nodes)
198
+ autocorrect_group_style(corrector, node)
202
199
  when :inline
200
+ autocorrect_inline_style(corrector, node)
201
+ end
202
+ end
203
+
204
+ def autocorrect_group_style(corrector, node)
205
+ def_nodes = find_corresponding_def_nodes(node)
206
+ return unless def_nodes.any?
207
+
208
+ replace_defs(corrector, node, def_nodes)
209
+ end
210
+
211
+ def autocorrect_inline_style(corrector, node)
212
+ if node.parent&.begin_type?
213
+ remove_modifier_node_within_begin(corrector, node, node.parent)
214
+ else
203
215
  remove_nodes(corrector, node)
204
- select_grouped_def_nodes(node).each do |grouped_def_node|
205
- insert_inline_modifier(corrector, grouped_def_node, node.method_name)
206
- end
216
+ end
217
+ select_grouped_def_nodes(node).each do |grouped_def_node|
218
+ insert_inline_modifier(corrector, grouped_def_node, node.method_name)
207
219
  end
208
220
  end
209
221
 
@@ -224,9 +236,13 @@ module RuboCop
224
236
  end
225
237
 
226
238
  def offense?(node)
227
- (group_style? && access_modifier_is_inlined?(node) &&
228
- !node.parent&.if_type? && !right_siblings_same_inline_method?(node)) ||
229
- (inline_style? && access_modifier_is_not_inlined?(node))
239
+ if group_style?
240
+ return false if node.parent ? node.parent.if_type? : access_modifier_with_symbol?(node)
241
+
242
+ access_modifier_is_inlined?(node) && !right_siblings_same_inline_method?(node)
243
+ else
244
+ access_modifier_is_not_inlined?(node) && select_grouped_def_nodes(node).any?
245
+ end
230
246
  end
231
247
 
232
248
  def correctable_group_offense?(node)
@@ -331,6 +347,12 @@ module RuboCop
331
347
  end
332
348
  end
333
349
 
350
+ def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
351
+ def_node = begin_node.children[1]
352
+ range = modifier_node.source_range.begin.join(def_node.source_range.begin)
353
+ corrector.remove(range)
354
+ end
355
+
334
356
  def def_source(node, def_nodes)
335
357
  [
336
358
  *processed_source.ast_with_comments[node].map(&:text),
@@ -173,7 +173,7 @@ module RuboCop
173
173
  end
174
174
 
175
175
  def preferred_delimiters_config
176
- config.for_cop('Style/PercentLiteralDelimiters') ['PreferredDelimiters']
176
+ config.for_cop('Style/PercentLiteralDelimiters')['PreferredDelimiters']
177
177
  end
178
178
  end
179
179
  end