rubocop 1.73.2 → 1.75.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/README.md +1 -1
- data/config/default.yml +63 -8
- 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_loader_resolver.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
- 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 +2 -1
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
- data/lib/rubocop/cop/layout/block_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +3 -3
- 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 +3 -5
- 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/deprecated_open_ssl_constant.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -3
- data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
- data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +16 -7
- 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/return_in_void_context.rb +9 -11
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
- 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/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/useless_constant_scoping.rb +2 -11
- 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/check_single_line_suitability.rb +2 -2
- 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/forbidden_identifiers.rb +20 -0
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- 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/class_and_module_children.rb +29 -7
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -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/commented_keyword.rb +9 -2
- data/lib/rubocop/cop/style/comparable_between.rb +75 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -0
- data/lib/rubocop/cop/style/double_negation.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +4 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +1 -0
- data/lib/rubocop/cop/style/format_string_token.rb +38 -11
- 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/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/hash_syntax.rb +3 -0
- data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
- data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -2
- 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/keyword_parameters_order.rb +1 -1
- 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_call_with_args_parentheses/omit_parentheses.rb +4 -4
- 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/raise_args.rb +8 -8
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +13 -1
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
- 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/rescue_modifier.rb +3 -0
- data/lib/rubocop/cop/style/return_nil.rb +2 -2
- 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/super_arguments.rb +1 -2
- 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/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +2 -7
- data/lib/rubocop/cop/variable_force.rb +1 -1
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- data/lib/rubocop/lsp/runtime.rb +4 -4
- data/lib/rubocop/lsp/stdin_runner.rb +3 -1
- data/lib/rubocop/magic_comment.rb +8 -0
- 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/server/cache.rb +13 -10
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +14 -7
- data/lib/rubocop.rb +5 -0
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +20 -2
- metadata +11 -6
@@ -35,12 +35,12 @@ module RuboCop
|
|
35
35
|
comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
|
36
36
|
|
37
37
|
comment_line_numbers.any? do |comment_line_number|
|
38
|
-
comment_line_number
|
38
|
+
comment_line_number.between?(node.first_line, node.last_line)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
def safe_to_split?(node)
|
43
|
-
node.each_descendant(:if, :case, :kwbegin, :
|
43
|
+
node.each_descendant(:if, :case, :kwbegin, :any_def).none? &&
|
44
44
|
node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
|
45
45
|
node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
|
46
46
|
end
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
|
20
20
|
# @!method non_public_modifier?(node)
|
21
21
|
def_node_matcher :non_public_modifier?, <<~PATTERN
|
22
|
-
(send nil? {:private :protected :private_class_method} (
|
22
|
+
(send nil? {:private :protected :private_class_method} (any_def ...))
|
23
23
|
PATTERN
|
24
24
|
end
|
25
25
|
end
|
@@ -21,7 +21,7 @@ module RuboCop
|
|
21
21
|
|
22
22
|
# @!method empty_line_required?(node)
|
23
23
|
def_node_matcher :empty_line_required?,
|
24
|
-
'{
|
24
|
+
'{any_def class module (send nil? {:private :protected :public})}'
|
25
25
|
|
26
26
|
def check(node, body, adjusted_first_line: nil)
|
27
27
|
return if valid_body_style?(body)
|
@@ -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,7 +6,6 @@ module RuboCop
|
|
6
6
|
module FrozenStringLiteral
|
7
7
|
module_function
|
8
8
|
|
9
|
-
FROZEN_STRING_LITERAL_REGEXP = /#\s*frozen[-_]?string[-_]?literal:/i.freeze
|
10
9
|
FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
|
11
10
|
FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
|
12
11
|
|
@@ -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
|
@@ -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.any_def_type?
|
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,
|
@@ -3,14 +3,26 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks
|
7
|
-
#
|
6
|
+
# Checks that namespaced classes and modules are defined with a consistent style.
|
7
|
+
#
|
8
|
+
# With `nested` style, classes and modules should be defined separately (one constant
|
9
|
+
# on each line, without `::`). With `compact` style, classes and modules should be
|
10
|
+
# defined with fully qualified names (using `::` for namespaces).
|
11
|
+
#
|
12
|
+
# NOTE: The style chosen will affect `Module.nesting` for the class or module. Using
|
13
|
+
# `nested` style will result in each level being added, whereas `compact` style will
|
14
|
+
# only include the fully qualified class or module name.
|
15
|
+
#
|
16
|
+
# By default, `EnforcedStyle` applies to both classes and modules. If desired, separate
|
17
|
+
# styles can be defined for classes and modules by using `EnforcedStyleForClasses` and
|
18
|
+
# `EnforcedStyleForModules` respectively. If not set, or set to nil, the `EnforcedStyle`
|
19
|
+
# value will be used.
|
8
20
|
#
|
9
21
|
# @safety
|
10
22
|
# Autocorrection is unsafe.
|
11
23
|
#
|
12
|
-
# Moving from compact to nested children requires knowledge of whether the
|
13
|
-
# outer parent is a module or a class. Moving from nested to compact requires
|
24
|
+
# Moving from `compact` to `nested` children requires knowledge of whether the
|
25
|
+
# outer parent is a module or a class. Moving from `nested` to `compact` requires
|
14
26
|
# verification that the outer parent is defined elsewhere. RuboCop does not
|
15
27
|
# have the knowledge to perform either operation safely and thus requires
|
16
28
|
# manual oversight.
|
@@ -42,16 +54,18 @@ module RuboCop
|
|
42
54
|
def on_class(node)
|
43
55
|
return if node.parent_class && style != :nested
|
44
56
|
|
45
|
-
check_style(node, node.body)
|
57
|
+
check_style(node, node.body, style_for_classes)
|
46
58
|
end
|
47
59
|
|
48
60
|
def on_module(node)
|
49
|
-
check_style(node, node.body)
|
61
|
+
check_style(node, node.body, style_for_modules)
|
50
62
|
end
|
51
63
|
|
52
64
|
private
|
53
65
|
|
54
66
|
def nest_or_compact(corrector, node)
|
67
|
+
style = node.class_type? ? style_for_classes : style_for_modules
|
68
|
+
|
55
69
|
if style == :nested
|
56
70
|
nest_definition(corrector, node)
|
57
71
|
else
|
@@ -141,7 +155,7 @@ module RuboCop
|
|
141
155
|
node.source_range.source_line[/\A\s*/]
|
142
156
|
end
|
143
157
|
|
144
|
-
def check_style(node, body)
|
158
|
+
def check_style(node, body, style)
|
145
159
|
return if node.identifier.namespace&.cbase_type?
|
146
160
|
|
147
161
|
if style == :nested
|
@@ -183,6 +197,14 @@ module RuboCop
|
|
183
197
|
def compact_node_name?(node)
|
184
198
|
node.identifier.source.include?('::')
|
185
199
|
end
|
200
|
+
|
201
|
+
def style_for_classes
|
202
|
+
cop_config['EnforcedStyleForClasses'] || style
|
203
|
+
end
|
204
|
+
|
205
|
+
def style_for_modules
|
206
|
+
cop_config['EnforcedStyleForModules'] || style
|
207
|
+
end
|
186
208
|
end
|
187
209
|
end
|
188
210
|
end
|
@@ -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))
|
@@ -9,8 +9,8 @@ module RuboCop
|
|
9
9
|
# These keywords are: `class`, `module`, `def`, `begin`, `end`.
|
10
10
|
#
|
11
11
|
# Note that some comments
|
12
|
-
# (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`)
|
13
|
-
#
|
12
|
+
# (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`),
|
13
|
+
# RBS::Inline annotation, and Steep annotation (`steep:ignore`) are allowed.
|
14
14
|
#
|
15
15
|
# Autocorrection removes comments from `end` keyword and keeps comments
|
16
16
|
# for `class`, `module`, `def` and `begin` above the keyword.
|
@@ -60,6 +60,8 @@ module RuboCop
|
|
60
60
|
SUBCLASS_DEFINITION = /\A\s*class\s+(\w|::)+\s*<\s*(\w|::)+/.freeze
|
61
61
|
METHOD_DEFINITION = /\A\s*def\s/.freeze
|
62
62
|
|
63
|
+
STEEP_REGEXP = /#\ssteep:ignore(\s|\z)/.freeze
|
64
|
+
|
63
65
|
def on_new_investigation
|
64
66
|
processed_source.comments.each do |comment|
|
65
67
|
next unless offensive?(comment) && (match = source_line(comment).match(REGEXP))
|
@@ -86,6 +88,7 @@ module RuboCop
|
|
86
88
|
def offensive?(comment)
|
87
89
|
line = source_line(comment)
|
88
90
|
return false if rbs_inline_annotation?(line, comment)
|
91
|
+
return false if steep_annotation?(comment)
|
89
92
|
|
90
93
|
KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
|
91
94
|
ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
|
@@ -105,6 +108,10 @@ module RuboCop
|
|
105
108
|
false
|
106
109
|
end
|
107
110
|
end
|
111
|
+
|
112
|
+
def steep_annotation?(comment)
|
113
|
+
comment.text.match?(STEEP_REGEXP)
|
114
|
+
end
|
108
115
|
end
|
109
116
|
end
|
110
117
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for logical comparison which can be replaced with `Comparable#between?`.
|
7
|
+
#
|
8
|
+
# NOTE: `Comparable#between?` is on average slightly slower than logical comparison,
|
9
|
+
# although the difference generally isn't observable. If you require maximum
|
10
|
+
# performance, consider using logical comparison.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# x >= min && x <= max
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# x <= max && x >= min
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# x.between?(min, max)
|
22
|
+
#
|
23
|
+
class ComparableBetween < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
|
26
|
+
MSG = 'Prefer `%<prefer>s` over logical comparison.'
|
27
|
+
|
28
|
+
# @!method logical_comparison_between_by_min_first?(node)
|
29
|
+
def_node_matcher :logical_comparison_between_by_min_first?, <<~PATTERN
|
30
|
+
(and
|
31
|
+
(send
|
32
|
+
{$_value :>= $_min | $_min :<= $_value})
|
33
|
+
(send
|
34
|
+
{$_value :<= $_max | $_max :>= $_value}))
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
# @!method logical_comparison_between_by_max_first?(node)
|
38
|
+
def_node_matcher :logical_comparison_between_by_max_first?, <<~PATTERN
|
39
|
+
(and
|
40
|
+
(send
|
41
|
+
{$_value :<= $_max | $_max :>= $_value})
|
42
|
+
(send
|
43
|
+
{$_value :>= $_min | $_min :<= $_value}))
|
44
|
+
PATTERN
|
45
|
+
|
46
|
+
def on_and(node)
|
47
|
+
logical_comparison_between_by_min_first?(node) do |*args|
|
48
|
+
min_and_value, max_and_value = args.each_slice(2).to_a
|
49
|
+
|
50
|
+
register_offense(node, min_and_value, max_and_value)
|
51
|
+
end
|
52
|
+
|
53
|
+
logical_comparison_between_by_max_first?(node) do |*args|
|
54
|
+
max_and_value, min_and_value = args.each_slice(2).to_a
|
55
|
+
|
56
|
+
register_offense(node, min_and_value, max_and_value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def register_offense(node, min_and_value, max_and_value)
|
63
|
+
value = (min_and_value & max_and_value).first
|
64
|
+
min = min_and_value.find { _1 != value }
|
65
|
+
max = max_and_value.find { _1 != value }
|
66
|
+
|
67
|
+
prefer = "#{value.source}.between?(#{min.source}, #{max.source})"
|
68
|
+
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
69
|
+
corrector.replace(node, prefer)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|