rubocop 1.56.2 → 1.57.1
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 +12 -6
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +3 -1
- data/lib/rubocop/cop/bundler/duplicated_group.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -22
- data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
- data/lib/rubocop/cop/layout/dot_position.rb +1 -5
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +41 -8
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +3 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +10 -1
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +0 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +20 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +11 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +37 -10
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +2 -2
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +5 -7
- data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -6
- data/lib/rubocop/cop/style/array_intersect.rb +13 -5
- data/lib/rubocop/cop/style/class_equality_comparison.rb +5 -0
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
- data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
- data/lib/rubocop/cop/style/for.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/guard_clause.rb +26 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +17 -3
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/operator_method_call.rb +6 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +9 -1
- data/lib/rubocop/cop/style/redundant_conditional.rb +1 -9
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +86 -5
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +18 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +21 -5
- data/lib/rubocop/cop/style/return_nil.rb +6 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +65 -0
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
- data/lib/rubocop/cop/style/symbol_array.rb +10 -11
- data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
- data/lib/rubocop/file_finder.rb +4 -7
- data/lib/rubocop/magic_comment.rb +12 -10
- data/lib/rubocop/rspec/shared_contexts.rb +2 -3
- data/lib/rubocop/server/cache.rb +1 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d38c0bf9376bd86de4bdf5561b74b11e895bc90ac263a8c29520afec2fb7d0b0
|
4
|
+
data.tar.gz: 5e624dd813953b2058306d07986c19d55fa170fa8f3960844c4d62f2f87b3277
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dee188b376a118be4c08956361312fc91bf4e55cdadfa8129611f8a3b19fef80fb8241658778a5f6fb042336ba4137c6c64d2a65189ad00567730934e3dcde74
|
7
|
+
data.tar.gz: 4dbf33a643a4f945d3564426b49338d463a55e734812d8c3113df04aa430577c2142b7685990bdd12915e537a1add4b181dd96488632dd89a544a33c5f712944
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
53
53
|
in your `Gemfile`:
|
54
54
|
|
55
55
|
```rb
|
56
|
-
gem 'rubocop', '~> 1.
|
56
|
+
gem 'rubocop', '~> 1.57', require: false
|
57
57
|
```
|
58
58
|
|
59
59
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/config/default.yml
CHANGED
@@ -2170,7 +2170,9 @@ Lint/RedundantRegexpQuantifiers:
|
|
2170
2170
|
Lint/RedundantRequireStatement:
|
2171
2171
|
Description: 'Checks for unnecessary `require` statement.'
|
2172
2172
|
Enabled: true
|
2173
|
+
SafeAutoCorrect: false
|
2173
2174
|
VersionAdded: '0.76'
|
2175
|
+
VersionChanged: '1.57'
|
2174
2176
|
|
2175
2177
|
Lint/RedundantSafeNavigation:
|
2176
2178
|
Description: 'Checks for redundant safe navigation calls.'
|
@@ -3354,7 +3356,9 @@ Style/ClassEqualityComparison:
|
|
3354
3356
|
Description: 'Enforces the use of `Object#instance_of?` instead of class comparison for equality.'
|
3355
3357
|
StyleGuide: '#instance-of-vs-class-comparison'
|
3356
3358
|
Enabled: true
|
3359
|
+
SafeAutoCorrect: false
|
3357
3360
|
VersionAdded: '0.93'
|
3361
|
+
VersionChanged: '1.57'
|
3358
3362
|
AllowedMethods:
|
3359
3363
|
- ==
|
3360
3364
|
- equal?
|
@@ -3409,6 +3413,7 @@ Style/CollectionMethods:
|
|
3409
3413
|
PreferredMethods:
|
3410
3414
|
collect: 'map'
|
3411
3415
|
collect!: 'map!'
|
3416
|
+
collect_concat: 'flat_map'
|
3412
3417
|
inject: 'reduce'
|
3413
3418
|
detect: 'find'
|
3414
3419
|
find_all: 'select'
|
@@ -4130,12 +4135,6 @@ Style/InvertibleUnlessCondition:
|
|
4130
4135
|
:none?: :any?
|
4131
4136
|
:even?: :odd?
|
4132
4137
|
:odd?: :even?
|
4133
|
-
# `ActiveSupport` defines some common inverse methods. They are listed below,
|
4134
|
-
# and not enabled by default.
|
4135
|
-
# :present?: :blank?
|
4136
|
-
# :blank?: :present?
|
4137
|
-
# :include?: :exclude?
|
4138
|
-
# :exclude?: :include?
|
4139
4138
|
|
4140
4139
|
Style/IpAddresses:
|
4141
4140
|
Description: "Don't include literal IP addresses in code."
|
@@ -4925,7 +4924,9 @@ Style/RedundantFilterChain:
|
|
4925
4924
|
Identifies usages of `any?`, `empty?`, `none?` or `one?` predicate methods chained to
|
4926
4925
|
`select`/`filter`/`find_all` and change them to use predicate method instead.
|
4927
4926
|
Enabled: pending
|
4927
|
+
SafeAutoCorrect: false
|
4928
4928
|
VersionAdded: '1.52'
|
4929
|
+
VersionChanged: '1.57'
|
4929
4930
|
|
4930
4931
|
Style/RedundantFreeze:
|
4931
4932
|
Description: "Checks usages of Object#freeze on immutable objects."
|
@@ -5187,6 +5188,11 @@ Style/SingleLineBlockParams:
|
|
5187
5188
|
- acc
|
5188
5189
|
- elem
|
5189
5190
|
|
5191
|
+
Style/SingleLineDoEndBlock:
|
5192
|
+
Description: 'Checks for single-line `do`...`end` blocks.'
|
5193
|
+
Enabled: pending
|
5194
|
+
VersionAdded: '1.57'
|
5195
|
+
|
5190
5196
|
Style/SingleLineMethods:
|
5191
5197
|
Description: 'Avoid single-line methods.'
|
5192
5198
|
StyleGuide: '#no-single-line-methods'
|
data/lib/rubocop/cli.rb
CHANGED
@@ -11,7 +11,7 @@ module RuboCop
|
|
11
11
|
STATUS_ERROR = 2
|
12
12
|
STATUS_INTERRUPTED = Signal.list['INT'] + 128
|
13
13
|
DEFAULT_PARALLEL_OPTIONS = %i[
|
14
|
-
color debug display_style_guide display_time display_only_fail_level_offenses
|
14
|
+
color config debug display_style_guide display_time display_only_fail_level_offenses
|
15
15
|
display_only_failed except extra_details fail_level fix_layout format
|
16
16
|
ignore_disable_comments lint only only_guide_cops require safe
|
17
17
|
autocorrect safe_autocorrect autocorrect_all
|
@@ -82,7 +82,9 @@ module RuboCop
|
|
82
82
|
node.array_type? && node.percent_literal?
|
83
83
|
end
|
84
84
|
|
85
|
-
percent_array.map(&:source_range).find
|
85
|
+
percent_array.map(&:source_range).find do |range|
|
86
|
+
offense_range.begin_pos > range.begin_pos && range.overlaps?(offense_range)
|
87
|
+
end
|
86
88
|
end
|
87
89
|
|
88
90
|
def range_of_first_line(range)
|
@@ -26,9 +26,7 @@ module RuboCop
|
|
26
26
|
# expect_no_offenses('...')
|
27
27
|
# end
|
28
28
|
class ExampleDescription < Base
|
29
|
-
|
30
|
-
attr_accessor :descriptions
|
31
|
-
end
|
29
|
+
extend AutoCorrector
|
32
30
|
|
33
31
|
MSG = 'Description does not match use of `%<method_name>s`.'
|
34
32
|
|
@@ -39,22 +37,31 @@ module RuboCop
|
|
39
37
|
expect_no_corrections
|
40
38
|
].to_set.freeze
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
EXPECT_NO_OFFENSES_DESCRIPTION_MAPPING = {
|
41
|
+
/\A(adds|registers|reports|finds) (an? )?offense/ => 'does not register an offense',
|
42
|
+
/\A(flags|handles|works)\b/ => 'does not register'
|
43
|
+
}.freeze
|
44
|
+
|
45
|
+
EXPECT_OFFENSE_DESCRIPTION_MAPPING = {
|
46
|
+
/\A(does not|doesn't) (register|find|flag|report)/ => 'registers',
|
47
|
+
/\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense',
|
48
|
+
/\Aaccepts\b/ => 'registers'
|
49
|
+
}.freeze
|
46
50
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
/^accepts\b/
|
51
|
-
].freeze
|
51
|
+
EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
|
52
|
+
/\A(auto[- ]?)?correct/ => 'does not correct'
|
53
|
+
}.freeze
|
52
54
|
|
53
|
-
|
55
|
+
EXPECT_CORRECTION_DESCRIPTION_MAPPING = {
|
56
|
+
/\b(does not|doesn't) (auto[- ]?)?correct/ => 'autocorrects'
|
57
|
+
}.freeze
|
54
58
|
|
55
|
-
|
56
|
-
|
57
|
-
|
59
|
+
EXAMPLE_DESCRIPTION_MAPPING = {
|
60
|
+
expect_no_offenses: EXPECT_NO_OFFENSES_DESCRIPTION_MAPPING,
|
61
|
+
expect_offense: EXPECT_OFFENSE_DESCRIPTION_MAPPING,
|
62
|
+
expect_no_corrections: EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING,
|
63
|
+
expect_correction: EXPECT_CORRECTION_DESCRIPTION_MAPPING
|
64
|
+
}.freeze
|
58
65
|
|
59
66
|
# @!method offense_example?(node)
|
60
67
|
def_node_matcher :offense_example?, <<~PATTERN
|
@@ -67,21 +74,34 @@ module RuboCop
|
|
67
74
|
|
68
75
|
def on_send(node)
|
69
76
|
parent = node.each_ancestor(:block).first
|
70
|
-
return unless parent && (
|
77
|
+
return unless parent && (current_description = offense_example?(parent))
|
71
78
|
|
72
79
|
method_name = node.method_name
|
73
80
|
message = format(MSG, method_name: method_name)
|
74
81
|
|
75
|
-
|
76
|
-
check_description(
|
82
|
+
description_map = EXAMPLE_DESCRIPTION_MAPPING[method_name]
|
83
|
+
check_description(current_description, description_map, message)
|
77
84
|
end
|
78
85
|
|
79
86
|
private
|
80
87
|
|
81
|
-
def check_description(
|
82
|
-
|
88
|
+
def check_description(current_description, description_map, message)
|
89
|
+
description_text = string_contents(current_description)
|
90
|
+
return unless (new_description = correct_description(description_text, description_map))
|
91
|
+
|
92
|
+
add_offense(current_description, message: message) do |corrector|
|
93
|
+
corrector.replace(current_description, "'#{new_description}'")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def correct_description(current_description, description_map)
|
98
|
+
description_map.each do |incorrect_description_pattern, preferred_description|
|
99
|
+
if incorrect_description_pattern.match?(current_description)
|
100
|
+
return current_description.gsub(incorrect_description_pattern, preferred_description)
|
101
|
+
end
|
102
|
+
end
|
83
103
|
|
84
|
-
|
104
|
+
nil
|
85
105
|
end
|
86
106
|
|
87
107
|
def string_contents(node)
|
@@ -14,6 +14,12 @@ module RuboCop
|
|
14
14
|
# node.method_name
|
15
15
|
#
|
16
16
|
# # bad
|
17
|
+
# node.send_node.method?(:method_name)
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# node.method?(:method_name)
|
21
|
+
#
|
22
|
+
# # bad
|
17
23
|
# node.send_node.receiver
|
18
24
|
#
|
19
25
|
# # good
|
@@ -24,11 +30,14 @@ module RuboCop
|
|
24
30
|
extend AutoCorrector
|
25
31
|
|
26
32
|
MSG = 'Remove the redundant `send_node`.'
|
27
|
-
RESTRICT_ON_SEND = %i[method_name receiver].freeze
|
33
|
+
RESTRICT_ON_SEND = %i[method_name method? receiver].freeze
|
28
34
|
|
29
35
|
# @!method dispatch_method(node)
|
30
36
|
def_node_matcher :dispatch_method, <<~PATTERN
|
31
|
-
|
37
|
+
{
|
38
|
+
(send $(send _ :send_node) {:method_name :receiver})
|
39
|
+
(send $(send _ :send_node) :method? _)
|
40
|
+
}
|
32
41
|
PATTERN
|
33
42
|
|
34
43
|
def on_send(node)
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def on_send(node)
|
35
|
-
return unless node.dot? ||
|
35
|
+
return unless node.dot? || node.safe_navigation?
|
36
36
|
|
37
37
|
return correct_style_detected if proper_dot_position?(node)
|
38
38
|
|
@@ -133,10 +133,6 @@ module RuboCop
|
|
133
133
|
# l.(1) has no selector, so we use the opening parenthesis instead
|
134
134
|
node.loc.selector || node.loc.begin
|
135
135
|
end
|
136
|
-
|
137
|
-
def ampersand_dot?(node)
|
138
|
-
node.loc.respond_to?(:dot) && node.loc.dot && node.loc.dot.is?('&.')
|
139
|
-
end
|
140
136
|
end
|
141
137
|
end
|
142
138
|
end
|
@@ -3,7 +3,23 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Layout
|
6
|
-
# Enforces empty line after guard clause
|
6
|
+
# Enforces empty line after guard clause.
|
7
|
+
#
|
8
|
+
# This cop allows `# :nocov:` directive after guard clause because
|
9
|
+
# SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# ----
|
13
|
+
# def foo
|
14
|
+
# # :nocov:
|
15
|
+
# return if condition
|
16
|
+
# # :nocov:
|
17
|
+
# bar
|
18
|
+
# end
|
19
|
+
# ----
|
20
|
+
#
|
21
|
+
# Refer to SimpleCov's documentation for more details:
|
22
|
+
# https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
|
7
23
|
#
|
8
24
|
# @example
|
9
25
|
#
|
@@ -42,19 +58,22 @@ module RuboCop
|
|
42
58
|
|
43
59
|
MSG = 'Add empty line after guard clause.'
|
44
60
|
END_OF_HEREDOC_LINE = 1
|
61
|
+
SIMPLE_DIRECTIVE_COMMENT_PATTERN = /\A# *:nocov:\z/.freeze
|
45
62
|
|
46
63
|
def on_if(node)
|
47
64
|
return if correct_style?(node)
|
48
65
|
return if multiple_statements_on_line?(node)
|
49
66
|
|
50
67
|
if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
|
51
|
-
|
68
|
+
if next_line_empty_or_allowed_directive_comment?(heredoc_line(node, heredoc_node))
|
69
|
+
return
|
70
|
+
end
|
52
71
|
|
53
72
|
add_offense(heredoc_node.loc.heredoc_end) do |corrector|
|
54
73
|
autocorrect(corrector, heredoc_node)
|
55
74
|
end
|
56
75
|
else
|
57
|
-
return if
|
76
|
+
return if next_line_empty_or_allowed_directive_comment?(node.last_line)
|
58
77
|
|
59
78
|
add_offense(offense_location(node)) { |corrector| autocorrect(corrector, node) }
|
60
79
|
end
|
@@ -70,7 +89,7 @@ module RuboCop
|
|
70
89
|
end
|
71
90
|
|
72
91
|
next_line = node_range.last_line + 1
|
73
|
-
if
|
92
|
+
if next_line_allowed_directive_comment?(next_line)
|
74
93
|
node_range = processed_source.comment_at_line(next_line)
|
75
94
|
end
|
76
95
|
|
@@ -88,21 +107,21 @@ module RuboCop
|
|
88
107
|
node.if_branch&.guard_clause?
|
89
108
|
end
|
90
109
|
|
91
|
-
def
|
110
|
+
def next_line_empty_or_allowed_directive_comment?(line)
|
92
111
|
return true if next_line_empty?(line)
|
93
112
|
|
94
113
|
next_line = line + 1
|
95
|
-
|
114
|
+
next_line_allowed_directive_comment?(next_line) && next_line_empty?(next_line)
|
96
115
|
end
|
97
116
|
|
98
117
|
def next_line_empty?(line)
|
99
118
|
processed_source[line].blank?
|
100
119
|
end
|
101
120
|
|
102
|
-
def
|
121
|
+
def next_line_allowed_directive_comment?(line)
|
103
122
|
return false unless (comment = processed_source.comment_at_line(line))
|
104
123
|
|
105
|
-
DirectiveComment.new(comment).enabled?
|
124
|
+
DirectiveComment.new(comment).enabled? || simplecov_directive_comment?(comment)
|
106
125
|
end
|
107
126
|
|
108
127
|
def next_line_rescue_or_ensure?(node)
|
@@ -145,6 +164,8 @@ module RuboCop
|
|
145
164
|
|
146
165
|
if node.if_branch.and_type?
|
147
166
|
node.if_branch.children.first
|
167
|
+
elsif use_heredoc_in_condition?(node.condition)
|
168
|
+
node.condition
|
148
169
|
else
|
149
170
|
node.if_branch.children.last
|
150
171
|
end
|
@@ -161,6 +182,12 @@ module RuboCop
|
|
161
182
|
node.respond_to?(:heredoc?) && node.heredoc?
|
162
183
|
end
|
163
184
|
|
185
|
+
def use_heredoc_in_condition?(condition)
|
186
|
+
condition.descendants.any? do |descendant|
|
187
|
+
descendant.respond_to?(:heredoc?) && descendant.heredoc?
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
164
191
|
def offense_location(node)
|
165
192
|
if node.loc.respond_to?(:end) && node.loc.end
|
166
193
|
node.loc.end
|
@@ -175,6 +202,12 @@ module RuboCop
|
|
175
202
|
|
176
203
|
parent.begin_type? && parent.single_line?
|
177
204
|
end
|
205
|
+
|
206
|
+
# SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
|
207
|
+
# https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
|
208
|
+
def simplecov_directive_comment?(comment)
|
209
|
+
SIMPLE_DIRECTIVE_COMMENT_PATTERN.match?(comment.text)
|
210
|
+
end
|
178
211
|
end
|
179
212
|
end
|
180
213
|
end
|
@@ -25,6 +25,9 @@ module RuboCop
|
|
25
25
|
include Alignment
|
26
26
|
include Heredoc
|
27
27
|
extend AutoCorrector
|
28
|
+
extend TargetRubyVersion
|
29
|
+
|
30
|
+
minimum_target_ruby_version 2.3
|
28
31
|
|
29
32
|
TYPE_MSG = 'Use %<indentation_width>d spaces for indentation in a ' \
|
30
33
|
'heredoc by using `<<~` instead of `%<current_indent_type>s`.'
|
@@ -354,7 +354,7 @@ module RuboCop
|
|
354
354
|
# Don't check indentation if the line doesn't start with the body.
|
355
355
|
# For example, lines like "else do_something".
|
356
356
|
first_char_pos_on_line = body_node.source_range.source_line =~ /\S/
|
357
|
-
|
357
|
+
body_node.loc.column != first_char_pos_on_line
|
358
358
|
end
|
359
359
|
|
360
360
|
def offending_range(body_node, indentation)
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
75
75
|
def right_hand_side(send_node)
|
76
76
|
dot = send_node.loc.dot
|
77
77
|
selector = send_node.loc.selector
|
78
|
-
if send_node.dot? && selector && same_line?(dot, selector)
|
78
|
+
if (send_node.dot? || send_node.safe_navigation?) && selector && same_line?(dot, selector)
|
79
79
|
dot.join(selector)
|
80
80
|
elsif selector
|
81
81
|
selector
|
@@ -179,10 +179,10 @@ module RuboCop
|
|
179
179
|
# a.b
|
180
180
|
# .c
|
181
181
|
def semantic_alignment_base(node, rhs)
|
182
|
-
return unless rhs.source.start_with?('.')
|
182
|
+
return unless rhs.source.start_with?('.', '&.')
|
183
183
|
|
184
184
|
node = semantic_alignment_node(node)
|
185
|
-
return unless node&.loc&.selector
|
185
|
+
return unless node&.loc&.selector && node.loc.dot
|
186
186
|
|
187
187
|
node.loc.dot.join(node.loc.selector)
|
188
188
|
end
|
@@ -204,6 +204,10 @@ module RuboCop
|
|
204
204
|
dot_right_above = get_dot_right_above(node)
|
205
205
|
return dot_right_above if dot_right_above
|
206
206
|
|
207
|
+
if (multiline_block_chain_node = find_multiline_block_chain_node(node))
|
208
|
+
return multiline_block_chain_node
|
209
|
+
end
|
210
|
+
|
207
211
|
node = first_call_has_a_dot(node)
|
208
212
|
return if node.loc.dot.line != node.first_line
|
209
213
|
|
@@ -219,6 +223,17 @@ module RuboCop
|
|
219
223
|
end
|
220
224
|
end
|
221
225
|
|
226
|
+
def find_multiline_block_chain_node(node)
|
227
|
+
return unless (block_node = node.each_descendant(:block, :numblock).first)
|
228
|
+
return unless block_node.multiline? && block_node.parent.call_type?
|
229
|
+
|
230
|
+
if node.receiver.call_type?
|
231
|
+
node.receiver
|
232
|
+
else
|
233
|
+
block_node.parent
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
222
237
|
def first_call_has_a_dot(node)
|
223
238
|
# descend to root of method chain
|
224
239
|
node = node.receiver while node.receiver
|
@@ -108,7 +108,7 @@ module RuboCop
|
|
108
108
|
!comment_within?(node) &&
|
109
109
|
node.each_descendant(:if, :case, :kwbegin, :def, :defs).none? &&
|
110
110
|
node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
|
111
|
-
node.each_descendant(:begin).none? { |b| !b.single_line? }
|
111
|
+
node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
|
112
112
|
end
|
113
113
|
|
114
114
|
def convertible_block?(node)
|
@@ -168,7 +168,7 @@ module RuboCop
|
|
168
168
|
# follows, and that the rules for space inside don't apply.
|
169
169
|
return true if token2.comment?
|
170
170
|
|
171
|
-
|
171
|
+
!same_line?(token1, token2) || token1.space_after?
|
172
172
|
end
|
173
173
|
end
|
174
174
|
end
|
@@ -95,8 +95,11 @@ module RuboCop
|
|
95
95
|
def assumed_usage_context?(node)
|
96
96
|
# Basically, debugger methods are not used as a method argument without arguments.
|
97
97
|
return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
|
98
|
+
return true if assumed_argument?(node)
|
98
99
|
|
99
|
-
node.each_ancestor.none?
|
100
|
+
node.each_ancestor.none? do |ancestor|
|
101
|
+
ancestor.block_type? || ancestor.numblock_type? || ancestor.lambda_or_proc?
|
102
|
+
end
|
100
103
|
end
|
101
104
|
|
102
105
|
def chained_method_name(send_node)
|
@@ -109,6 +112,12 @@ module RuboCop
|
|
109
112
|
end
|
110
113
|
chained_method_name
|
111
114
|
end
|
115
|
+
|
116
|
+
def assumed_argument?(node)
|
117
|
+
parent = node.parent
|
118
|
+
|
119
|
+
parent.call_type? || parent.literal? || parent.pair_type?
|
120
|
+
end
|
112
121
|
end
|
113
122
|
end
|
114
123
|
end
|
@@ -5,7 +5,7 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# Checks for blocks without a body.
|
7
7
|
# Such empty blocks are typically an oversight or we should provide a comment
|
8
|
-
#
|
8
|
+
# to clarify what we're aiming for.
|
9
9
|
#
|
10
10
|
# Empty lambdas and procs are ignored by default.
|
11
11
|
#
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
# interpolation should not be removed if the expanded value
|
35
35
|
# contains a space character.
|
36
36
|
expanded_value = autocorrected_value(final_node)
|
37
|
-
return if in_array_percent_literal?(begin_node) && /\s/.match?(expanded_value)
|
37
|
+
return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(expanded_value)
|
38
38
|
|
39
39
|
add_offense(final_node) do |corrector|
|
40
40
|
return if final_node.dstr_type? # nested, fixed in next iteration
|
@@ -24,6 +24,10 @@ module RuboCop
|
|
24
24
|
#
|
25
25
|
# This cop target those features.
|
26
26
|
#
|
27
|
+
# @safety
|
28
|
+
# This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file,
|
29
|
+
# `NameError` can be encountered when another file uses `PP.pp`.
|
30
|
+
#
|
27
31
|
# @example
|
28
32
|
# # bad
|
29
33
|
# require 'unloaded_feature'
|
@@ -4,8 +4,12 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for redundant safe navigation calls.
|
7
|
-
#
|
8
|
-
#
|
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 snake case constant.
|
9
|
+
#
|
10
|
+
# For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
|
11
|
+
# and `equal?` methods are checked by default.
|
12
|
+
# These are customizable with `AllowedMethods` option.
|
9
13
|
#
|
10
14
|
# The `AllowedMethods` option specifies nil-safe methods,
|
11
15
|
# in other words, it is a method that is allowed to skip safe navigation.
|
@@ -22,6 +26,9 @@ module RuboCop
|
|
22
26
|
#
|
23
27
|
# @example
|
24
28
|
# # bad
|
29
|
+
# CamelCaseConst&.do_something
|
30
|
+
#
|
31
|
+
# # bad
|
25
32
|
# do_something if attrs&.respond_to?(:[])
|
26
33
|
#
|
27
34
|
# # good
|
@@ -33,6 +40,9 @@ module RuboCop
|
|
33
40
|
# end
|
34
41
|
#
|
35
42
|
# # good
|
43
|
+
# CamelCaseConst.do_something
|
44
|
+
#
|
45
|
+
# # good
|
36
46
|
# while node.is_a?(BeginNode)
|
37
47
|
# node = node.parent
|
38
48
|
# end
|
@@ -57,18 +67,24 @@ module RuboCop
|
|
57
67
|
|
58
68
|
NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
|
59
69
|
|
70
|
+
SNAKE_CASE = /\A[[:digit:][:upper:]_]+\z/.freeze
|
71
|
+
|
60
72
|
# @!method respond_to_nil_specific_method?(node)
|
61
73
|
def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN
|
62
74
|
(csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
|
63
75
|
PATTERN
|
64
76
|
|
77
|
+
# rubocop:disable Metrics/AbcSize
|
65
78
|
def on_csend(node)
|
66
|
-
|
67
|
-
|
79
|
+
unless node.receiver.const_type? && !node.receiver.source.match?(SNAKE_CASE)
|
80
|
+
return unless check?(node) && allowed_method?(node.method_name)
|
81
|
+
return if respond_to_nil_specific_method?(node)
|
82
|
+
end
|
68
83
|
|
69
84
|
range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
|
70
85
|
add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') }
|
71
86
|
end
|
87
|
+
# rubocop:enable Metrics/AbcSize
|
72
88
|
|
73
89
|
private
|
74
90
|
|
@@ -82,16 +82,23 @@ module RuboCop
|
|
82
82
|
def autocorrect(corrector, offense_range:, send_node:)
|
83
83
|
corrector.replace(
|
84
84
|
offense_range,
|
85
|
-
add_safe_navigation_operator(
|
86
|
-
offense_range: offense_range,
|
87
|
-
send_node: send_node
|
88
|
-
)
|
85
|
+
add_safe_navigation_operator(offense_range: offense_range, send_node: send_node)
|
89
86
|
)
|
87
|
+
|
88
|
+
corrector.wrap(send_node, '(', ')') if require_parentheses?(send_node)
|
90
89
|
end
|
91
90
|
|
92
91
|
def brackets?(send_node)
|
93
92
|
send_node.method?(:[]) || send_node.method?(:[]=)
|
94
93
|
end
|
94
|
+
|
95
|
+
def require_parentheses?(send_node)
|
96
|
+
return false unless send_node.comparison_method?
|
97
|
+
return false unless (node = send_node.parent)
|
98
|
+
|
99
|
+
(node.respond_to?(:logical_operator?) && node.logical_operator?) ||
|
100
|
+
(node.respond_to?(:comparison_method?) && node.comparison_method?)
|
101
|
+
end
|
95
102
|
end
|
96
103
|
end
|
97
104
|
end
|