rubocop 1.78.0 → 1.79.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +32 -19
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/naming/method_name.rb +15 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +4 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/array_intersect.rb +51 -23
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -0
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +2 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +30 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +16 -7
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +2 -0
- metadata +22 -6
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
module Utils
|
7
|
+
# Utility class that checks if the receiver can't be nil.
|
8
|
+
class NilReceiverChecker
|
9
|
+
NIL_METHODS = (nil.methods + %i[!]).to_set.freeze
|
10
|
+
|
11
|
+
def initialize(receiver, additional_nil_methods)
|
12
|
+
@receiver = receiver
|
13
|
+
@additional_nil_methods = additional_nil_methods
|
14
|
+
@checked_nodes = {}.compare_by_identity
|
15
|
+
end
|
16
|
+
|
17
|
+
def cant_be_nil?
|
18
|
+
sole_condition_of_parent_if?(@receiver) || _cant_be_nil?(@receiver.parent, @receiver)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# rubocop:disable Metrics
|
24
|
+
def _cant_be_nil?(node, receiver)
|
25
|
+
return false unless node
|
26
|
+
|
27
|
+
# For some nodes, we check their parent and then some children for these parents.
|
28
|
+
# This is added to avoid infinite loops.
|
29
|
+
return false if @checked_nodes.key?(node)
|
30
|
+
|
31
|
+
@checked_nodes[node] = true
|
32
|
+
|
33
|
+
case node.type
|
34
|
+
when :def, :class, :module, :sclass
|
35
|
+
return false
|
36
|
+
when :send
|
37
|
+
return non_nil_method?(node.method_name) if node.receiver == receiver
|
38
|
+
|
39
|
+
node.arguments.each do |argument|
|
40
|
+
return true if _cant_be_nil?(argument, receiver)
|
41
|
+
end
|
42
|
+
|
43
|
+
return true if _cant_be_nil?(node.receiver, receiver)
|
44
|
+
when :begin
|
45
|
+
return true if _cant_be_nil?(node.children.first, receiver)
|
46
|
+
when :if, :case
|
47
|
+
return true if _cant_be_nil?(node.condition, receiver)
|
48
|
+
when :and, :or
|
49
|
+
return true if _cant_be_nil?(node.lhs, receiver)
|
50
|
+
when :pair
|
51
|
+
if _cant_be_nil?(node.key, receiver) ||
|
52
|
+
_cant_be_nil?(node.value, receiver)
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
when :when
|
56
|
+
node.each_condition do |condition|
|
57
|
+
return true if _cant_be_nil?(condition, receiver)
|
58
|
+
end
|
59
|
+
when :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
|
60
|
+
return true if _cant_be_nil?(node.expression, receiver)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Due to how `if/else` are implemented (`elsif` is a child of `if` or another `elsif`),
|
64
|
+
# using left_siblings will not work correctly for them.
|
65
|
+
if !else_branch?(node) || (node.if_type? && !node.elsif?)
|
66
|
+
node.left_siblings.reverse_each do |sibling|
|
67
|
+
next unless sibling.is_a?(AST::Node)
|
68
|
+
|
69
|
+
return true if _cant_be_nil?(sibling, receiver)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if node.parent
|
74
|
+
_cant_be_nil?(node.parent, receiver)
|
75
|
+
else
|
76
|
+
false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
# rubocop:enable Metrics
|
80
|
+
|
81
|
+
def non_nil_method?(method_name)
|
82
|
+
!NIL_METHODS.include?(method_name) && !@additional_nil_methods.include?(method_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
86
|
+
def sole_condition_of_parent_if?(node)
|
87
|
+
parent = node.parent
|
88
|
+
|
89
|
+
while parent
|
90
|
+
if parent.if_type?
|
91
|
+
if parent.condition == node
|
92
|
+
return true
|
93
|
+
elsif parent.elsif?
|
94
|
+
parent = find_top_if(parent)
|
95
|
+
end
|
96
|
+
elsif else_branch?(parent)
|
97
|
+
# Find the top `if` for `else`.
|
98
|
+
parent = parent.parent
|
99
|
+
end
|
100
|
+
|
101
|
+
parent = parent&.parent
|
102
|
+
end
|
103
|
+
|
104
|
+
false
|
105
|
+
end
|
106
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
107
|
+
|
108
|
+
def else_branch?(node)
|
109
|
+
node.parent&.if_type? && node.parent.else_branch == node
|
110
|
+
end
|
111
|
+
|
112
|
+
def find_top_if(node)
|
113
|
+
node = node.parent while node.elsif?
|
114
|
+
|
115
|
+
node
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -94,6 +94,9 @@ module RuboCop
|
|
94
94
|
MSG = 'Use %<style>s for method names.'
|
95
95
|
MSG_FORBIDDEN = '`%<identifier>s` is forbidden, use another method name instead.'
|
96
96
|
|
97
|
+
OPERATOR_METHODS = %i[| ^ & <=> == === =~ > >= < <= << >> + - * /
|
98
|
+
% ** ~ +@ -@ !@ ~@ [] []= ! != !~ `].to_set.freeze
|
99
|
+
|
97
100
|
# @!method sym_name(node)
|
98
101
|
def_node_matcher :sym_name, '(sym $_name)'
|
99
102
|
|
@@ -103,11 +106,16 @@ module RuboCop
|
|
103
106
|
# @!method new_struct?(node)
|
104
107
|
def_node_matcher :new_struct?, '(send (const {nil? cbase} :Struct) :new ...)'
|
105
108
|
|
109
|
+
# @!method define_data?(node)
|
110
|
+
def_node_matcher :define_data?, '(send (const {nil? cbase} :Data) :define ...)'
|
111
|
+
|
106
112
|
def on_send(node)
|
107
113
|
if node.method?(:define_method) || node.method?(:define_singleton_method)
|
108
114
|
handle_define_method(node)
|
109
115
|
elsif new_struct?(node)
|
110
116
|
handle_new_struct(node)
|
117
|
+
elsif define_data?(node)
|
118
|
+
handle_define_data(node)
|
111
119
|
else
|
112
120
|
handle_attr_accessor(node)
|
113
121
|
end
|
@@ -139,6 +147,12 @@ module RuboCop
|
|
139
147
|
end
|
140
148
|
end
|
141
149
|
|
150
|
+
def handle_define_data(node)
|
151
|
+
node.arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
|
152
|
+
handle_method_name(name, name.value)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
142
156
|
def handle_attr_accessor(node)
|
143
157
|
return unless (attrs = node.attribute_accessor?)
|
144
158
|
|
@@ -159,7 +173,7 @@ module RuboCop
|
|
159
173
|
|
160
174
|
if forbidden_name?(name.to_s)
|
161
175
|
register_forbidden_name(node)
|
162
|
-
|
176
|
+
elsif !OPERATOR_METHODS.include?(name)
|
163
177
|
check_name(node, name, range_position(node))
|
164
178
|
end
|
165
179
|
end
|
@@ -269,7 +269,10 @@ module RuboCop
|
|
269
269
|
node.body ? [last_value(node.body)] : [s(:nil)]
|
270
270
|
else
|
271
271
|
# Branches with no value act as an implicit `nil`.
|
272
|
-
node.branches.
|
272
|
+
branches = node.branches.map { |branch| branch ? last_value(branch) : s(:nil) }
|
273
|
+
# Missing else branches also act as an implicit `nil`.
|
274
|
+
branches.push(s(:nil)) unless node.else_branch
|
275
|
+
branches
|
273
276
|
end
|
274
277
|
end
|
275
278
|
|
@@ -348,7 +348,7 @@ module RuboCop
|
|
348
348
|
end
|
349
349
|
|
350
350
|
def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
|
351
|
-
def_node = begin_node.children[1]
|
351
|
+
def_node = begin_node.children[begin_node.children.index(modifier_node) + 1]
|
352
352
|
range = modifier_node.source_range.begin.join(def_node.source_range.begin)
|
353
353
|
corrector.remove(range)
|
354
354
|
end
|
@@ -84,7 +84,10 @@ module RuboCop
|
|
84
84
|
|
85
85
|
def autocorrect(corrector, node)
|
86
86
|
if (preferred_accessors = preferred_accessors(node))
|
87
|
-
corrector.replace(
|
87
|
+
corrector.replace(
|
88
|
+
grouped_style? ? node : range_with_trailing_argument_comment(node),
|
89
|
+
preferred_accessors
|
90
|
+
)
|
88
91
|
else
|
89
92
|
range = range_with_surrounding_space(node.source_range, side: :left)
|
90
93
|
corrector.remove(range)
|
@@ -196,6 +199,15 @@ module RuboCop
|
|
196
199
|
end
|
197
200
|
end.join("\n")
|
198
201
|
end
|
202
|
+
|
203
|
+
def range_with_trailing_argument_comment(node)
|
204
|
+
comment = processed_source.ast_with_comments[node.last_argument].last
|
205
|
+
if comment
|
206
|
+
add_range(node.source_range, comment.source_range)
|
207
|
+
else
|
208
|
+
node
|
209
|
+
end
|
210
|
+
end
|
199
211
|
end
|
200
212
|
end
|
201
213
|
end
|
@@ -5,12 +5,13 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# In Ruby 3.1, `Array#intersect?` has been added.
|
7
7
|
#
|
8
|
-
# This cop identifies places where
|
9
|
-
#
|
10
|
-
# `array1.
|
8
|
+
# This cop identifies places where:
|
9
|
+
# * `(array1 & array2).any?`
|
10
|
+
# * `(array1.intersection(array2)).any?`
|
11
|
+
# * `array1.any? { |elem| array2.member?(elem) }`
|
12
|
+
# can be replaced with `array1.intersect?(array2)`.
|
11
13
|
#
|
12
|
-
#
|
13
|
-
# `(array1 & array2).any?` and is more readable.
|
14
|
+
# `array1.intersect?(array2)` is faster and more readable.
|
14
15
|
#
|
15
16
|
# In cases like the following, compatibility is not ensured,
|
16
17
|
# so it will not be detected when using block argument.
|
@@ -40,6 +41,10 @@ module RuboCop
|
|
40
41
|
# array1.intersection(array2).empty?
|
41
42
|
# array1.intersection(array2).none?
|
42
43
|
#
|
44
|
+
# # bad
|
45
|
+
# array1.any? { |elem| array2.member?(elem) }
|
46
|
+
# array1.none? { |elem| array2.member?(elem) }
|
47
|
+
#
|
43
48
|
# # good
|
44
49
|
# array1.intersect?(array2)
|
45
50
|
# !array1.intersect?(array2)
|
@@ -77,8 +82,26 @@ module RuboCop
|
|
77
82
|
)
|
78
83
|
PATTERN
|
79
84
|
|
80
|
-
|
81
|
-
|
85
|
+
# @!method any_none_block_intersection(node)
|
86
|
+
def_node_matcher :any_none_block_intersection, <<~PATTERN
|
87
|
+
{
|
88
|
+
(block
|
89
|
+
(call $_receiver ${:any? :none?})
|
90
|
+
(args (arg _key))
|
91
|
+
(send $_argument :member? (lvar _key))
|
92
|
+
)
|
93
|
+
(numblock
|
94
|
+
(call $_receiver ${:any? :none?}) 1
|
95
|
+
(send $_argument :member? (lvar :_1))
|
96
|
+
)
|
97
|
+
(itblock
|
98
|
+
(call $_receiver ${:any? :none?}) :it
|
99
|
+
(send $_argument :member? (lvar :it))
|
100
|
+
)
|
101
|
+
}
|
102
|
+
PATTERN
|
103
|
+
|
104
|
+
MSG = 'Use `%<replacement>s` instead of `%<existing>s`.'
|
82
105
|
STRAIGHT_METHODS = %i[present? any?].freeze
|
83
106
|
NEGATED_METHODS = %i[blank? empty? none?].freeze
|
84
107
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
@@ -88,16 +111,25 @@ module RuboCop
|
|
88
111
|
return unless (receiver, argument, method_name = bad_intersection?(node))
|
89
112
|
|
90
113
|
dot = node.loc.dot.source
|
91
|
-
|
114
|
+
bang = straight?(method_name) ? '' : '!'
|
115
|
+
replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
|
92
116
|
|
93
|
-
|
94
|
-
bang = straight?(method_name) ? '' : '!'
|
95
|
-
|
96
|
-
corrector.replace(node, "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})")
|
97
|
-
end
|
117
|
+
register_offense(node, replacement)
|
98
118
|
end
|
99
119
|
alias on_csend on_send
|
100
120
|
|
121
|
+
def on_block(node)
|
122
|
+
return unless (receiver, method_name, argument = any_none_block_intersection(node))
|
123
|
+
|
124
|
+
dot = node.send_node.loc.dot.source
|
125
|
+
bang = method_name == :any? ? '' : '!'
|
126
|
+
replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
|
127
|
+
|
128
|
+
register_offense(node, replacement)
|
129
|
+
end
|
130
|
+
alias on_numblock on_block
|
131
|
+
alias on_itblock on_block
|
132
|
+
|
101
133
|
private
|
102
134
|
|
103
135
|
def bad_intersection?(node)
|
@@ -114,16 +146,12 @@ module RuboCop
|
|
114
146
|
STRAIGHT_METHODS.include?(method_name.to_sym)
|
115
147
|
end
|
116
148
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
argument: argument,
|
124
|
-
dot: dot,
|
125
|
-
existing: existing
|
126
|
-
)
|
149
|
+
def register_offense(node, replacement)
|
150
|
+
message = format(MSG, replacement: replacement, existing: node.source)
|
151
|
+
|
152
|
+
add_offense(node, message: message) do |corrector|
|
153
|
+
corrector.replace(node, replacement)
|
154
|
+
end
|
127
155
|
end
|
128
156
|
end
|
129
157
|
end
|
@@ -111,7 +111,7 @@ module RuboCop
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
#
|
114
|
+
# Checks for `if` and `case` statements where each branch is used for
|
115
115
|
# both the assignment and comparison of the same variable
|
116
116
|
# when using the return of the condition can be used instead.
|
117
117
|
#
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for chained `dig` calls that can be collapsed into a single `dig`.
|
7
7
|
#
|
8
8
|
# @safety
|
9
9
|
# This cop is unsafe because it cannot be guaranteed that the receiver
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for usages of not (`not` or `!`) called on a method
|
7
7
|
# when an inverse of that method can be used instead.
|
8
8
|
#
|
9
9
|
# Methods that can be inverted by a not (`not` or `!`) should be defined
|
@@ -3,33 +3,90 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks for
|
6
|
+
# Checks for local variables and method parameters named `it`,
|
7
7
|
# where `it` can refer to the first anonymous parameter as of Ruby 3.4.
|
8
|
+
# Use a meaningful variable name instead.
|
8
9
|
#
|
9
|
-
# Although Ruby allows reassigning `it` in these cases, it could
|
10
|
+
# NOTE: Although Ruby allows reassigning `it` in these cases, it could
|
10
11
|
# cause confusion if `it` is used as a block parameter elsewhere.
|
11
|
-
# For consistency, this also applies to numblocks and blocks with
|
12
|
-
# parameters, even though `it` cannot be used in those cases.
|
13
12
|
#
|
14
13
|
# @example
|
15
14
|
# # bad
|
16
|
-
#
|
17
|
-
# foo { |bar| it = bar }
|
18
|
-
# foo { it = _2 }
|
15
|
+
# it = 5
|
19
16
|
#
|
20
|
-
# # good
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
17
|
+
# # good
|
18
|
+
# var = 5
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# def foo(it)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# def foo(arg)
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # bad
|
29
|
+
# def foo(it = 5)
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# def foo(arg = 5)
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # bad
|
37
|
+
# def foo(*it)
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# def foo(*args)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # bad
|
45
|
+
# def foo(it:)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# # good
|
49
|
+
# def foo(arg:)
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # bad
|
53
|
+
# def foo(it: 5)
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# def foo(arg: 5)
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# # bad
|
61
|
+
# def foo(**it)
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# # good
|
65
|
+
# def foo(**kwargs)
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # bad
|
69
|
+
# def foo(&it)
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# # good
|
73
|
+
# def foo(&block)
|
74
|
+
# end
|
24
75
|
class ItAssignment < Base
|
25
76
|
MSG = '`it` is the default block parameter; consider another name.'
|
26
77
|
|
27
78
|
def on_lvasgn(node)
|
28
79
|
return unless node.name == :it
|
29
|
-
return unless node.each_ancestor(:any_block).any?
|
30
80
|
|
31
81
|
add_offense(node.loc.name)
|
32
82
|
end
|
83
|
+
alias on_arg on_lvasgn
|
84
|
+
alias on_optarg on_lvasgn
|
85
|
+
alias on_restarg on_lvasgn
|
86
|
+
alias on_blockarg on_lvasgn
|
87
|
+
alias on_kwarg on_lvasgn
|
88
|
+
alias on_kwoptarg on_lvasgn
|
89
|
+
alias on_kwrestarg on_lvasgn
|
33
90
|
end
|
34
91
|
end
|
35
92
|
end
|
@@ -222,11 +222,9 @@ module RuboCop
|
|
222
222
|
end
|
223
223
|
|
224
224
|
def unary_literal?(node)
|
225
|
-
|
226
|
-
return node.source.match?(/\A[+-]/) if node.complex_type?
|
225
|
+
return true if node.numeric_type? && node.sign?
|
227
226
|
|
228
|
-
|
229
|
-
(node.parent&.send_type? && node.parent.unary_operation?)
|
227
|
+
node.parent&.send_type? && node.parent.unary_operation?
|
230
228
|
end
|
231
229
|
|
232
230
|
def assigned_before?(node, target)
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
MSG = 'Do not use parallel assignment.'
|
30
30
|
|
31
31
|
def on_masgn(node) # rubocop:disable Metrics/AbcSize
|
32
|
+
return if part_of_ignored_node?(node)
|
33
|
+
|
32
34
|
rhs = node.rhs
|
33
35
|
rhs = rhs.body if rhs.rescue_type?
|
34
36
|
rhs_elements = Array(rhs).compact # edge case for one constant
|
@@ -41,6 +43,7 @@ module RuboCop
|
|
41
43
|
add_offense(range) do |corrector|
|
42
44
|
autocorrect(corrector, node, rhs)
|
43
45
|
end
|
46
|
+
ignore_node(node)
|
44
47
|
end
|
45
48
|
|
46
49
|
private
|
@@ -169,6 +169,7 @@ module RuboCop
|
|
169
169
|
end
|
170
170
|
return 'an interpolated expression' if interpolation?(begin_node)
|
171
171
|
return 'a method argument' if argument_of_parenthesized_method_call?(begin_node, node)
|
172
|
+
return 'a one-line rescue' if !begin_node.parent&.call_type? && node.rescue_type?
|
172
173
|
|
173
174
|
return if begin_node.chained?
|
174
175
|
|
@@ -65,7 +65,7 @@ module RuboCop
|
|
65
65
|
return false if target_ruby_version < 3.0
|
66
66
|
return false if disallow_endless_method_style?
|
67
67
|
return false unless body_node
|
68
|
-
return false if body_node.parent.assignment_method? ||
|
68
|
+
return false if body_node.basic_conditional? || body_node.parent.assignment_method? ||
|
69
69
|
NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
|
70
70
|
|
71
71
|
!body_node.type?(:begin, :kwbegin)
|
@@ -86,10 +86,10 @@ module RuboCop
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def correct_to_endless(corrector, node)
|
89
|
-
|
89
|
+
receiver = "#{node.receiver.source}." if node.receiver
|
90
90
|
arguments = node.arguments.any? ? node.arguments.source : '()'
|
91
91
|
body_source = method_body_source(node.body)
|
92
|
-
replacement = "def #{
|
92
|
+
replacement = "def #{receiver}#{node.method_name}#{arguments} = #{body_source}"
|
93
93
|
|
94
94
|
corrector.replace(node, replacement)
|
95
95
|
end
|
@@ -175,6 +175,8 @@ module RuboCop
|
|
175
175
|
|
176
176
|
if parenthesize_method?(condition)
|
177
177
|
parenthesized_method_arguments(condition)
|
178
|
+
elsif condition.and_type?
|
179
|
+
parenthesized_and(condition)
|
178
180
|
else
|
179
181
|
"(#{condition.source})"
|
180
182
|
end
|
@@ -186,12 +188,19 @@ module RuboCop
|
|
186
188
|
end
|
187
189
|
|
188
190
|
def add_parentheses?(node)
|
189
|
-
return true if node.assignment? ||
|
191
|
+
return true if node.assignment? || node.or_type?
|
192
|
+
return true if assignment_in_and?(node)
|
190
193
|
return false unless node.call_type?
|
191
194
|
|
192
195
|
(node.arguments.any? && !node.parenthesized?) || node.prefix_not?
|
193
196
|
end
|
194
197
|
|
198
|
+
def assignment_in_and?(node)
|
199
|
+
return false unless node.and_type?
|
200
|
+
|
201
|
+
node.each_descendant.any?(&:assignment?)
|
202
|
+
end
|
203
|
+
|
195
204
|
def parenthesized_method_arguments(node)
|
196
205
|
method_call = node.source_range.begin.join(node.loc.selector.end).source
|
197
206
|
arguments = node.first_argument.source_range.begin.join(node.source_range.end).source
|
@@ -199,6 +208,26 @@ module RuboCop
|
|
199
208
|
"#{method_call}(#{arguments})"
|
200
209
|
end
|
201
210
|
|
211
|
+
def parenthesized_and(node)
|
212
|
+
# We only need to add parentheses around the last clause if it's an assignment,
|
213
|
+
# because other clauses will be unchanged by merging conditionals.
|
214
|
+
lhs = node.lhs.source
|
215
|
+
rhs = parenthesized_and_clause(node.rhs)
|
216
|
+
operator = range_with_surrounding_space(node.loc.operator, whitespace: true).source
|
217
|
+
|
218
|
+
"#{lhs}#{operator}#{rhs}"
|
219
|
+
end
|
220
|
+
|
221
|
+
def parenthesized_and_clause(node)
|
222
|
+
if node.and_type?
|
223
|
+
parenthesized_and(node)
|
224
|
+
elsif node.assignment?
|
225
|
+
"(#{node.source})"
|
226
|
+
else
|
227
|
+
node.source
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
202
231
|
def allow_modifier?
|
203
232
|
cop_config['AllowModifier']
|
204
233
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for parentheses around stabby lambda arguments.
|
7
7
|
# There are two different styles. Defaults to `require_parentheses`.
|
8
8
|
#
|
9
9
|
# @example EnforcedStyle: require_parentheses (default)
|