rubocop 1.86.1 → 1.86.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/config/default.yml +8 -1
- data/lib/rubocop/cli/command/auto_generate_config.rb +27 -1
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +3 -7
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +4 -7
- data/lib/rubocop/comment_config.rb +12 -15
- data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/require_mfa.rb +3 -3
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +26 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +2 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +3 -8
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +18 -7
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin.rb +85 -0
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +8 -0
- data/lib/rubocop/cop/registry.rb +19 -24
- data/lib/rubocop/cop/style/copyright.rb +21 -10
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/hash_lookup_method.rb +12 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +15 -2
- data/lib/rubocop/cop/style/module_member_existence_check.rb +6 -3
- data/lib/rubocop/cop/style/reduce_to_hash.rb +16 -0
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +29 -0
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +3 -3
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/team.rb +86 -35
- data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -1
- data/lib/rubocop/lsp/runtime.rb +1 -2
- data/lib/rubocop/options.rb +8 -4
- data/lib/rubocop/rspec/shared_contexts.rb +21 -0
- data/lib/rubocop/runner.rb +77 -55
- data/lib/rubocop/target_finder.rb +13 -6
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +7 -96
- metadata +5 -2
|
@@ -109,7 +109,7 @@ module RuboCop
|
|
|
109
109
|
# @_foo = calculate_expensive_thing
|
|
110
110
|
# end
|
|
111
111
|
#
|
|
112
|
-
# @example EnforcedStyleForLeadingUnderscores
|
|
112
|
+
# @example EnforcedStyleForLeadingUnderscores: optional
|
|
113
113
|
# # bad
|
|
114
114
|
# def foo
|
|
115
115
|
# @something ||= calculate_expensive_thing
|
data/lib/rubocop/cop/offense.rb
CHANGED
|
@@ -98,6 +98,14 @@ module RuboCop
|
|
|
98
98
|
freeze
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
def marshal_dump
|
|
102
|
+
[@severity, @location, @message, @cop_name, @status]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def marshal_load(array)
|
|
106
|
+
@severity, @location, @message, @cop_name, @status = array
|
|
107
|
+
end
|
|
108
|
+
|
|
101
109
|
# @api public
|
|
102
110
|
#
|
|
103
111
|
# @!attribute [r] correctable?
|
data/lib/rubocop/cop/registry.rb
CHANGED
|
@@ -49,9 +49,8 @@ module RuboCop
|
|
|
49
49
|
attr_reader :options, :warnings
|
|
50
50
|
|
|
51
51
|
def initialize(cops = [], options = {})
|
|
52
|
-
@
|
|
53
|
-
@
|
|
54
|
-
@cops_by_cop_name = Hash.new { |hash, key| hash[key] = [] }
|
|
52
|
+
@departments = Set.new
|
|
53
|
+
@cops_by_badge = {}
|
|
55
54
|
|
|
56
55
|
@enrollment_queue = cops
|
|
57
56
|
@options = options
|
|
@@ -72,22 +71,17 @@ module RuboCop
|
|
|
72
71
|
# @return [Array<Symbol>] list of departments for current cops.
|
|
73
72
|
def departments
|
|
74
73
|
clear_enrollment_queue
|
|
75
|
-
@departments.
|
|
74
|
+
@departments.to_a
|
|
76
75
|
end
|
|
77
76
|
|
|
78
77
|
# @return [Registry] Cops for that specific department.
|
|
79
78
|
def with_department(department)
|
|
80
|
-
|
|
81
|
-
with(@departments.fetch(department, []))
|
|
79
|
+
with(cops.select { |cop| cop.department == department })
|
|
82
80
|
end
|
|
83
81
|
|
|
84
82
|
# @return [Registry] Cops not for a specific department.
|
|
85
83
|
def without_department(department)
|
|
86
|
-
|
|
87
|
-
without_department = @departments.dup
|
|
88
|
-
without_department.delete(department)
|
|
89
|
-
|
|
90
|
-
with(without_department.values.flatten)
|
|
84
|
+
with(cops.reject { |cop| cop.department == department })
|
|
91
85
|
end
|
|
92
86
|
|
|
93
87
|
# @return [Boolean] Checks if given name is department
|
|
@@ -160,31 +154,31 @@ module RuboCop
|
|
|
160
154
|
def unqualified_cop_names
|
|
161
155
|
clear_enrollment_queue
|
|
162
156
|
@unqualified_cop_names ||=
|
|
163
|
-
Set.new(@
|
|
157
|
+
Set.new(@cops_by_badge.keys.map { |badge| File.basename(badge.to_s) }) <<
|
|
164
158
|
'RedundantCopDisableDirective'
|
|
165
159
|
end
|
|
166
160
|
|
|
167
161
|
def qualify_badge(badge)
|
|
168
162
|
clear_enrollment_queue
|
|
169
163
|
@departments
|
|
170
|
-
.map { |department
|
|
164
|
+
.map { |department| badge.with_department(department) }
|
|
171
165
|
.select { |potential_badge| registered?(potential_badge) }
|
|
172
166
|
end
|
|
173
167
|
|
|
174
168
|
# @return [Hash{String => Array<Class>}]
|
|
175
169
|
def to_h
|
|
176
170
|
clear_enrollment_queue
|
|
177
|
-
@
|
|
171
|
+
@cops_by_badge.to_h { |_badge, cop| [cop.cop_name, [cop]] }
|
|
178
172
|
end
|
|
179
173
|
|
|
180
174
|
def cops
|
|
181
175
|
clear_enrollment_queue
|
|
182
|
-
@
|
|
176
|
+
@cops_by_badge.values
|
|
183
177
|
end
|
|
184
178
|
|
|
185
179
|
def length
|
|
186
180
|
clear_enrollment_queue
|
|
187
|
-
@
|
|
181
|
+
@cops_by_badge.size
|
|
188
182
|
end
|
|
189
183
|
|
|
190
184
|
def enabled(config)
|
|
@@ -219,7 +213,8 @@ module RuboCop
|
|
|
219
213
|
end
|
|
220
214
|
|
|
221
215
|
def names
|
|
222
|
-
|
|
216
|
+
clear_enrollment_queue
|
|
217
|
+
@cops_by_badge.keys.map(&:to_s)
|
|
223
218
|
end
|
|
224
219
|
|
|
225
220
|
def cops_for_department(department)
|
|
@@ -236,7 +231,7 @@ module RuboCop
|
|
|
236
231
|
|
|
237
232
|
def sort!
|
|
238
233
|
clear_enrollment_queue
|
|
239
|
-
@
|
|
234
|
+
@cops_by_badge = @cops_by_badge.sort_by { |badge, _cop| badge.cop_name }.to_h
|
|
240
235
|
|
|
241
236
|
self
|
|
242
237
|
end
|
|
@@ -252,7 +247,9 @@ module RuboCop
|
|
|
252
247
|
# @param [String] cop_name
|
|
253
248
|
# @return [Class, nil]
|
|
254
249
|
def find_by_cop_name(cop_name)
|
|
255
|
-
|
|
250
|
+
clear_enrollment_queue
|
|
251
|
+
badge = Badge.parse(cop_name)
|
|
252
|
+
@cops_by_badge[badge]
|
|
256
253
|
end
|
|
257
254
|
|
|
258
255
|
# When a cop name is given returns a single-element array with the cop class.
|
|
@@ -289,10 +286,8 @@ module RuboCop
|
|
|
289
286
|
return if @enrollment_queue.empty?
|
|
290
287
|
|
|
291
288
|
@enrollment_queue.each do |cop|
|
|
292
|
-
@
|
|
293
|
-
@departments
|
|
294
|
-
@departments[cop.department] << cop
|
|
295
|
-
@cops_by_cop_name[cop.cop_name] << cop
|
|
289
|
+
@cops_by_badge[cop.badge] = cop
|
|
290
|
+
@departments << cop.department
|
|
296
291
|
end
|
|
297
292
|
@enrollment_queue = []
|
|
298
293
|
end
|
|
@@ -318,7 +313,7 @@ module RuboCop
|
|
|
318
313
|
|
|
319
314
|
def registered?(badge)
|
|
320
315
|
clear_enrollment_queue
|
|
321
|
-
@
|
|
316
|
+
@cops_by_badge.key?(badge)
|
|
322
317
|
end
|
|
323
318
|
end
|
|
324
319
|
end
|
|
@@ -46,15 +46,16 @@ module RuboCop
|
|
|
46
46
|
token = insert_notice_before(processed_source)
|
|
47
47
|
range = token.nil? ? range_between(0, 0) : token.pos
|
|
48
48
|
|
|
49
|
-
corrector.insert_before(range, "#{
|
|
49
|
+
corrector.insert_before(range, "#{normalized_autocorrect_notice}\n")
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
def normalized_autocorrect_notice
|
|
53
|
+
autocorrect_notice.lines.map do |line|
|
|
54
|
+
next line if line.start_with?('#')
|
|
55
|
+
next "#\n" if line.chomp.empty?
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
"# #{line}"
|
|
58
|
+
end.join
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
def verify_autocorrect_notice!
|
|
@@ -62,8 +63,7 @@ module RuboCop
|
|
|
62
63
|
raise Warning, "#{cop_name}: #{AUTOCORRECT_EMPTY_WARNING}"
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
return if autocorrect_notice.gsub(/^# */, '').match?(regex)
|
|
66
|
+
return if normalized_autocorrect_notice.gsub(/^# */, '').match?(notice_regexp)
|
|
67
67
|
|
|
68
68
|
message = "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
|
|
69
69
|
raise Warning, "#{cop_name}: #{message}"
|
|
@@ -91,18 +91,29 @@ module RuboCop
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def notice_found?(processed_source)
|
|
94
|
-
notice_regexp = Regexp.new(notice.lines.map(&:strip).join)
|
|
95
94
|
multiline_notice = +''
|
|
96
95
|
processed_source.tokens.each do |token|
|
|
97
96
|
break unless token.comment?
|
|
98
97
|
|
|
99
|
-
multiline_notice << token.text.sub(/\A# */, '')
|
|
98
|
+
multiline_notice << token.text.sub(/\A# */, '') << "\n"
|
|
100
99
|
|
|
101
100
|
break if notice_regexp.match?(token.text)
|
|
102
101
|
end
|
|
103
102
|
|
|
104
103
|
multiline_notice.match?(notice_regexp)
|
|
105
104
|
end
|
|
105
|
+
|
|
106
|
+
def notice_regexp
|
|
107
|
+
@notice_regexp ||= Regexp.new(notice.sub(/\A(?:\\A|\^)?#(?:\\s[*+?]?|\s)*/, ''))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def notice
|
|
111
|
+
cop_config['Notice']
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def autocorrect_notice
|
|
115
|
+
cop_config['AutocorrectNotice']
|
|
116
|
+
end
|
|
106
117
|
end
|
|
107
118
|
end
|
|
108
119
|
end
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for consistent usage of the `
|
|
7
|
-
# `
|
|
6
|
+
# Checks for consistent usage of the `Time` class over the
|
|
7
|
+
# `DateTime` class. This cop is disabled by default since these classes,
|
|
8
8
|
# although highly overlapping, have particularities that make them not
|
|
9
9
|
# replaceable in certain situations when dealing with multiple timezones
|
|
10
10
|
# and/or DST.
|
|
@@ -161,7 +161,12 @@ module RuboCop
|
|
|
161
161
|
source = source.gsub(COMMENT_REGEXP, '')
|
|
162
162
|
return if source.blank?
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
# Treat `\#` (an escaped interpolation marker in the heredoc) as matching
|
|
165
|
+
# either `\#` or `#` in the comment, since the comment may show either
|
|
166
|
+
# the literal source form or the runtime appearance.
|
|
167
|
+
segments = source.strip.split('\\#', -1).map { |segment| Regexp.escape(segment) }
|
|
168
|
+
|
|
169
|
+
/\s*#{segments.join('\\\\?#')}/
|
|
165
170
|
end
|
|
166
171
|
end
|
|
167
172
|
end
|
|
@@ -82,18 +82,23 @@ module RuboCop
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def correct_fetch_to_brackets(corrector, node)
|
|
85
|
-
receiver = node.receiver.source
|
|
86
85
|
key = node.first_argument.source
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
|
|
87
|
+
if node.csend_type?
|
|
88
|
+
corrector.replace(node, "(#{node.receiver.source}[#{key}])")
|
|
89
|
+
else
|
|
90
|
+
corrector.replace(node.loc.dot.join(node.source_range.end), "[#{key}]")
|
|
91
|
+
end
|
|
90
92
|
end
|
|
91
93
|
|
|
92
94
|
def correct_brackets_to_fetch(corrector, node)
|
|
93
|
-
receiver = node.receiver.source
|
|
94
95
|
key = node.first_argument.source
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
|
|
97
|
+
if node.csend_type?
|
|
98
|
+
corrector.replace(node.loc.dot.join(node.source_range.end), "&.fetch(#{key})")
|
|
99
|
+
else
|
|
100
|
+
corrector.replace(node.loc.selector.join(node.source_range.end), ".fetch(#{key})")
|
|
101
|
+
end
|
|
97
102
|
end
|
|
98
103
|
end
|
|
99
104
|
end
|
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
|
64
64
|
|
|
65
65
|
MSG = 'Convert `if` nested inside `else` to `elsif`.'
|
|
66
66
|
|
|
67
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
67
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
68
68
|
def on_if(node)
|
|
69
69
|
return if node.ternary? || node.unless?
|
|
70
70
|
|
|
@@ -72,6 +72,7 @@ module RuboCop
|
|
|
72
72
|
|
|
73
73
|
return unless else_branch&.if_type? && else_branch.if?
|
|
74
74
|
return if allow_if_modifier_in_else_branch?(else_branch)
|
|
75
|
+
return if comments_between_else_and_if?(node, else_branch)
|
|
75
76
|
|
|
76
77
|
add_offense(else_branch.loc.keyword) do |corrector|
|
|
77
78
|
next if part_of_ignored_node?(node)
|
|
@@ -80,7 +81,7 @@ module RuboCop
|
|
|
80
81
|
ignore_node(node)
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
84
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
84
85
|
|
|
85
86
|
private
|
|
86
87
|
|
|
@@ -135,6 +136,18 @@ module RuboCop
|
|
|
135
136
|
range_between(node.loc.keyword.begin_pos, condition.source_range.end_pos)
|
|
136
137
|
end
|
|
137
138
|
|
|
139
|
+
def comments_between_else_and_if?(node, else_branch)
|
|
140
|
+
return false if else_branch.modifier_form?
|
|
141
|
+
|
|
142
|
+
else_end = node.loc.else.end_pos
|
|
143
|
+
if_begin = else_branch.loc.keyword.begin_pos
|
|
144
|
+
|
|
145
|
+
processed_source.comments.any? do |comment|
|
|
146
|
+
comment_pos = comment.source_range.begin_pos
|
|
147
|
+
comment_pos > else_end && comment_pos < if_begin
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
138
151
|
def allow_if_modifier_in_else_branch?(else_branch)
|
|
139
152
|
allow_if_modifier? && else_branch&.modifier_form?
|
|
140
153
|
end
|
|
@@ -13,6 +13,12 @@ module RuboCop
|
|
|
13
13
|
# array, while `method_defined?` will do direct method lookup, which is much
|
|
14
14
|
# faster and consumes less memory.
|
|
15
15
|
#
|
|
16
|
+
# NOTE: `constants.include?` is not handled by this cop because
|
|
17
|
+
# `Module#const_defined?` has different lookup behavior than
|
|
18
|
+
# `Module#constants` - `const_defined?` searches up to `Object`
|
|
19
|
+
# (top-level constants like `String`, `Integer`, etc.) while
|
|
20
|
+
# `constants` does not, which can cause behavior changes after autocorrection.
|
|
21
|
+
#
|
|
16
22
|
# @example
|
|
17
23
|
# # bad
|
|
18
24
|
# Array.instance_methods.include?(:size)
|
|
@@ -28,14 +34,12 @@ module RuboCop
|
|
|
28
34
|
#
|
|
29
35
|
# # bad
|
|
30
36
|
# Array.class_variables.include?(:foo)
|
|
31
|
-
# Array.constants.include?(:foo)
|
|
32
37
|
# Array.private_instance_methods.include?(:foo)
|
|
33
38
|
# Array.protected_instance_methods.include?(:foo)
|
|
34
39
|
# Array.public_instance_methods.include?(:foo)
|
|
35
40
|
#
|
|
36
41
|
# # good
|
|
37
42
|
# Array.class_variable_defined?(:foo)
|
|
38
|
-
# Array.const_defined?(:foo)
|
|
39
43
|
# Array.private_method_defined?(:foo)
|
|
40
44
|
# Array.protected_method_defined?(:foo)
|
|
41
45
|
# Array.public_method_defined?(:foo)
|
|
@@ -55,7 +59,6 @@ module RuboCop
|
|
|
55
59
|
|
|
56
60
|
METHOD_REPLACEMENTS = {
|
|
57
61
|
class_variables: :class_variable_defined?,
|
|
58
|
-
constants: :const_defined?,
|
|
59
62
|
instance_methods: :method_defined?,
|
|
60
63
|
private_instance_methods: :private_method_defined?,
|
|
61
64
|
protected_instance_methods: :protected_method_defined?,
|
|
@@ -99,6 +99,7 @@ module RuboCop
|
|
|
99
99
|
end
|
|
100
100
|
return unless key
|
|
101
101
|
return if accumulator_used_in_expressions?(block_node, key, value)
|
|
102
|
+
return if nested_match?(key) || nested_match?(value)
|
|
102
103
|
|
|
103
104
|
register_offense(node, block_node, key, value)
|
|
104
105
|
end
|
|
@@ -108,6 +109,21 @@ module RuboCop
|
|
|
108
109
|
references_variable?(key, acc_name) || references_variable?(value, acc_name)
|
|
109
110
|
end
|
|
110
111
|
|
|
112
|
+
def nested_match?(node)
|
|
113
|
+
node.each_node(:call).any? do |send_node|
|
|
114
|
+
next false unless RESTRICT_ON_SEND.include?(send_node.method_name)
|
|
115
|
+
|
|
116
|
+
inner_block = send_node.block_node
|
|
117
|
+
next false unless inner_block
|
|
118
|
+
|
|
119
|
+
if send_node.method?(:each_with_object)
|
|
120
|
+
each_with_object_to_hash?(inner_block)
|
|
121
|
+
else
|
|
122
|
+
inject_to_hash?(inner_block)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
111
127
|
def accumulator_name(block_node)
|
|
112
128
|
index = block_node.method?(:each_with_object) ? 1 : 0
|
|
113
129
|
block_node.argument_list[index].name
|
|
@@ -59,7 +59,7 @@ module RuboCop
|
|
|
59
59
|
|
|
60
60
|
def initialize(config = nil, options = nil)
|
|
61
61
|
super
|
|
62
|
-
@allowed_send_nodes =
|
|
62
|
+
@allowed_send_nodes = Set.new.compare_by_identity
|
|
63
63
|
@local_variables_scopes = Hash.new { |hash, key| hash[key] = [] }.compare_by_identity
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -187,7 +187,7 @@ module RuboCop
|
|
|
187
187
|
def allow_self(node)
|
|
188
188
|
return unless node.send_type? && node.self_receiver?
|
|
189
189
|
|
|
190
|
-
@allowed_send_nodes
|
|
190
|
+
@allowed_send_nodes.add(node)
|
|
191
191
|
end
|
|
192
192
|
|
|
193
193
|
def add_lhs_to_local_variables_scopes(rhs, lhs)
|
|
@@ -98,7 +98,16 @@ module RuboCop
|
|
|
98
98
|
MSG_USE_SLASHES = 'Use `//` around regular expression.'
|
|
99
99
|
MSG_USE_PERCENT_R = 'Use `%r` around regular expression.'
|
|
100
100
|
|
|
101
|
+
PAIR_DELIMITER_PATTERNS = {
|
|
102
|
+
['(', ')'] => /\\.|[()]/,
|
|
103
|
+
['[', ']'] => /\\.|[\[\]]/,
|
|
104
|
+
['{', '}'] => /\\.|[{}]/,
|
|
105
|
+
['<', '>'] => /\\.|[<>]/
|
|
106
|
+
}.freeze
|
|
107
|
+
|
|
101
108
|
def on_regexp(node)
|
|
109
|
+
return if slash_literal?(node) && percent_r_delimiters_conflict?(node)
|
|
110
|
+
|
|
102
111
|
message = if slash_literal?(node)
|
|
103
112
|
MSG_USE_PERCENT_R unless allowed_slash_literal?(node)
|
|
104
113
|
else
|
|
@@ -115,6 +124,26 @@ module RuboCop
|
|
|
115
124
|
|
|
116
125
|
private
|
|
117
126
|
|
|
127
|
+
def percent_r_delimiters_conflict?(node)
|
|
128
|
+
opening, closing = preferred_delimiters
|
|
129
|
+
return false unless (pattern = PAIR_DELIMITER_PATTERNS[[opening, closing]])
|
|
130
|
+
|
|
131
|
+
!balanced_delimiters?(node_body(node), opening, closing, pattern)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def balanced_delimiters?(text, opening, closing, pattern)
|
|
135
|
+
depth = 0
|
|
136
|
+
text.scan(pattern) do |match|
|
|
137
|
+
if match == opening
|
|
138
|
+
depth += 1
|
|
139
|
+
elsif match == closing
|
|
140
|
+
depth -= 1
|
|
141
|
+
return false if depth.negative?
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
depth.zero?
|
|
145
|
+
end
|
|
146
|
+
|
|
118
147
|
def allowed_slash_literal?(node)
|
|
119
148
|
(style == :slashes && !contains_disallowed_slash?(node)) || allowed_mixed_slash?(node)
|
|
120
149
|
end
|
|
@@ -65,7 +65,10 @@ module RuboCop
|
|
|
65
65
|
|
|
66
66
|
message = format(MSG, conditional_type: node.keyword)
|
|
67
67
|
add_offense(if_branch.loc.keyword, message: message) do |corrector|
|
|
68
|
+
next if ignored_node?(node)
|
|
69
|
+
|
|
68
70
|
autocorrect(corrector, node, if_branch)
|
|
71
|
+
ignore_node(if_branch)
|
|
69
72
|
end
|
|
70
73
|
end
|
|
71
74
|
|
|
@@ -115,9 +118,8 @@ module RuboCop
|
|
|
115
118
|
end
|
|
116
119
|
|
|
117
120
|
def correct_node(corrector, node)
|
|
118
|
-
corrector.replace(node.loc.keyword, 'if') if node.unless?
|
|
121
|
+
corrector.replace(node.loc.keyword, 'if') if node.unless?
|
|
119
122
|
corrector.replace(node.condition, chainable_condition(node))
|
|
120
|
-
ignore_node(node)
|
|
121
123
|
end
|
|
122
124
|
|
|
123
125
|
def correct_for_guard_condition_style(corrector, node, if_branch)
|
|
@@ -260,10 +260,10 @@ module RuboCop
|
|
|
260
260
|
end
|
|
261
261
|
|
|
262
262
|
def begin_pos_for_replacement(node)
|
|
263
|
-
|
|
263
|
+
send_node = node.send_node
|
|
264
264
|
|
|
265
|
-
if
|
|
266
|
-
|
|
265
|
+
if send_node.parenthesized? && send_node.arguments.empty?
|
|
266
|
+
send_node.loc.begin.begin_pos
|
|
267
267
|
else
|
|
268
268
|
node.loc.begin.begin_pos
|
|
269
269
|
end
|
|
@@ -16,6 +16,11 @@ module RuboCop
|
|
|
16
16
|
# # good
|
|
17
17
|
# x += 1 while x < 10
|
|
18
18
|
#
|
|
19
|
+
# # good
|
|
20
|
+
# while x < 10
|
|
21
|
+
# y += 1 if x.odd?
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
19
24
|
# # bad
|
|
20
25
|
# until x > 10
|
|
21
26
|
# x += 1
|
|
@@ -24,6 +29,11 @@ module RuboCop
|
|
|
24
29
|
# # good
|
|
25
30
|
# x += 1 until x > 10
|
|
26
31
|
#
|
|
32
|
+
# # good
|
|
33
|
+
# until x > 10
|
|
34
|
+
# y += 1 unless x.even?
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
27
37
|
# # bad
|
|
28
38
|
# x += 100 while x < 500 # a long comment that makes code too long if it were a single line
|
|
29
39
|
#
|
|
@@ -45,6 +55,12 @@ module RuboCop
|
|
|
45
55
|
end
|
|
46
56
|
end
|
|
47
57
|
alias on_until on_while
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def non_eligible_body?(body)
|
|
62
|
+
body&.conditional? || super
|
|
63
|
+
end
|
|
48
64
|
end
|
|
49
65
|
end
|
|
50
66
|
end
|