rubocop 1.75.1 → 1.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +19 -13
- data/config/default.yml +79 -23
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/config_validator.rb +6 -6
- data/lib/rubocop/cop/autocorrect_logic.rb +18 -10
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +50 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +2 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +6 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/class_structure.rb +35 -0
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -2
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -4
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +10 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -32
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +5 -1
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +86 -5
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +27 -0
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +31 -25
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +7 -4
- data/lib/rubocop/cop/lint/return_in_void_context.rb +7 -2
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +87 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +2 -2
- data/lib/rubocop/cop/message_annotator.rb +7 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +9 -5
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +216 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
- data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -5
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -3
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
- data/lib/rubocop/cop/style/comparable_between.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +16 -4
- data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
- data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +4 -0
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
- data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +0 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +3 -0
- data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
- data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +3 -3
- data/lib/rubocop/cop/style/if_unless_modifier.rb +22 -4
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
- data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/map_into_array.rb +3 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +11 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -2
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +48 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +13 -1
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +6 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +0 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +31 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
- data/lib/rubocop/cop/style/return_nil.rb +2 -2
- data/lib/rubocop/cop/style/safe_navigation.rb +28 -10
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -2
- data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
- data/lib/rubocop/cop/style/super_arguments.rb +1 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +7 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +6 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
- data/lib/rubocop/magic_comment.rb +8 -0
- data/lib/rubocop/rspec/cop_helper.rb +2 -2
- data/lib/rubocop/rspec/shared_contexts.rb +1 -2
- data/lib/rubocop/server/cache.rb +13 -10
- data/lib/rubocop/target_finder.rb +6 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +6 -1
- metadata +12 -7
|
@@ -242,7 +242,7 @@ module RuboCop
|
|
|
242
242
|
def find_definition(node)
|
|
243
243
|
# Methods can be defined in a `def` or `defs`,
|
|
244
244
|
# or dynamically via a `block` node.
|
|
245
|
-
node.each_ancestor(:
|
|
245
|
+
node.each_ancestor(:any_def, :block).each do |ancestor|
|
|
246
246
|
method_node, method_name = method_definition?(ancestor)
|
|
247
247
|
return [method_node, method_name] if method_node
|
|
248
248
|
end
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Naming
|
|
6
|
+
# Checks that predicate methods end with `?` and non-predicate methods do not.
|
|
7
|
+
#
|
|
8
|
+
# The names of predicate methods (methods that return a boolean value) should end
|
|
9
|
+
# in a question mark. Methods that don’t return a boolean, shouldn’t
|
|
10
|
+
# end in a question mark.
|
|
11
|
+
#
|
|
12
|
+
# The cop assesses a predicate method as one that returns boolean values. Likewise,
|
|
13
|
+
# a method that only returns literal values is assessed as non-predicate. The cop does
|
|
14
|
+
# not make an assessment if the return type is unknown (method calls, variables, etc.).
|
|
15
|
+
#
|
|
16
|
+
# NOTE: Operator methods (`def ==`, etc.) are ignored.
|
|
17
|
+
#
|
|
18
|
+
# By default, the cop runs in `conservative` mode, which allows a method to be named
|
|
19
|
+
# with a question mark as long as at least one return value is boolean. In `aggressive`
|
|
20
|
+
# mode, methods with a question mark will register an offense if any known non-boolean
|
|
21
|
+
# return values are detected.
|
|
22
|
+
#
|
|
23
|
+
# The cop also has `AllowedMethods` configuration in order to prevent the cop from
|
|
24
|
+
# registering an offense from a method name that does not confirm to the naming
|
|
25
|
+
# guidelines. By default, `call` is allowed.
|
|
26
|
+
#
|
|
27
|
+
# @example Mode: conservative (default)
|
|
28
|
+
# # bad
|
|
29
|
+
# def foo
|
|
30
|
+
# bar == baz
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# # good
|
|
34
|
+
# def foo?
|
|
35
|
+
# bar == baz
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# # bad
|
|
39
|
+
# def foo?
|
|
40
|
+
# 5
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# # good
|
|
44
|
+
# def foo
|
|
45
|
+
# 5
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# # good - operator method
|
|
49
|
+
# def ==(other)
|
|
50
|
+
# hash == other.hash
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# # good - at least one return value is boolean
|
|
54
|
+
# def foo?
|
|
55
|
+
# return unless bar?
|
|
56
|
+
# true
|
|
57
|
+
# end
|
|
58
|
+
#
|
|
59
|
+
# # ok - return type is not known
|
|
60
|
+
# def foo?
|
|
61
|
+
# bar
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# # ok - return type is not known
|
|
65
|
+
# def foo
|
|
66
|
+
# bar?
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# @example Mode: aggressive
|
|
70
|
+
# # bad - the method returns nil in some cases
|
|
71
|
+
# def foo?
|
|
72
|
+
# return unless bar?
|
|
73
|
+
# true
|
|
74
|
+
# end
|
|
75
|
+
#
|
|
76
|
+
class PredicateMethod < Base
|
|
77
|
+
include AllowedMethods
|
|
78
|
+
|
|
79
|
+
MSG_PREDICATE = 'Predicate method names should end with `?`.'
|
|
80
|
+
MSG_NON_PREDICATE = 'Non-predicate method names should not end with `?`.'
|
|
81
|
+
|
|
82
|
+
def on_def(node)
|
|
83
|
+
return if allowed?(node)
|
|
84
|
+
|
|
85
|
+
return_values = return_values(node.body)
|
|
86
|
+
return if acceptable?(return_values)
|
|
87
|
+
|
|
88
|
+
if node.predicate_method? && potential_non_predicate?(return_values)
|
|
89
|
+
add_offense(node.loc.name, message: MSG_NON_PREDICATE)
|
|
90
|
+
elsif !node.predicate_method? && all_return_values_boolean?(return_values)
|
|
91
|
+
add_offense(node.loc.name, message: MSG_PREDICATE)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
alias on_defs on_def
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def allowed?(node)
|
|
99
|
+
allowed_method?(node.method_name) ||
|
|
100
|
+
node.operator_method? ||
|
|
101
|
+
node.body.nil?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def acceptable?(return_values)
|
|
105
|
+
# In `conservative` mode, if the method returns `super`, `zsuper`, or a
|
|
106
|
+
# non-comparison method call, the method name is acceptable.
|
|
107
|
+
return false unless conservative?
|
|
108
|
+
|
|
109
|
+
return_values.any? do |value|
|
|
110
|
+
value.type?(:super, :zsuper) || non_comparison_call?(value)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def non_comparison_call?(value)
|
|
115
|
+
value.call_type? && !value.comparison_method?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def return_values(node)
|
|
119
|
+
# Collect all the (implicit and explicit) return values of a node
|
|
120
|
+
return_values = Set.new(node.begin_type? ? [] : [extract_return_value(node)])
|
|
121
|
+
|
|
122
|
+
node.each_descendant(:return) do |return_node|
|
|
123
|
+
return_values << extract_return_value(return_node)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
last_value = last_value(node)
|
|
127
|
+
return_values << last_value if last_value
|
|
128
|
+
|
|
129
|
+
process_return_values(return_values)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def all_return_values_boolean?(return_values)
|
|
133
|
+
values = return_values.reject { |value| value.type?(:super, :zsuper) }
|
|
134
|
+
return false if values.empty?
|
|
135
|
+
|
|
136
|
+
values.all? { |value| boolean_return?(value) }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def boolean_return?(value)
|
|
140
|
+
value.boolean_type? || (value.call_type? && value.comparison_method?)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def potential_non_predicate?(return_values)
|
|
144
|
+
# Assumes a method to be non-predicate if all return values are non-boolean literals.
|
|
145
|
+
#
|
|
146
|
+
# In `Mode: conservative`, if any of the return values is a boolean,
|
|
147
|
+
# the method name is acceptable.
|
|
148
|
+
# In `Mode: aggressive`, all return values must be booleans for a predicate
|
|
149
|
+
# method, or else an offense will be registered.
|
|
150
|
+
return false if conservative? && return_values.any? { |value| boolean_return?(value) }
|
|
151
|
+
|
|
152
|
+
return_values.any? do |value|
|
|
153
|
+
value.literal? && !value.boolean_type?
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def extract_return_value(node)
|
|
158
|
+
return node unless node.return_type?
|
|
159
|
+
|
|
160
|
+
# `return` without a value is a `nil` return.
|
|
161
|
+
return s(:nil) if node.arguments.empty?
|
|
162
|
+
|
|
163
|
+
# When there's a multiple return, it cannot be a predicate
|
|
164
|
+
# so just return an `array` sexp for simplicity.
|
|
165
|
+
return s(:array) unless node.arguments.one?
|
|
166
|
+
|
|
167
|
+
node.first_argument
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def last_value(node)
|
|
171
|
+
value = node.begin_type? ? node.children.last : node
|
|
172
|
+
value.return_type? ? extract_return_value(value) : value
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def process_return_values(return_values)
|
|
176
|
+
return_values.flat_map do |value|
|
|
177
|
+
if value.conditional?
|
|
178
|
+
process_return_values(extract_conditional_branches(value))
|
|
179
|
+
elsif and_or?(value)
|
|
180
|
+
process_return_values(extract_and_or_clauses(value))
|
|
181
|
+
else
|
|
182
|
+
value
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def and_or?(node)
|
|
188
|
+
node.type?(:and, :or)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def extract_and_or_clauses(node)
|
|
192
|
+
# Recursively traverse an `and` or `or` node to collect all clauses within
|
|
193
|
+
return node unless and_or?(node)
|
|
194
|
+
|
|
195
|
+
[extract_and_or_clauses(node.lhs), extract_and_or_clauses(node.rhs)].flatten
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def extract_conditional_branches(node)
|
|
199
|
+
return node unless node.conditional?
|
|
200
|
+
|
|
201
|
+
if node.type?(:while, :until)
|
|
202
|
+
# If there is no body, act as implicit `nil`.
|
|
203
|
+
node.body ? [last_value(node.body)] : [s(:nil)]
|
|
204
|
+
else
|
|
205
|
+
# Branches with no value act as an implicit `nil`.
|
|
206
|
+
node.branches.filter_map { |branch| branch ? last_value(branch) : s(:nil) }
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def conservative?
|
|
211
|
+
cop_config.fetch('Mode', :conservative).to_sym == :conservative
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
@@ -100,7 +100,7 @@ module RuboCop
|
|
|
100
100
|
# # good
|
|
101
101
|
# def_node_matcher(:even?) { |value| }
|
|
102
102
|
#
|
|
103
|
-
class
|
|
103
|
+
class PredicatePrefix < Base
|
|
104
104
|
include AllowedMethods
|
|
105
105
|
|
|
106
106
|
# @!method dynamic_method_define(node)
|
|
@@ -143,7 +143,7 @@ module RuboCop
|
|
|
143
143
|
next if predicate_prefixes.include?(forbidden_prefix)
|
|
144
144
|
|
|
145
145
|
raise ValidationError, <<~MSG.chomp
|
|
146
|
-
The `Naming/
|
|
146
|
+
The `Naming/PredicatePrefix` cop is misconfigured. Prefix #{forbidden_prefix} must be included in NamePrefix because it is included in ForbiddenPrefixes.
|
|
147
147
|
MSG
|
|
148
148
|
end
|
|
149
149
|
end
|
|
@@ -195,15 +195,27 @@ module RuboCop
|
|
|
195
195
|
def autocorrect(corrector, node)
|
|
196
196
|
case style
|
|
197
197
|
when :group
|
|
198
|
-
|
|
199
|
-
return unless def_nodes.any?
|
|
200
|
-
|
|
201
|
-
replace_defs(corrector, node, def_nodes)
|
|
198
|
+
autocorrect_group_style(corrector, node)
|
|
202
199
|
when :inline
|
|
200
|
+
autocorrect_inline_style(corrector, node)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def autocorrect_group_style(corrector, node)
|
|
205
|
+
def_nodes = find_corresponding_def_nodes(node)
|
|
206
|
+
return unless def_nodes.any?
|
|
207
|
+
|
|
208
|
+
replace_defs(corrector, node, def_nodes)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def autocorrect_inline_style(corrector, node)
|
|
212
|
+
if node.parent&.begin_type?
|
|
213
|
+
remove_modifier_node_within_begin(corrector, node, node.parent)
|
|
214
|
+
else
|
|
203
215
|
remove_nodes(corrector, node)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
216
|
+
end
|
|
217
|
+
select_grouped_def_nodes(node).each do |grouped_def_node|
|
|
218
|
+
insert_inline_modifier(corrector, grouped_def_node, node.method_name)
|
|
207
219
|
end
|
|
208
220
|
end
|
|
209
221
|
|
|
@@ -224,9 +236,13 @@ module RuboCop
|
|
|
224
236
|
end
|
|
225
237
|
|
|
226
238
|
def offense?(node)
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
239
|
+
if group_style?
|
|
240
|
+
return false if node.parent ? node.parent.if_type? : access_modifier_with_symbol?(node)
|
|
241
|
+
|
|
242
|
+
access_modifier_is_inlined?(node) && !right_siblings_same_inline_method?(node)
|
|
243
|
+
else
|
|
244
|
+
access_modifier_is_not_inlined?(node) && select_grouped_def_nodes(node).any?
|
|
245
|
+
end
|
|
230
246
|
end
|
|
231
247
|
|
|
232
248
|
def correctable_group_offense?(node)
|
|
@@ -331,6 +347,12 @@ module RuboCop
|
|
|
331
347
|
end
|
|
332
348
|
end
|
|
333
349
|
|
|
350
|
+
def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
|
|
351
|
+
def_node = begin_node.children[1]
|
|
352
|
+
range = modifier_node.source_range.begin.join(def_node.source_range.begin)
|
|
353
|
+
corrector.remove(range)
|
|
354
|
+
end
|
|
355
|
+
|
|
334
356
|
def def_source(node, def_nodes)
|
|
335
357
|
[
|
|
336
358
|
*processed_source.ast_with_comments[node].map(&:text),
|
|
@@ -16,16 +16,16 @@ module RuboCop
|
|
|
16
16
|
#
|
|
17
17
|
# In Ruby 3.2, anonymous args/kwargs forwarding has been added.
|
|
18
18
|
#
|
|
19
|
-
# This cop also identifies places where
|
|
20
|
-
# replaced by
|
|
21
|
-
# by setting `UseAnonymousForwarding: false`.
|
|
19
|
+
# This cop also identifies places where `+use_args(*args)+`/`+use_kwargs(**kwargs)+` can be
|
|
20
|
+
# replaced by `+use_args(*)+`/`+use_kwargs(**)+`; if desired, this functionality can be
|
|
21
|
+
# disabled by setting `UseAnonymousForwarding: false`.
|
|
22
22
|
#
|
|
23
23
|
# And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
|
|
24
24
|
# and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
|
|
25
25
|
# that are sufficient for anonymizing meaningless naming.
|
|
26
26
|
#
|
|
27
27
|
# Meaningless names that are commonly used can be anonymized by default:
|
|
28
|
-
# e.g.,
|
|
28
|
+
# e.g., `+*args+`, `+**options+`, `&block`, and so on.
|
|
29
29
|
#
|
|
30
30
|
# Names not on this list are likely to be meaningful and are allowed by default.
|
|
31
31
|
#
|
|
@@ -146,7 +146,7 @@ module RuboCop
|
|
|
146
146
|
minimum_target_ruby_version 2.7
|
|
147
147
|
|
|
148
148
|
FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
|
|
149
|
-
ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
|
|
149
|
+
ADDITIONAL_ARG_TYPES = %i[lvar arg optarg].freeze
|
|
150
150
|
|
|
151
151
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
|
152
152
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
|
@@ -479,6 +479,9 @@ module RuboCop
|
|
|
479
479
|
end
|
|
480
480
|
|
|
481
481
|
def ruby_32_only_anonymous_forwarding?
|
|
482
|
+
# A block argument and an anonymous block argument are never passed together.
|
|
483
|
+
return false if @send_node.each_ancestor(:any_block).any?
|
|
484
|
+
|
|
482
485
|
def_all_anonymous_args?(@def_node) && send_all_anonymous_args?(@send_node)
|
|
483
486
|
end
|
|
484
487
|
|
|
@@ -131,21 +131,27 @@ module RuboCop
|
|
|
131
131
|
"#{node.body.children.first.const_name}"
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
# rubocop:disable Metrics/AbcSize
|
|
134
135
|
def remove_end(corrector, body)
|
|
135
|
-
remove_begin_pos = body.loc.
|
|
136
|
+
remove_begin_pos = if same_line?(body.loc.name, body.loc.end)
|
|
137
|
+
body.loc.name.end_pos
|
|
138
|
+
else
|
|
139
|
+
body.loc.end.begin_pos - leading_spaces(body).size
|
|
140
|
+
end
|
|
136
141
|
adjustment = processed_source.raw_source[remove_begin_pos] == ';' ? 0 : 1
|
|
137
142
|
range = range_between(remove_begin_pos, body.loc.end.end_pos + adjustment)
|
|
138
143
|
|
|
139
144
|
corrector.remove(range)
|
|
140
145
|
end
|
|
146
|
+
# rubocop:enable Metrics/AbcSize
|
|
141
147
|
|
|
142
148
|
def unindent(corrector, node)
|
|
143
149
|
return unless node.body.children.last
|
|
144
150
|
|
|
145
151
|
last_child_leading_spaces = leading_spaces(node.body.children.last)
|
|
146
|
-
return if leading_spaces(node)
|
|
152
|
+
return if spaces_size(leading_spaces(node)) == spaces_size(last_child_leading_spaces)
|
|
147
153
|
|
|
148
|
-
column_delta = configured_indentation_width - last_child_leading_spaces
|
|
154
|
+
column_delta = configured_indentation_width - spaces_size(last_child_leading_spaces)
|
|
149
155
|
return if column_delta.zero?
|
|
150
156
|
|
|
151
157
|
AlignmentCorrector.correct(corrector, processed_source, node, column_delta)
|
|
@@ -155,6 +161,16 @@ module RuboCop
|
|
|
155
161
|
node.source_range.source_line[/\A\s*/]
|
|
156
162
|
end
|
|
157
163
|
|
|
164
|
+
def spaces_size(spaces_string)
|
|
165
|
+
mapping = { "\t" => tab_indentation_width }
|
|
166
|
+
spaces_string.chars.sum { |character| mapping.fetch(character, 1) }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def tab_indentation_width
|
|
170
|
+
config.for_cop('Layout/IndentationStyle')['IndentationWidth'] ||
|
|
171
|
+
configured_indentation_width
|
|
172
|
+
end
|
|
173
|
+
|
|
158
174
|
def check_style(node, body, style)
|
|
159
175
|
return if node.identifier.namespace&.cbase_type?
|
|
160
176
|
|
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
|
68
68
|
PATTERN
|
|
69
69
|
|
|
70
70
|
def on_send(node)
|
|
71
|
-
def_node = node.each_ancestor(:
|
|
71
|
+
def_node = node.each_ancestor(:any_def).first
|
|
72
72
|
return if def_node &&
|
|
73
73
|
(allowed_method?(def_node.method_name) ||
|
|
74
74
|
matches_allowed_pattern?(def_node.method_name))
|
|
@@ -58,7 +58,7 @@ module RuboCop
|
|
|
58
58
|
REGEXP = /(?<keyword>\S+).*#/.freeze
|
|
59
59
|
|
|
60
60
|
SUBCLASS_DEFINITION = /\A\s*class\s+(\w|::)+\s*<\s*(\w|::)+/.freeze
|
|
61
|
-
|
|
61
|
+
METHOD_OR_END_DEFINITIONS = /\A\s*(def\s|end)/.freeze
|
|
62
62
|
|
|
63
63
|
STEEP_REGEXP = /#\ssteep:ignore(\s|\z)/.freeze
|
|
64
64
|
|
|
@@ -102,7 +102,7 @@ module RuboCop
|
|
|
102
102
|
case line
|
|
103
103
|
when SUBCLASS_DEFINITION
|
|
104
104
|
comment.text.start_with?(/#\[.+\]/)
|
|
105
|
-
when
|
|
105
|
+
when METHOD_OR_END_DEFINITIONS
|
|
106
106
|
comment.text.start_with?('#:')
|
|
107
107
|
else
|
|
108
108
|
false
|
|
@@ -9,6 +9,9 @@ module RuboCop
|
|
|
9
9
|
# although the difference generally isn't observable. If you require maximum
|
|
10
10
|
# performance, consider using logical comparison.
|
|
11
11
|
#
|
|
12
|
+
# @safety
|
|
13
|
+
# This cop is unsafe because the receiver may not respond to `between?`.
|
|
14
|
+
#
|
|
12
15
|
# @example
|
|
13
16
|
#
|
|
14
17
|
# # bad
|
|
@@ -61,8 +64,8 @@ module RuboCop
|
|
|
61
64
|
|
|
62
65
|
def register_offense(node, min_and_value, max_and_value)
|
|
63
66
|
value = (min_and_value & max_and_value).first
|
|
64
|
-
min = min_and_value.find { _1 != value }
|
|
65
|
-
max = max_and_value.find { _1 != value }
|
|
67
|
+
min = min_and_value.find { _1 != value } || value
|
|
68
|
+
max = max_and_value.find { _1 != value } || value
|
|
66
69
|
|
|
67
70
|
prefer = "#{value.source}.between?(#{min.source}, #{max.source})"
|
|
68
71
|
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
|
@@ -314,6 +314,7 @@ module RuboCop
|
|
|
314
314
|
|
|
315
315
|
def assignment_node(node)
|
|
316
316
|
assignment = node.send_type? ? node.last_argument : node.expression
|
|
317
|
+
return unless assignment
|
|
317
318
|
|
|
318
319
|
# ignore pseudo-assignments without rhs in for nodes
|
|
319
320
|
return if node.parent&.for_type?
|
|
@@ -436,19 +437,28 @@ module RuboCop
|
|
|
436
437
|
# Helper module to provide common methods to ConditionalAssignment
|
|
437
438
|
# correctors
|
|
438
439
|
module ConditionalCorrectorHelper
|
|
440
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
439
441
|
def remove_whitespace_in_branches(corrector, branch, condition, column)
|
|
440
442
|
branch.each_node do |child|
|
|
441
443
|
next if child.source_range.nil?
|
|
444
|
+
next if child.parent.dstr_type?
|
|
442
445
|
|
|
443
446
|
white_space = white_space_range(child, column)
|
|
444
447
|
corrector.remove(white_space) if white_space.source.strip.empty?
|
|
445
448
|
end
|
|
446
449
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
corrector.remove_preceding(loc, loc.column - column)
|
|
450
|
+
if condition.loc.else && !same_line?(condition.else_branch, condition)
|
|
451
|
+
corrector.remove_preceding(condition.loc.else, condition.loc.else.column - column)
|
|
451
452
|
end
|
|
453
|
+
|
|
454
|
+
return unless condition.loc.end && !same_line?(condition.loc.end, condition)
|
|
455
|
+
|
|
456
|
+
corrector.remove_preceding(condition.loc.end, condition.loc.end.column - column)
|
|
457
|
+
end
|
|
458
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
459
|
+
|
|
460
|
+
def same_line?(node1, node2)
|
|
461
|
+
RuboCop::Cop::Util.same_line?(node1, node2)
|
|
452
462
|
end
|
|
453
463
|
|
|
454
464
|
def white_space_range(node, column)
|
|
@@ -595,6 +605,8 @@ module RuboCop
|
|
|
595
605
|
|
|
596
606
|
return unless (branch_else = branch.parent.loc.else)
|
|
597
607
|
|
|
608
|
+
return if same_line?(branch_else, condition)
|
|
609
|
+
|
|
598
610
|
corrector.remove_preceding(branch_else, branch_else.column - column)
|
|
599
611
|
end
|
|
600
612
|
end
|
|
@@ -4,6 +4,7 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for inheritance from `Data.define` to avoid creating the anonymous parent class.
|
|
7
|
+
# Inheriting from `Data.define` adds a superfluous level in inheritance tree.
|
|
7
8
|
#
|
|
8
9
|
# @safety
|
|
9
10
|
# Autocorrection is unsafe because it will change the inheritance
|
|
@@ -17,12 +18,18 @@ module RuboCop
|
|
|
17
18
|
# end
|
|
18
19
|
# end
|
|
19
20
|
#
|
|
21
|
+
# Person.ancestors
|
|
22
|
+
# # => [Person, #<Class:0x000000010b4e14a0>, Data, (...)]
|
|
23
|
+
#
|
|
20
24
|
# # good
|
|
21
25
|
# Person = Data.define(:first_name, :last_name) do
|
|
22
26
|
# def age
|
|
23
27
|
# 42
|
|
24
28
|
# end
|
|
25
29
|
# end
|
|
30
|
+
#
|
|
31
|
+
# Person.ancestors
|
|
32
|
+
# # => [Person, Data, (...)]
|
|
26
33
|
class DataInheritance < Base
|
|
27
34
|
include RangeHelp
|
|
28
35
|
extend AutoCorrector
|
|
@@ -25,8 +25,9 @@ module RuboCop
|
|
|
25
25
|
# # good
|
|
26
26
|
# def foo = do_something
|
|
27
27
|
#
|
|
28
|
-
# # good
|
|
28
|
+
# # good - without parentheses it's a syntax error
|
|
29
29
|
# def foo() do_something end
|
|
30
|
+
# def foo()=do_something
|
|
30
31
|
#
|
|
31
32
|
# # bad
|
|
32
33
|
# def Baz.foo()
|
|
@@ -38,19 +39,31 @@ module RuboCop
|
|
|
38
39
|
# do_something
|
|
39
40
|
# end
|
|
40
41
|
class DefWithParentheses < Base
|
|
42
|
+
include RangeHelp
|
|
41
43
|
extend AutoCorrector
|
|
42
44
|
|
|
43
45
|
MSG = "Omit the parentheses in defs when the method doesn't accept any arguments."
|
|
44
46
|
|
|
45
47
|
def on_def(node)
|
|
46
|
-
return
|
|
47
|
-
return
|
|
48
|
+
return unless !node.arguments? && (arguments_range = node.arguments.source_range)
|
|
49
|
+
return if parentheses_required?(node, arguments_range)
|
|
48
50
|
|
|
49
|
-
add_offense(
|
|
50
|
-
corrector.remove(
|
|
51
|
+
add_offense(arguments_range) do |corrector|
|
|
52
|
+
corrector.remove(arguments_range)
|
|
51
53
|
end
|
|
52
54
|
end
|
|
53
55
|
alias on_defs on_def
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def parentheses_required?(node, arguments_range)
|
|
60
|
+
return true if node.single_line? && !node.endless?
|
|
61
|
+
|
|
62
|
+
end_pos = arguments_range.end.end_pos
|
|
63
|
+
token_after_argument = range_between(end_pos, end_pos + 1).source
|
|
64
|
+
|
|
65
|
+
token_after_argument == '='
|
|
66
|
+
end
|
|
54
67
|
end
|
|
55
68
|
end
|
|
56
69
|
end
|
|
@@ -102,7 +102,7 @@ module RuboCop
|
|
|
102
102
|
|
|
103
103
|
def find_def_node_from_ascendant(node)
|
|
104
104
|
return unless (parent = node.parent)
|
|
105
|
-
return parent if parent.
|
|
105
|
+
return parent if parent.any_def_type?
|
|
106
106
|
return node.parent.child_nodes.first if define_method?(parent)
|
|
107
107
|
|
|
108
108
|
find_def_node_from_ascendant(node.parent)
|
|
@@ -6,6 +6,10 @@ module RuboCop
|
|
|
6
6
|
# Checks for the use of a method, the result of which
|
|
7
7
|
# would be a literal, like an empty array, hash, or string.
|
|
8
8
|
#
|
|
9
|
+
# NOTE: When frozen string literals are enabled, `String.new`
|
|
10
|
+
# isn't corrected to an empty string since the former is
|
|
11
|
+
# mutable and the latter would be frozen.
|
|
12
|
+
#
|
|
9
13
|
# @example
|
|
10
14
|
# # bad
|
|
11
15
|
# a = Array.new
|