rubocop 1.71.2 → 1.73.1
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 +3 -3
- data/config/default.yml +54 -11
- data/config/internal_affairs.yml +16 -0
- data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_loader.rb +44 -8
- data/lib/rubocop/config_loader_resolver.rb +23 -9
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
- data/lib/rubocop/cop/internal_affairs.rb +1 -16
- data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +26 -1
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +3 -3
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +10 -5
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -6
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +99 -9
- data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +252 -0
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
- data/lib/rubocop/cop/lint/void.rb +6 -0
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
- data/lib/rubocop/cop/mixin/alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +18 -18
- data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/range_help.rb +3 -3
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +12 -0
- data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
- data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
- data/lib/rubocop/cop/naming/variable_name.rb +64 -6
- data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
- data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
- data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +163 -18
- data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +46 -0
- data/lib/rubocop/cop/style/redundant_format.rb +250 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +18 -4
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/utils/format_string.rb +7 -5
- data/lib/rubocop/cops_documentation_generator.rb +12 -1
- data/lib/rubocop/directive_comment.rb +35 -2
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -2
- data/lib/rubocop/options.rb +26 -11
- data/lib/rubocop/path_util.rb +4 -0
- data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
- data/lib/rubocop/plugin/load_error.rb +26 -0
- data/lib/rubocop/plugin/loader.rb +100 -0
- data/lib/rubocop/plugin/not_supported_error.rb +29 -0
- data/lib/rubocop/plugin.rb +46 -0
- data/lib/rubocop/rake_task.rb +4 -1
- data/lib/rubocop/rspec/cop_helper.rb +9 -0
- data/lib/rubocop/rspec/shared_contexts.rb +15 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/server/cache.rb +35 -2
- data/lib/rubocop/server/cli.rb +2 -2
- data/lib/rubocop/version.rb +17 -2
- data/lib/rubocop.rb +5 -1
- data/lib/ruby_lsp/rubocop/addon.rb +7 -10
- data/lib/ruby_lsp/rubocop/{wraps_built_in_lsp_runtime.rb → runtime_adapter.rb} +5 -8
- metadata +35 -10
- data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
@@ -9,6 +9,80 @@ module RuboCop
|
|
9
9
|
|
10
10
|
RESTRICT_ON_SEND = %i[[] to_h].freeze
|
11
11
|
|
12
|
+
# Internal helper class to hold match data
|
13
|
+
Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
|
14
|
+
def noop_transformation?
|
15
|
+
transforming_body_expr.lvar_type? &&
|
16
|
+
transforming_body_expr.children == [transformed_argname]
|
17
|
+
end
|
18
|
+
|
19
|
+
def transformation_uses_both_args?
|
20
|
+
transforming_body_expr.descendants.include?(unchanged_body_expr)
|
21
|
+
end
|
22
|
+
|
23
|
+
def use_transformed_argname?
|
24
|
+
transforming_body_expr.each_descendant(:lvar).any? do |node|
|
25
|
+
node.source == transformed_argname.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Internal helper class to hold autocorrect data
|
31
|
+
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
32
|
+
def self.from_each_with_object(node, match)
|
33
|
+
new(match, node, 0, 0)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_hash_brackets_map(node, match)
|
37
|
+
new(match, node.children.last, 'Hash['.length, ']'.length)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.from_map_to_h(node, match)
|
41
|
+
if node.parent&.block_type? && node.parent.send_node == node
|
42
|
+
strip_trailing_chars = 0
|
43
|
+
else
|
44
|
+
map_range = node.children.first.source_range
|
45
|
+
node_range = node.source_range
|
46
|
+
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
47
|
+
end
|
48
|
+
|
49
|
+
new(match, node.children.first, 0, strip_trailing_chars)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.from_to_h(node, match)
|
53
|
+
new(match, node, 0, 0)
|
54
|
+
end
|
55
|
+
|
56
|
+
def strip_prefix_and_suffix(node, corrector)
|
57
|
+
expression = node.source_range
|
58
|
+
corrector.remove_leading(expression, leading)
|
59
|
+
corrector.remove_trailing(expression, trailing)
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_new_method_name(new_method_name, corrector)
|
63
|
+
range = block_node.send_node.loc.selector
|
64
|
+
if (send_end = block_node.send_node.loc.end)
|
65
|
+
# If there are arguments (only true in the `each_with_object`
|
66
|
+
# case)
|
67
|
+
range = range.begin.join(send_end)
|
68
|
+
end
|
69
|
+
corrector.replace(range, new_method_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_new_arg_name(transformed_argname, corrector)
|
73
|
+
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_new_body_expression(transforming_body_expr, corrector)
|
77
|
+
body_source = transforming_body_expr.source
|
78
|
+
if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
79
|
+
body_source = "{ #{body_source} }"
|
80
|
+
end
|
81
|
+
|
82
|
+
corrector.replace(block_node.body, body_source)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
12
86
|
# @!method array_receiver?(node)
|
13
87
|
def_node_matcher :array_receiver?, <<~PATTERN
|
14
88
|
{(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)}
|
@@ -113,80 +187,6 @@ module RuboCop
|
|
113
187
|
correction.set_new_arg_name(captures.transformed_argname, corrector)
|
114
188
|
correction.set_new_body_expression(captures.transforming_body_expr, corrector)
|
115
189
|
end
|
116
|
-
|
117
|
-
# Internal helper class to hold match data
|
118
|
-
Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
|
119
|
-
def noop_transformation?
|
120
|
-
transforming_body_expr.lvar_type? &&
|
121
|
-
transforming_body_expr.children == [transformed_argname]
|
122
|
-
end
|
123
|
-
|
124
|
-
def transformation_uses_both_args?
|
125
|
-
transforming_body_expr.descendants.include?(unchanged_body_expr)
|
126
|
-
end
|
127
|
-
|
128
|
-
def use_transformed_argname?
|
129
|
-
transforming_body_expr.each_descendant(:lvar).any? do |node|
|
130
|
-
node.source == transformed_argname.to_s
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# Internal helper class to hold autocorrect data
|
136
|
-
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
137
|
-
def self.from_each_with_object(node, match)
|
138
|
-
new(match, node, 0, 0)
|
139
|
-
end
|
140
|
-
|
141
|
-
def self.from_hash_brackets_map(node, match)
|
142
|
-
new(match, node.children.last, 'Hash['.length, ']'.length)
|
143
|
-
end
|
144
|
-
|
145
|
-
def self.from_map_to_h(node, match)
|
146
|
-
if node.parent&.block_type? && node.parent.send_node == node
|
147
|
-
strip_trailing_chars = 0
|
148
|
-
else
|
149
|
-
map_range = node.children.first.source_range
|
150
|
-
node_range = node.source_range
|
151
|
-
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
152
|
-
end
|
153
|
-
|
154
|
-
new(match, node.children.first, 0, strip_trailing_chars)
|
155
|
-
end
|
156
|
-
|
157
|
-
def self.from_to_h(node, match)
|
158
|
-
new(match, node, 0, 0)
|
159
|
-
end
|
160
|
-
|
161
|
-
def strip_prefix_and_suffix(node, corrector)
|
162
|
-
expression = node.source_range
|
163
|
-
corrector.remove_leading(expression, leading)
|
164
|
-
corrector.remove_trailing(expression, trailing)
|
165
|
-
end
|
166
|
-
|
167
|
-
def set_new_method_name(new_method_name, corrector)
|
168
|
-
range = block_node.send_node.loc.selector
|
169
|
-
if (send_end = block_node.send_node.loc.end)
|
170
|
-
# If there are arguments (only true in the `each_with_object`
|
171
|
-
# case)
|
172
|
-
range = range.begin.join(send_end)
|
173
|
-
end
|
174
|
-
corrector.replace(range, new_method_name)
|
175
|
-
end
|
176
|
-
|
177
|
-
def set_new_arg_name(transformed_argname, corrector)
|
178
|
-
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
179
|
-
end
|
180
|
-
|
181
|
-
def set_new_body_expression(transforming_body_expr, corrector)
|
182
|
-
body_source = transforming_body_expr.source
|
183
|
-
if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
184
|
-
body_source = "{ #{body_source} }"
|
185
|
-
end
|
186
|
-
|
187
|
-
corrector.replace(block_node.body, body_source)
|
188
|
-
end
|
189
|
-
end
|
190
190
|
end
|
191
191
|
end
|
192
192
|
end
|
@@ -4,9 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Methods that calculate and return Parser::Source::Ranges
|
6
6
|
module RangeHelp
|
7
|
-
private
|
8
|
-
|
9
7
|
BYTE_ORDER_MARK = 0xfeff # The Unicode codepoint
|
8
|
+
NOT_GIVEN = Module.new
|
9
|
+
|
10
|
+
private
|
10
11
|
|
11
12
|
def source_range(source_buffer, line_number, column, length = 1)
|
12
13
|
if column.is_a?(Range)
|
@@ -51,7 +52,6 @@ module RuboCop
|
|
51
52
|
Parser::Source::Range.new(buffer, begin_pos, end_pos)
|
52
53
|
end
|
53
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
57
|
whitespace: false, continuations: false,
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
def on_str(node)
|
11
11
|
# Constants like __FILE__ are handled as strings,
|
12
12
|
# but don't respond to begin.
|
13
|
-
return unless node.loc
|
13
|
+
return unless node.loc?(:begin)
|
14
14
|
return if part_of_ignored_node?(node)
|
15
15
|
|
16
16
|
if offense?(node)
|
@@ -4,6 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common methods shared by Style/TrailingCommaInArguments,
|
6
6
|
# Style/TrailingCommaInArrayLiteral and Style/TrailingCommaInHashLiteral
|
7
|
+
# rubocop:disable Metrics/ModuleLength
|
7
8
|
module TrailingComma
|
8
9
|
include ConfigurableEnforcedStyle
|
9
10
|
include RangeHelp
|
@@ -57,6 +58,8 @@ module RuboCop
|
|
57
58
|
', unless each item is on its own line'
|
58
59
|
when :consistent_comma
|
59
60
|
', unless items are split onto multiple lines'
|
61
|
+
when :diff_comma
|
62
|
+
', unless that item immediately precedes a newline'
|
60
63
|
else
|
61
64
|
''
|
62
65
|
end
|
@@ -68,6 +71,8 @@ module RuboCop
|
|
68
71
|
multiline?(node) && no_elements_on_same_line?(node)
|
69
72
|
when :consistent_comma
|
70
73
|
multiline?(node) && !method_name_and_arguments_on_same_line?(node)
|
74
|
+
when :diff_comma
|
75
|
+
multiline?(node) && last_item_precedes_newline?(node)
|
71
76
|
else
|
72
77
|
false
|
73
78
|
end
|
@@ -130,6 +135,12 @@ module RuboCop
|
|
130
135
|
range1.last_line == range2.line
|
131
136
|
end
|
132
137
|
|
138
|
+
def last_item_precedes_newline?(node)
|
139
|
+
after_last_item =
|
140
|
+
range_between(node.children.last.source_range.end_pos, node.loc.end.begin_pos)
|
141
|
+
after_last_item.source =~ /\A,?\s*\n/
|
142
|
+
end
|
143
|
+
|
133
144
|
def avoid_comma(kind, comma_begin_pos, extra_info)
|
134
145
|
range = range_between(comma_begin_pos, comma_begin_pos + 1)
|
135
146
|
article = kind.include?('array') ? 'an' : 'a'
|
@@ -205,5 +216,6 @@ module RuboCop
|
|
205
216
|
false
|
206
217
|
end
|
207
218
|
end
|
219
|
+
# rubocop:enable Metrics/ModuleLength
|
208
220
|
end
|
209
221
|
end
|
@@ -14,10 +14,10 @@ module RuboCop
|
|
14
14
|
# autocorrected.
|
15
15
|
#
|
16
16
|
# [NOTE]
|
17
|
-
#
|
17
|
+
# ====
|
18
18
|
# Because of a bug in Ruby 3.3.0, when a block is referenced inside of another block,
|
19
19
|
# no offense will be registered until Ruby 3.4:
|
20
|
-
|
20
|
+
#
|
21
21
|
# [source,ruby]
|
22
22
|
# ----
|
23
23
|
# def foo(&block)
|
@@ -25,7 +25,7 @@ module RuboCop
|
|
25
25
|
# block_method { bar(&block) }
|
26
26
|
# end
|
27
27
|
# ----
|
28
|
-
#
|
28
|
+
# ====
|
29
29
|
#
|
30
30
|
# @example EnforcedStyle: anonymous (default)
|
31
31
|
#
|
@@ -17,6 +17,10 @@ module RuboCop
|
|
17
17
|
# they end with a `?`. These methods should be changed to remove the
|
18
18
|
# prefix.
|
19
19
|
#
|
20
|
+
# When `UseSorbetSigs` set to true (optional), the cop will only report
|
21
|
+
# offenses if the method has a Sorbet `sig` with a return type of
|
22
|
+
# `T::Boolean`. Dynamic methods are not supported with this configuration.
|
23
|
+
#
|
20
24
|
# @example NamePrefix: ['is_', 'has_', 'have_'] (default)
|
21
25
|
# # bad
|
22
26
|
# def is_even(value)
|
@@ -58,6 +62,30 @@ module RuboCop
|
|
58
62
|
# def is_even?(value)
|
59
63
|
# end
|
60
64
|
#
|
65
|
+
# @example UseSorbetSigs: false (default)
|
66
|
+
# # bad
|
67
|
+
# sig { returns(String) }
|
68
|
+
# def is_this_thing_on
|
69
|
+
# "yes"
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# # good - Sorbet signature is not evaluated
|
73
|
+
# sig { returns(String) }
|
74
|
+
# def is_this_thing_on?
|
75
|
+
# "yes"
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# @example UseSorbetSigs: true
|
79
|
+
# # bad
|
80
|
+
# sig { returns(T::Boolean) }
|
81
|
+
# def odd(value)
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# # good
|
85
|
+
# sig { returns(T::Boolean) }
|
86
|
+
# def odd?(value)
|
87
|
+
# end
|
88
|
+
#
|
61
89
|
# @example MethodDefinitionMacros: ['define_method', 'define_singleton_method'] (default)
|
62
90
|
# # bad
|
63
91
|
# define_method(:is_even) { |value| }
|
@@ -100,6 +128,7 @@ module RuboCop
|
|
100
128
|
method_name = node.method_name.to_s
|
101
129
|
|
102
130
|
next if allowed_method_name?(method_name, prefix)
|
131
|
+
next if use_sorbet_sigs? && !sorbet_sig?(node, return_type: 'T::Boolean')
|
103
132
|
|
104
133
|
add_offense(
|
105
134
|
node.loc.name,
|
@@ -121,6 +150,17 @@ module RuboCop
|
|
121
150
|
|
122
151
|
private
|
123
152
|
|
153
|
+
# @!method sorbet_return_type(node)
|
154
|
+
def_node_matcher :sorbet_return_type, <<~PATTERN
|
155
|
+
(block (send nil? :sig) args (send _ :returns $_type))
|
156
|
+
PATTERN
|
157
|
+
|
158
|
+
def sorbet_sig?(node, return_type: nil)
|
159
|
+
return false unless (type = sorbet_return_type(node.left_sibling))
|
160
|
+
|
161
|
+
type.source == return_type
|
162
|
+
end
|
163
|
+
|
124
164
|
def allowed_method_name?(method_name, prefix)
|
125
165
|
!(method_name.start_with?(prefix) && # cheap check to avoid allocating Regexp
|
126
166
|
method_name.match?(/^#{prefix}[^0-9]/)) ||
|
@@ -151,6 +191,10 @@ module RuboCop
|
|
151
191
|
cop_config['NamePrefix']
|
152
192
|
end
|
153
193
|
|
194
|
+
def use_sorbet_sigs?
|
195
|
+
cop_config['UseSorbetSigs']
|
196
|
+
end
|
197
|
+
|
154
198
|
def method_definition_macros(macro_name)
|
155
199
|
cop_config['MethodDefinitionMacros'].include?(macro_name.to_s)
|
156
200
|
end
|
@@ -3,8 +3,15 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Naming
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Checks that the configured style (snake_case or camelCase) is used for all variable names.
|
7
|
+
# This includes local variables, instance variables, class variables, method arguments
|
8
|
+
# (positional, keyword, rest or block), and block arguments.
|
9
|
+
#
|
10
|
+
# The cop can also be configured to forbid using specific names for variables, using
|
11
|
+
# `ForbiddenIdentifiers` or `ForbiddenPatterns`. In addition to the above, this applies
|
12
|
+
# to global variables as well.
|
13
|
+
#
|
14
|
+
# Method definitions and method calls are not affected by this cop.
|
8
15
|
#
|
9
16
|
# @example EnforcedStyle: snake_case (default)
|
10
17
|
# # bad
|
@@ -26,7 +33,21 @@ module RuboCop
|
|
26
33
|
#
|
27
34
|
# @example AllowedPatterns: ['_v\d+\z']
|
28
35
|
# # good (with EnforcedStyle: camelCase)
|
29
|
-
#
|
36
|
+
# release_v1 = true
|
37
|
+
#
|
38
|
+
# @example ForbiddenIdentifiers: ['fooBar']
|
39
|
+
# # bad (in all cases)
|
40
|
+
# fooBar = 1
|
41
|
+
# @fooBar = 1
|
42
|
+
# @@fooBar = 1
|
43
|
+
# $fooBar = 1
|
44
|
+
#
|
45
|
+
# @example ForbiddenPatterns: ['_v\d+\z']
|
46
|
+
# # bad (in all cases)
|
47
|
+
# release_v1 = true
|
48
|
+
# @release_v1 = true
|
49
|
+
# @@release_v1 = true
|
50
|
+
# $release_v1 = true
|
30
51
|
#
|
31
52
|
class VariableName < Base
|
32
53
|
include AllowedIdentifiers
|
@@ -34,16 +55,21 @@ module RuboCop
|
|
34
55
|
include AllowedPattern
|
35
56
|
|
36
57
|
MSG = 'Use %<style>s for variable names.'
|
58
|
+
MSG_FORBIDDEN = '`%<identifier>s` is forbidden, use another name instead.'
|
37
59
|
|
38
60
|
def valid_name?(node, name, given_style = style)
|
39
61
|
super || matches_allowed_pattern?(name)
|
40
62
|
end
|
41
63
|
|
42
64
|
def on_lvasgn(node)
|
43
|
-
return unless node.name
|
44
|
-
return if allowed_identifier?(
|
65
|
+
return unless (name = node.name)
|
66
|
+
return if allowed_identifier?(name)
|
45
67
|
|
46
|
-
|
68
|
+
if forbidden_name?(name)
|
69
|
+
register_forbidden_name(node)
|
70
|
+
else
|
71
|
+
check_name(node, name, node.loc.name)
|
72
|
+
end
|
47
73
|
end
|
48
74
|
alias on_ivasgn on_lvasgn
|
49
75
|
alias on_cvasgn on_lvasgn
|
@@ -56,11 +82,43 @@ module RuboCop
|
|
56
82
|
alias on_blockarg on_lvasgn
|
57
83
|
alias on_lvar on_lvasgn
|
58
84
|
|
85
|
+
# Only forbidden names are checked for global variable assignment
|
86
|
+
def on_gvasgn(node)
|
87
|
+
return unless (name = node.name)
|
88
|
+
return unless forbidden_name?(name)
|
89
|
+
|
90
|
+
register_forbidden_name(node)
|
91
|
+
end
|
92
|
+
|
59
93
|
private
|
60
94
|
|
61
95
|
def message(style)
|
62
96
|
format(MSG, style: style)
|
63
97
|
end
|
98
|
+
|
99
|
+
def forbidden_identifiers
|
100
|
+
cop_config.fetch('ForbiddenIdentifiers', [])
|
101
|
+
end
|
102
|
+
|
103
|
+
def forbidden_patterns
|
104
|
+
cop_config.fetch('ForbiddenPatterns', [])
|
105
|
+
end
|
106
|
+
|
107
|
+
def matches_forbidden_pattern?(name)
|
108
|
+
forbidden_patterns.any? { |pattern| Regexp.new(pattern).match?(name) }
|
109
|
+
end
|
110
|
+
|
111
|
+
def forbidden_name?(name)
|
112
|
+
name = name.to_s.delete(SIGILS)
|
113
|
+
|
114
|
+
(forbidden_identifiers.any? && forbidden_identifiers.include?(name)) ||
|
115
|
+
(forbidden_patterns.any? && matches_forbidden_pattern?(name))
|
116
|
+
end
|
117
|
+
|
118
|
+
def register_forbidden_name(node)
|
119
|
+
message = format(MSG_FORBIDDEN, identifier: node.name)
|
120
|
+
add_offense(node.loc.name, message: message)
|
121
|
+
end
|
64
122
|
end
|
65
123
|
end
|
66
124
|
end
|
@@ -139,12 +139,16 @@ module RuboCop
|
|
139
139
|
style == :separated
|
140
140
|
end
|
141
141
|
|
142
|
+
def groupable_sibling_accessor?(node, sibling)
|
143
|
+
sibling.attribute_accessor? &&
|
144
|
+
sibling.method?(node.method_name) &&
|
145
|
+
node_visibility(sibling) == node_visibility(node) &&
|
146
|
+
groupable_accessor?(sibling) && !previous_line_comment?(sibling)
|
147
|
+
end
|
148
|
+
|
142
149
|
def groupable_sibling_accessors(send_node)
|
143
150
|
send_node.parent.each_child_node(:send).select do |sibling|
|
144
|
-
|
145
|
-
sibling.method?(send_node.method_name) &&
|
146
|
-
node_visibility(sibling) == node_visibility(send_node) &&
|
147
|
-
groupable_accessor?(sibling) && !previous_line_comment?(sibling)
|
151
|
+
groupable_sibling_accessor?(send_node, sibling)
|
148
152
|
end
|
149
153
|
end
|
150
154
|
|
@@ -155,13 +159,23 @@ module RuboCop
|
|
155
159
|
|
156
160
|
def preferred_accessors(node)
|
157
161
|
if grouped_style?
|
162
|
+
return if skip_for_grouping?(node)
|
163
|
+
|
158
164
|
accessors = groupable_sibling_accessors(node)
|
159
|
-
|
165
|
+
if node.loc == accessors.first.loc || skip_for_grouping?(accessors.first)
|
166
|
+
group_accessors(node, accessors)
|
167
|
+
end
|
160
168
|
else
|
161
169
|
separate_accessors(node)
|
162
170
|
end
|
163
171
|
end
|
164
172
|
|
173
|
+
# Group after constants
|
174
|
+
def skip_for_grouping?(node)
|
175
|
+
node.right_siblings.any?(&:casgn_type?) &&
|
176
|
+
node.right_siblings.any? { |n| n.send_type? && groupable_sibling_accessor?(node, n) }
|
177
|
+
end
|
178
|
+
|
165
179
|
def group_accessors(node, accessors)
|
166
180
|
accessor_names = accessors.flat_map { |accessor| accessor.arguments.map(&:source) }.uniq
|
167
181
|
|
@@ -32,10 +32,10 @@ module RuboCop
|
|
32
32
|
# This cop handles not only method forwarding but also forwarding to `super`.
|
33
33
|
#
|
34
34
|
# [NOTE]
|
35
|
-
#
|
35
|
+
# ====
|
36
36
|
# Because of a bug in Ruby 3.3.0, when a block is referenced inside of another block,
|
37
37
|
# no offense will be registered until Ruby 3.4:
|
38
|
-
|
38
|
+
#
|
39
39
|
# [source,ruby]
|
40
40
|
# ----
|
41
41
|
# def foo(&block)
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
# block_method { bar(&block) }
|
44
44
|
# end
|
45
45
|
# ----
|
46
|
-
#
|
46
|
+
# ====
|
47
47
|
#
|
48
48
|
# @example
|
49
49
|
# # bad
|
@@ -57,7 +57,7 @@ module RuboCop
|
|
57
57
|
|
58
58
|
REGEXP = /(?<keyword>\S+).*#/.freeze
|
59
59
|
|
60
|
-
SUBCLASS_DEFINITION = /\A\s*class\s
|
60
|
+
SUBCLASS_DEFINITION = /\A\s*class\s+(\w|::)+\s*<\s*(\w|::)+/.freeze
|
61
61
|
METHOD_DEFINITION = /\A\s*def\s/.freeze
|
62
62
|
|
63
63
|
def on_new_investigation
|