rubocop 1.57.2 → 1.60.2
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 +4 -4
- data/config/default.yml +46 -3
- data/lib/rubocop/config.rb +0 -2
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_obsoletion.rb +11 -8
- data/lib/rubocop/config_validator.rb +0 -2
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +7 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
- data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +43 -0
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +14 -1
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
- data/lib/rubocop/cop/naming/constant_name.rb +1 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +127 -17
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/case_like_if.rb +4 -4
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/collection_compact.rb +18 -8
- data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
- data/lib/rubocop/cop/style/hash_except.rb +2 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +39 -2
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
- data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -3
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -2
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +10 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -10
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
- data/lib/rubocop/cop/style/sample.rb +2 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +8 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +5 -2
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cops_documentation_generator.rb +11 -1
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +1 -2
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/options.rb +0 -8
- data/lib/rubocop/result_cache.rb +0 -1
- data/lib/rubocop/rspec/shared_contexts.rb +6 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/server/cache.rb +1 -2
- data/lib/rubocop/server/client_command/exec.rb +0 -1
- data/lib/rubocop/server/server_command/exec.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +4 -0
- metadata +15 -10
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -12,7 +12,16 @@ module RuboCop
|
|
12
12
|
#
|
13
13
|
# This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
|
14
14
|
# replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
|
15
|
-
# by setting UseAnonymousForwarding: false
|
15
|
+
# by setting `UseAnonymousForwarding: false`.
|
16
|
+
#
|
17
|
+
# And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
|
18
|
+
# and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
|
19
|
+
# that are sufficient for anonymizing meaningless naming.
|
20
|
+
#
|
21
|
+
# Meaningless names that are commonly used can be anonymized by default:
|
22
|
+
# e.g., `*args`, `**options`, `&block`, and so on.
|
23
|
+
#
|
24
|
+
# Names not on this list are likely to be meaningful and are allowed by default.
|
16
25
|
#
|
17
26
|
# @example
|
18
27
|
# # bad
|
@@ -72,6 +81,38 @@ module RuboCop
|
|
72
81
|
# bar(**kwargs)
|
73
82
|
# end
|
74
83
|
#
|
84
|
+
# @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
|
85
|
+
# # bad
|
86
|
+
# def foo(*args)
|
87
|
+
# bar(*args)
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # good
|
91
|
+
# def foo(*)
|
92
|
+
# bar(*)
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
|
96
|
+
# # bad
|
97
|
+
# def foo(**kwargs)
|
98
|
+
# bar(**kwargs)
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# # good
|
102
|
+
# def foo(**)
|
103
|
+
# bar(**)
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
|
107
|
+
# # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
|
108
|
+
# def foo(&block)
|
109
|
+
# bar(&block)
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# # good
|
113
|
+
# def foo(&)
|
114
|
+
# bar(&)
|
115
|
+
# end
|
75
116
|
class ArgumentsForwarding < Base
|
76
117
|
include RangeHelp
|
77
118
|
extend AutoCorrector
|
@@ -85,17 +126,21 @@ module RuboCop
|
|
85
126
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
86
127
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
87
128
|
KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
|
129
|
+
BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
|
130
|
+
|
131
|
+
def self.autocorrect_incompatible_with
|
132
|
+
[Naming::BlockForwarding]
|
133
|
+
end
|
88
134
|
|
89
135
|
def on_def(node)
|
90
136
|
return unless node.body
|
91
137
|
|
92
|
-
|
138
|
+
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
139
|
+
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
140
|
+
send_nodes = node.each_descendant(:send).to_a
|
93
141
|
|
94
142
|
send_classifications = classify_send_nodes(
|
95
|
-
node,
|
96
|
-
node.each_descendant(:send).to_a,
|
97
|
-
non_splat_or_block_pass_lvar_references(node.body),
|
98
|
-
forwardable_args
|
143
|
+
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
99
144
|
)
|
100
145
|
|
101
146
|
return if send_classifications.empty?
|
@@ -115,31 +160,54 @@ module RuboCop
|
|
115
160
|
[args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
|
116
161
|
end
|
117
162
|
|
163
|
+
def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
164
|
+
restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
|
165
|
+
kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
|
166
|
+
blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
|
167
|
+
|
168
|
+
[restarg_node, kwrestarg_node, blockarg_node]
|
169
|
+
end
|
170
|
+
|
118
171
|
def only_forwards_all?(send_classifications)
|
119
172
|
send_classifications.all? { |_, c, _, _| c == :all }
|
120
173
|
end
|
121
174
|
|
175
|
+
# rubocop:disable Metrics/MethodLength
|
122
176
|
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
123
|
-
|
124
|
-
|
177
|
+
_rest_arg, _kwrest_arg, block_arg = *forwardable_args
|
178
|
+
registered_block_arg_offense = false
|
179
|
+
|
180
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
181
|
+
if !forward_rest && !forward_kwrest
|
182
|
+
register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
|
183
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
184
|
+
|
185
|
+
registered_block_arg_offense = true
|
186
|
+
break
|
187
|
+
else
|
188
|
+
register_forward_all_offense(send_node, send_node, forward_rest)
|
189
|
+
end
|
125
190
|
end
|
126
191
|
|
192
|
+
return if registered_block_arg_offense
|
193
|
+
|
127
194
|
rest_arg, _kwrest_arg, _block_arg = *forwardable_args
|
128
195
|
register_forward_all_offense(node, node.arguments, rest_arg)
|
129
196
|
end
|
197
|
+
# rubocop:enable Metrics/MethodLength
|
130
198
|
|
131
199
|
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
132
200
|
return unless use_anonymous_forwarding?
|
133
201
|
|
134
202
|
rest_arg, kwrest_arg, _block_arg = *forwardable_args
|
135
203
|
|
136
|
-
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
|
137
|
-
if forward_rest
|
204
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, _forward_block_arg| # rubocop:disable Layout/LineLength
|
205
|
+
if outside_block?(forward_rest)
|
138
206
|
register_forward_args_offense(def_node.arguments, rest_arg)
|
139
207
|
register_forward_args_offense(send_node, forward_rest)
|
140
208
|
end
|
141
209
|
|
142
|
-
if forward_kwrest
|
210
|
+
if outside_block?(forward_kwrest)
|
143
211
|
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
144
212
|
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
145
213
|
end
|
@@ -173,10 +241,7 @@ module RuboCop
|
|
173
241
|
|
174
242
|
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
175
243
|
classifier = SendNodeClassifier.new(
|
176
|
-
def_node,
|
177
|
-
send_node,
|
178
|
-
referenced_lvars,
|
179
|
-
forwardable_args,
|
244
|
+
def_node, send_node, referenced_lvars, forwardable_args,
|
180
245
|
target_ruby_version: target_ruby_version,
|
181
246
|
allow_only_rest_arguments: allow_only_rest_arguments?
|
182
247
|
)
|
@@ -185,7 +250,28 @@ module RuboCop
|
|
185
250
|
|
186
251
|
return unless classification
|
187
252
|
|
188
|
-
[
|
253
|
+
[
|
254
|
+
classification,
|
255
|
+
classifier.forwarded_rest_arg,
|
256
|
+
classifier.forwarded_kwrest_arg,
|
257
|
+
classifier.forwarded_block_arg
|
258
|
+
]
|
259
|
+
end
|
260
|
+
|
261
|
+
def redundant_named_arg(arg, config_name, keyword)
|
262
|
+
return nil unless arg
|
263
|
+
|
264
|
+
redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
|
265
|
+
"#{keyword}#{redundant_arg_name}"
|
266
|
+
end << keyword
|
267
|
+
|
268
|
+
redundant_arg_names.include?(arg.source) ? arg : nil
|
269
|
+
end
|
270
|
+
|
271
|
+
def outside_block?(node)
|
272
|
+
return false unless node
|
273
|
+
|
274
|
+
node.each_ancestor(:block, :numblock).none?
|
189
275
|
end
|
190
276
|
|
191
277
|
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
@@ -204,6 +290,16 @@ module RuboCop
|
|
204
290
|
end
|
205
291
|
end
|
206
292
|
|
293
|
+
def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
|
294
|
+
return if target_ruby_version <= 3.0 || block_arg.source == '&' || explicit_block_name?
|
295
|
+
|
296
|
+
add_offense(block_arg, message: BLOCK_MSG) do |corrector|
|
297
|
+
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
298
|
+
|
299
|
+
corrector.replace(block_arg, '&')
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
207
303
|
def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
|
208
304
|
arg_range = arguments_range(def_or_send, rest_or_splat)
|
209
305
|
|
@@ -278,7 +374,7 @@ module RuboCop
|
|
278
374
|
end
|
279
375
|
|
280
376
|
def classification
|
281
|
-
return nil unless forwarded_rest_arg || forwarded_kwrest_arg
|
377
|
+
return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
|
282
378
|
|
283
379
|
if can_forward_all?
|
284
380
|
:all
|
@@ -362,9 +458,23 @@ module RuboCop
|
|
362
458
|
def no_additional_args?
|
363
459
|
forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
|
364
460
|
|
461
|
+
return false if missing_rest_arg_or_kwrest_arg?
|
462
|
+
|
365
463
|
@def_node.arguments.size == forwardable_count &&
|
366
464
|
@send_node.arguments.size == forwardable_count
|
367
465
|
end
|
466
|
+
|
467
|
+
def missing_rest_arg_or_kwrest_arg?
|
468
|
+
(@rest_arg_name && !forwarded_rest_arg) ||
|
469
|
+
(@kwrest_arg_name && !forwarded_kwrest_arg)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def explicit_block_name?
|
474
|
+
block_forwarding_config = config.for_cop('Naming/BlockForwarding')
|
475
|
+
return false unless block_forwarding_config['Enabled']
|
476
|
+
|
477
|
+
block_forwarding_config['EnforcedStyle'] == 'explicit'
|
368
478
|
end
|
369
479
|
end
|
370
480
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
|
7
|
+
# them to use `arr.first` and `arr.last` instead.
|
8
|
+
#
|
9
|
+
# The cop is disabled by default due to safety concerns.
|
10
|
+
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
|
13
|
+
# which returns a value for `0` or `-1` key, but changing these to use
|
14
|
+
# `.first` or `.last` will return first/last tuple instead. Also, String
|
15
|
+
# does not implement `first`/`last` methods.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# arr[0]
|
20
|
+
# arr[-1]
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# arr.first
|
24
|
+
# arr.last
|
25
|
+
# arr[0] = 2
|
26
|
+
# arr[0][-2]
|
27
|
+
#
|
28
|
+
class ArrayFirstLast < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Use `%<preferred>s`.'
|
32
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
33
|
+
|
34
|
+
# rubocop:disable Metrics/AbcSize
|
35
|
+
def on_send(node)
|
36
|
+
return unless node.arguments.size == 1 && node.first_argument.int_type?
|
37
|
+
|
38
|
+
value = node.first_argument.value
|
39
|
+
return unless [0, -1].include?(value)
|
40
|
+
|
41
|
+
node = innermost_braces_node(node)
|
42
|
+
return if node.parent && brace_method?(node.parent)
|
43
|
+
|
44
|
+
preferred = (value.zero? ? 'first' : 'last')
|
45
|
+
add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
|
46
|
+
corrector.replace(node.loc.selector, ".#{preferred}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/AbcSize
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def innermost_braces_node(node)
|
54
|
+
node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
|
55
|
+
node
|
56
|
+
end
|
57
|
+
|
58
|
+
def brace_method?(node)
|
59
|
+
node.send_type? && (node.method?(:[]) || node.method?(:[]=))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -16,31 +16,38 @@ module RuboCop
|
|
16
16
|
# File.open('file') do |f|
|
17
17
|
# # ...
|
18
18
|
# end
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# f = Tempfile.open('temp')
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# Tempfile.open('temp') do |f|
|
25
|
+
# # ...
|
26
|
+
# end
|
19
27
|
class AutoResourceCleanup < Base
|
20
|
-
MSG = 'Use the block version of `%<
|
21
|
-
|
22
|
-
TARGET_METHODS = { File: :open }.freeze
|
28
|
+
MSG = 'Use the block version of `%<current>s`.'
|
29
|
+
RESTRICT_ON_SEND = %i[open].freeze
|
23
30
|
|
24
|
-
|
31
|
+
# @!method file_open_method?(node)
|
32
|
+
def_node_matcher :file_open_method?, <<~PATTERN
|
33
|
+
(send (const {nil? cbase} {:File :Tempfile}) :open ...)
|
34
|
+
PATTERN
|
25
35
|
|
26
36
|
def on_send(node)
|
27
|
-
|
28
|
-
next if node.method_name != target_method
|
37
|
+
return if !file_open_method?(node) || cleanup?(node)
|
29
38
|
|
30
|
-
|
31
|
-
next if node.receiver != target_receiver
|
39
|
+
current = node.receiver.source_range.begin.join(node.selector.end).source
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
add_offense(node, message: format(MSG, class: target_class, method: target_method))
|
36
|
-
end
|
41
|
+
add_offense(node, message: format(MSG, current: current))
|
37
42
|
end
|
38
43
|
|
39
44
|
private
|
40
45
|
|
41
46
|
def cleanup?(node)
|
42
|
-
|
43
|
-
|
47
|
+
return true if node.block_argument?
|
48
|
+
return false unless (parent = node.parent)
|
49
|
+
|
50
|
+
parent.block_type? || !parent.lvasgn_type?
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
def on_class(class_node)
|
34
34
|
@macros_to_rewrite[class_node] = Set.new
|
35
35
|
|
36
|
-
find_macros(class_node.body).
|
36
|
+
find_macros(class_node.body).each_value do |macros|
|
37
37
|
bisected = find_bisection(macros)
|
38
38
|
next unless bisected.any?
|
39
39
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
def find_macros(class_def)
|
75
75
|
# Find all the macros (`attr_reader`, `attr_writer`, etc.) in the class body
|
76
76
|
# and turn them into `Macro` objects so that they can be processed.
|
77
|
-
return
|
77
|
+
return {} if !class_def || class_def.def_type?
|
78
78
|
|
79
79
|
send_nodes =
|
80
80
|
if class_def.send_type?
|
@@ -125,7 +125,7 @@ module RuboCop
|
|
125
125
|
when :==, :eql?, :equal?
|
126
126
|
find_target_in_equality_node(node)
|
127
127
|
when :===
|
128
|
-
node.
|
128
|
+
node.first_argument
|
129
129
|
when :include?, :cover?
|
130
130
|
find_target_in_include_or_cover_node(node)
|
131
131
|
when :match, :match?, :=~
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def find_target_in_equality_node(node)
|
137
|
-
argument = node.
|
137
|
+
argument = node.first_argument
|
138
138
|
receiver = node.receiver
|
139
139
|
return unless argument && receiver
|
140
140
|
|
@@ -152,7 +152,7 @@ module RuboCop
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def find_target_in_match_node(node)
|
155
|
-
argument = node.
|
155
|
+
argument = node.first_argument
|
156
156
|
receiver = node.receiver
|
157
157
|
return unless receiver
|
158
158
|
|
@@ -185,7 +185,7 @@ module RuboCop
|
|
185
185
|
def condition_from_send_node(node, target)
|
186
186
|
case node.method_name
|
187
187
|
when :is_a?
|
188
|
-
node.
|
188
|
+
node.first_argument if node.receiver == target
|
189
189
|
when :==, :eql?, :equal?
|
190
190
|
condition_from_equality_node(node, target)
|
191
191
|
when :=~, :match, :match?
|
@@ -23,6 +23,8 @@ module RuboCop
|
|
23
23
|
# array.reject { |e| e.nil? }
|
24
24
|
# array.delete_if { |e| e.nil? }
|
25
25
|
# array.select { |e| !e.nil? }
|
26
|
+
# array.grep_v(nil)
|
27
|
+
# array.grep_v(NilClass)
|
26
28
|
#
|
27
29
|
# # good
|
28
30
|
# array.compact
|
@@ -46,14 +48,14 @@ module RuboCop
|
|
46
48
|
extend TargetRubyVersion
|
47
49
|
|
48
50
|
MSG = 'Use `%<good>s` instead of `%<bad>s`.'
|
49
|
-
RESTRICT_ON_SEND = %i[reject delete_if reject! select select!].freeze
|
51
|
+
RESTRICT_ON_SEND = %i[reject delete_if reject! select select! grep_v].freeze
|
50
52
|
TO_ENUM_METHODS = %i[to_enum lazy].freeze
|
51
53
|
|
52
54
|
minimum_target_ruby_version 2.4
|
53
55
|
|
54
56
|
# @!method reject_method_with_block_pass?(node)
|
55
57
|
def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
|
56
|
-
(
|
58
|
+
(call !nil? {:reject :delete_if :reject!}
|
57
59
|
(block_pass
|
58
60
|
(sym :nil?)))
|
59
61
|
PATTERN
|
@@ -61,24 +63,29 @@ module RuboCop
|
|
61
63
|
# @!method reject_method?(node)
|
62
64
|
def_node_matcher :reject_method?, <<~PATTERN
|
63
65
|
(block
|
64
|
-
(
|
66
|
+
(call
|
65
67
|
!nil? {:reject :delete_if :reject!})
|
66
68
|
$(args ...)
|
67
|
-
(
|
69
|
+
(call
|
68
70
|
$(lvar _) :nil?))
|
69
71
|
PATTERN
|
70
72
|
|
71
73
|
# @!method select_method?(node)
|
72
74
|
def_node_matcher :select_method?, <<~PATTERN
|
73
75
|
(block
|
74
|
-
(
|
76
|
+
(call
|
75
77
|
!nil? {:select :select!})
|
76
78
|
$(args ...)
|
77
|
-
(
|
78
|
-
(
|
79
|
+
(call
|
80
|
+
(call
|
79
81
|
$(lvar _) :nil?) :!))
|
80
82
|
PATTERN
|
81
83
|
|
84
|
+
# @!method grep_v_with_nil?(node)
|
85
|
+
def_node_matcher :grep_v_with_nil?, <<~PATTERN
|
86
|
+
(send _ :grep_v {(nil) (const {nil? cbase} :NilClass)})
|
87
|
+
PATTERN
|
88
|
+
|
82
89
|
def on_send(node)
|
83
90
|
return unless (range = offense_range(node))
|
84
91
|
return if allowed_receiver?(node.receiver)
|
@@ -91,11 +98,13 @@ module RuboCop
|
|
91
98
|
|
92
99
|
add_offense(range, message: message) { |corrector| corrector.replace(range, good) }
|
93
100
|
end
|
101
|
+
alias on_csend on_send
|
94
102
|
|
95
103
|
private
|
96
104
|
|
105
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
97
106
|
def offense_range(node)
|
98
|
-
if reject_method_with_block_pass?(node)
|
107
|
+
if reject_method_with_block_pass?(node) || grep_v_with_nil?(node)
|
99
108
|
range(node, node)
|
100
109
|
else
|
101
110
|
block_node = node.parent
|
@@ -109,6 +118,7 @@ module RuboCop
|
|
109
118
|
range(node, block_node)
|
110
119
|
end
|
111
120
|
end
|
121
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
112
122
|
|
113
123
|
def to_enum_method?(node)
|
114
124
|
return false unless node.receiver.send_type?
|
@@ -59,8 +59,6 @@ module RuboCop
|
|
59
59
|
class CombinableLoops < Base
|
60
60
|
extend AutoCorrector
|
61
61
|
|
62
|
-
include RangeHelp
|
63
|
-
|
64
62
|
MSG = 'Combine this loop with the previous loop.'
|
65
63
|
|
66
64
|
def on_block(node)
|
@@ -105,11 +103,19 @@ module RuboCop
|
|
105
103
|
end
|
106
104
|
|
107
105
|
def combine_with_left_sibling(corrector, node)
|
108
|
-
corrector.
|
109
|
-
|
110
|
-
|
111
|
-
)
|
112
|
-
|
106
|
+
corrector.remove(node.left_sibling.body.source_range.end.join(node.left_sibling.loc.end))
|
107
|
+
corrector.remove(node.source_range.begin.join(node.body.source_range.begin))
|
108
|
+
|
109
|
+
correct_end_of_block(corrector, node)
|
110
|
+
end
|
111
|
+
|
112
|
+
def correct_end_of_block(corrector, node)
|
113
|
+
return unless node.left_sibling.respond_to?(:braces?)
|
114
|
+
return if node.right_sibling&.block_type? || node.right_sibling&.numblock_type?
|
115
|
+
|
116
|
+
end_of_block = node.left_sibling.braces? ? '}' : ' end'
|
117
|
+
corrector.remove(node.loc.end)
|
118
|
+
corrector.insert_before(node.source_range.end, end_of_block)
|
113
119
|
end
|
114
120
|
end
|
115
121
|
end
|
@@ -233,7 +233,7 @@ module RuboCop
|
|
233
233
|
PATTERN
|
234
234
|
|
235
235
|
ASSIGNMENT_TYPES.each do |type|
|
236
|
-
define_method "on_#{type}" do |node|
|
236
|
+
define_method :"on_#{type}" do |node|
|
237
237
|
return if part_of_ignored_node?(node)
|
238
238
|
return if node.parent&.shorthand_asgn?
|
239
239
|
|
@@ -534,7 +534,7 @@ module RuboCop
|
|
534
534
|
end
|
535
535
|
|
536
536
|
def element_assignment?(node)
|
537
|
-
node.send_type? && node.
|
537
|
+
node.send_type? && !node.method?(:[]=)
|
538
538
|
end
|
539
539
|
|
540
540
|
def extract_branches(node)
|
@@ -49,12 +49,12 @@ module RuboCop
|
|
49
49
|
class DateTime < Base
|
50
50
|
extend AutoCorrector
|
51
51
|
|
52
|
-
CLASS_MSG = 'Prefer Time over DateTime
|
53
|
-
COERCION_MSG = 'Do not use
|
52
|
+
CLASS_MSG = 'Prefer `Time` over `DateTime`.'
|
53
|
+
COERCION_MSG = 'Do not use `#to_datetime`.'
|
54
54
|
|
55
55
|
# @!method date_time?(node)
|
56
56
|
def_node_matcher :date_time?, <<~PATTERN
|
57
|
-
(
|
57
|
+
(call (const {nil? (cbase)} :DateTime) ...)
|
58
58
|
PATTERN
|
59
59
|
|
60
60
|
# @!method historic_date?(node)
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
|
65
65
|
# @!method to_datetime?(node)
|
66
66
|
def_node_matcher :to_datetime?, <<~PATTERN
|
67
|
-
(
|
67
|
+
(call _ :to_datetime)
|
68
68
|
PATTERN
|
69
69
|
|
70
70
|
def on_send(node)
|
@@ -75,6 +75,7 @@ module RuboCop
|
|
75
75
|
|
76
76
|
add_offense(node, message: message) { |corrector| autocorrect(corrector, node) }
|
77
77
|
end
|
78
|
+
alias on_csend on_send
|
78
79
|
|
79
80
|
private
|
80
81
|
|
@@ -32,27 +32,27 @@ module RuboCop
|
|
32
32
|
|
33
33
|
send_node = node.send_node
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
add_offense(range) do |corrector|
|
35
|
+
add_offense(send_node) do |corrector|
|
38
36
|
range_type, min, max = each_range(node)
|
39
37
|
|
40
38
|
max += 1 if range_type == :irange
|
41
39
|
|
42
|
-
corrector.replace(
|
40
|
+
corrector.replace(send_node, "#{max - min}.times")
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
44
|
private
|
47
45
|
|
48
46
|
def offending?(node)
|
47
|
+
return false unless node.arguments.empty?
|
48
|
+
|
49
49
|
each_range_with_zero_origin?(node) || each_range_without_block_argument?(node)
|
50
50
|
end
|
51
51
|
|
52
52
|
# @!method each_range(node)
|
53
53
|
def_node_matcher :each_range, <<~PATTERN
|
54
54
|
(block
|
55
|
-
(
|
55
|
+
(call
|
56
56
|
(begin
|
57
57
|
(${irange erange}
|
58
58
|
(int $_) (int $_)))
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
# @!method each_range_with_zero_origin?(node)
|
65
65
|
def_node_matcher :each_range_with_zero_origin?, <<~PATTERN
|
66
66
|
(block
|
67
|
-
(
|
67
|
+
(call
|
68
68
|
(begin
|
69
69
|
({irange erange}
|
70
70
|
(int 0) (int _)))
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
# @!method each_range_without_block_argument?(node)
|
77
77
|
def_node_matcher :each_range_without_block_argument?, <<~PATTERN
|
78
78
|
(block
|
79
|
-
(
|
79
|
+
(call
|
80
80
|
(begin
|
81
81
|
({irange erange}
|
82
82
|
(int _) (int _)))
|
@@ -58,12 +58,12 @@ module RuboCop
|
|
58
58
|
|
59
59
|
# @!method each_with_object_block_candidate?(node)
|
60
60
|
def_node_matcher :each_with_object_block_candidate?, <<~PATTERN
|
61
|
-
(block $(
|
61
|
+
(block $(call _ {:inject :reduce} _) $_ $_)
|
62
62
|
PATTERN
|
63
63
|
|
64
64
|
# @!method each_with_object_numblock_candidate?(node)
|
65
65
|
def_node_matcher :each_with_object_numblock_candidate?, <<~PATTERN
|
66
|
-
(numblock $(
|
66
|
+
(numblock $(call _ {:inject :reduce} _) 2 $_)
|
67
67
|
PATTERN
|
68
68
|
|
69
69
|
def autocorrect_block(corrector, node, return_value)
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
83
83
|
parent = node.parent
|
84
84
|
return false unless parent && %i[send super zsuper].include?(parent.type)
|
85
85
|
|
86
|
-
node.equal?(parent.
|
86
|
+
node.equal?(parent.first_argument) && !parentheses?(node.parent)
|
87
87
|
end
|
88
88
|
|
89
89
|
def replacement_range(node)
|