rubocop 1.65.1 → 1.66.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +67 -67
- data/config/default.yml +18 -2
- data/exe/rubocop +4 -3
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +5 -1
- data/lib/rubocop/config_loader.rb +14 -8
- data/lib/rubocop/config_loader_resolver.rb +1 -2
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/base.rb +4 -0
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -0
- data/lib/rubocop/cop/documentation.rb +18 -1
- data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +11 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +30 -12
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +8 -3
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +0 -3
- data/lib/rubocop/cop/layout/line_length.rb +14 -14
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +27 -6
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -3
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +4 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +18 -11
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +77 -0
- data/lib/rubocop/cop/lint/void.rb +30 -8
- data/lib/rubocop/cop/metrics/block_length.rb +6 -5
- data/lib/rubocop/cop/metrics/class_length.rb +6 -5
- data/lib/rubocop/cop/metrics/method_length.rb +6 -5
- data/lib/rubocop/cop/metrics/module_length.rb +6 -5
- data/lib/rubocop/cop/mixin/annotation_comment.rb +0 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +19 -9
- data/lib/rubocop/cop/mixin/line_length_help.rb +7 -2
- data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +5 -0
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/style/alias.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -3
- data/lib/rubocop/cop/style/empty_else.rb +6 -5
- data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
- data/lib/rubocop/cop/style/empty_literal.rb +31 -22
- data/lib/rubocop/cop/style/format_string_token.rb +2 -2
- data/lib/rubocop/cop/style/guard_clause.rb +2 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +45 -6
- data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +12 -5
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/multiple_comparison.rb +3 -11
- data/lib/rubocop/cop/style/numeric_predicate.rb +2 -2
- data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
- data/lib/rubocop/cop/style/parallel_assignment.rb +5 -4
- data/lib/rubocop/cop/style/quoted_symbols.rb +0 -2
- data/lib/rubocop/cop/style/redundant_condition.rb +3 -2
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
- data/lib/rubocop/cop/team.rb +6 -2
- data/lib/rubocop/formatter/junit_formatter.rb +70 -23
- data/lib/rubocop/lockfile.rb +6 -4
- data/lib/rubocop/remote_config.rb +5 -1
- data/lib/rubocop/result_cache.rb +2 -8
- data/lib/rubocop/rspec/shared_contexts.rb +2 -2
- data/lib/rubocop/server/cache.rb +1 -1
- data/lib/rubocop/target_ruby.rb +7 -3
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/yaml_duplication_checker.rb +1 -0
- data/lib/rubocop.rb +2 -1
- metadata +12 -30
@@ -334,13 +334,18 @@ module RuboCop
|
|
334
334
|
end
|
335
335
|
end
|
336
336
|
|
337
|
+
# rubocop:disable Metrics/AbcSize
|
337
338
|
def arguments_range(node, first_node)
|
338
|
-
arguments = node.arguments.reject
|
339
|
+
arguments = node.arguments.reject do |arg|
|
340
|
+
next true if ADDITIONAL_ARG_TYPES.include?(arg.type) || arg.variable? || arg.call_type?
|
339
341
|
|
340
|
-
|
342
|
+
arg.literal? && arg.each_descendant(:kwsplat).none?
|
343
|
+
end
|
341
344
|
|
342
|
-
|
345
|
+
start_node = first_node || arguments.first
|
346
|
+
start_node.source_range.begin.join(arguments.last.source_range.end)
|
343
347
|
end
|
348
|
+
# rubocop:enable Metrics/AbcSize
|
344
349
|
|
345
350
|
def allow_only_rest_arguments?
|
346
351
|
cop_config.fetch('AllowOnlyRestArgument', true)
|
@@ -143,7 +143,7 @@ module RuboCop
|
|
143
143
|
private
|
144
144
|
|
145
145
|
def check(node)
|
146
|
-
return if cop_config['AllowComments'] && comment_in_else?(node
|
146
|
+
return if cop_config['AllowComments'] && comment_in_else?(node)
|
147
147
|
|
148
148
|
empty_check(node) if empty_style?
|
149
149
|
nil_check(node) if nil_style?
|
@@ -171,16 +171,17 @@ module RuboCop
|
|
171
171
|
|
172
172
|
def autocorrect(corrector, node)
|
173
173
|
return false if autocorrect_forbidden?(node.type.to_s)
|
174
|
-
return false if comment_in_else?(node
|
174
|
+
return false if comment_in_else?(node)
|
175
175
|
|
176
176
|
end_pos = base_node(node).loc.end.begin_pos
|
177
177
|
corrector.remove(range_between(node.loc.else.begin_pos, end_pos))
|
178
178
|
end
|
179
179
|
|
180
|
-
def comment_in_else?(
|
181
|
-
|
180
|
+
def comment_in_else?(node)
|
181
|
+
node = node.parent while node.if_type? && node.elsif?
|
182
|
+
return false unless node.else?
|
182
183
|
|
183
|
-
processed_source.contains_comment?(loc.else.join(
|
184
|
+
processed_source.contains_comment?(node.loc.else.join(node.source_range.end))
|
184
185
|
end
|
185
186
|
|
186
187
|
def base_node(node)
|
@@ -36,6 +36,7 @@ module RuboCop
|
|
36
36
|
class EmptyHeredoc < Base
|
37
37
|
include Heredoc
|
38
38
|
include RangeHelp
|
39
|
+
include StringLiteralsHelp
|
39
40
|
extend AutoCorrector
|
40
41
|
|
41
42
|
MSG = 'Use an empty string literal instead of heredoc.'
|
@@ -53,20 +54,6 @@ module RuboCop
|
|
53
54
|
corrector.remove(range_by_whole_lines(heredoc_end, include_final_newline: true))
|
54
55
|
end
|
55
56
|
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def preferred_string_literal
|
60
|
-
enforce_double_quotes? ? '""' : "''"
|
61
|
-
end
|
62
|
-
|
63
|
-
def enforce_double_quotes?
|
64
|
-
string_literals_config['EnforcedStyle'] == 'double_quotes'
|
65
|
-
end
|
66
|
-
|
67
|
-
def string_literals_config
|
68
|
-
config.for_cop('Style/StringLiterals')
|
69
|
-
end
|
70
57
|
end
|
71
58
|
end
|
72
59
|
end
|
@@ -9,7 +9,9 @@ module RuboCop
|
|
9
9
|
# @example
|
10
10
|
# # bad
|
11
11
|
# a = Array.new
|
12
|
+
# a = Array[]
|
12
13
|
# h = Hash.new
|
14
|
+
# h = Hash[]
|
13
15
|
# s = String.new
|
14
16
|
#
|
15
17
|
# # good
|
@@ -19,16 +21,17 @@ module RuboCop
|
|
19
21
|
class EmptyLiteral < Base
|
20
22
|
include FrozenStringLiteral
|
21
23
|
include RangeHelp
|
24
|
+
include StringLiteralsHelp
|
22
25
|
extend AutoCorrector
|
23
26
|
|
24
|
-
ARR_MSG = 'Use array literal `[]` instead of
|
25
|
-
HASH_MSG = 'Use hash literal `{}` instead of
|
27
|
+
ARR_MSG = 'Use array literal `[]` instead of `%<current>s`.'
|
28
|
+
HASH_MSG = 'Use hash literal `{}` instead of `%<current>s`.'
|
26
29
|
STR_MSG = 'Use string literal `%<prefer>s` instead of `String.new`.'
|
27
30
|
|
28
|
-
RESTRICT_ON_SEND = %i[new].freeze
|
31
|
+
RESTRICT_ON_SEND = %i[new [] Array Hash].freeze
|
29
32
|
|
30
33
|
# @!method array_node(node)
|
31
|
-
def_node_matcher :array_node, '(send (const {nil? cbase} :Array) :new)'
|
34
|
+
def_node_matcher :array_node, '(send (const {nil? cbase} :Array) :new (array)?)'
|
32
35
|
|
33
36
|
# @!method hash_node(node)
|
34
37
|
def_node_matcher :hash_node, '(send (const {nil? cbase} :Hash) :new)'
|
@@ -47,6 +50,22 @@ module RuboCop
|
|
47
50
|
}
|
48
51
|
PATTERN
|
49
52
|
|
53
|
+
# @!method array_with_index(node)
|
54
|
+
def_node_matcher :array_with_index, <<~PATTERN
|
55
|
+
{
|
56
|
+
(send (const {nil? cbase} :Array) :[])
|
57
|
+
(send nil? :Array (array))
|
58
|
+
}
|
59
|
+
PATTERN
|
60
|
+
|
61
|
+
# @!method hash_with_index(node)
|
62
|
+
def_node_matcher :hash_with_index, <<~PATTERN
|
63
|
+
{
|
64
|
+
(send (const {nil? cbase} :Hash) :[])
|
65
|
+
(send nil? :Hash (array))
|
66
|
+
}
|
67
|
+
PATTERN
|
68
|
+
|
50
69
|
def on_send(node)
|
51
70
|
return unless (message = offense_message(node))
|
52
71
|
|
@@ -59,26 +78,14 @@ module RuboCop
|
|
59
78
|
|
60
79
|
def offense_message(node)
|
61
80
|
if offense_array_node?(node)
|
62
|
-
ARR_MSG
|
81
|
+
format(ARR_MSG, current: node.source)
|
63
82
|
elsif offense_hash_node?(node)
|
64
|
-
HASH_MSG
|
83
|
+
format(HASH_MSG, current: node.source)
|
65
84
|
elsif str_node(node) && !frozen_strings?
|
66
85
|
format(STR_MSG, prefer: preferred_string_literal)
|
67
86
|
end
|
68
87
|
end
|
69
88
|
|
70
|
-
def preferred_string_literal
|
71
|
-
enforce_double_quotes? ? '""' : "''"
|
72
|
-
end
|
73
|
-
|
74
|
-
def enforce_double_quotes?
|
75
|
-
string_literals_config['EnforcedStyle'] == 'double_quotes'
|
76
|
-
end
|
77
|
-
|
78
|
-
def string_literals_config
|
79
|
-
config.for_cop('Style/StringLiterals')
|
80
|
-
end
|
81
|
-
|
82
89
|
def first_argument_unparenthesized?(node)
|
83
90
|
parent = node.parent
|
84
91
|
return false unless parent && %i[send super zsuper].include?(parent.type)
|
@@ -100,12 +107,12 @@ module RuboCop
|
|
100
107
|
end
|
101
108
|
|
102
109
|
def offense_array_node?(node)
|
103
|
-
array_node(node) && !array_with_block(node.parent)
|
110
|
+
(array_node(node) && !array_with_block(node.parent)) || array_with_index(node)
|
104
111
|
end
|
105
112
|
|
106
113
|
def offense_hash_node?(node)
|
107
114
|
# If Hash.new takes a block, it can't be changed to {}.
|
108
|
-
hash_node(node) && !hash_with_block(node.parent)
|
115
|
+
(hash_node(node) && !hash_with_block(node.parent)) || hash_with_index(node)
|
109
116
|
end
|
110
117
|
|
111
118
|
def correction(node)
|
@@ -129,8 +136,10 @@ module RuboCop
|
|
129
136
|
def frozen_strings?
|
130
137
|
return true if frozen_string_literals_enabled?
|
131
138
|
|
132
|
-
frozen_string_cop_enabled = config.for_cop('Style/
|
133
|
-
frozen_string_cop_enabled &&
|
139
|
+
frozen_string_cop_enabled = config.for_cop('Style/FrozenStringLiteralComment')['Enabled']
|
140
|
+
frozen_string_cop_enabled &&
|
141
|
+
!frozen_string_literals_disabled? &&
|
142
|
+
string_literals_frozen_by_default?.nil?
|
134
143
|
end
|
135
144
|
end
|
136
145
|
end
|
@@ -11,8 +11,8 @@ module RuboCop
|
|
11
11
|
# The reason is that _unannotated_ format is very similar
|
12
12
|
# to encoded URLs or Date/Time formatting strings.
|
13
13
|
#
|
14
|
-
# This cop can be customized
|
15
|
-
# By default, there are no methods
|
14
|
+
# This cop's allowed methods can be customized with `AllowedMethods`.
|
15
|
+
# By default, there are no allowed methods.
|
16
16
|
#
|
17
17
|
# @example EnforcedStyle: annotated (default)
|
18
18
|
#
|
@@ -155,7 +155,7 @@ module RuboCop
|
|
155
155
|
condition_variable = assignable_condition_value(node)
|
156
156
|
|
157
157
|
head = heads.first
|
158
|
-
if head.assignment?
|
158
|
+
if head.respond_to?(:assignment?) && head.assignment?
|
159
159
|
# The `send` node is used instead of the `indexasgn` node, so `name` cannot be used.
|
160
160
|
# https://github.com/rubocop/rubocop-ast/blob/v1.29.0/lib/rubocop/ast/node/indexasgn_node.rb
|
161
161
|
#
|
@@ -18,6 +18,7 @@ module RuboCop
|
|
18
18
|
extend AutoCorrector
|
19
19
|
|
20
20
|
MSG_IF_ELSE = 'Do not use `if %<expr>s;` - use `if/else` instead.'
|
21
|
+
MSG_NEWLINE = 'Do not use `if %<expr>s;` - use a newline instead.'
|
21
22
|
MSG_TERNARY = 'Do not use `if %<expr>s;` - use a ternary operator instead.'
|
22
23
|
|
23
24
|
def on_normal_if_unless(node)
|
@@ -26,20 +27,47 @@ module RuboCop
|
|
26
27
|
beginning = node.loc.begin
|
27
28
|
return unless beginning&.is?(';')
|
28
29
|
|
29
|
-
message = node
|
30
|
+
message = message(node)
|
30
31
|
|
31
|
-
add_offense(node, message:
|
32
|
-
corrector
|
32
|
+
add_offense(node, message: message) do |corrector|
|
33
|
+
autocorrect(corrector, node)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|
37
38
|
|
38
|
-
|
39
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
40
|
+
def message(node)
|
41
|
+
template = if node.if_branch&.begin_type?
|
42
|
+
MSG_NEWLINE
|
43
|
+
elsif node.else_branch&.if_type? || node.else_branch&.begin_type? ||
|
44
|
+
use_block_in_branches?(node)
|
45
|
+
MSG_IF_ELSE
|
46
|
+
else
|
47
|
+
MSG_TERNARY
|
48
|
+
end
|
49
|
+
|
50
|
+
format(template, expr: node.condition.source)
|
51
|
+
end
|
52
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
53
|
+
|
54
|
+
def autocorrect(corrector, node)
|
55
|
+
if node.branches.compact.any?(&:begin_type?) || use_block_in_branches?(node)
|
56
|
+
corrector.replace(node.loc.begin, "\n")
|
57
|
+
else
|
58
|
+
corrector.replace(node, replacement(node))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def use_block_in_branches?(node)
|
63
|
+
node.branches.compact.any? { |branch| branch.block_type? || branch.numblock_type? }
|
64
|
+
end
|
65
|
+
|
66
|
+
def replacement(node)
|
39
67
|
return correct_elsif(node) if node.else_branch&.if_type?
|
40
68
|
|
41
|
-
then_code = node.if_branch ? node.if_branch
|
42
|
-
else_code = node.else_branch ? node.else_branch
|
69
|
+
then_code = node.if_branch ? build_expression(node.if_branch) : 'nil'
|
70
|
+
else_code = node.else_branch ? build_expression(node.else_branch) : 'nil'
|
43
71
|
|
44
72
|
"#{node.condition.source} ? #{then_code} : #{else_code}"
|
45
73
|
end
|
@@ -53,6 +81,17 @@ module RuboCop
|
|
53
81
|
RUBY
|
54
82
|
end
|
55
83
|
|
84
|
+
# rubocop:disable Metrics/AbcSize
|
85
|
+
def build_expression(expr)
|
86
|
+
return expr.source if !expr.call_type? || expr.parenthesized? || expr.arguments.empty?
|
87
|
+
|
88
|
+
method = expr.source_range.begin.join(expr.loc.selector.end)
|
89
|
+
arguments = expr.first_argument.source_range.begin.join(expr.source_range.end)
|
90
|
+
|
91
|
+
"#{method.source}(#{arguments.source})"
|
92
|
+
end
|
93
|
+
# rubocop:enable Metrics/AbcSize
|
94
|
+
|
56
95
|
def build_else_branch(second_condition)
|
57
96
|
result = <<~RUBY
|
58
97
|
elsif #{second_condition.condition.source}
|
@@ -44,11 +44,15 @@ module RuboCop
|
|
44
44
|
private
|
45
45
|
|
46
46
|
def alternative_pattern_source(pattern)
|
47
|
+
collect_alternative_patterns(pattern).join(' | ')
|
48
|
+
end
|
49
|
+
|
50
|
+
def collect_alternative_patterns(pattern)
|
47
51
|
return pattern.children.map(&:source) unless pattern.children.first.match_alt_type?
|
48
52
|
|
49
|
-
pattern_sources =
|
53
|
+
pattern_sources = collect_alternative_patterns(pattern.children.first)
|
50
54
|
|
51
|
-
|
55
|
+
pattern_sources << pattern.children[1].source
|
52
56
|
end
|
53
57
|
end
|
54
58
|
end
|
@@ -105,7 +105,7 @@ module RuboCop
|
|
105
105
|
|
106
106
|
# Value object to extract source ranges for the different parts of a magic comment
|
107
107
|
class CommentRange
|
108
|
-
extend
|
108
|
+
extend SimpleForwardable
|
109
109
|
|
110
110
|
DIRECTIVE_REGEXP = Regexp.union(MagicComment::KEYWORDS.map do |_, v|
|
111
111
|
Regexp.new(v, Regexp::IGNORECASE)
|
@@ -58,12 +58,21 @@ module RuboCop
|
|
58
58
|
[
|
59
59
|
^({begin kwbegin} ...)
|
60
60
|
({block numblock} (send !{nil? self} :each) _
|
61
|
-
(send (lvar _) {:<< :push :append}
|
61
|
+
(send (lvar _) {:<< :push :append} {send lvar begin}))
|
62
62
|
]
|
63
63
|
PATTERN
|
64
64
|
|
65
65
|
# @!method empty_array_asgn?(node)
|
66
|
-
def_node_matcher :empty_array_asgn?,
|
66
|
+
def_node_matcher :empty_array_asgn?, <<~PATTERN
|
67
|
+
(
|
68
|
+
lvasgn _ {
|
69
|
+
(array)
|
70
|
+
(send (const {nil? cbase} :Array) :[])
|
71
|
+
(send (const {nil? cbase} :Array) :new (array)?)
|
72
|
+
(send nil? :Array (array))
|
73
|
+
}
|
74
|
+
)
|
75
|
+
PATTERN
|
67
76
|
|
68
77
|
# @!method lvar_ref?(node, name)
|
69
78
|
def_node_matcher :lvar_ref?, '(lvar %1)'
|
@@ -138,10 +147,8 @@ module RuboCop
|
|
138
147
|
false
|
139
148
|
when :begin, :kwbegin
|
140
149
|
!node.right_sibling && return_value_used?(parent)
|
141
|
-
when :block, :numblock
|
142
|
-
!parent.void_context?
|
143
150
|
else
|
144
|
-
|
151
|
+
!parent.respond_to?(:void_context?) || !parent.void_context?
|
145
152
|
end
|
146
153
|
end
|
147
154
|
|
@@ -5,8 +5,8 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# Checks for unwanted parentheses in parameterless method calls.
|
7
7
|
#
|
8
|
-
# This cop can be customized
|
9
|
-
# By default, there are no methods
|
8
|
+
# This cop's allowed methods can be customized with `AllowedMethods`.
|
9
|
+
# By default, there are no allowed methods.
|
10
10
|
#
|
11
11
|
# NOTE: This cop allows the use of `it()` without arguments in blocks,
|
12
12
|
# as in `0.times { it() }`, following `Lint/ItWithoutArgumentsInBlock` cop.
|
@@ -56,12 +56,10 @@ module RuboCop
|
|
56
56
|
'in a conditional, use `Array#include?` instead.'
|
57
57
|
|
58
58
|
def on_new_investigation
|
59
|
-
|
59
|
+
reset_comparison
|
60
60
|
end
|
61
61
|
|
62
62
|
def on_or(node)
|
63
|
-
reset_comparison if switch_comparison?(node)
|
64
|
-
|
65
63
|
root_of_or_node = root_of_or_node(node)
|
66
64
|
|
67
65
|
return unless node == root_of_or_node
|
@@ -74,9 +72,9 @@ module RuboCop
|
|
74
72
|
prefer_method = "[#{elements}].include?(#{variables_in_node(node).first})"
|
75
73
|
|
76
74
|
corrector.replace(node, prefer_method)
|
77
|
-
end
|
78
75
|
|
79
|
-
|
76
|
+
reset_comparison
|
77
|
+
end
|
80
78
|
end
|
81
79
|
|
82
80
|
private
|
@@ -147,12 +145,6 @@ module RuboCop
|
|
147
145
|
end
|
148
146
|
end
|
149
147
|
|
150
|
-
def switch_comparison?(node)
|
151
|
-
return true if @last_comparison.nil?
|
152
|
-
|
153
|
-
@last_comparison.descendants.none?(node)
|
154
|
-
end
|
155
|
-
|
156
148
|
def reset_comparison
|
157
149
|
@compared_elements = []
|
158
150
|
@allowed_method_comparison = false
|
@@ -8,8 +8,8 @@ module RuboCop
|
|
8
8
|
# These can be replaced by their respective predicate methods.
|
9
9
|
# This cop can also be configured to do the reverse.
|
10
10
|
#
|
11
|
-
# This cop can be customized
|
12
|
-
# By default, there are no methods
|
11
|
+
# This cop's allowed methods can be customized with `AllowedMethods`.
|
12
|
+
# By default, there are no allowed methods.
|
13
13
|
#
|
14
14
|
# This cop disregards `#nonzero?` as its value is truthy or falsey,
|
15
15
|
# but not `true` and `false`, and thus not always interchangeable with
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
def on_normal_if_unless(node)
|
43
43
|
return unless node.single_line?
|
44
44
|
return unless node.else_branch
|
45
|
-
return if node.elsif?
|
45
|
+
return if node.elsif? || node.if_branch&.begin_type?
|
46
46
|
|
47
47
|
message = message(node)
|
48
48
|
add_offense(node, message: message) do |corrector|
|
@@ -211,15 +211,16 @@ module RuboCop
|
|
211
211
|
protected
|
212
212
|
|
213
213
|
def assignment
|
214
|
-
@new_elements.map { |lhs, rhs| "#{lhs.source} = #{source(rhs)}" }
|
214
|
+
@new_elements.map { |lhs, rhs| "#{lhs.source} = #{source(rhs, rhs.loc)}" }
|
215
215
|
end
|
216
216
|
|
217
217
|
private
|
218
218
|
|
219
|
-
def source(node)
|
220
|
-
|
219
|
+
def source(node, loc)
|
220
|
+
# __FILE__ is treated as a StrNode but has no begin
|
221
|
+
if node.str_type? && loc.respond_to?(:begin) && loc.begin.nil?
|
221
222
|
"'#{node.source}'"
|
222
|
-
elsif node.sym_type? &&
|
223
|
+
elsif node.sym_type? && loc.begin.nil?
|
223
224
|
":#{node.source}"
|
224
225
|
else
|
225
226
|
node.source
|
@@ -98,8 +98,6 @@ module RuboCop
|
|
98
98
|
|
99
99
|
def style
|
100
100
|
return super unless super == :same_as_string_literals
|
101
|
-
|
102
|
-
string_literals_config = config.for_cop('Style/StringLiterals')
|
103
101
|
return :single_quotes unless string_literals_config['Enabled']
|
104
102
|
|
105
103
|
string_literals_config['EnforcedStyle'].to_sym
|
@@ -39,9 +39,9 @@ module RuboCop
|
|
39
39
|
splat block_pass forwarded_restarg forwarded_kwrestarg forwarded_args
|
40
40
|
].freeze
|
41
41
|
|
42
|
+
# rubocop:disable Metrics/AbcSize
|
42
43
|
def on_if(node)
|
43
|
-
return if node.elsif_conditional?
|
44
|
-
return unless offense?(node)
|
44
|
+
return if node.modifier_form? || node.elsif_conditional? || !offense?(node)
|
45
45
|
|
46
46
|
message = message(node)
|
47
47
|
|
@@ -57,6 +57,7 @@ module RuboCop
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
|
+
# rubocop:enable Metrics/AbcSize
|
60
61
|
|
61
62
|
private
|
62
63
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Before Ruby 3.0, interpolated strings followed the frozen string literal
|
7
|
+
# magic comment which sometimes made it necessary to explicitly unfreeze them.
|
8
|
+
# Ruby 3.0 changed interpolated strings to always be unfrozen which makes
|
9
|
+
# unfreezing them redundant.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# +"#{foo} bar"
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# "#{foo} bar".dup
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# "#{foo} bar"
|
20
|
+
#
|
21
|
+
class RedundantInterpolationUnfreeze < Base
|
22
|
+
include FrozenStringLiteral
|
23
|
+
extend AutoCorrector
|
24
|
+
extend TargetRubyVersion
|
25
|
+
|
26
|
+
MSG = "Don't unfreeze interpolated strings as they are already unfrozen."
|
27
|
+
|
28
|
+
RESTRICT_ON_SEND = %i[+@ dup].freeze
|
29
|
+
|
30
|
+
minimum_target_ruby_version 3.0
|
31
|
+
|
32
|
+
def on_send(node)
|
33
|
+
return if node.arguments?
|
34
|
+
return unless (receiver = node.receiver)
|
35
|
+
return unless receiver.dstr_type?
|
36
|
+
return if uninterpolated_string?(receiver) || uninterpolated_heredoc?(receiver)
|
37
|
+
|
38
|
+
add_offense(node.loc.selector) do |corrector|
|
39
|
+
corrector.remove(node.loc.selector)
|
40
|
+
corrector.remove(node.loc.dot) unless node.unary_operation?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -33,6 +33,7 @@ module RuboCop
|
|
33
33
|
# 'foo'.sub('f', 'x')
|
34
34
|
# 'foo'.sub!('f', 'x')
|
35
35
|
class RedundantRegexpArgument < Base
|
36
|
+
include StringLiteralsHelp
|
36
37
|
extend AutoCorrector
|
37
38
|
|
38
39
|
MSG = 'Use string `%<prefer>s` as argument instead of regexp `%<current>s`.'
|
@@ -71,8 +72,10 @@ module RuboCop
|
|
71
72
|
if new_argument.include?('"')
|
72
73
|
new_argument.gsub!("'", "\\\\'")
|
73
74
|
quote = "'"
|
74
|
-
|
75
|
+
elsif new_argument.include?('\\')
|
75
76
|
quote = '"'
|
77
|
+
else
|
78
|
+
quote = enforce_double_quotes? ? '"' : "'"
|
76
79
|
end
|
77
80
|
|
78
81
|
"#{quote}#{new_argument}#{quote}"
|
@@ -17,9 +17,9 @@ module RuboCop
|
|
17
17
|
# `foo&.bar` can start returning `nil` as well as what the method
|
18
18
|
# returns.
|
19
19
|
#
|
20
|
-
# The default for `MaxChainLength` is `2
|
20
|
+
# The default for `MaxChainLength` is `2`.
|
21
21
|
# We have limited the cop to not register an offense for method chains
|
22
|
-
# that exceed this option
|
22
|
+
# that exceed this option's value.
|
23
23
|
#
|
24
24
|
# @safety
|
25
25
|
# Autocorrection is unsafe because if a value is `false`, the resulting
|
data/lib/rubocop/cop/team.rb
CHANGED
@@ -120,8 +120,12 @@ module RuboCop
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def external_dependency_checksum
|
123
|
-
|
124
|
-
|
123
|
+
# The external dependency checksums are cached per RuboCop team so that
|
124
|
+
# the checksums don't need to be recomputed for each file.
|
125
|
+
@external_dependency_checksum ||= begin
|
126
|
+
keys = cops.filter_map(&:external_dependency_checksum)
|
127
|
+
Digest::SHA1.hexdigest(keys.join)
|
128
|
+
end
|
125
129
|
end
|
126
130
|
|
127
131
|
private
|