rubocop 1.64.0 → 1.65.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -2
- data/config/default.yml +11 -1
- data/lib/rubocop/config_loader.rb +1 -1
- data/lib/rubocop/config_loader_resolver.rb +9 -3
- data/lib/rubocop/cop/cop.rb +20 -2
- data/lib/rubocop/cop/force.rb +12 -0
- data/lib/rubocop/cop/gemspec/add_runtime_dependency.rb +38 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
- data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +20 -20
- data/lib/rubocop/cop/layout/space_around_operators.rb +3 -0
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
- data/lib/rubocop/cop/legacy/corrector.rb +12 -2
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +1 -1
- data/lib/rubocop/cop/lint/empty_when.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +21 -14
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +14 -7
- data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +2 -9
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/void.rb +5 -0
- data/lib/rubocop/cop/metrics/block_nesting.rb +19 -7
- data/lib/rubocop/cop/mixin/alignment.rb +5 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +7 -1
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +15 -3
- data/lib/rubocop/cop/mixin/configurable_max.rb +5 -1
- data/lib/rubocop/cop/mixin/rescue_node.rb +4 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -1
- data/lib/rubocop/cop/style/copyright.rb +5 -2
- data/lib/rubocop/cop/style/documentation.rb +24 -24
- data/lib/rubocop/cop/style/hash_except.rb +8 -5
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +77 -43
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -0
- data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -1
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +23 -2
- data/lib/rubocop/cop/style/super_arguments.rb +52 -15
- data/lib/rubocop/cop/style/symbol_proc.rb +8 -1
- data/lib/rubocop/cop/style/zero_length_predicate.rb +28 -24
- data/lib/rubocop/cop/team.rb +10 -0
- data/lib/rubocop/cop/util.rb +7 -1
- data/lib/rubocop/cops_documentation_generator.rb +1 -1
- data/lib/rubocop/ext/regexp_parser.rb +4 -21
- data/lib/rubocop/formatter/html_formatter.rb +3 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts.rb +20 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/server/cache.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -2
- data/lib/rubocop/server/client_command/start.rb +1 -1
- data/lib/rubocop/server/core.rb +4 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +7 -6
@@ -3,12 +3,12 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Metrics
|
6
|
-
# Checks for excessive nesting of conditional and looping
|
7
|
-
# constructs.
|
6
|
+
# Checks for excessive nesting of conditional and looping constructs.
|
8
7
|
#
|
9
|
-
# You can configure if blocks are considered using the `CountBlocks`
|
10
|
-
#
|
11
|
-
# towards the nesting level. Set to `true` to
|
8
|
+
# You can configure if blocks are considered using the `CountBlocks` and `CountModifierForms`
|
9
|
+
# options. When both are set to `false` (the default) blocks and modifier forms are not
|
10
|
+
# counted towards the nesting level. Set them to `true` to include these in the nesting level
|
11
|
+
# calculation as well.
|
12
12
|
#
|
13
13
|
# The maximum level of nesting allowed is configurable.
|
14
14
|
class BlockNesting < Base
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
|
28
28
|
def check_nesting_level(node, max, current_level)
|
29
29
|
if consider_node?(node)
|
30
|
-
current_level += 1
|
30
|
+
current_level += 1 if count_if_block?(node)
|
31
31
|
if current_level > max
|
32
32
|
self.max = current_level
|
33
33
|
unless part_of_ignored_node?(node)
|
@@ -41,6 +41,14 @@ module RuboCop
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def count_if_block?(node)
|
45
|
+
return true unless node.if_type?
|
46
|
+
return false if node.elsif?
|
47
|
+
return count_modifier_forms? if node.modifier_form?
|
48
|
+
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
44
52
|
def consider_node?(node)
|
45
53
|
return true if NESTING_BLOCKS.include?(node.type)
|
46
54
|
|
@@ -52,7 +60,11 @@ module RuboCop
|
|
52
60
|
end
|
53
61
|
|
54
62
|
def count_blocks?
|
55
|
-
cop_config
|
63
|
+
cop_config.fetch('CountBlocks', false)
|
64
|
+
end
|
65
|
+
|
66
|
+
def count_modifier_forms?
|
67
|
+
cop_config.fetch('CountModifierForms', false)
|
56
68
|
end
|
57
69
|
end
|
58
70
|
end
|
@@ -65,8 +65,12 @@ module RuboCop
|
|
65
65
|
inner.begin_pos >= outer.begin_pos && inner.end_pos <= outer.end_pos
|
66
66
|
end
|
67
67
|
|
68
|
-
# @deprecated Use processed_source.
|
68
|
+
# @deprecated Use processed_source.line_with_comment?(line)
|
69
69
|
def end_of_line_comment(line)
|
70
|
+
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
71
|
+
`end_of_line_comment` is deprecated. Use `processed_source.line_with_comment?` instead.
|
72
|
+
WARNING
|
73
|
+
|
70
74
|
processed_source.line_with_comment?(line)
|
71
75
|
end
|
72
76
|
|
@@ -15,7 +15,13 @@ module RuboCop
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# @deprecated Use allowed_method? instead
|
18
|
-
|
18
|
+
def ignored_method?
|
19
|
+
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
20
|
+
`ignored_method?` is deprecated. Use `allowed_method?` instead.
|
21
|
+
WARNING
|
22
|
+
|
23
|
+
allowed_method?
|
24
|
+
end
|
19
25
|
|
20
26
|
# @api public
|
21
27
|
def allowed_methods
|
@@ -18,14 +18,26 @@ module RuboCop
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# @deprecated Use allowed_line? instead
|
21
|
-
|
21
|
+
def ignored_line?
|
22
|
+
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
23
|
+
`ignored_line?` is deprecated. Use `allowed_line?` instead.
|
24
|
+
WARNING
|
25
|
+
|
26
|
+
allowed_line?
|
27
|
+
end
|
22
28
|
|
23
29
|
def matches_allowed_pattern?(line)
|
24
30
|
allowed_patterns.any? { |pattern| Regexp.new(pattern).match?(line) }
|
25
31
|
end
|
26
32
|
|
27
|
-
# @deprecated Use matches_allowed_pattern
|
28
|
-
|
33
|
+
# @deprecated Use matches_allowed_pattern? instead
|
34
|
+
def matches_ignored_pattern?
|
35
|
+
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
36
|
+
`matches_ignored_pattern?` is deprecated. Use `matches_allowed_pattern?` instead.
|
37
|
+
WARNING
|
38
|
+
|
39
|
+
matches_allowed_pattern?
|
40
|
+
end
|
29
41
|
|
30
42
|
def allowed_patterns
|
31
43
|
# Since there could be a pattern specified in the default config, merge the two
|
@@ -4,11 +4,15 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Handles `Max` configuration parameters, especially setting them to an
|
6
6
|
# appropriate value with --auto-gen-config.
|
7
|
-
# @deprecated Use `exclude_limit ParameterName
|
7
|
+
# @deprecated Use `exclude_limit <ParameterName>` instead.
|
8
8
|
module ConfigurableMax
|
9
9
|
private
|
10
10
|
|
11
11
|
def max=(value)
|
12
|
+
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
13
|
+
`max=` is deprecated. Use `exclude_limit <ParameterName>` instead.
|
14
|
+
WARNING
|
15
|
+
|
12
16
|
cfg = config_to_allow_offenses
|
13
17
|
cfg[:exclude_limit] ||= {}
|
14
18
|
current_max = cfg[:exclude_limit][max_parameter_name]
|
@@ -18,6 +18,10 @@ module RuboCop
|
|
18
18
|
|
19
19
|
# @deprecated Use ResbodyNode#exceptions instead
|
20
20
|
def rescued_exceptions(resbody)
|
21
|
+
warn Rainbow(<<~WARNING).yellow, uplevel: 1
|
22
|
+
`rescued_exceptions` is deprecated. Use `ResbodyNode#exceptions` instead.
|
23
|
+
WARNING
|
24
|
+
|
21
25
|
rescue_group, = *resbody
|
22
26
|
if rescue_group
|
23
27
|
rescue_group.values
|
@@ -148,7 +148,7 @@ module RuboCop
|
|
148
148
|
|
149
149
|
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
150
150
|
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
151
|
-
send_nodes = node.each_descendant(:send, :csend, :super).to_a
|
151
|
+
send_nodes = node.each_descendant(:send, :csend, :super, :yield).to_a
|
152
152
|
|
153
153
|
send_classifications = classify_send_nodes(
|
154
154
|
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
@@ -58,12 +58,15 @@ module RuboCop
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def verify_autocorrect_notice!
|
61
|
-
|
61
|
+
if autocorrect_notice.nil? || autocorrect_notice.empty?
|
62
|
+
raise Warning, "#{cop_name}: #{AUTOCORRECT_EMPTY_WARNING}"
|
63
|
+
end
|
62
64
|
|
63
65
|
regex = Regexp.new(notice)
|
64
66
|
return if autocorrect_notice.gsub(/^# */, '').match?(regex)
|
65
67
|
|
66
|
-
|
68
|
+
message = "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
|
69
|
+
raise Warning, "#{cop_name}: #{message}"
|
67
70
|
end
|
68
71
|
|
69
72
|
def insert_notice_before(processed_source)
|
@@ -29,36 +29,36 @@ module RuboCop
|
|
29
29
|
# end
|
30
30
|
#
|
31
31
|
# # allowed
|
32
|
-
#
|
32
|
+
# # Class without body
|
33
|
+
# class Person
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # Namespace - A namespace can be a class or a module
|
37
|
+
# # Containing a class
|
38
|
+
# module Namespace
|
39
|
+
# # Description/Explanation of Person class
|
33
40
|
# class Person
|
41
|
+
# # ...
|
34
42
|
# end
|
43
|
+
# end
|
35
44
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# # Description/Explanation of Person class
|
40
|
-
# class Person
|
41
|
-
# # ...
|
42
|
-
# end
|
45
|
+
# # Containing constant visibility declaration
|
46
|
+
# module Namespace
|
47
|
+
# class Private
|
43
48
|
# end
|
44
49
|
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
# class Private
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
# private_constant :Private
|
51
|
-
# end
|
50
|
+
# private_constant :Private
|
51
|
+
# end
|
52
52
|
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
53
|
+
# # Containing constant definition
|
54
|
+
# module Namespace
|
55
|
+
# Public = Class.new
|
56
|
+
# end
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
58
|
+
# # Macro calls
|
59
|
+
# module Namespace
|
60
|
+
# extend Foo
|
61
|
+
# end
|
62
62
|
#
|
63
63
|
# @example AllowedConstants: ['ClassMethods']
|
64
64
|
#
|
@@ -67,7 +67,7 @@ module RuboCop
|
|
67
67
|
# module ClassMethods
|
68
68
|
# # ...
|
69
69
|
# end
|
70
|
-
#
|
70
|
+
# end
|
71
71
|
#
|
72
72
|
class Documentation < Base
|
73
73
|
include DocumentationComment
|
@@ -23,9 +23,9 @@ module RuboCop
|
|
23
23
|
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| k == :bar }
|
24
24
|
# {foo: 1, bar: 2, baz: 3}.select {|k, v| k != :bar }
|
25
25
|
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| k != :bar }
|
26
|
-
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[
|
27
|
-
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[
|
28
|
-
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| !%i[
|
26
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].include?(k) }
|
27
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].include?(k) }
|
28
|
+
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| !%i[bar].include?(k) }
|
29
29
|
#
|
30
30
|
# # good
|
31
31
|
# {foo: 1, bar: 2, baz: 3}.except(:bar)
|
@@ -73,8 +73,9 @@ module RuboCop
|
|
73
73
|
PATTERN
|
74
74
|
|
75
75
|
def on_send(node)
|
76
|
+
method_name = node.method_name
|
76
77
|
block = node.parent
|
77
|
-
return unless bad_method?(block) && semantically_except_method?(node, block)
|
78
|
+
return unless bad_method?(method_name, block) && semantically_except_method?(node, block)
|
78
79
|
|
79
80
|
except_key = except_key(block)
|
80
81
|
return if except_key.nil? || !safe_to_register_offense?(block, except_key)
|
@@ -91,7 +92,7 @@ module RuboCop
|
|
91
92
|
private
|
92
93
|
|
93
94
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
94
|
-
def bad_method?(block)
|
95
|
+
def bad_method?(method_name, block)
|
95
96
|
if active_support_extensions_enabled?
|
96
97
|
bad_method_with_active_support?(block) do |key_arg, send_node|
|
97
98
|
if send_node.method?(:in?) && send_node.receiver&.source != key_arg.source
|
@@ -103,6 +104,8 @@ module RuboCop
|
|
103
104
|
end
|
104
105
|
else
|
105
106
|
bad_method_with_poro?(block) do |key_arg, send_node|
|
107
|
+
return false if method_name == :reject && block.body.method?(:!)
|
108
|
+
|
106
109
|
!send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
|
107
110
|
end
|
108
111
|
end
|
@@ -4,6 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# Prefer `select` or `reject` over `map { ... }.compact`.
|
7
|
+
# This cop also handles `filter_map { ... }`, similar to `map { ... }.compact`.
|
7
8
|
#
|
8
9
|
# @example
|
9
10
|
#
|
@@ -11,6 +12,9 @@ module RuboCop
|
|
11
12
|
# array.map { |e| some_condition? ? e : next }.compact
|
12
13
|
#
|
13
14
|
# # bad
|
15
|
+
# array.filter_map { |e| some_condition? ? e : next }
|
16
|
+
#
|
17
|
+
# # bad
|
14
18
|
# array.map do |e|
|
15
19
|
# if some_condition?
|
16
20
|
# e
|
@@ -40,55 +44,73 @@ module RuboCop
|
|
40
44
|
class MapCompactWithConditionalBlock < Base
|
41
45
|
extend AutoCorrector
|
42
46
|
|
43
|
-
MSG = 'Replace `
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
47
|
+
MSG = 'Replace `%<current>s` with `%<method>s`.'
|
48
|
+
RESTRICT_ON_SEND = %i[compact filter_map].freeze
|
49
|
+
|
50
|
+
# @!method conditional_block(node)
|
51
|
+
def_node_matcher :conditional_block, <<~RUBY
|
52
|
+
(block
|
53
|
+
(call _ {:map :filter_map})
|
54
|
+
(args
|
55
|
+
$(arg _))
|
56
|
+
{
|
57
|
+
(if $_ $(lvar _) {next nil?})
|
58
|
+
(if $_ {next nil?} $(lvar _))
|
59
|
+
(if $_ (next $(lvar _)) {next nil nil?})
|
60
|
+
(if $_ {next nil nil?} (next $(lvar _)))
|
61
|
+
(begin
|
62
|
+
{
|
63
|
+
(if $_ next nil?)
|
64
|
+
(if $_ nil? next)
|
65
|
+
}
|
66
|
+
$(lvar _))
|
67
|
+
(begin
|
68
|
+
{
|
69
|
+
(if $_ (next $(lvar _)) nil?)
|
70
|
+
(if $_ nil? (next $(lvar _)))
|
71
|
+
}
|
72
|
+
(nil))
|
73
|
+
})
|
70
74
|
RUBY
|
71
75
|
|
72
76
|
def on_send(node)
|
73
|
-
|
74
|
-
|
75
|
-
return
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
)
|
85
|
-
end
|
77
|
+
map_candidate = node.children.first
|
78
|
+
if (block_argument, condition, return_value = conditional_block(map_candidate))
|
79
|
+
return unless node.method?(:compact) && node.arguments.empty?
|
80
|
+
|
81
|
+
range = map_with_compact_range(node)
|
82
|
+
elsif (block_argument, condition, return_value = conditional_block(node.parent))
|
83
|
+
return unless node.method?(:filter_map)
|
84
|
+
|
85
|
+
range = filter_map_range(node)
|
86
|
+
else
|
87
|
+
return
|
86
88
|
end
|
89
|
+
|
90
|
+
inspect(node, block_argument, condition, return_value, range)
|
87
91
|
end
|
88
92
|
alias on_csend on_send
|
89
93
|
|
90
94
|
private
|
91
95
|
|
96
|
+
def inspect(node, block_argument_node, condition_node, return_value_node, range)
|
97
|
+
return unless returns_block_argument?(block_argument_node, return_value_node)
|
98
|
+
return if condition_node.parent.elsif?
|
99
|
+
|
100
|
+
method = truthy_branch?(return_value_node) ? 'select' : 'reject'
|
101
|
+
current = current(node)
|
102
|
+
|
103
|
+
add_offense(range, message: format(MSG, current: current, method: method)) do |corrector|
|
104
|
+
return if part_of_ignored_node?(node) || ignored_node?(node)
|
105
|
+
|
106
|
+
corrector.replace(
|
107
|
+
range, "#{method} { |#{block_argument_node.source}| #{condition_node.source} }"
|
108
|
+
)
|
109
|
+
|
110
|
+
ignore_node(node)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
92
114
|
def returns_block_argument?(block_argument_node, return_value_node)
|
93
115
|
block_argument_node.name == return_value_node.children.first
|
94
116
|
end
|
@@ -123,10 +145,22 @@ module RuboCop
|
|
123
145
|
end
|
124
146
|
end
|
125
147
|
|
126
|
-
def
|
127
|
-
|
148
|
+
def current(node)
|
149
|
+
if node.method?(:compact)
|
150
|
+
map_or_filter_map_method = node.children.first
|
151
|
+
|
152
|
+
"#{map_or_filter_map_method.method_name} { ... }.compact"
|
153
|
+
else
|
154
|
+
'filter_map { ... }'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def map_with_compact_range(node)
|
159
|
+
node.receiver.send_node.loc.selector.begin.join(node.source_range.end)
|
160
|
+
end
|
128
161
|
|
129
|
-
|
162
|
+
def filter_map_range(node)
|
163
|
+
node.loc.selector.join(node.parent.source_range.end)
|
130
164
|
end
|
131
165
|
end
|
132
166
|
end
|
@@ -18,6 +18,7 @@ module RuboCop
|
|
18
18
|
return if inside_endless_method_def?(node)
|
19
19
|
return if require_parentheses_for_hash_value_omission?(node)
|
20
20
|
return if syntax_like_method_call?(node)
|
21
|
+
return if method_call_before_constant_resolution?(node)
|
21
22
|
return if super_call_without_arguments?(node)
|
22
23
|
return if legitimate_call_with_parentheses?(node)
|
23
24
|
return if allowed_camel_case_method_call?(node)
|
@@ -63,6 +64,10 @@ module RuboCop
|
|
63
64
|
node.implicit_call? || node.operator_method?
|
64
65
|
end
|
65
66
|
|
67
|
+
def method_call_before_constant_resolution?(node)
|
68
|
+
node.parent&.const_type?
|
69
|
+
end
|
70
|
+
|
66
71
|
def super_call_without_arguments?(node)
|
67
72
|
node.super_type? && node.arguments.none?
|
68
73
|
end
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# String interpolation is always kept in double quotes.
|
11
11
|
#
|
12
|
-
#
|
12
|
+
# NOTE: `Lint/SymbolConversion` can be used in parallel to ensure that symbols
|
13
13
|
# are not quoted that don't need to be. This cop is for configuring the quoting
|
14
14
|
# style to use for symbols that require quotes.
|
15
15
|
#
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks for the presence of superfluous `.rb` extension in
|
7
7
|
# the filename provided to `require` and `require_relative`.
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# NOTE: If the extension is omitted, Ruby tries adding '.rb', '.so',
|
10
10
|
# and so on to the name until found. If the file named cannot be found,
|
11
11
|
# a `LoadError` will be raised.
|
12
12
|
# There is an edge case where `foo.so` file is loaded instead of a `LoadError`
|
@@ -74,6 +74,7 @@ module RuboCop
|
|
74
74
|
kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
|
75
75
|
tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
|
76
76
|
].freeze
|
77
|
+
ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
|
77
78
|
|
78
79
|
def on_new_investigation
|
79
80
|
return unless processed_source.ast
|
@@ -137,7 +138,7 @@ module RuboCop
|
|
137
138
|
# do_something \
|
138
139
|
# argument
|
139
140
|
def method_with_argument?(current_token, next_token)
|
140
|
-
return false
|
141
|
+
return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
|
141
142
|
|
142
143
|
ARGUMENT_TYPES.include?(next_token.type)
|
143
144
|
end
|
@@ -7,6 +7,20 @@ module RuboCop
|
|
7
7
|
# Since the `send` method can be used to call private methods, by default,
|
8
8
|
# only the `public_send` method is detected.
|
9
9
|
#
|
10
|
+
# NOTE: Writer methods with names ending in `=` are always permitted because their
|
11
|
+
# behavior differs as follows:
|
12
|
+
#
|
13
|
+
# [source,ruby]
|
14
|
+
# ----
|
15
|
+
# def foo=(foo)
|
16
|
+
# @foo = foo
|
17
|
+
# 42
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# self.foo = 1 # => 1
|
21
|
+
# send(:foo=, 1) # => 42
|
22
|
+
# ----
|
23
|
+
#
|
10
24
|
# @safety
|
11
25
|
# This cop is not safe because it can incorrectly detect based on the receiver.
|
12
26
|
# Additionally, when `AllowSend` is set to `true`, it cannot determine whether
|
@@ -43,8 +57,14 @@ module RuboCop
|
|
43
57
|
MSG = 'Use `%<method_name>s` method call directly instead.'
|
44
58
|
RESTRICT_ON_SEND = %i[public_send send __send__].freeze
|
45
59
|
STATIC_METHOD_NAME_NODE_TYPES = %i[sym str].freeze
|
60
|
+
METHOD_NAME_PATTERN = /\A[a-zA-Z_][a-zA-Z0-9_]*[!?]?\z/.freeze
|
61
|
+
RESERVED_WORDS = %i[
|
62
|
+
BEGIN END alias and begin break case class def defined? do else elsif end ensure
|
63
|
+
false for if in module next nil not or redo rescue retry return self super then true
|
64
|
+
undef unless until when while yield
|
65
|
+
].freeze
|
46
66
|
|
47
|
-
# rubocop:disable Metrics/AbcSize
|
67
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
48
68
|
def on_send(node)
|
49
69
|
return if allow_send? && !node.method?(:public_send)
|
50
70
|
return unless (first_argument = node.first_argument)
|
@@ -52,6 +72,7 @@ module RuboCop
|
|
52
72
|
|
53
73
|
offense_range = offense_range(node)
|
54
74
|
method_name = first_argument.value
|
75
|
+
return if !METHOD_NAME_PATTERN.match?(method_name) || RESERVED_WORDS.include?(method_name)
|
55
76
|
|
56
77
|
add_offense(offense_range, message: format(MSG, method_name: method_name)) do |corrector|
|
57
78
|
if node.arguments.one?
|
@@ -62,7 +83,7 @@ module RuboCop
|
|
62
83
|
end
|
63
84
|
end
|
64
85
|
end
|
65
|
-
# rubocop:enable Metrics/AbcSize
|
86
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
66
87
|
|
67
88
|
private
|
68
89
|
|