rubocop 1.74.0 → 1.75.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 +1 -1
- data/config/default.yml +32 -6
- data/config/obsoletion.yml +3 -1
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +35 -6
- data/lib/rubocop/config_loader.rb +4 -0
- data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
- data/lib/rubocop/config_obsoletion.rb +46 -2
- data/lib/rubocop/config_validator.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
- data/lib/rubocop/cop/layout/line_length.rb +5 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +9 -5
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -2
- data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
- data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
- data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -0
- data/lib/rubocop/cop/lint/void.rb +1 -0
- data/lib/rubocop/cop/metrics/block_length.rb +1 -0
- data/lib/rubocop/cop/metrics/method_length.rb +1 -0
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
- data/lib/rubocop/cop/naming/method_name.rb +64 -8
- data/lib/rubocop/cop/naming/variable_name.rb +6 -19
- data/lib/rubocop/cop/registry.rb +9 -6
- data/lib/rubocop/cop/style/array_intersect.rb +39 -28
- data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
- data/lib/rubocop/cop/style/collection_methods.rb +1 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +1 -0
- data/lib/rubocop/cop/style/for.rb +1 -0
- data/lib/rubocop/cop/style/guard_clause.rb +2 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +3 -2
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +105 -0
- data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -0
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
- data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
- data/lib/rubocop/cop/style/lambda.rb +1 -0
- data/lib/rubocop/cop/style/map_into_array.rb +1 -0
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -0
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -0
- data/lib/rubocop/cop/style/next.rb +44 -0
- data/lib/rubocop/cop/style/object_then.rb +1 -0
- data/lib/rubocop/cop/style/proc.rb +1 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
- data/lib/rubocop/cop/style/redundant_format.rb +10 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/redundant_self.rb +1 -0
- data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +41 -100
- data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -0
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +1 -6
- data/lib/rubocop/cop/variable_force.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +4 -4
- data/lib/rubocop/lsp/stdin_runner.rb +3 -1
- data/lib/rubocop/rspec/cop_helper.rb +4 -1
- data/lib/rubocop/rspec/shared_contexts.rb +20 -0
- data/lib/rubocop/rspec/support.rb +2 -0
- data/lib/rubocop/runner.rb +5 -1
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +14 -7
- data/lib/rubocop.rb +4 -0
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +20 -2
- metadata +10 -6
@@ -3,15 +3,18 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Checks for `raise` or `fail` statements which
|
7
|
-
#
|
6
|
+
# Checks for `raise` or `fail` statements which raise `Exception` or
|
7
|
+
# `Exception.new`. Use `StandardError` or a specific exception class instead.
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
9
|
+
# If you have defined your own namespaced `Exception` class, it is possible
|
10
|
+
# to configure the cop to allow it by setting `AllowedImplicitNamespaces` to
|
11
|
+
# an array with the names of the namespaces to allow. By default, this is set to
|
12
|
+
# `['Gem']`, which allows `Gem::Exception` to be raised without an explicit namespace.
|
13
|
+
# If not allowed, a false positive may be registered if `raise Exception` is called
|
14
|
+
# within the namespace.
|
15
|
+
#
|
16
|
+
# Alternatively, use a fully qualified name with `raise`/`fail`
|
17
|
+
# (eg. `raise Namespace::Exception`).
|
15
18
|
#
|
16
19
|
# @safety
|
17
20
|
# This cop is unsafe because it will change the exception class being
|
@@ -20,15 +23,31 @@ module RuboCop
|
|
20
23
|
# @example
|
21
24
|
# # bad
|
22
25
|
# raise Exception, 'Error message here'
|
26
|
+
# raise Exception.new('Error message here')
|
23
27
|
#
|
24
28
|
# # good
|
25
29
|
# raise StandardError, 'Error message here'
|
30
|
+
# raise MyError.new, 'Error message here'
|
31
|
+
#
|
32
|
+
# @example AllowedImplicitNamespaces: ['Gem'] (default)
|
33
|
+
# # bad - `Foo` is not an allowed implicit namespace
|
34
|
+
# module Foo
|
35
|
+
# def self.foo
|
36
|
+
# raise Exception # This is qualified to `Foo::Exception`.
|
37
|
+
# end
|
38
|
+
# end
|
26
39
|
#
|
27
|
-
# @example AllowedImplicitNamespaces: ['Gem']
|
28
40
|
# # good
|
29
41
|
# module Gem
|
30
42
|
# def self.foo
|
31
|
-
# raise Exception # This
|
43
|
+
# raise Exception # This is qualified to `Gem::Exception`.
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # good
|
48
|
+
# module Foo
|
49
|
+
# def self.foo
|
50
|
+
# raise Foo::Exception
|
32
51
|
# end
|
33
52
|
# end
|
34
53
|
class RaiseException < Base
|
@@ -53,6 +53,7 @@ module RuboCop
|
|
53
53
|
# rubocop:enable Metrics/AbcSize
|
54
54
|
|
55
55
|
alias on_numblock on_block
|
56
|
+
alias on_itblock on_block
|
56
57
|
|
57
58
|
private
|
58
59
|
|
@@ -64,6 +65,8 @@ module RuboCop
|
|
64
65
|
(args (arg _)) ...)
|
65
66
|
(numblock
|
66
67
|
$(call _ {:each_with_index :with_index} ...) 1 ...)
|
68
|
+
(itblock
|
69
|
+
$(call _ {:each_with_index :with_index} ...) _ ...)
|
67
70
|
}
|
68
71
|
PATTERN
|
69
72
|
|
@@ -49,6 +49,7 @@ module RuboCop
|
|
49
49
|
end
|
50
50
|
|
51
51
|
alias on_numblock on_block
|
52
|
+
alias on_itblock on_block
|
52
53
|
|
53
54
|
private
|
54
55
|
|
@@ -59,6 +60,8 @@ module RuboCop
|
|
59
60
|
$(call _ {:each_with_object :with_object} _) (args (arg _)) ...)
|
60
61
|
(numblock
|
61
62
|
$(call _ {:each_with_object :with_object} _) 1 ...)
|
63
|
+
(itblock
|
64
|
+
$(call _ {:each_with_object :with_object} _) _ ...)
|
62
65
|
}
|
63
66
|
PATTERN
|
64
67
|
|
@@ -56,19 +56,26 @@ module RuboCop
|
|
56
56
|
|
57
57
|
outer_local_variable = variable_table.find_variable(variable.name)
|
58
58
|
return unless outer_local_variable
|
59
|
+
return if variable_used_in_declaration_of_outer?(variable, outer_local_variable)
|
59
60
|
return if same_conditions_node_different_branch?(variable, outer_local_variable)
|
60
61
|
|
61
62
|
message = format(MSG, variable: variable.name)
|
62
63
|
add_offense(variable.declaration_node, message: message)
|
63
64
|
end
|
64
65
|
|
66
|
+
private
|
67
|
+
|
68
|
+
def variable_used_in_declaration_of_outer?(variable, outer_local_variable)
|
69
|
+
variable.scope.node.each_ancestor.any?(outer_local_variable.declaration_node)
|
70
|
+
end
|
71
|
+
|
65
72
|
def same_conditions_node_different_branch?(variable, outer_local_variable)
|
66
73
|
variable_node = variable_node(variable)
|
67
74
|
return false unless node_or_its_ascendant_conditional?(variable_node)
|
68
75
|
|
69
76
|
outer_local_variable_node =
|
70
77
|
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
71
|
-
return
|
78
|
+
return false unless outer_local_variable_node
|
72
79
|
return false unless outer_local_variable_node.conditional?
|
73
80
|
return true if variable_node == outer_local_variable_node
|
74
81
|
|
@@ -53,6 +53,7 @@ module RuboCop
|
|
53
53
|
end
|
54
54
|
|
55
55
|
alias on_numblock on_block
|
56
|
+
alias on_itblock on_block
|
56
57
|
|
57
58
|
private
|
58
59
|
|
@@ -74,6 +75,7 @@ module RuboCop
|
|
74
75
|
|
75
76
|
def arg_count(node)
|
76
77
|
return node.children[1] if node.numblock_type? # the maximum numbered param for the block
|
78
|
+
return 1 if node.itblock_type? # `it` block parameter is always one
|
77
79
|
|
78
80
|
# Only `arg`, `optarg` and `mlhs` (destructuring) count as arguments that
|
79
81
|
# can be used. Keyword arguments are not used for these methods so are
|
@@ -101,9 +101,8 @@ module RuboCop
|
|
101
101
|
check(node) if loop_method?(node)
|
102
102
|
end
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
end
|
104
|
+
alias on_numblock on_block
|
105
|
+
alias on_itblock on_block
|
107
106
|
|
108
107
|
private
|
109
108
|
|
@@ -189,8 +188,9 @@ module RuboCop
|
|
189
188
|
|
190
189
|
def preceded_by_continue_statement?(break_statement)
|
191
190
|
break_statement.left_siblings.any? do |sibling|
|
192
|
-
# Numblocks have the arguments count as a number
|
193
|
-
|
191
|
+
# Numblocks have the arguments count as a number or,
|
192
|
+
# itblocks have `:it` symbol in the AST.
|
193
|
+
next if sibling.is_a?(Integer) || sibling.is_a?(Symbol)
|
194
194
|
next if sibling.loop_keyword? || loop_method?(sibling)
|
195
195
|
|
196
196
|
sibling.each_descendant(*CONTINUE_KEYWORDS).any?
|
@@ -145,7 +145,7 @@ module RuboCop
|
|
145
145
|
|
146
146
|
def extract_body(node)
|
147
147
|
case node.type
|
148
|
-
when :class, :module, :sclass, :block, :numblock, :def, :defs
|
148
|
+
when :class, :module, :sclass, :block, :numblock, :itblock, :def, :defs
|
149
149
|
node.body
|
150
150
|
when :casgn
|
151
151
|
extract_body(node.expression)
|
@@ -48,7 +48,7 @@ module RuboCop
|
|
48
48
|
|
49
49
|
args = process_args(node.arguments)
|
50
50
|
return extract_breakable_node_from_elements(node, args, max)
|
51
|
-
elsif node.
|
51
|
+
elsif node.type?(:def, :defs)
|
52
52
|
return extract_breakable_node_from_elements(node, node.arguments, max)
|
53
53
|
elsif node.type?(:array, :hash)
|
54
54
|
return extract_breakable_node_from_elements(node, node.children, max)
|
@@ -220,7 +220,7 @@ module RuboCop
|
|
220
220
|
|
221
221
|
# @api private
|
222
222
|
def already_on_multiple_lines?(node)
|
223
|
-
return node.first_line != node.last_argument.last_line if node.
|
223
|
+
return node.first_line != node.last_argument.last_line if node.type?(:def, :defs)
|
224
224
|
|
225
225
|
!node.single_line?
|
226
226
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# This module encapsulates the ability to forbid certain identifiers in a cop.
|
6
|
+
module ForbiddenIdentifiers
|
7
|
+
SIGILS = '@$' # if a variable starts with a sigil it will be removed
|
8
|
+
|
9
|
+
def forbidden_identifier?(name)
|
10
|
+
name = name.to_s.delete(SIGILS)
|
11
|
+
|
12
|
+
forbidden_identifiers.any? && forbidden_identifiers.include?(name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def forbidden_identifiers
|
16
|
+
cop_config.fetch('ForbiddenIdentifiers', [])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# This module encapsulates the ability to forbid certain patterns in a cop.
|
6
|
+
module ForbiddenPattern
|
7
|
+
def forbidden_pattern?(name)
|
8
|
+
forbidden_patterns.any? { |pattern| Regexp.new(pattern).match?(name) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def forbidden_patterns
|
12
|
+
cop_config.fetch('ForbiddenPatterns', [])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -6,14 +6,31 @@ module RuboCop
|
|
6
6
|
# Makes sure that all methods use the configured style,
|
7
7
|
# snake_case or camelCase, for their names.
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# Method names matching patterns are always allowed.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# AllowedPatterns:
|
13
|
-
# - '\AonSelectionBulkChange\z'
|
14
|
-
# - '\AonSelectionCleared\z'
|
11
|
+
# The cop can be configured with `AllowedPatterns` to allow certain regexp patterns:
|
15
12
|
#
|
16
|
-
#
|
13
|
+
# [source,yaml]
|
14
|
+
# ----
|
15
|
+
# Naming/MethodName:
|
16
|
+
# AllowedPatterns:
|
17
|
+
# - '\AonSelectionBulkChange\z'
|
18
|
+
# - '\AonSelectionCleared\z'
|
19
|
+
# ----
|
20
|
+
#
|
21
|
+
# As well, you can also forbid specific method names or regexp patterns
|
22
|
+
# using `ForbiddenIdentifiers` or `ForbiddenPatterns`:
|
23
|
+
#
|
24
|
+
# [source,yaml]
|
25
|
+
# ----
|
26
|
+
# Naming/MethodName:
|
27
|
+
# ForbiddenIdentifiers:
|
28
|
+
# - 'def'
|
29
|
+
# - 'super'
|
30
|
+
# ForbiddenPatterns:
|
31
|
+
# - '_v1\z'
|
32
|
+
# - '_gen1\z'
|
33
|
+
# ----
|
17
34
|
#
|
18
35
|
# @example EnforcedStyle: snake_case (default)
|
19
36
|
# # bad
|
@@ -28,12 +45,26 @@ module RuboCop
|
|
28
45
|
#
|
29
46
|
# # good
|
30
47
|
# def fooBar; end
|
48
|
+
#
|
49
|
+
# @example ForbiddenIdentifiers: ['def', 'super']
|
50
|
+
# # bad
|
51
|
+
# def def; end
|
52
|
+
# def super; end
|
53
|
+
#
|
54
|
+
# @example ForbiddenPatterns: ['_v1\z', '_gen1\z']
|
55
|
+
# # bad
|
56
|
+
# def release_v1; end
|
57
|
+
# def api_gen1; end
|
58
|
+
#
|
31
59
|
class MethodName < Base
|
32
60
|
include ConfigurableNaming
|
33
61
|
include AllowedPattern
|
34
62
|
include RangeHelp
|
63
|
+
include ForbiddenIdentifiers
|
64
|
+
include ForbiddenPattern
|
35
65
|
|
36
66
|
MSG = 'Use %<style>s for method names.'
|
67
|
+
MSG_FORBIDDEN = '`%<identifier>s` is forbidden, use another method name instead.'
|
37
68
|
|
38
69
|
# @!method sym_name(node)
|
39
70
|
def_node_matcher :sym_name, '(sym $_name)'
|
@@ -48,19 +79,44 @@ module RuboCop
|
|
48
79
|
name = attr_name(name_item)
|
49
80
|
next if !name || matches_allowed_pattern?(name)
|
50
81
|
|
51
|
-
|
82
|
+
if forbidden_name?(name.to_s)
|
83
|
+
register_forbidden_name(node)
|
84
|
+
else
|
85
|
+
check_name(node, name, range_position(node))
|
86
|
+
end
|
52
87
|
end
|
53
88
|
end
|
54
89
|
|
55
90
|
def on_def(node)
|
56
91
|
return if node.operator_method? || matches_allowed_pattern?(node.method_name)
|
57
92
|
|
58
|
-
|
93
|
+
if forbidden_name?(node.method_name.to_s)
|
94
|
+
register_forbidden_name(node)
|
95
|
+
else
|
96
|
+
check_name(node, node.method_name, node.loc.name)
|
97
|
+
end
|
59
98
|
end
|
60
99
|
alias on_defs on_def
|
61
100
|
|
62
101
|
private
|
63
102
|
|
103
|
+
def forbidden_name?(name)
|
104
|
+
forbidden_identifier?(name) || forbidden_pattern?(name)
|
105
|
+
end
|
106
|
+
|
107
|
+
def register_forbidden_name(node)
|
108
|
+
if node.type?(:def, :defs)
|
109
|
+
name_node = node.loc.name
|
110
|
+
method_name = node.method_name
|
111
|
+
else
|
112
|
+
attrs = node.attribute_accessor?
|
113
|
+
name_node = attrs.last.last
|
114
|
+
method_name = attr_name(name_node)
|
115
|
+
end
|
116
|
+
message = format(MSG_FORBIDDEN, identifier: method_name)
|
117
|
+
add_offense(name_node, message: message)
|
118
|
+
end
|
119
|
+
|
64
120
|
def attr_name(name_item)
|
65
121
|
sym_name(name_item) || str_name(name_item)
|
66
122
|
end
|
@@ -53,6 +53,8 @@ module RuboCop
|
|
53
53
|
include AllowedIdentifiers
|
54
54
|
include ConfigurableNaming
|
55
55
|
include AllowedPattern
|
56
|
+
include ForbiddenIdentifiers
|
57
|
+
include ForbiddenPattern
|
56
58
|
|
57
59
|
MSG = 'Use %<style>s for variable names.'
|
58
60
|
MSG_FORBIDDEN = '`%<identifier>s` is forbidden, use another name instead.'
|
@@ -92,27 +94,12 @@ module RuboCop
|
|
92
94
|
|
93
95
|
private
|
94
96
|
|
95
|
-
def message(style)
|
96
|
-
format(MSG, style: style)
|
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
97
|
def forbidden_name?(name)
|
112
|
-
name
|
98
|
+
forbidden_identifier?(name) || forbidden_pattern?(name)
|
99
|
+
end
|
113
100
|
|
114
|
-
|
115
|
-
|
101
|
+
def message(style)
|
102
|
+
format(MSG, style: style)
|
116
103
|
end
|
117
104
|
|
118
105
|
def register_forbidden_name(node)
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -23,8 +23,8 @@ module RuboCop
|
|
23
23
|
global.without_department(:Test).cops
|
24
24
|
end
|
25
25
|
|
26
|
-
def self.qualified_cop_name(name, origin)
|
27
|
-
global.qualified_cop_name(name, origin)
|
26
|
+
def self.qualified_cop_name(name, origin, warn: true)
|
27
|
+
global.qualified_cop_name(name, origin, warn: warn)
|
28
28
|
end
|
29
29
|
|
30
30
|
# Changes momentarily the global registry
|
@@ -139,7 +139,7 @@ module RuboCop
|
|
139
139
|
|
140
140
|
case potential_badges.size
|
141
141
|
when 0 then name # No namespace found. Deal with it later in caller.
|
142
|
-
when 1 then resolve_badge(badge, potential_badges.first, path)
|
142
|
+
when 1 then resolve_badge(badge, potential_badges.first, path, warn: warn)
|
143
143
|
else raise AmbiguousCopName.new(badge, path, potential_badges)
|
144
144
|
end
|
145
145
|
end
|
@@ -296,11 +296,14 @@ module RuboCop
|
|
296
296
|
self.class.new(cops)
|
297
297
|
end
|
298
298
|
|
299
|
-
def resolve_badge(given_badge, real_badge, source_path)
|
299
|
+
def resolve_badge(given_badge, real_badge, source_path, warn: true)
|
300
300
|
unless given_badge.match?(real_badge)
|
301
301
|
path = PathUtil.smart_path(source_path)
|
302
|
-
|
303
|
-
|
302
|
+
|
303
|
+
if warn
|
304
|
+
warn("#{path}: #{given_badge} has the wrong namespace - " \
|
305
|
+
"replace it with #{given_badge.with_department(real_badge.department)}")
|
306
|
+
end
|
304
307
|
end
|
305
308
|
|
306
309
|
real_badge.to_s
|
@@ -6,7 +6,8 @@ module RuboCop
|
|
6
6
|
# In Ruby 3.1, `Array#intersect?` has been added.
|
7
7
|
#
|
8
8
|
# This cop identifies places where `(array1 & array2).any?`
|
9
|
-
# can be replaced by
|
9
|
+
# or `(array1.intersection(array2)).any?` can be replaced by
|
10
|
+
# `array1.intersect?(array2)`.
|
10
11
|
#
|
11
12
|
# The `array1.intersect?(array2)` method is faster than
|
12
13
|
# `(array1 & array2).any?` and is more readable.
|
@@ -20,6 +21,10 @@ module RuboCop
|
|
20
21
|
# [1].intersect?([1,2]) { |x| false } # => true
|
21
22
|
# ----
|
22
23
|
#
|
24
|
+
# NOTE: Although `Array#intersection` can take zero or multiple arguments,
|
25
|
+
# only cases where exactly one argument is provided can be replaced with
|
26
|
+
# `Array#intersect?` and are handled by this cop.
|
27
|
+
#
|
23
28
|
# @safety
|
24
29
|
# This cop cannot guarantee that `array1` and `array2` are
|
25
30
|
# actually arrays while method `intersect?` is for arrays only.
|
@@ -30,6 +35,11 @@ module RuboCop
|
|
30
35
|
# (array1 & array2).empty?
|
31
36
|
# (array1 & array2).none?
|
32
37
|
#
|
38
|
+
# # bad
|
39
|
+
# array1.intersection(array2).any?
|
40
|
+
# array1.intersection(array2).empty?
|
41
|
+
# array1.intersection(array2).none?
|
42
|
+
#
|
33
43
|
# # good
|
34
44
|
# array1.intersect?(array2)
|
35
45
|
# !array1.intersect?(array2)
|
@@ -53,65 +63,66 @@ module RuboCop
|
|
53
63
|
|
54
64
|
minimum_target_ruby_version 3.1
|
55
65
|
|
56
|
-
|
57
|
-
|
58
|
-
(send
|
59
|
-
(begin
|
60
|
-
(send $(...) :& $(...))
|
61
|
-
) ${:any? :empty? :none?}
|
62
|
-
)
|
63
|
-
PATTERN
|
66
|
+
PREDICATES = %i[any? empty? none?].to_set.freeze
|
67
|
+
ACTIVE_SUPPORT_PREDICATES = (PREDICATES + %i[present? blank?]).freeze
|
64
68
|
|
65
|
-
# @!method
|
66
|
-
def_node_matcher :
|
67
|
-
(
|
68
|
-
|
69
|
-
(send $
|
70
|
-
|
69
|
+
# @!method bad_intersection_check?(node, predicates)
|
70
|
+
def_node_matcher :bad_intersection_check?, <<~PATTERN
|
71
|
+
(call
|
72
|
+
{
|
73
|
+
(begin (send $_ :& $_))
|
74
|
+
(call $_ :intersection $_)
|
75
|
+
}
|
76
|
+
$%1
|
71
77
|
)
|
72
78
|
PATTERN
|
73
79
|
|
74
|
-
MSG = 'Use `%<negated>s%<receiver>s
|
75
|
-
'instead of
|
80
|
+
MSG = 'Use `%<negated>s%<receiver>s%<dot>sintersect?(%<argument>s)` ' \
|
81
|
+
'instead of `%<existing>s`.'
|
76
82
|
STRAIGHT_METHODS = %i[present? any?].freeze
|
77
83
|
NEGATED_METHODS = %i[blank? empty? none?].freeze
|
78
84
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
79
85
|
|
80
86
|
def on_send(node)
|
81
87
|
return if node.block_literal?
|
82
|
-
return unless (receiver, argument, method_name =
|
88
|
+
return unless (receiver, argument, method_name = bad_intersection?(node))
|
83
89
|
|
84
|
-
|
90
|
+
dot = node.loc.dot.source
|
91
|
+
message = message(receiver.source, argument.source, method_name, dot, node.source)
|
85
92
|
|
86
93
|
add_offense(node, message: message) do |corrector|
|
87
94
|
bang = straight?(method_name) ? '' : '!'
|
88
95
|
|
89
|
-
corrector.replace(node, "#{bang}#{receiver.source}
|
96
|
+
corrector.replace(node, "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})")
|
90
97
|
end
|
91
98
|
end
|
99
|
+
alias on_csend on_send
|
92
100
|
|
93
101
|
private
|
94
102
|
|
95
|
-
def
|
96
|
-
if active_support_extensions_enabled?
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
103
|
+
def bad_intersection?(node)
|
104
|
+
predicates = if active_support_extensions_enabled?
|
105
|
+
ACTIVE_SUPPORT_PREDICATES
|
106
|
+
else
|
107
|
+
PREDICATES
|
108
|
+
end
|
109
|
+
|
110
|
+
bad_intersection_check?(node, predicates)
|
101
111
|
end
|
102
112
|
|
103
113
|
def straight?(method_name)
|
104
114
|
STRAIGHT_METHODS.include?(method_name.to_sym)
|
105
115
|
end
|
106
116
|
|
107
|
-
def message(receiver, argument, method_name)
|
117
|
+
def message(receiver, argument, method_name, dot, existing)
|
108
118
|
negated = straight?(method_name) ? '' : '!'
|
109
119
|
format(
|
110
120
|
MSG,
|
111
121
|
negated: negated,
|
112
122
|
receiver: receiver,
|
113
123
|
argument: argument,
|
114
|
-
|
124
|
+
dot: dot,
|
125
|
+
existing: existing
|
115
126
|
)
|
116
127
|
end
|
117
128
|
end
|
@@ -208,6 +208,7 @@ module RuboCop
|
|
208
208
|
end
|
209
209
|
|
210
210
|
alias on_numblock on_block
|
211
|
+
alias on_itblock on_block
|
211
212
|
|
212
213
|
private
|
213
214
|
|
@@ -347,7 +348,7 @@ module RuboCop
|
|
347
348
|
# rubocop:disable Metrics/CyclomaticComplexity
|
348
349
|
def get_blocks(node, &block)
|
349
350
|
case node.type
|
350
|
-
when :block, :numblock
|
351
|
+
when :block, :numblock, :itblock
|
351
352
|
yield node
|
352
353
|
when :send, :csend
|
353
354
|
# When a method has an argument which is another method with a block,
|
@@ -135,6 +135,7 @@ module RuboCop
|
|
135
135
|
on_def(node)
|
136
136
|
end
|
137
137
|
alias on_numblock on_block
|
138
|
+
alias on_itblock on_block
|
138
139
|
|
139
140
|
def on_if(node)
|
140
141
|
return if accepted_form?(node)
|
@@ -213,7 +214,7 @@ module RuboCop
|
|
213
214
|
if_branch = node.if_branch
|
214
215
|
else_branch = node.else_branch
|
215
216
|
|
216
|
-
corrector.replace(node.loc.begin, "\n") if node.
|
217
|
+
corrector.replace(node.loc.begin, "\n") if node.then?
|
217
218
|
|
218
219
|
if if_branch&.send_type? && heredoc?(if_branch.last_argument)
|
219
220
|
autocorrect_heredoc_argument(corrector, node, if_branch, else_branch, guard)
|