rubocop 1.60.0 → 1.61.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.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +35 -12
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli.rb +6 -1
- data/lib/rubocop/config_finder.rb +12 -2
- data/lib/rubocop/config_validator.rb +14 -5
- data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
- data/lib/rubocop/cop/base.rb +12 -7
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +2 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +7 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -9
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/syntax.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +6 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/registry.rb +5 -5
- data/lib/rubocop/cop/style/arguments_forwarding.rb +69 -13
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/collection_compact.rb +11 -2
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -5
- data/lib/rubocop/cop/style/hash_each_methods.rb +26 -5
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -8
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -5
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +5 -8
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +4 -0
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
- data/lib/rubocop/cop/style/raise_args.rb +3 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -2
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -5
- data/lib/rubocop/cop/style/redundant_parentheses.rb +8 -1
- data/lib/rubocop/cop/style/redundant_return.rb +6 -0
- data/lib/rubocop/cop/style/sample.rb +1 -3
- data/lib/rubocop/cops_documentation_generator.rb +4 -2
- data/lib/rubocop/formatter/html_formatter.rb +30 -10
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/lsp/logger.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +1 -1
- data/lib/rubocop/lsp/server.rb +5 -2
- data/lib/rubocop/lsp/severity.rb +1 -1
- data/lib/rubocop/lsp.rb +29 -0
- data/lib/rubocop/options.rb +11 -0
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/rspec/shared_contexts.rb +10 -6
- data/lib/rubocop/rspec/support.rb +1 -1
- data/lib/rubocop/server/cache.rb +1 -1
- data/lib/rubocop/server/client_command/exec.rb +0 -1
- data/lib/rubocop/server/server_command/exec.rb +0 -1
- data/lib/rubocop/target_ruby.rb +79 -79
- data/lib/rubocop/version.rb +1 -1
- metadata +11 -8
|
@@ -34,18 +34,14 @@ module RuboCop
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def offending_range
|
|
37
|
+
begin_range = block_node.source_range.begin
|
|
38
|
+
|
|
37
39
|
if block_node.arguments?
|
|
38
|
-
|
|
40
|
+
begin_range.join(argument_node.source_range.end)
|
|
39
41
|
else
|
|
40
|
-
|
|
42
|
+
begin_range.join(block_node.loc.begin.end)
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
|
-
|
|
44
|
-
def replacement_range(end_pos)
|
|
45
|
-
Parser::Source::Range.new(block_node.source_range.source_buffer,
|
|
46
|
-
block_node.source_range.begin_pos,
|
|
47
|
-
end_pos)
|
|
48
|
-
end
|
|
49
45
|
end
|
|
50
46
|
end
|
|
51
47
|
end
|
|
@@ -15,6 +15,8 @@ module RuboCop
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def call(corrector)
|
|
18
|
+
offending_range = for_node.source_range.begin.join(end_range)
|
|
19
|
+
|
|
18
20
|
corrector.replace(offending_range, correction)
|
|
19
21
|
end
|
|
20
22
|
|
|
@@ -40,11 +42,11 @@ module RuboCop
|
|
|
40
42
|
collection_node.range_type? || collection_node.or_type? || collection_node.and_type?
|
|
41
43
|
end
|
|
42
44
|
|
|
43
|
-
def
|
|
45
|
+
def end_range
|
|
44
46
|
if for_node.do?
|
|
45
|
-
keyword_begin.
|
|
47
|
+
keyword_begin.end
|
|
46
48
|
else
|
|
47
|
-
collection_end.
|
|
49
|
+
collection_end.end
|
|
48
50
|
end
|
|
49
51
|
end
|
|
50
52
|
|
|
@@ -59,16 +61,6 @@ module RuboCop
|
|
|
59
61
|
collection_node.source_range
|
|
60
62
|
end
|
|
61
63
|
end
|
|
62
|
-
|
|
63
|
-
def offending_range
|
|
64
|
-
replacement_range(end_position)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def replacement_range(end_pos)
|
|
68
|
-
Parser::Source::Range.new(for_node.source_range.source_buffer,
|
|
69
|
-
for_node.source_range.begin_pos,
|
|
70
|
-
end_pos)
|
|
71
|
-
end
|
|
72
64
|
end
|
|
73
65
|
end
|
|
74
66
|
end
|
|
@@ -63,10 +63,10 @@ module RuboCop
|
|
|
63
63
|
expect_correction: EXPECT_CORRECTION_DESCRIPTION_MAPPING
|
|
64
64
|
}.freeze
|
|
65
65
|
|
|
66
|
-
# @!method offense_example
|
|
67
|
-
def_node_matcher :offense_example
|
|
66
|
+
# @!method offense_example(node)
|
|
67
|
+
def_node_matcher :offense_example, <<~PATTERN
|
|
68
68
|
(block
|
|
69
|
-
(send _ {:it :specify}
|
|
69
|
+
(send _ {:it :specify} $...)
|
|
70
70
|
_args
|
|
71
71
|
`(send nil? %RESTRICT_ON_SEND ...)
|
|
72
72
|
)
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
|
74
74
|
|
|
75
75
|
def on_send(node)
|
|
76
76
|
parent = node.each_ancestor(:block).first
|
|
77
|
-
return unless parent && (current_description = offense_example
|
|
77
|
+
return unless parent && (current_description = offense_example(parent)&.first)
|
|
78
78
|
|
|
79
79
|
method_name = node.method_name
|
|
80
80
|
message = format(MSG, method_name: method_name)
|
|
@@ -30,6 +30,7 @@ module RuboCop
|
|
|
30
30
|
extend AutoCorrector
|
|
31
31
|
|
|
32
32
|
MSG = 'Use `%<method_name>s` instead of `%<method_suffix>s`.'
|
|
33
|
+
RESTRICT_ON_SEND = %i[end_with?].freeze
|
|
33
34
|
SUGGEST_METHOD_FOR_SUFFIX = {
|
|
34
35
|
'=' => 'assignment_method?',
|
|
35
36
|
'!' => 'bang_method?',
|
|
@@ -51,14 +52,15 @@ module RuboCop
|
|
|
51
52
|
|
|
52
53
|
def on_send(node)
|
|
53
54
|
method_name_end_with?(node) do |method_name_node, end_with_arg|
|
|
55
|
+
next unless method_name_node.receiver
|
|
56
|
+
|
|
57
|
+
preferred_method = SUGGEST_METHOD_FOR_SUFFIX[end_with_arg.value]
|
|
54
58
|
range = range(method_name_node, node)
|
|
55
|
-
message = format(
|
|
56
|
-
MSG,
|
|
57
|
-
method_name: SUGGEST_METHOD_FOR_SUFFIX[end_with_arg.value],
|
|
58
|
-
method_suffix: range.source
|
|
59
|
-
)
|
|
59
|
+
message = format(MSG, method_name: preferred_method, method_suffix: range.source)
|
|
60
60
|
|
|
61
|
-
add_offense(range, message: message)
|
|
61
|
+
add_offense(range, message: message) do |corrector|
|
|
62
|
+
corrector.replace(range, preferred_method)
|
|
63
|
+
end
|
|
62
64
|
end
|
|
63
65
|
end
|
|
64
66
|
alias on_csend on_send
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module InternalAffairs
|
|
6
|
+
# Checks for redundant arguments of `RuboCop::RSpec::ExpectOffense`'s methods.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
#
|
|
10
|
+
# # bad
|
|
11
|
+
# expect_no_offenses('code', keyword: keyword)
|
|
12
|
+
#
|
|
13
|
+
# # good
|
|
14
|
+
# expect_no_offenses('code')
|
|
15
|
+
#
|
|
16
|
+
class RedundantExpectOffenseArguments < Base
|
|
17
|
+
extend AutoCorrector
|
|
18
|
+
|
|
19
|
+
MSG = 'Remove the redundant arguments.'
|
|
20
|
+
RESTRICT_ON_SEND = %i[expect_no_offenses].freeze
|
|
21
|
+
|
|
22
|
+
def on_send(node)
|
|
23
|
+
return if node.arguments.one? || !node.arguments[1]&.hash_type?
|
|
24
|
+
|
|
25
|
+
range = node.first_argument.source_range.end.join(node.last_argument.source_range.end)
|
|
26
|
+
|
|
27
|
+
add_offense(range) do |corrector|
|
|
28
|
+
corrector.remove(range)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -20,6 +20,7 @@ require_relative 'internal_affairs/offense_location_keyword'
|
|
|
20
20
|
require_relative 'internal_affairs/processed_source_buffer_name'
|
|
21
21
|
require_relative 'internal_affairs/redundant_context_config_parameter'
|
|
22
22
|
require_relative 'internal_affairs/redundant_described_class_as_subject'
|
|
23
|
+
require_relative 'internal_affairs/redundant_expect_offense_arguments'
|
|
23
24
|
require_relative 'internal_affairs/redundant_let_rubocop_config_new'
|
|
24
25
|
require_relative 'internal_affairs/redundant_location_argument'
|
|
25
26
|
require_relative 'internal_affairs/redundant_message_argument'
|
|
@@ -20,7 +20,9 @@ module RuboCop
|
|
|
20
20
|
# This `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`)
|
|
21
21
|
# by default. On the other hand, `Layout/BeginEndAlignment` cop aligns with
|
|
22
22
|
# `EnforcedStyleAlignWith: start_of_line` by default due to `||= begin` tends
|
|
23
|
-
# to align with the start of the line.
|
|
23
|
+
# to align with the start of the line. `Layout/DefEndAlignment` cop also aligns with
|
|
24
|
+
# `EnforcedStyleAlignWith: start_of_line` by default.
|
|
25
|
+
# These style can be configured by each cop.
|
|
24
26
|
#
|
|
25
27
|
# @example EnforcedStyleAlignWith: keyword (default)
|
|
26
28
|
# # bad
|
|
@@ -85,7 +85,13 @@ module RuboCop
|
|
|
85
85
|
|
|
86
86
|
def offense?(node)
|
|
87
87
|
node.multiline? && !too_long?(node) && suitable_as_single_line?(node) &&
|
|
88
|
-
!configured_to_not_be_inspected?(node)
|
|
88
|
+
!index_access_call_chained?(node) && !configured_to_not_be_inspected?(node)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def index_access_call_chained?(node)
|
|
92
|
+
return false unless node.send_type? && node.method?(:[])
|
|
93
|
+
|
|
94
|
+
node.children.first.send_type? && node.children.first.method?(:[])
|
|
89
95
|
end
|
|
90
96
|
|
|
91
97
|
def configured_to_not_be_inspected?(node)
|
|
@@ -81,19 +81,28 @@ module RuboCop
|
|
|
81
81
|
private
|
|
82
82
|
|
|
83
83
|
def check_empty(left_brace, space_plus_brace, used_style)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
if style_for_empty_braces == used_style
|
|
85
|
+
handle_different_styles_for_empty_braces(used_style)
|
|
86
|
+
return
|
|
87
|
+
elsif !config_to_allow_offenses.key?('Enabled')
|
|
88
|
+
config_to_allow_offenses['EnforcedStyleForEmptyBraces'] = used_style.to_s
|
|
89
|
+
end
|
|
87
90
|
|
|
88
91
|
if style_for_empty_braces == :space
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
end
|
|
92
|
+
range = left_brace
|
|
93
|
+
msg = MISSING_MSG
|
|
92
94
|
else
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
range = range_between(space_plus_brace.begin_pos, left_brace.begin_pos)
|
|
96
|
+
msg = DETECTED_MSG
|
|
97
|
+
end
|
|
98
|
+
add_offense(range, message: msg) { |corrector| autocorrect(corrector, range) }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def handle_different_styles_for_empty_braces(used_style)
|
|
102
|
+
if config_to_allow_offenses['EnforcedStyleForEmptyBraces'] &&
|
|
103
|
+
config_to_allow_offenses['EnforcedStyleForEmptyBraces'].to_sym != used_style
|
|
104
|
+
config_to_allow_offenses.clear
|
|
105
|
+
config_to_allow_offenses['Enabled'] = false
|
|
97
106
|
end
|
|
98
107
|
end
|
|
99
108
|
|
|
@@ -104,7 +104,7 @@ module RuboCop
|
|
|
104
104
|
def correct_other_branches(corrector, node)
|
|
105
105
|
return unless require_other_branches_correction?(node)
|
|
106
106
|
|
|
107
|
-
if node.else_branch&.if_type?
|
|
107
|
+
if node.else_branch&.if_type? && !node.else_branch.modifier_form?
|
|
108
108
|
# Replace an orphaned `elsif` with `if`
|
|
109
109
|
corrector.replace(node.else_branch.loc.keyword, 'if')
|
|
110
110
|
else
|
|
@@ -5,7 +5,8 @@ module RuboCop
|
|
|
5
5
|
module Lint
|
|
6
6
|
# Checks for redundant safe navigation calls.
|
|
7
7
|
# Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
|
|
8
|
-
# and an offense is not detected when the receiver is a
|
|
8
|
+
# and an offense is not detected when the receiver is a constant. The detection also applies
|
|
9
|
+
# to literal receivers, except for `nil`.
|
|
9
10
|
#
|
|
10
11
|
# For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
|
|
11
12
|
# and `equal?` methods are checked by default.
|
|
@@ -76,10 +77,9 @@ module RuboCop
|
|
|
76
77
|
#
|
|
77
78
|
class RedundantSafeNavigation < Base
|
|
78
79
|
include AllowedMethods
|
|
79
|
-
include RangeHelp
|
|
80
80
|
extend AutoCorrector
|
|
81
81
|
|
|
82
|
-
MSG = 'Redundant safe navigation detected.'
|
|
82
|
+
MSG = 'Redundant safe navigation detected, use `.` instead.'
|
|
83
83
|
MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
|
|
84
84
|
|
|
85
85
|
NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
|
|
@@ -105,24 +105,23 @@ module RuboCop
|
|
|
105
105
|
|
|
106
106
|
# rubocop:disable Metrics/AbcSize
|
|
107
107
|
def on_csend(node)
|
|
108
|
-
unless
|
|
108
|
+
unless assume_receiver_instance_exists?(node.receiver)
|
|
109
109
|
return unless check?(node) && allowed_method?(node.method_name)
|
|
110
110
|
return if respond_to_nil_specific_method?(node)
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
range =
|
|
114
|
-
add_offense(range) { |corrector| corrector.replace(
|
|
113
|
+
range = node.loc.dot
|
|
114
|
+
add_offense(range) { |corrector| corrector.replace(range, '.') }
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def on_or(node)
|
|
118
118
|
conversion_with_default?(node) do |send_node|
|
|
119
|
-
range =
|
|
119
|
+
range = send_node.loc.dot.begin.join(node.source_range.end)
|
|
120
120
|
|
|
121
121
|
add_offense(range, message: MSG_LITERAL) do |corrector|
|
|
122
122
|
corrector.replace(send_node.loc.dot, '.')
|
|
123
123
|
|
|
124
|
-
range_with_default =
|
|
125
|
-
node.source_range.end.end_pos)
|
|
124
|
+
range_with_default = node.lhs.source_range.end.begin.join(node.source_range.end)
|
|
126
125
|
corrector.remove(range_with_default)
|
|
127
126
|
end
|
|
128
127
|
end
|
|
@@ -131,6 +130,12 @@ module RuboCop
|
|
|
131
130
|
|
|
132
131
|
private
|
|
133
132
|
|
|
133
|
+
def assume_receiver_instance_exists?(receiver)
|
|
134
|
+
return true if receiver.const_type? && !receiver.source.match?(SNAKE_CASE)
|
|
135
|
+
|
|
136
|
+
receiver.literal? && !receiver.nil_type?
|
|
137
|
+
end
|
|
138
|
+
|
|
134
139
|
def check?(node)
|
|
135
140
|
parent = node.parent
|
|
136
141
|
return false unless parent
|
|
@@ -59,9 +59,7 @@ module RuboCop
|
|
|
59
59
|
|
|
60
60
|
def autocorrect(corrector, node)
|
|
61
61
|
rescued, _, _body = *node
|
|
62
|
-
range =
|
|
63
|
-
node.loc.keyword.end_pos,
|
|
64
|
-
rescued.source_range.end_pos)
|
|
62
|
+
range = node.loc.keyword.end.join(rescued.source_range.end)
|
|
65
63
|
|
|
66
64
|
corrector.replace(range, correction(*rescued))
|
|
67
65
|
end
|
|
@@ -46,14 +46,14 @@ module RuboCop
|
|
|
46
46
|
message = format_message_from(processed_source)
|
|
47
47
|
|
|
48
48
|
add_offense(comment, message: message) do
|
|
49
|
-
autocorrect
|
|
49
|
+
autocorrect if autocorrect_requested?
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
private
|
|
54
54
|
|
|
55
|
-
def autocorrect
|
|
56
|
-
FileUtils.chmod('+x',
|
|
55
|
+
def autocorrect
|
|
56
|
+
FileUtils.chmod('+x', processed_source.file_path)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def executable?(processed_source)
|
|
@@ -100,7 +100,12 @@ module RuboCop
|
|
|
100
100
|
expressions = *node
|
|
101
101
|
expressions.pop unless in_void_context?(node)
|
|
102
102
|
expressions.each do |expr|
|
|
103
|
-
check_void_op(expr)
|
|
103
|
+
check_void_op(expr) do
|
|
104
|
+
block_node = node.each_ancestor(:block).first
|
|
105
|
+
|
|
106
|
+
block_node&.method?(:each)
|
|
107
|
+
end
|
|
108
|
+
|
|
104
109
|
check_expression(expr)
|
|
105
110
|
end
|
|
106
111
|
end
|
|
@@ -99,7 +99,7 @@ module RuboCop
|
|
|
99
99
|
!(method_name.start_with?(prefix) && # cheap check to avoid allocating Regexp
|
|
100
100
|
method_name.match?(/^#{prefix}[^0-9]/)) ||
|
|
101
101
|
method_name == expected_name(method_name, prefix) ||
|
|
102
|
-
method_name.end_with?('=') ||
|
|
102
|
+
method_name.end_with?('=') ||
|
|
103
103
|
allowed_method?(method_name)
|
|
104
104
|
end
|
|
105
105
|
|
|
@@ -109,7 +109,7 @@ module RuboCop
|
|
|
109
109
|
else
|
|
110
110
|
method_name.dup
|
|
111
111
|
end
|
|
112
|
-
new_name << '?' unless method_name.end_with?('?')
|
|
112
|
+
new_name << '?' unless method_name.end_with?('?')
|
|
113
113
|
new_name
|
|
114
114
|
end
|
|
115
115
|
|
data/lib/rubocop/cop/registry.rb
CHANGED
|
@@ -240,12 +240,12 @@ module RuboCop
|
|
|
240
240
|
self
|
|
241
241
|
end
|
|
242
242
|
|
|
243
|
-
def select(
|
|
244
|
-
cops.select(
|
|
243
|
+
def select(&block)
|
|
244
|
+
cops.select(&block)
|
|
245
245
|
end
|
|
246
246
|
|
|
247
|
-
def each(
|
|
248
|
-
cops.each(
|
|
247
|
+
def each(&block)
|
|
248
|
+
cops.each(&block)
|
|
249
249
|
end
|
|
250
250
|
|
|
251
251
|
# @param [String] cop_name
|
|
@@ -300,7 +300,7 @@ module RuboCop
|
|
|
300
300
|
unless given_badge.match?(real_badge)
|
|
301
301
|
path = PathUtil.smart_path(source_path)
|
|
302
302
|
warn "#{path}: #{given_badge} has the wrong namespace - " \
|
|
303
|
-
"
|
|
303
|
+
"replace it with #{given_badge.with_department(real_badge.department)}"
|
|
304
304
|
end
|
|
305
305
|
|
|
306
306
|
real_badge.to_s
|
|
@@ -8,6 +8,12 @@ module RuboCop
|
|
|
8
8
|
# This cop identifies places where `do_something(*args, &block)`
|
|
9
9
|
# can be replaced by `do_something(...)`.
|
|
10
10
|
#
|
|
11
|
+
# In Ruby 3.1, anonymous block forwarding has been added.
|
|
12
|
+
#
|
|
13
|
+
# This cop identifies places where `do_something(&block)` can be replaced
|
|
14
|
+
# by `do_something(&)`; if desired, this functionality can be disabled
|
|
15
|
+
# by setting `UseAnonymousForwarding: false`.
|
|
16
|
+
#
|
|
11
17
|
# In Ruby 3.2, anonymous args/kwargs forwarding has been added.
|
|
12
18
|
#
|
|
13
19
|
# This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
|
|
@@ -41,22 +47,25 @@ module RuboCop
|
|
|
41
47
|
#
|
|
42
48
|
# @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
|
|
43
49
|
# # bad
|
|
44
|
-
# def foo(*args, **kwargs)
|
|
50
|
+
# def foo(*args, **kwargs, &block)
|
|
45
51
|
# args_only(*args)
|
|
46
52
|
# kwargs_only(**kwargs)
|
|
53
|
+
# block_only(&block)
|
|
47
54
|
# end
|
|
48
55
|
#
|
|
49
56
|
# # good
|
|
50
|
-
# def foo(*,
|
|
57
|
+
# def foo(*, **, &)
|
|
51
58
|
# args_only(*)
|
|
52
59
|
# kwargs_only(**)
|
|
60
|
+
# block_only(&)
|
|
53
61
|
# end
|
|
54
62
|
#
|
|
55
63
|
# @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
|
|
56
64
|
# # good
|
|
57
|
-
# def foo(*args, **kwargs)
|
|
65
|
+
# def foo(*args, **kwargs, &block)
|
|
58
66
|
# args_only(*args)
|
|
59
67
|
# kwargs_only(**kwargs)
|
|
68
|
+
# block_only(&block)
|
|
60
69
|
# end
|
|
61
70
|
#
|
|
62
71
|
# @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
|
|
@@ -104,7 +113,7 @@ module RuboCop
|
|
|
104
113
|
# end
|
|
105
114
|
#
|
|
106
115
|
# @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
|
|
107
|
-
# # bad
|
|
116
|
+
# # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
|
|
108
117
|
# def foo(&block)
|
|
109
118
|
# bar(&block)
|
|
110
119
|
# end
|
|
@@ -126,6 +135,7 @@ module RuboCop
|
|
|
126
135
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
|
127
136
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
|
128
137
|
KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
|
|
138
|
+
BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
|
|
129
139
|
|
|
130
140
|
def self.autocorrect_incompatible_with
|
|
131
141
|
[Naming::BlockForwarding]
|
|
@@ -171,21 +181,40 @@ module RuboCop
|
|
|
171
181
|
send_classifications.all? { |_, c, _, _| c == :all }
|
|
172
182
|
end
|
|
173
183
|
|
|
184
|
+
# rubocop:disable Metrics/MethodLength
|
|
174
185
|
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
_rest_arg, _kwrest_arg, block_arg = *forwardable_args
|
|
187
|
+
registered_block_arg_offense = false
|
|
188
|
+
|
|
189
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
|
190
|
+
if !forward_rest && !forward_kwrest
|
|
191
|
+
# Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
|
|
192
|
+
# in Ruby 3.3.0.
|
|
193
|
+
if outside_block?(forward_block_arg)
|
|
194
|
+
register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
|
|
195
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
|
196
|
+
end
|
|
197
|
+
registered_block_arg_offense = true
|
|
198
|
+
break
|
|
199
|
+
else
|
|
200
|
+
register_forward_all_offense(send_node, send_node, forward_rest)
|
|
201
|
+
end
|
|
177
202
|
end
|
|
178
203
|
|
|
204
|
+
return if registered_block_arg_offense
|
|
205
|
+
|
|
179
206
|
rest_arg, _kwrest_arg, _block_arg = *forwardable_args
|
|
180
207
|
register_forward_all_offense(node, node.arguments, rest_arg)
|
|
181
208
|
end
|
|
209
|
+
# rubocop:enable Metrics/MethodLength
|
|
182
210
|
|
|
211
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
183
212
|
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
|
184
213
|
return unless use_anonymous_forwarding?
|
|
185
214
|
|
|
186
|
-
rest_arg, kwrest_arg,
|
|
215
|
+
rest_arg, kwrest_arg, block_arg = *forwardable_args
|
|
187
216
|
|
|
188
|
-
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
|
|
217
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
|
189
218
|
if outside_block?(forward_rest)
|
|
190
219
|
register_forward_args_offense(def_node.arguments, rest_arg)
|
|
191
220
|
register_forward_args_offense(send_node, forward_rest)
|
|
@@ -195,8 +224,16 @@ module RuboCop
|
|
|
195
224
|
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
|
196
225
|
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
|
197
226
|
end
|
|
227
|
+
|
|
228
|
+
# Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
|
|
229
|
+
# in Ruby 3.3.0.
|
|
230
|
+
if outside_block?(forward_block_arg)
|
|
231
|
+
register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
|
|
232
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
|
233
|
+
end
|
|
198
234
|
end
|
|
199
235
|
end
|
|
236
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
200
237
|
|
|
201
238
|
def non_splat_or_block_pass_lvar_references(body)
|
|
202
239
|
body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
|
|
@@ -225,10 +262,7 @@ module RuboCop
|
|
|
225
262
|
|
|
226
263
|
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
|
227
264
|
classifier = SendNodeClassifier.new(
|
|
228
|
-
def_node,
|
|
229
|
-
send_node,
|
|
230
|
-
referenced_lvars,
|
|
231
|
-
forwardable_args,
|
|
265
|
+
def_node, send_node, referenced_lvars, forwardable_args,
|
|
232
266
|
target_ruby_version: target_ruby_version,
|
|
233
267
|
allow_only_rest_arguments: allow_only_rest_arguments?
|
|
234
268
|
)
|
|
@@ -237,7 +271,12 @@ module RuboCop
|
|
|
237
271
|
|
|
238
272
|
return unless classification
|
|
239
273
|
|
|
240
|
-
[
|
|
274
|
+
[
|
|
275
|
+
classification,
|
|
276
|
+
classifier.forwarded_rest_arg,
|
|
277
|
+
classifier.forwarded_kwrest_arg,
|
|
278
|
+
classifier.forwarded_block_arg
|
|
279
|
+
]
|
|
241
280
|
end
|
|
242
281
|
|
|
243
282
|
def redundant_named_arg(arg, config_name, keyword)
|
|
@@ -272,6 +311,16 @@ module RuboCop
|
|
|
272
311
|
end
|
|
273
312
|
end
|
|
274
313
|
|
|
314
|
+
def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
|
|
315
|
+
return if target_ruby_version <= 3.0 || block_arg.source == '&' || explicit_block_name?
|
|
316
|
+
|
|
317
|
+
add_offense(block_arg, message: BLOCK_MSG) do |corrector|
|
|
318
|
+
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
|
319
|
+
|
|
320
|
+
corrector.replace(block_arg, '&')
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
275
324
|
def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
|
|
276
325
|
arg_range = arguments_range(def_or_send, rest_or_splat)
|
|
277
326
|
|
|
@@ -441,6 +490,13 @@ module RuboCop
|
|
|
441
490
|
(@kwrest_arg_name && !forwarded_kwrest_arg)
|
|
442
491
|
end
|
|
443
492
|
end
|
|
493
|
+
|
|
494
|
+
def explicit_block_name?
|
|
495
|
+
block_forwarding_config = config.for_cop('Naming/BlockForwarding')
|
|
496
|
+
return false unless block_forwarding_config['Enabled']
|
|
497
|
+
|
|
498
|
+
block_forwarding_config['EnforcedStyle'] == 'explicit'
|
|
499
|
+
end
|
|
444
500
|
end
|
|
445
501
|
end
|
|
446
502
|
end
|
|
@@ -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,7 +48,7 @@ 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
|
|
@@ -79,6 +81,11 @@ module RuboCop
|
|
|
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)
|
|
@@ -95,8 +102,9 @@ module RuboCop
|
|
|
95
102
|
|
|
96
103
|
private
|
|
97
104
|
|
|
105
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
98
106
|
def offense_range(node)
|
|
99
|
-
if reject_method_with_block_pass?(node)
|
|
107
|
+
if reject_method_with_block_pass?(node) || grep_v_with_nil?(node)
|
|
100
108
|
range(node, node)
|
|
101
109
|
else
|
|
102
110
|
block_node = node.parent
|
|
@@ -110,6 +118,7 @@ module RuboCop
|
|
|
110
118
|
range(node, block_node)
|
|
111
119
|
end
|
|
112
120
|
end
|
|
121
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
113
122
|
|
|
114
123
|
def to_enum_method?(node)
|
|
115
124
|
return false unless node.receiver.send_type?
|