rubocop 1.33.0 → 1.35.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +29 -1
- data/lib/rubocop/cli/command/suggest_extensions.rb +53 -15
- data/lib/rubocop/config_loader.rb +12 -0
- data/lib/rubocop/config_loader_resolver.rb +1 -5
- data/lib/rubocop/cop/cop.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +58 -0
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +61 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/block_end_newline.rb +4 -1
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +2 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -0
- data/lib/rubocop/cop/layout/line_length.rb +4 -1
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
- data/lib/rubocop/cop/legacy/corrections_proxy.rb +1 -1
- data/lib/rubocop/cop/legacy/corrector.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +15 -15
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +5 -0
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -9
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +25 -6
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +12 -0
- data/lib/rubocop/cop/lint/redundant_with_index.rb +13 -10
- data/lib/rubocop/cop/lint/redundant_with_object.rb +12 -11
- data/lib/rubocop/cop/lint/shadowed_exception.rb +15 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +10 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +7 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +6 -4
- data/lib/rubocop/cop/lint/void.rb +2 -0
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +76 -1
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +4 -4
- data/lib/rubocop/cop/mixin/range_help.rb +4 -5
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
- data/lib/rubocop/cop/style/class_methods_definitions.rb +2 -1
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -1
- data/lib/rubocop/cop/style/double_negation.rb +2 -0
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +39 -8
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +3 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +17 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -6
- data/lib/rubocop/cop/style/magic_comment_format.rb +307 -0
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -1
- data/lib/rubocop/cop/style/next.rb +2 -0
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +16 -1
- data/lib/rubocop/cop/style/object_then.rb +2 -0
- data/lib/rubocop/cop/style/proc.rb +4 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -0
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -22
- data/lib/rubocop/cop/style/redundant_self.rb +2 -0
- data/lib/rubocop/cop/style/redundant_sort_by.rb +24 -8
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -3
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -13
- data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/ext/range.rb +15 -0
- data/lib/rubocop/feature_loader.rb +92 -0
- data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -1
- data/lib/rubocop/formatter/tap_formatter.rb +1 -1
- data/lib/rubocop/server/cache.rb +4 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +4 -1
- metadata +13 -8
@@ -67,19 +67,6 @@ module RuboCop
|
|
67
67
|
class Debugger < Base
|
68
68
|
MSG = 'Remove debugger entry point `%<source>s`.'
|
69
69
|
|
70
|
-
# @!method kernel?(node)
|
71
|
-
def_node_matcher :kernel?, <<~PATTERN
|
72
|
-
(const {nil? cbase} :Kernel)
|
73
|
-
PATTERN
|
74
|
-
|
75
|
-
# @!method valid_receiver?(node, arg1)
|
76
|
-
def_node_matcher :valid_receiver?, <<~PATTERN
|
77
|
-
{
|
78
|
-
(const {nil? cbase} %1)
|
79
|
-
(send {nil? #kernel?} %1)
|
80
|
-
}
|
81
|
-
PATTERN
|
82
|
-
|
83
70
|
def on_send(node)
|
84
71
|
return unless debugger_method?(node)
|
85
72
|
|
@@ -101,7 +88,7 @@ module RuboCop
|
|
101
88
|
|
102
89
|
*receiver, method_name = v.split('.')
|
103
90
|
{
|
104
|
-
receiver: receiver.empty? ? nil : receiver.
|
91
|
+
receiver: receiver.empty? ? nil : receiver.map(&:to_sym),
|
105
92
|
method_name: method_name.to_sym
|
106
93
|
}
|
107
94
|
end.compact
|
@@ -115,10 +102,23 @@ module RuboCop
|
|
115
102
|
if method[:receiver].nil?
|
116
103
|
send_node.receiver.nil?
|
117
104
|
else
|
118
|
-
|
105
|
+
method[:receiver] == receiver_chain(send_node)
|
119
106
|
end
|
120
107
|
end
|
121
108
|
end
|
109
|
+
|
110
|
+
def receiver_chain(send_node)
|
111
|
+
receivers = []
|
112
|
+
receiver = send_node.receiver
|
113
|
+
|
114
|
+
while receiver
|
115
|
+
name = receiver.send_type? ? receiver.method_name : receiver.const_name&.to_sym
|
116
|
+
receivers.unshift(name)
|
117
|
+
receiver = receiver.receiver
|
118
|
+
end
|
119
|
+
|
120
|
+
receivers
|
121
|
+
end
|
122
122
|
end
|
123
123
|
end
|
124
124
|
end
|
@@ -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)
|
@@ -7,6 +7,11 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# NOTE: empty `else` branches are handled by `Style/EmptyElse`.
|
9
9
|
#
|
10
|
+
# @safety
|
11
|
+
# Autocorrection for this cop is not safe. The conditions for empty branches that
|
12
|
+
# the autocorrection removes may have side effects, or the logic in subsequent
|
13
|
+
# branches may change due to the removal of a previous condition.
|
14
|
+
#
|
10
15
|
# @example
|
11
16
|
# # bad
|
12
17
|
# if condition
|
@@ -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
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# ERB.new(str,
|
18
|
-
#
|
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.
|
@@ -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
|
-
|
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
|
@@ -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)
|
@@ -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
|
@@ -7,6 +7,14 @@ module RuboCop
|
|
7
7
|
# less specific exception being rescued before a more specific
|
8
8
|
# exception is rescued.
|
9
9
|
#
|
10
|
+
# An exception is considered shadowed if it is rescued after its
|
11
|
+
# ancestor is, or if it and its ancestor are both rescued in the
|
12
|
+
# same `rescue` statement. In both cases, the more specific rescue is
|
13
|
+
# unnecessary because it is covered by rescuing the less specific
|
14
|
+
# exception. (ie. `rescue Exception, StandardError` has the same behavior
|
15
|
+
# whether `StandardError` is included or not, because all `StandardError`s
|
16
|
+
# are rescued by `rescue Exception`).
|
17
|
+
#
|
10
18
|
# @example
|
11
19
|
#
|
12
20
|
# # bad
|
@@ -19,6 +27,13 @@ module RuboCop
|
|
19
27
|
# handle_standard_error
|
20
28
|
# end
|
21
29
|
#
|
30
|
+
# # bad
|
31
|
+
# begin
|
32
|
+
# something
|
33
|
+
# rescue Exception, StandardError
|
34
|
+
# handle_error
|
35
|
+
# end
|
36
|
+
#
|
22
37
|
# # good
|
23
38
|
#
|
24
39
|
# begin
|
@@ -67,10 +67,19 @@ module RuboCop
|
|
67
67
|
variable_node = variable.scope.node.parent
|
68
68
|
return false unless variable_node.conditional?
|
69
69
|
|
70
|
-
outer_local_variable_node =
|
70
|
+
outer_local_variable_node =
|
71
|
+
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
72
|
+
return true unless outer_local_variable_node
|
71
73
|
|
72
74
|
outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
|
73
75
|
end
|
76
|
+
|
77
|
+
def find_conditional_node_from_ascendant(node)
|
78
|
+
return unless (parent = node.parent)
|
79
|
+
return parent if parent.conditional?
|
80
|
+
|
81
|
+
find_conditional_node_from_ascendant(parent)
|
82
|
+
end
|
74
83
|
end
|
75
84
|
end
|
76
85
|
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
|
|
@@ -6,7 +6,8 @@ module RuboCop
|
|
6
6
|
#
|
7
7
|
# IMPORTANT: RuboCop core depended on this module when it supported Rails department.
|
8
8
|
# Rails department has been extracted to RuboCop Rails gem.
|
9
|
-
#
|
9
|
+
#
|
10
|
+
# @deprecated This module is deprecated and will be removed by RuboCop 2.0.
|
10
11
|
# It will not be updated to `RuboCop::Cop::Base` v1 API to maintain compatibility
|
11
12
|
# with existing RuboCop Rails 2.8 or lower.
|
12
13
|
#
|
@@ -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 = '
|
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)
|
@@ -54,11 +54,11 @@ module RuboCop
|
|
54
54
|
NOT_GIVEN = Module.new
|
55
55
|
def range_with_surrounding_space(range_positional = NOT_GIVEN, # rubocop:disable Metrics/ParameterLists
|
56
56
|
range: NOT_GIVEN, side: :both, newlines: true,
|
57
|
-
whitespace: false, continuations: false
|
57
|
+
whitespace: false, continuations: false,
|
58
|
+
buffer: @processed_source.buffer)
|
58
59
|
|
59
60
|
range = range_positional unless range_positional == NOT_GIVEN
|
60
61
|
|
61
|
-
buffer = @processed_source.buffer
|
62
62
|
src = buffer.source
|
63
63
|
|
64
64
|
go_left, go_right = directions(side)
|
@@ -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
|
-
|
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
|
@@ -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.
|
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)
|
@@ -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
|
@@ -93,6 +93,8 @@ module RuboCop
|
|
93
93
|
|
94
94
|
if conditional_node
|
95
95
|
double_negative_condition_return_value?(node, last_child, conditional_node)
|
96
|
+
elsif last_child.pair_type? || last_child.hash_type? || last_child.parent.array_type?
|
97
|
+
false
|
96
98
|
else
|
97
99
|
last_child.last_line <= node.last_line
|
98
100
|
end
|
@@ -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
|