rubocop 1.39.0 → 1.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +65 -9
- data/exe/rubocop +1 -1
- data/lib/rubocop/comment_config.rb +5 -0
- data/lib/rubocop/config.rb +33 -9
- data/lib/rubocop/config_loader.rb +14 -5
- data/lib/rubocop/config_loader_resolver.rb +1 -1
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/badge.rb +9 -4
- data/lib/rubocop/cop/base.rb +26 -17
- data/lib/rubocop/cop/commissioner.rb +8 -3
- data/lib/rubocop/cop/cop.rb +1 -1
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines.rb +2 -0
- data/lib/rubocop/cop/layout/extra_spacing.rb +10 -6
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +38 -2
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +49 -2
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +61 -2
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +52 -2
- data/lib/rubocop/cop/layout/indentation_style.rb +3 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +5 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
- data/lib/rubocop/cop/layout/line_length.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_array_line_breaks.rb +51 -2
- data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +49 -2
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +53 -2
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +58 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -2
- data/lib/rubocop/cop/layout/trailing_empty_lines.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +6 -2
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/constant_resolution.rb +4 -0
- data/lib/rubocop/cop/lint/debugger.rb +3 -1
- data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
- data/lib/rubocop/cop/lint/duplicate_branch.rb +0 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +19 -8
- data/lib/rubocop/cop/lint/empty_block.rb +1 -5
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -5
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +13 -3
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +10 -12
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
- data/lib/rubocop/cop/lint/void.rb +6 -6
- data/lib/rubocop/cop/metrics/block_length.rb +9 -4
- data/lib/rubocop/cop/metrics/class_length.rb +10 -5
- data/lib/rubocop/cop/metrics/method_length.rb +9 -4
- data/lib/rubocop/cop/metrics/module_length.rb +10 -5
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +6 -3
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/annotation_comment.rb +13 -6
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +21 -9
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +11 -7
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +28 -5
- data/lib/rubocop/cop/mixin/line_length_help.rb +8 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +5 -3
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +5 -3
- data/lib/rubocop/cop/mixin/percent_array.rb +3 -5
- data/lib/rubocop/cop/mixin/require_library.rb +2 -0
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +2 -0
- data/lib/rubocop/cop/naming/inclusive_language.rb +4 -1
- data/lib/rubocop/cop/registry.rb +29 -14
- data/lib/rubocop/cop/style/array_intersect.rb +111 -0
- data/lib/rubocop/cop/style/concat_array_literals.rb +66 -0
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +36 -5
- data/lib/rubocop/cop/style/if_with_semicolon.rb +4 -4
- data/lib/rubocop/cop/style/inverse_methods.rb +2 -0
- data/lib/rubocop/cop/style/line_end_concatenation.rb +4 -1
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
- data/lib/rubocop/cop/style/redundant_constant_base.rb +85 -0
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +39 -0
- data/lib/rubocop/cop/style/redundant_return.rb +7 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/require_order.rb +140 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
- data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
- data/lib/rubocop/cop/style/semicolon.rb +2 -1
- data/lib/rubocop/cop/style/string_literals.rb +1 -5
- data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +32 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +20 -29
- data/lib/rubocop/cops_documentation_generator.rb +22 -3
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/file_patterns.rb +43 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +3 -1
- data/lib/rubocop/options.rb +8 -0
- data/lib/rubocop/path_util.rb +34 -16
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/rspec/cop_helper.rb +4 -1
- data/lib/rubocop/rspec/support.rb +2 -2
- data/lib/rubocop/server/core.rb +1 -1
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +16 -6
- metadata +10 -3
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -28,6 +28,9 @@ module RuboCop
|
|
28
28
|
|
29
29
|
@enrollment_queue = cops
|
30
30
|
@options = options
|
31
|
+
|
32
|
+
@enabled_cache = {}.compare_by_identity
|
33
|
+
@disabled_cache = {}.compare_by_identity
|
31
34
|
end
|
32
35
|
|
33
36
|
def enlist(cop)
|
@@ -61,7 +64,7 @@ module RuboCop
|
|
61
64
|
|
62
65
|
# @return [Boolean] Checks if given name is department
|
63
66
|
def department?(name)
|
64
|
-
departments.include?
|
67
|
+
departments.include?(name.to_sym)
|
65
68
|
end
|
66
69
|
|
67
70
|
def contains_cop_matching?(names)
|
@@ -72,27 +75,27 @@ module RuboCop
|
|
72
75
|
#
|
73
76
|
# @example gives back a correctly qualified cop name
|
74
77
|
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
# qualified_cop_name('Layout/EndOfLine') # => 'Layout/EndOfLine'
|
78
|
+
# registry = RuboCop::Cop::Registry
|
79
|
+
# registry.qualified_cop_name('Layout/EndOfLine', '') # => 'Layout/EndOfLine'
|
78
80
|
#
|
79
81
|
# @example fixes incorrect namespaces
|
80
82
|
#
|
81
|
-
#
|
82
|
-
#
|
83
|
+
# registry = RuboCop::Cop::Registry
|
84
|
+
# registry.qualified_cop_name('Lint/EndOfLine', '') # => 'Layout/EndOfLine'
|
83
85
|
#
|
84
86
|
# @example namespaces bare cop identifiers
|
85
87
|
#
|
86
|
-
#
|
87
|
-
#
|
88
|
+
# registry = RuboCop::Cop::Registry
|
89
|
+
# registry.qualified_cop_name('EndOfLine', '') # => 'Layout/EndOfLine'
|
88
90
|
#
|
89
91
|
# @example passes back unrecognized cop names
|
90
92
|
#
|
91
|
-
#
|
92
|
-
#
|
93
|
+
# registry = RuboCop::Cop::Registry
|
94
|
+
# registry.qualified_cop_name('NotACop', '') # => 'NotACop'
|
93
95
|
#
|
94
96
|
# @param name [String] Cop name extracted from config
|
95
97
|
# @param path [String, nil] Path of file that `name` was extracted from
|
98
|
+
# @param warn [Boolean] Print a warning if no department given for `name`
|
96
99
|
#
|
97
100
|
# @raise [AmbiguousCopName]
|
98
101
|
# if a bare identifier with two possible namespaces is provided
|
@@ -150,15 +153,15 @@ module RuboCop
|
|
150
153
|
end
|
151
154
|
|
152
155
|
def enabled(config)
|
153
|
-
select { |cop| enabled?(cop, config) }
|
156
|
+
@enabled_cache[config] ||= select { |cop| enabled?(cop, config) }
|
154
157
|
end
|
155
158
|
|
156
159
|
def disabled(config)
|
157
|
-
reject { |cop| enabled?(cop, config) }
|
160
|
+
@disabled_cache[config] ||= reject { |cop| enabled?(cop, config) }
|
158
161
|
end
|
159
162
|
|
160
163
|
def enabled?(cop, config)
|
161
|
-
return true if options
|
164
|
+
return true if options[:only]&.include?(cop.cop_name)
|
162
165
|
|
163
166
|
cfg = config.for_cop(cop)
|
164
167
|
|
@@ -182,8 +185,12 @@ module RuboCop
|
|
182
185
|
cops.map(&:cop_name)
|
183
186
|
end
|
184
187
|
|
188
|
+
def cops_for_department(department)
|
189
|
+
cops.select { |cop| cop.department == department.to_sym }
|
190
|
+
end
|
191
|
+
|
185
192
|
def names_for_department(department)
|
186
|
-
|
193
|
+
cops_for_department(department).map(&:cop_name)
|
187
194
|
end
|
188
195
|
|
189
196
|
def ==(other)
|
@@ -211,6 +218,14 @@ module RuboCop
|
|
211
218
|
to_h[cop_name].first
|
212
219
|
end
|
213
220
|
|
221
|
+
# When a cop name is given returns a single-element array with the cop class.
|
222
|
+
# When a department name is given returns an array with all the cop classes
|
223
|
+
# for that department.
|
224
|
+
def find_cops_by_directive(directive)
|
225
|
+
cop = find_by_cop_name(directive)
|
226
|
+
cop ? [cop] : cops_for_department(directive)
|
227
|
+
end
|
228
|
+
|
214
229
|
def freeze
|
215
230
|
clear_enrollment_queue
|
216
231
|
unqualified_cop_names # build cache
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# In Ruby 3.1, `Array#intersect?` has been added.
|
7
|
+
#
|
8
|
+
# This cop identifies places where `(array1 & array2).any?`
|
9
|
+
# can be replaced by `array1.intersect?(array2)`.
|
10
|
+
#
|
11
|
+
# The `array1.intersect?(array2)` method is faster than
|
12
|
+
# `(array1 & array2).any?` and is more readable.
|
13
|
+
#
|
14
|
+
# @safety
|
15
|
+
# This cop cannot guarantee that array1 and array2 are
|
16
|
+
# actually arrays while method `intersect?` is for arrays only.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# # bad
|
20
|
+
# (array1 & array2).any?
|
21
|
+
# (array1 & array2).empty?
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# array1.intersect?(array2)
|
25
|
+
# !array1.intersect?(array2)
|
26
|
+
#
|
27
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
28
|
+
# # good
|
29
|
+
# (array1 & array2).present?
|
30
|
+
# (array1 & array2).blank?
|
31
|
+
#
|
32
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
33
|
+
# # bad
|
34
|
+
# (array1 & array2).present?
|
35
|
+
# (array1 & array2).blank?
|
36
|
+
#
|
37
|
+
# # good
|
38
|
+
# array1.intersect?(array2)
|
39
|
+
# !array1.intersect?(array2)
|
40
|
+
class ArrayIntersect < Base
|
41
|
+
extend AutoCorrector
|
42
|
+
extend TargetRubyVersion
|
43
|
+
|
44
|
+
minimum_target_ruby_version 3.1
|
45
|
+
|
46
|
+
# @!method regular_bad_intersection_check?(node)
|
47
|
+
def_node_matcher :regular_bad_intersection_check?, <<~PATTERN
|
48
|
+
(send
|
49
|
+
(begin
|
50
|
+
(send $(...) :& $(...))
|
51
|
+
) ${:any? :empty?}
|
52
|
+
)
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
# @!method active_support_bad_intersection_check?(node)
|
56
|
+
def_node_matcher :active_support_bad_intersection_check?, <<~PATTERN
|
57
|
+
(send
|
58
|
+
(begin
|
59
|
+
(send $(...) :& $(...))
|
60
|
+
) ${:present? :any? :blank? :empty?}
|
61
|
+
)
|
62
|
+
PATTERN
|
63
|
+
|
64
|
+
MSG = 'Use `%<negated>s%<receiver>s.intersect?(%<argument>s)` ' \
|
65
|
+
'instead of `(%<receiver>s & %<argument>s).%<method_name>s`.'
|
66
|
+
STRAIGHT_METHODS = %i[present? any?].freeze
|
67
|
+
NEGATED_METHODS = %i[blank? empty?].freeze
|
68
|
+
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
69
|
+
|
70
|
+
def on_send(node)
|
71
|
+
return unless (receiver, argument, method_name = bad_intersection_check?(node))
|
72
|
+
|
73
|
+
message = message(receiver.source, argument.source, method_name)
|
74
|
+
|
75
|
+
add_offense(node, message: message) do |corrector|
|
76
|
+
if straight?(method_name)
|
77
|
+
corrector.replace(node, "#{receiver.source}.intersect?(#{argument.source})")
|
78
|
+
else
|
79
|
+
corrector.replace(node, "!#{receiver.source}.intersect?(#{argument.source})")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def bad_intersection_check?(node)
|
87
|
+
if active_support_extensions_enabled?
|
88
|
+
active_support_bad_intersection_check?(node)
|
89
|
+
else
|
90
|
+
regular_bad_intersection_check?(node)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def straight?(method_name)
|
95
|
+
STRAIGHT_METHODS.include?(method_name.to_sym)
|
96
|
+
end
|
97
|
+
|
98
|
+
def message(receiver, argument, method_name)
|
99
|
+
negated = straight?(method_name) ? '' : '!'
|
100
|
+
format(
|
101
|
+
MSG,
|
102
|
+
negated: negated,
|
103
|
+
receiver: receiver,
|
104
|
+
argument: argument,
|
105
|
+
method_name: method_name
|
106
|
+
)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Enforces the use of `Array#push(item)` instead of `Array#concat([item])`
|
7
|
+
# to avoid redundant array literals.
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe, as it can produce false positives if the receiver
|
11
|
+
# is not an `Array` object.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# list.concat([foo])
|
17
|
+
# list.concat([bar, baz])
|
18
|
+
# list.concat([qux, quux], [corge])
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# list.push(foo)
|
22
|
+
# list.push(bar, baz)
|
23
|
+
# list.push(qux, quux, corge)
|
24
|
+
#
|
25
|
+
class ConcatArrayLiterals < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
29
|
+
MSG_FOR_PERCENT_LITERALS =
|
30
|
+
'Use `push` with elements as arguments without array brackets instead of `%<current>s`.'
|
31
|
+
RESTRICT_ON_SEND = %i[concat].freeze
|
32
|
+
|
33
|
+
def on_send(node)
|
34
|
+
return if node.arguments.empty?
|
35
|
+
return unless node.arguments.all?(&:array_type?)
|
36
|
+
|
37
|
+
offense = offense_range(node)
|
38
|
+
current = offense.source
|
39
|
+
|
40
|
+
if node.arguments.any?(&:percent_literal?)
|
41
|
+
message = format(MSG_FOR_PERCENT_LITERALS, current: current)
|
42
|
+
else
|
43
|
+
prefer = preferred_method(node)
|
44
|
+
message = format(MSG, prefer: prefer, current: current)
|
45
|
+
end
|
46
|
+
|
47
|
+
add_offense(offense, message: message) do |corrector|
|
48
|
+
corrector.replace(offense, prefer)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def offense_range(node)
|
55
|
+
node.loc.selector.join(node.source_range.end)
|
56
|
+
end
|
57
|
+
|
58
|
+
def preferred_method(node)
|
59
|
+
new_arguments = node.arguments.map { |arg| arg.children.map(&:source) }.join(', ')
|
60
|
+
|
61
|
+
"push(#{new_arguments})"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -176,7 +176,7 @@ module RuboCop
|
|
176
176
|
end
|
177
177
|
|
178
178
|
def qualify_const(node)
|
179
|
-
return if node.nil? || node.cbase_type?
|
179
|
+
return if node.nil? || node.cbase_type? || node.self_type? || node.send_type?
|
180
180
|
|
181
181
|
[qualify_const(node.namespace), node.short_name].compact
|
182
182
|
end
|
@@ -94,6 +94,7 @@ module RuboCop
|
|
94
94
|
#
|
95
95
|
class GuardClause < Base
|
96
96
|
extend AutoCorrector
|
97
|
+
include RangeHelp
|
97
98
|
include MinBodyLength
|
98
99
|
include StatementModifier
|
99
100
|
|
@@ -179,13 +180,39 @@ module RuboCop
|
|
179
180
|
end
|
180
181
|
end
|
181
182
|
|
183
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
182
184
|
def autocorrect(corrector, node, condition, replacement, guard)
|
183
185
|
corrector.replace(node.loc.keyword.join(condition.loc.expression), replacement)
|
184
|
-
corrector.remove(node.loc.end)
|
185
|
-
return unless node.else?
|
186
186
|
|
187
|
-
|
188
|
-
|
187
|
+
if_branch = node.if_branch
|
188
|
+
else_branch = node.else_branch
|
189
|
+
|
190
|
+
if if_branch&.send_type? && heredoc?(if_branch.last_argument)
|
191
|
+
autocorrect_heredoc_argument(corrector, node, if_branch, else_branch, guard)
|
192
|
+
elsif else_branch&.send_type? && else_branch.last_argument&.heredoc?
|
193
|
+
autocorrect_heredoc_argument(corrector, node, else_branch, if_branch, guard)
|
194
|
+
else
|
195
|
+
corrector.remove(node.loc.end)
|
196
|
+
return unless node.else?
|
197
|
+
|
198
|
+
corrector.remove(node.loc.else)
|
199
|
+
corrector.remove(branch_to_remove(node, guard))
|
200
|
+
end
|
201
|
+
end
|
202
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
203
|
+
|
204
|
+
def heredoc?(argument)
|
205
|
+
argument.respond_to?(:heredoc?) && argument.heredoc?
|
206
|
+
end
|
207
|
+
|
208
|
+
def autocorrect_heredoc_argument(corrector, node, heredoc_branch, leave_branch, guard)
|
209
|
+
remove_whole_lines(corrector, leave_branch.source_range)
|
210
|
+
remove_whole_lines(corrector, node.loc.else)
|
211
|
+
remove_whole_lines(corrector, node.loc.end)
|
212
|
+
remove_whole_lines(corrector, branch_to_remove(node, guard).source_range)
|
213
|
+
corrector.insert_after(
|
214
|
+
heredoc_branch.last_argument.loc.heredoc_end, "\n#{leave_branch.source}"
|
215
|
+
)
|
189
216
|
end
|
190
217
|
|
191
218
|
def branch_to_remove(node, guard)
|
@@ -222,7 +249,7 @@ module RuboCop
|
|
222
249
|
end
|
223
250
|
|
224
251
|
def accepted_if?(node, ending)
|
225
|
-
return true if node.modifier_form? || node.ternary?
|
252
|
+
return true if node.modifier_form? || node.ternary? || node.elsif_conditional?
|
226
253
|
|
227
254
|
if ending
|
228
255
|
node.else?
|
@@ -231,6 +258,10 @@ module RuboCop
|
|
231
258
|
end
|
232
259
|
end
|
233
260
|
|
261
|
+
def remove_whole_lines(corrector, range)
|
262
|
+
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
263
|
+
end
|
264
|
+
|
234
265
|
def allowed_consecutive_conditionals?
|
235
266
|
cop_config.fetch('AllowConsecutiveConditionals', false)
|
236
267
|
end
|
@@ -21,13 +21,12 @@ module RuboCop
|
|
21
21
|
MSG_TERNARY = 'Do not use `if %<expr>s;` - use a ternary operator instead.'
|
22
22
|
|
23
23
|
def on_normal_if_unless(node)
|
24
|
-
return unless node.else_branch
|
25
24
|
return if node.parent&.if_type?
|
26
25
|
|
27
26
|
beginning = node.loc.begin
|
28
27
|
return unless beginning&.is?(';')
|
29
28
|
|
30
|
-
message = node.else_branch
|
29
|
+
message = node.else_branch&.if_type? ? MSG_IF_ELSE : MSG_TERNARY
|
31
30
|
|
32
31
|
add_offense(node, message: format(message, expr: node.condition.source)) do |corrector|
|
33
32
|
corrector.replace(node, autocorrect(node))
|
@@ -37,11 +36,12 @@ module RuboCop
|
|
37
36
|
private
|
38
37
|
|
39
38
|
def autocorrect(node)
|
40
|
-
return correct_elsif(node) if node.else_branch
|
39
|
+
return correct_elsif(node) if node.else_branch&.if_type?
|
41
40
|
|
41
|
+
then_code = node.if_branch ? node.if_branch.source : 'nil'
|
42
42
|
else_code = node.else_branch ? node.else_branch.source : 'nil'
|
43
43
|
|
44
|
-
"#{node.condition.source} ? #{
|
44
|
+
"#{node.condition.source} ? #{then_code} : #{else_code}"
|
45
45
|
end
|
46
46
|
|
47
47
|
def correct_elsif(node)
|
@@ -55,7 +55,10 @@ module RuboCop
|
|
55
55
|
private
|
56
56
|
|
57
57
|
def check_token_set(index)
|
58
|
-
|
58
|
+
tokens = processed_source.tokens
|
59
|
+
predecessor = tokens[index]
|
60
|
+
operator = tokens[index + 1]
|
61
|
+
successor = tokens[index + 2]
|
59
62
|
|
60
63
|
return unless eligible_token_set?(predecessor, operator, successor)
|
61
64
|
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
PATTERN
|
45
45
|
|
46
46
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
47
|
-
return unless node.
|
47
|
+
return unless node.lambda_or_proc?
|
48
48
|
return unless nil_return?(node.body)
|
49
49
|
|
50
50
|
message = format(MSG, type: node.lambda? ? 'lambda' : 'proc')
|
@@ -13,6 +13,7 @@ module RuboCop
|
|
13
13
|
# ----
|
14
14
|
# Methods:
|
15
15
|
# join: ''
|
16
|
+
# sum: 0
|
16
17
|
# split: ' '
|
17
18
|
# chomp: "\n"
|
18
19
|
# chomp!: "\n"
|
@@ -33,6 +34,7 @@ module RuboCop
|
|
33
34
|
# # bad
|
34
35
|
# array.join('')
|
35
36
|
# [1, 2, 3].join("")
|
37
|
+
# array.sum(0)
|
36
38
|
# string.split(" ")
|
37
39
|
# "first\nsecond".split(" ")
|
38
40
|
# string.chomp("\n")
|
@@ -42,6 +44,7 @@ module RuboCop
|
|
42
44
|
# # good
|
43
45
|
# array.join
|
44
46
|
# [1, 2, 3].join
|
47
|
+
# array.sum
|
45
48
|
# string.split
|
46
49
|
# "first second".split
|
47
50
|
# string.chomp
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Avoid redundant `::` prefix on constant.
|
7
|
+
#
|
8
|
+
# How Ruby searches constant is a bit complicated, and it can often be difficult to
|
9
|
+
# understand from the code whether the `::` is intended or not. Where `Module.nesting`
|
10
|
+
# is empty, there is no need to prepend `::`, so it would be nice to consistently
|
11
|
+
# avoid such meaningless `::` prefix to avoid confusion.
|
12
|
+
#
|
13
|
+
# NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled to prevent
|
14
|
+
# conflicting rules. Because it respects user configurations that want to enable
|
15
|
+
# `Lint/ConstantResolution` cop which is disabled by default.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# ::Const
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# Const
|
23
|
+
#
|
24
|
+
# # bad
|
25
|
+
# class << self
|
26
|
+
# ::Const
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
# class << self
|
31
|
+
# Const
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# class A
|
36
|
+
# ::Const
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # good
|
40
|
+
# module A
|
41
|
+
# ::Const
|
42
|
+
# end
|
43
|
+
class RedundantConstantBase < Base
|
44
|
+
extend AutoCorrector
|
45
|
+
|
46
|
+
MSG = 'Remove redundant `::`.'
|
47
|
+
|
48
|
+
def on_cbase(node)
|
49
|
+
return if lint_constant_resolution_cop_enabled?
|
50
|
+
return unless bad?(node)
|
51
|
+
|
52
|
+
add_offense(node) do |corrector|
|
53
|
+
corrector.remove(node)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def lint_constant_resolution_cop_enabled?
|
60
|
+
lint_constant_resolution_config.fetch('Enabled', false)
|
61
|
+
end
|
62
|
+
|
63
|
+
def lint_constant_resolution_config
|
64
|
+
config.for_cop('Lint/ConstantResolution')
|
65
|
+
end
|
66
|
+
|
67
|
+
def bad?(node)
|
68
|
+
module_nesting_ancestors_of(node).none?
|
69
|
+
end
|
70
|
+
|
71
|
+
def module_nesting_ancestors_of(node)
|
72
|
+
node.each_ancestor(:class, :module).reject do |ancestor|
|
73
|
+
ancestor.class_type? && used_in_super_class_part?(node, class_node: ancestor)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def used_in_super_class_part?(node, class_node:)
|
78
|
+
class_node.parent_class&.each_descendant(:cbase)&.any? do |descendant|
|
79
|
+
descendant.equal?(node)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for redundant uses of double splat hash braces.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# do_something(**{foo: bar, baz: qux})
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# do_something(foo: bar, baz: qux)
|
15
|
+
#
|
16
|
+
class RedundantDoubleSplatHashBraces < Base
|
17
|
+
extend AutoCorrector
|
18
|
+
|
19
|
+
MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.'
|
20
|
+
|
21
|
+
# @!method double_splat_hash_braces?(node)
|
22
|
+
def_node_matcher :double_splat_hash_braces?, <<~PATTERN
|
23
|
+
(hash (kwsplat (hash ...)))
|
24
|
+
PATTERN
|
25
|
+
|
26
|
+
def on_hash(node)
|
27
|
+
return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?)
|
28
|
+
|
29
|
+
grandparent = node.parent&.parent
|
30
|
+
return unless double_splat_hash_braces?(grandparent)
|
31
|
+
|
32
|
+
add_offense(grandparent) do |corrector|
|
33
|
+
corrector.replace(grandparent, node.pairs.map(&:source).join(', '))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -53,6 +53,13 @@ module RuboCop
|
|
53
53
|
|
54
54
|
MSG = 'Redundant `return` detected.'
|
55
55
|
MULTI_RETURN_MSG = 'To return multiple values, use an array.'
|
56
|
+
RESTRICT_ON_SEND = %i[define_method define_singleton_method].freeze
|
57
|
+
|
58
|
+
def on_send(node)
|
59
|
+
return unless (parent = node.parent) && parent.block_type?
|
60
|
+
|
61
|
+
check_branch(parent.body)
|
62
|
+
end
|
56
63
|
|
57
64
|
def on_def(node)
|
58
65
|
check_branch(node.body)
|