rubocop 1.69.2 → 1.70.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/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +19 -2
- data/lib/rubocop/cli/command/execute_runner.rb +3 -3
- data/lib/rubocop/config.rb +13 -4
- data/lib/rubocop/config_loader.rb +4 -0
- data/lib/rubocop/config_loader_resolver.rb +14 -3
- data/lib/rubocop/config_validator.rb +18 -8
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
- data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -7
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -6
- data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +24 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +11 -3
- data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +6 -14
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
- data/lib/rubocop/cop/lint/syntax.rb +4 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
- data/lib/rubocop/cop/lint/void.rb +3 -2
- data/lib/rubocop/cop/metrics/method_length.rb +8 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
- data/lib/rubocop/cop/mixin/comments_help.rb +2 -0
- data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +26 -16
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -4
- data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +3 -6
- data/lib/rubocop/cop/style/empty_else.rb +4 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -9
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
- data/lib/rubocop/cop/style/float_division.rb +8 -4
- data/lib/rubocop/cop/style/hash_except.rb +54 -67
- data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
- data/lib/rubocop/cop/style/it_assignment.rb +36 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/missing_else.rb +2 -0
- data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +13 -15
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +5 -3
- data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
- data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -4
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +6 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/single_line_methods.rb +2 -3
- data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
- data/lib/rubocop/cop/style/super_arguments.rb +63 -15
- data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -0
- data/lib/rubocop/cop/util.rb +9 -2
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/lsp/diagnostic.rb +189 -0
- data/lib/rubocop/lsp/logger.rb +2 -2
- data/lib/rubocop/lsp/routes.rb +7 -23
- data/lib/rubocop/lsp/runtime.rb +15 -49
- data/lib/rubocop/lsp/stdin_runner.rb +83 -0
- data/lib/rubocop/path_util.rb +11 -8
- data/lib/rubocop/rspec/shared_contexts.rb +4 -1
- data/lib/rubocop/runner.rb +5 -6
- data/lib/rubocop/target_ruby.rb +15 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- data/lib/ruby_lsp/rubocop/addon.rb +78 -0
- data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
- metadata +12 -4
@@ -5,6 +5,10 @@ module RuboCop
|
|
5
5
|
# Common functionality for checking whether an AST node/token is aligned
|
6
6
|
# with something on a preceding or following line
|
7
7
|
module PrecedingFollowingAlignment
|
8
|
+
# Tokens that end with an `=`, as well as `<<`, that can be aligned together:
|
9
|
+
# `=`, `==`, `===`, `!=`, `<=`, `>=`, `<<` and operator assignment (`+=`, etc).
|
10
|
+
ASSIGNMENT_OR_COMPARISON_TOKENS = %i[tEQL tEQ tEQQ tNEQ tLEQ tGEQ tOP_ASGN tLSHFT].freeze
|
11
|
+
|
8
12
|
private
|
9
13
|
|
10
14
|
def allow_for_alignment?
|
@@ -19,16 +23,20 @@ module RuboCop
|
|
19
23
|
aligned_with_adjacent_line?(range, method(:aligned_operator?))
|
20
24
|
end
|
21
25
|
|
22
|
-
|
26
|
+
# Allows alignment with a preceding operator that ends with an `=`,
|
27
|
+
# including assignment and comparison operators.
|
28
|
+
def aligned_with_preceding_equals_operator(token)
|
23
29
|
preceding_line_range = token.line.downto(1)
|
24
30
|
|
25
|
-
|
31
|
+
aligned_with_equals_sign(token, preceding_line_range)
|
26
32
|
end
|
27
33
|
|
28
|
-
|
34
|
+
# Allows alignment with a subsequent operator that ends with an `=`,
|
35
|
+
# including assignment and comparison operators.
|
36
|
+
def aligned_with_subsequent_equals_operator(token)
|
29
37
|
subsequent_line_range = token.line.upto(processed_source.lines.length)
|
30
38
|
|
31
|
-
|
39
|
+
aligned_with_equals_sign(token, subsequent_line_range)
|
32
40
|
end
|
33
41
|
|
34
42
|
def aligned_with_adjacent_line?(range, predicate)
|
@@ -75,11 +83,11 @@ module RuboCop
|
|
75
83
|
end
|
76
84
|
|
77
85
|
def aligned_token?(range, line, lineno)
|
78
|
-
aligned_words?(range, line) ||
|
86
|
+
aligned_words?(range, line) || aligned_equals_operator?(range, lineno)
|
79
87
|
end
|
80
88
|
|
81
89
|
def aligned_operator?(range, line, lineno)
|
82
|
-
aligned_identical?(range, line) ||
|
90
|
+
aligned_identical?(range, line) || aligned_equals_operator?(range, lineno)
|
83
91
|
end
|
84
92
|
|
85
93
|
def aligned_words?(range, line)
|
@@ -90,22 +98,24 @@ module RuboCop
|
|
90
98
|
token == line[left_edge, token.length]
|
91
99
|
end
|
92
100
|
|
93
|
-
def
|
94
|
-
# Check that
|
95
|
-
# ie. an equals sign, an operator assignment,
|
101
|
+
def aligned_equals_operator?(range, lineno)
|
102
|
+
# Check that the operator is aligned with a previous assignment or comparison operator
|
103
|
+
# ie. an equals sign, an operator assignment (eg. `+=`), a comparison (`==`, `<=`, etc.).
|
104
|
+
# Since append operators (`<<`) are a type of assignment, they are allowed as well,
|
105
|
+
# despite not ending with a literal equals character.
|
96
106
|
line_range = processed_source.buffer.line_range(lineno)
|
97
107
|
return false unless line_range
|
98
108
|
|
99
109
|
# Find the specific token to avoid matching up to operators inside strings
|
100
|
-
|
101
|
-
|
110
|
+
operator_token = processed_source.tokens_within(line_range).detect do |token|
|
111
|
+
ASSIGNMENT_OR_COMPARISON_TOKENS.include?(token.type)
|
102
112
|
end
|
103
113
|
|
104
|
-
|
105
|
-
aligned_with_append_operator?(range,
|
114
|
+
aligned_with_preceding_equals?(range, operator_token) ||
|
115
|
+
aligned_with_append_operator?(range, operator_token)
|
106
116
|
end
|
107
117
|
|
108
|
-
def
|
118
|
+
def aligned_with_preceding_equals?(range, token)
|
109
119
|
return false unless token
|
110
120
|
|
111
121
|
range.source[-1] == '=' && range.last_column == token.pos.last_column
|
@@ -123,7 +133,7 @@ module RuboCop
|
|
123
133
|
range.source == line[range.column, range.size]
|
124
134
|
end
|
125
135
|
|
126
|
-
def
|
136
|
+
def aligned_with_equals_sign(token, line_range)
|
127
137
|
token_line_indent = processed_source.line_indentation(token.line)
|
128
138
|
assignment_lines = relevant_assignment_lines(line_range)
|
129
139
|
relevant_line_number = assignment_lines[1]
|
@@ -135,7 +145,7 @@ module RuboCop
|
|
135
145
|
return :none if relevant_indent < token_line_indent
|
136
146
|
return :none unless processed_source.lines[relevant_line_number - 1]
|
137
147
|
|
138
|
-
|
148
|
+
aligned_equals_operator?(token.pos, relevant_line_number) ? :yes : :no
|
139
149
|
end
|
140
150
|
|
141
151
|
def assignment_lines
|
@@ -138,7 +138,7 @@ module RuboCop
|
|
138
138
|
def use_block_argument_as_local_variable?(node, last_argument)
|
139
139
|
return false if node.body.nil?
|
140
140
|
|
141
|
-
node.body.
|
141
|
+
node.body.each_node(:lvar, :lvasgn).any? do |lvar|
|
142
142
|
!lvar.parent.block_pass_type? && lvar.node_parts[0].to_s == last_argument
|
143
143
|
end
|
144
144
|
end
|
@@ -112,6 +112,26 @@ module RuboCop
|
|
112
112
|
# private attr :quux
|
113
113
|
#
|
114
114
|
# end
|
115
|
+
#
|
116
|
+
# @example AllowModifiersOnAliasMethod: true (default)
|
117
|
+
# # good
|
118
|
+
# class Foo
|
119
|
+
#
|
120
|
+
# public alias_method :bar, :foo
|
121
|
+
# protected alias_method :baz, :foo
|
122
|
+
# private alias_method :qux, :foo
|
123
|
+
#
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# @example AllowModifiersOnAliasMethod: false
|
127
|
+
# # bad
|
128
|
+
# class Foo
|
129
|
+
#
|
130
|
+
# public alias_method :bar, :foo
|
131
|
+
# protected alias_method :baz, :foo
|
132
|
+
# private alias_method :qux, :foo
|
133
|
+
#
|
134
|
+
# end
|
115
135
|
class AccessModifierDeclarations < Base
|
116
136
|
extend AutoCorrector
|
117
137
|
|
@@ -145,6 +165,12 @@ module RuboCop
|
|
145
165
|
(send nil? {:attr :attr_reader :attr_writer :attr_accessor} _+))
|
146
166
|
PATTERN
|
147
167
|
|
168
|
+
# @!method access_modifier_with_alias_method?, <<~PATTERN
|
169
|
+
def_node_matcher :access_modifier_with_alias_method?, <<~PATTERN
|
170
|
+
(send nil? {:private :protected :public :module_function}
|
171
|
+
(send nil? :alias_method _ _))
|
172
|
+
PATTERN
|
173
|
+
|
148
174
|
def on_send(node)
|
149
175
|
return if allowed?(node)
|
150
176
|
|
@@ -164,7 +190,8 @@ module RuboCop
|
|
164
190
|
!node.access_modifier? ||
|
165
191
|
ALLOWED_NODE_TYPES.include?(node.parent&.type) ||
|
166
192
|
allow_modifiers_on_symbols?(node) ||
|
167
|
-
allow_modifiers_on_attrs?(node)
|
193
|
+
allow_modifiers_on_attrs?(node) ||
|
194
|
+
allow_modifiers_on_alias_method?(node)
|
168
195
|
end
|
169
196
|
|
170
197
|
def autocorrect(corrector, node)
|
@@ -194,6 +221,10 @@ module RuboCop
|
|
194
221
|
cop_config['AllowModifiersOnAttrs'] && access_modifier_with_attr?(node)
|
195
222
|
end
|
196
223
|
|
224
|
+
def allow_modifiers_on_alias_method?(node)
|
225
|
+
cop_config['AllowModifiersOnAliasMethod'] && access_modifier_with_alias_method?(node)
|
226
|
+
end
|
227
|
+
|
197
228
|
def offense?(node)
|
198
229
|
(group_style? && access_modifier_is_inlined?(node) &&
|
199
230
|
!node.parent&.if_type? && !right_siblings_same_inline_method?(node)) ||
|
@@ -540,10 +540,7 @@ module RuboCop
|
|
540
540
|
end
|
541
541
|
|
542
542
|
def explicit_block_name?
|
543
|
-
|
544
|
-
return false unless block_forwarding_config['Enabled']
|
545
|
-
|
546
|
-
block_forwarding_config['EnforcedStyle'] == 'explicit'
|
543
|
+
config.for_enabled_cop('Naming/BlockForwarding')['EnforcedStyle'] == 'explicit'
|
547
544
|
end
|
548
545
|
end
|
549
546
|
end
|
@@ -126,9 +126,12 @@ module RuboCop
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def unindent(corrector, node)
|
129
|
-
return
|
129
|
+
return unless node.body.children.last
|
130
130
|
|
131
|
-
|
131
|
+
last_child_leading_spaces = leading_spaces(node.body.children.last)
|
132
|
+
return if leading_spaces(node).size == last_child_leading_spaces.size
|
133
|
+
|
134
|
+
column_delta = configured_indentation_width - last_child_leading_spaces.size
|
132
135
|
return if column_delta.zero?
|
133
136
|
|
134
137
|
AlignmentCorrector.correct(corrector, processed_source, node, column_delta)
|
@@ -53,8 +53,7 @@ module RuboCop
|
|
53
53
|
(block
|
54
54
|
(call
|
55
55
|
(begin
|
56
|
-
($
|
57
|
-
(int $_) (int $_)))
|
56
|
+
($range (int $_) (int $_)))
|
58
57
|
:each)
|
59
58
|
(args ...)
|
60
59
|
...)
|
@@ -65,8 +64,7 @@ module RuboCop
|
|
65
64
|
(block
|
66
65
|
(call
|
67
66
|
(begin
|
68
|
-
(
|
69
|
-
(int 0) (int _)))
|
67
|
+
(range (int 0) (int _)))
|
70
68
|
:each)
|
71
69
|
(args ...)
|
72
70
|
...)
|
@@ -77,8 +75,7 @@ module RuboCop
|
|
77
75
|
(block
|
78
76
|
(call
|
79
77
|
(begin
|
80
|
-
(
|
81
|
-
(int _) (int _)))
|
78
|
+
(range (int _) (int _)))
|
82
79
|
:each)
|
83
80
|
(args)
|
84
81
|
...)
|
@@ -131,6 +131,8 @@ module RuboCop
|
|
131
131
|
extend AutoCorrector
|
132
132
|
|
133
133
|
MSG = 'Redundant `else`-clause.'
|
134
|
+
NIL_STYLES = %i[nil both].freeze
|
135
|
+
EMPTY_STYLES = %i[empty both].freeze
|
134
136
|
|
135
137
|
def on_normal_if_unless(node)
|
136
138
|
check(node)
|
@@ -150,11 +152,11 @@ module RuboCop
|
|
150
152
|
end
|
151
153
|
|
152
154
|
def nil_style?
|
153
|
-
style
|
155
|
+
NIL_STYLES.include?(style)
|
154
156
|
end
|
155
157
|
|
156
158
|
def empty_style?
|
157
|
-
style
|
159
|
+
EMPTY_STYLES.include?(style)
|
158
160
|
end
|
159
161
|
|
160
162
|
def empty_check(node)
|
@@ -136,7 +136,7 @@ module RuboCop
|
|
136
136
|
def frozen_strings?
|
137
137
|
return true if frozen_string_literals_enabled?
|
138
138
|
|
139
|
-
frozen_string_cop_enabled = config.
|
139
|
+
frozen_string_cop_enabled = config.cop_enabled?('Style/FrozenStringLiteralComment')
|
140
140
|
frozen_string_cop_enabled &&
|
141
141
|
!frozen_string_literals_disabled? &&
|
142
142
|
string_literals_frozen_by_default?.nil?
|
@@ -40,15 +40,8 @@ module RuboCop
|
|
40
40
|
def on_send(node)
|
41
41
|
return unless (receiver = node.receiver)
|
42
42
|
return unless (regexp = exact_regexp_match(node))
|
43
|
-
|
44
|
-
|
45
|
-
Regexp::Parser.parse(regexp)
|
46
|
-
rescue Regexp::Parser::Error
|
47
|
-
# Upon encountering an invalid regular expression,
|
48
|
-
# we aim to proceed and identify any remaining potential offenses.
|
49
|
-
end
|
50
|
-
|
51
|
-
return unless parsed_regexp && exact_match_pattern?(parsed_regexp)
|
43
|
+
return unless (parsed_regexp = parse_regexp(regexp))
|
44
|
+
return unless exact_match_pattern?(parsed_regexp)
|
52
45
|
|
53
46
|
prefer = "#{receiver.source} #{new_method(node)} '#{parsed_regexp[1].text}'"
|
54
47
|
|
@@ -8,7 +8,7 @@ module RuboCop
|
|
8
8
|
#
|
9
9
|
# * `scientific` which enforces a mantissa between 1 (inclusive) and 10 (exclusive).
|
10
10
|
# * `engineering` which enforces the exponent to be a multiple of 3 and the mantissa
|
11
|
-
# to be between 0.1 (inclusive) and
|
11
|
+
# to be between 0.1 (inclusive) and 1000 (exclusive).
|
12
12
|
# * `integral` which enforces the mantissa to always be a whole number without
|
13
13
|
# trailing zeroes.
|
14
14
|
#
|
@@ -65,19 +65,23 @@ module RuboCop
|
|
65
65
|
|
66
66
|
# @!method right_coerce?(node)
|
67
67
|
def_node_matcher :right_coerce?, <<~PATTERN
|
68
|
-
(send _ :/
|
68
|
+
(send _ :/ #to_f_method?)
|
69
69
|
PATTERN
|
70
70
|
# @!method left_coerce?(node)
|
71
71
|
def_node_matcher :left_coerce?, <<~PATTERN
|
72
|
-
(send
|
72
|
+
(send #to_f_method? :/ _)
|
73
73
|
PATTERN
|
74
74
|
# @!method both_coerce?(node)
|
75
75
|
def_node_matcher :both_coerce?, <<~PATTERN
|
76
|
-
(send
|
76
|
+
(send #to_f_method? :/ #to_f_method?)
|
77
77
|
PATTERN
|
78
78
|
# @!method any_coerce?(node)
|
79
79
|
def_node_matcher :any_coerce?, <<~PATTERN
|
80
|
-
{(send _ :/
|
80
|
+
{(send _ :/ #to_f_method?) (send #to_f_method? :/ _)}
|
81
|
+
PATTERN
|
82
|
+
# @!method to_f_method?(node)
|
83
|
+
def_node_matcher :to_f_method?, <<~PATTERN
|
84
|
+
(send !nil? :to_f)
|
81
85
|
PATTERN
|
82
86
|
|
83
87
|
def on_send(node)
|
@@ -10,8 +10,10 @@ module RuboCop
|
|
10
10
|
# (`Hash#except` was added in Ruby 3.0.)
|
11
11
|
#
|
12
12
|
# For safe detection, it is limited to commonly used string and symbol comparisons
|
13
|
-
# when
|
14
|
-
#
|
13
|
+
# when using `==` or `!=`.
|
14
|
+
#
|
15
|
+
# This cop doesn't check for `Hash#delete_if` and `Hash#keep_if` because they
|
16
|
+
# modify the receiver.
|
15
17
|
#
|
16
18
|
# @safety
|
17
19
|
# This cop is unsafe because it cannot be guaranteed that the receiver
|
@@ -51,44 +53,31 @@ module RuboCop
|
|
51
53
|
MSG = 'Use `%<prefer>s` instead.'
|
52
54
|
RESTRICT_ON_SEND = %i[reject select filter].freeze
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
(block
|
57
|
-
(call _ _)
|
58
|
-
(args
|
59
|
-
$(arg _)
|
60
|
-
(arg _))
|
61
|
-
{
|
62
|
-
$(send
|
63
|
-
_ {:== :!= :eql? :include?} _)
|
64
|
-
(send
|
65
|
-
$(send
|
66
|
-
_ {:== :!= :eql? :include?} _) :!)
|
67
|
-
})
|
68
|
-
PATTERN
|
56
|
+
SUBSET_METHODS = %i[== != eql? include?].freeze
|
57
|
+
ACTIVE_SUPPORT_SUBSET_METHODS = (SUBSET_METHODS + %i[in? exclude?]).freeze
|
69
58
|
|
70
|
-
# @!method
|
71
|
-
def_node_matcher :
|
59
|
+
# @!method block_with_first_arg_check?(node)
|
60
|
+
def_node_matcher :block_with_first_arg_check?, <<~PATTERN
|
72
61
|
(block
|
73
|
-
(
|
62
|
+
(call _ _)
|
74
63
|
(args
|
75
|
-
$(arg
|
64
|
+
$(arg _key)
|
76
65
|
(arg _))
|
77
66
|
{
|
78
67
|
$(send
|
79
|
-
|
68
|
+
{(lvar _key) $_ _ | _ $_ (lvar _key)})
|
80
69
|
(send
|
81
70
|
$(send
|
82
|
-
|
71
|
+
{(lvar _key) $_ _ | _ $_ (lvar _key)}) :!)
|
83
72
|
})
|
84
73
|
PATTERN
|
85
74
|
|
86
75
|
def on_send(node)
|
87
76
|
block = node.parent
|
88
|
-
return unless
|
77
|
+
return unless extracts_hash_subset?(block) && semantically_except_method?(node, block)
|
89
78
|
|
90
79
|
except_key = except_key(block)
|
91
|
-
return
|
80
|
+
return unless safe_to_register_offense?(block, except_key)
|
92
81
|
|
93
82
|
range = offense_range(node)
|
94
83
|
preferred_method = "except(#{except_key_source(except_key)})"
|
@@ -101,42 +90,40 @@ module RuboCop
|
|
101
90
|
|
102
91
|
private
|
103
92
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
else
|
116
|
-
bad_method_with_poro?(block) do |key_arg, send_node|
|
117
|
-
!send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
|
93
|
+
def extracts_hash_subset?(block)
|
94
|
+
block_with_first_arg_check?(block) do |key_arg, send_node, method|
|
95
|
+
return false unless supported_subset_method?(method)
|
96
|
+
|
97
|
+
case method
|
98
|
+
when :include?, :exclude?
|
99
|
+
send_node.first_argument.source == key_arg.source
|
100
|
+
when :in?
|
101
|
+
send_node.receiver.source == key_arg.source
|
102
|
+
else
|
103
|
+
true
|
118
104
|
end
|
119
105
|
end
|
120
106
|
end
|
121
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
122
107
|
|
123
|
-
def
|
124
|
-
|
108
|
+
def supported_subset_method?(method)
|
109
|
+
if active_support_extensions_enabled?
|
110
|
+
ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
|
111
|
+
else
|
112
|
+
SUBSET_METHODS.include?(method)
|
113
|
+
end
|
114
|
+
end
|
125
115
|
|
126
|
-
|
127
|
-
body = body
|
116
|
+
def semantically_except_method?(node, block)
|
117
|
+
body, negated = extract_body_if_negated(block.body)
|
128
118
|
|
129
|
-
|
130
|
-
|
131
|
-
body.method?('==') || body.method?('eql?') || included?(negated, body)
|
132
|
-
when :select, :filter
|
133
|
-
body.method?('!=') || not_included?(negated, body)
|
119
|
+
if node.method?('reject')
|
120
|
+
body.method?('==') || body.method?('eql?') || included?(body, negated)
|
134
121
|
else
|
135
|
-
|
122
|
+
body.method?('!=') || not_included?(body, negated)
|
136
123
|
end
|
137
124
|
end
|
138
125
|
|
139
|
-
def included?(
|
126
|
+
def included?(body, negated)
|
140
127
|
if negated
|
141
128
|
body.method?('exclude?')
|
142
129
|
else
|
@@ -144,25 +131,26 @@ module RuboCop
|
|
144
131
|
end
|
145
132
|
end
|
146
133
|
|
147
|
-
def not_included?(
|
148
|
-
included?(!negated
|
134
|
+
def not_included?(body, negated)
|
135
|
+
included?(body, !negated)
|
149
136
|
end
|
150
137
|
|
151
138
|
def safe_to_register_offense?(block, except_key)
|
152
|
-
|
153
|
-
if extracted.method?('in?') || extracted.method?('include?') ||
|
154
|
-
extracted.method?('exclude?')
|
155
|
-
return true
|
156
|
-
end
|
157
|
-
return true if block.body.method?('eql?')
|
139
|
+
body = block.body
|
158
140
|
|
159
|
-
|
141
|
+
if body.method?('==') || body.method?('!=')
|
142
|
+
except_key.sym_type? || except_key.str_type?
|
143
|
+
else
|
144
|
+
true
|
145
|
+
end
|
160
146
|
end
|
161
147
|
|
162
148
|
def extract_body_if_negated(body)
|
163
|
-
|
164
|
-
|
165
|
-
|
149
|
+
if body.method?('!')
|
150
|
+
[body.receiver, true]
|
151
|
+
else
|
152
|
+
[body, false]
|
153
|
+
end
|
166
154
|
end
|
167
155
|
|
168
156
|
def except_key_source(key)
|
@@ -187,12 +175,11 @@ module RuboCop
|
|
187
175
|
end
|
188
176
|
|
189
177
|
def except_key(node)
|
190
|
-
|
191
|
-
body = extract_body_if_negated(node.body)
|
178
|
+
key_arg = node.argument_list.first.source
|
179
|
+
body, = extract_body_if_negated(node.body)
|
192
180
|
lhs, _method_name, rhs = *body
|
193
|
-
return if [lhs, rhs].map(&:source).none?(key_argument)
|
194
181
|
|
195
|
-
|
182
|
+
lhs.source == key_arg ? rhs : lhs
|
196
183
|
end
|
197
184
|
|
198
185
|
def offense_range(node)
|
@@ -137,6 +137,7 @@ module RuboCop
|
|
137
137
|
MSG_19 = 'Use the new Ruby 1.9 hash syntax.'
|
138
138
|
MSG_NO_MIXED_KEYS = "Don't mix styles in the same hash."
|
139
139
|
MSG_HASH_ROCKETS = 'Use hash rockets syntax.'
|
140
|
+
NO_MIXED_KEYS_STYLES = %i[ruby19_no_mixed_keys no_mixed_keys].freeze
|
140
141
|
|
141
142
|
def on_hash(node)
|
142
143
|
pairs = node.pairs
|
@@ -196,7 +197,7 @@ module RuboCop
|
|
196
197
|
def autocorrect(corrector, node)
|
197
198
|
if style == :hash_rockets || force_hash_rockets?(node.parent.pairs)
|
198
199
|
autocorrect_hash_rockets(corrector, node)
|
199
|
-
elsif style
|
200
|
+
elsif NO_MIXED_KEYS_STYLES.include?(style)
|
200
201
|
autocorrect_no_mixed_keys(corrector, node)
|
201
202
|
else
|
202
203
|
autocorrect_ruby19(corrector, node)
|
@@ -272,7 +273,9 @@ module RuboCop
|
|
272
273
|
end
|
273
274
|
|
274
275
|
def argument_without_space?(node)
|
275
|
-
node.argument?
|
276
|
+
return false if !node.argument? || !node.parent.loc.selector
|
277
|
+
|
278
|
+
node.source_range.begin_pos == node.parent.loc.selector.end_pos
|
276
279
|
end
|
277
280
|
|
278
281
|
def autocorrect_hash_rockets(corrector, pair_node)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for assignments to a local `it` variable inside a block
|
7
|
+
# where `it` can refer to the first anonymous parameter as of Ruby 3.4.
|
8
|
+
#
|
9
|
+
# Although Ruby allows reassigning `it` in these cases, it could
|
10
|
+
# 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
|
+
#
|
14
|
+
# @example
|
15
|
+
# # bad
|
16
|
+
# foo { it = 5 }
|
17
|
+
# foo { |bar| it = bar }
|
18
|
+
# foo { it = _2 }
|
19
|
+
#
|
20
|
+
# # good - use a different variable name
|
21
|
+
# foo { var = 5 }
|
22
|
+
# foo { |bar| var = bar }
|
23
|
+
# foo { bar = _2 }
|
24
|
+
class ItAssignment < Base
|
25
|
+
MSG = '`it` is the default block parameter; consider another name.'
|
26
|
+
|
27
|
+
def on_lvasgn(node)
|
28
|
+
return unless node.name == :it
|
29
|
+
return unless node.each_ancestor(:block, :numblock).any?
|
30
|
+
|
31
|
+
add_offense(node.loc.name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -135,17 +135,20 @@ module RuboCop
|
|
135
135
|
node.parent&.class_type? && node.parent.single_line?
|
136
136
|
end
|
137
137
|
|
138
|
-
|
138
|
+
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
139
|
+
def call_with_ambiguous_arguments?(node)
|
139
140
|
call_with_braced_block?(node) ||
|
140
141
|
call_in_argument_with_block?(node) ||
|
141
142
|
call_as_argument_or_chain?(node) ||
|
142
143
|
call_in_match_pattern?(node) ||
|
143
144
|
hash_literal_in_arguments?(node) ||
|
145
|
+
ambiguous_range_argument?(node) ||
|
144
146
|
node.descendants.any? do |n|
|
145
147
|
n.forwarded_args_type? || n.block_type? || n.numblock_type? ||
|
146
148
|
ambiguous_literal?(n) || logical_operator?(n)
|
147
149
|
end
|
148
150
|
end
|
151
|
+
# rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity
|
149
152
|
|
150
153
|
def call_with_braced_block?(node)
|
151
154
|
(node.call_type? || node.super_type?) && node.block_node&.braces?
|
@@ -177,6 +180,13 @@ module RuboCop
|
|
177
180
|
end
|
178
181
|
end
|
179
182
|
|
183
|
+
def ambiguous_range_argument?(node)
|
184
|
+
return true if (first_arg = node.first_argument)&.range_type? && first_arg.begin.nil?
|
185
|
+
return true if (last_arg = node.last_argument)&.range_type? && last_arg.end.nil?
|
186
|
+
|
187
|
+
false
|
188
|
+
end
|
189
|
+
|
180
190
|
def allowed_multiline_call_with_parentheses?(node)
|
181
191
|
cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
|
182
192
|
end
|