rubocop 1.5.0 → 1.7.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 +52 -7
- data/config/obsoletion.yml +196 -0
- data/lib/rubocop.rb +14 -0
- data/lib/rubocop/cli/command/suggest_extensions.rb +21 -8
- data/lib/rubocop/config.rb +8 -5
- data/lib/rubocop/config_loader.rb +10 -6
- data/lib/rubocop/config_loader_resolver.rb +21 -4
- data/lib/rubocop/config_obsoletion.rb +64 -262
- data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
- data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
- data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
- data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
- data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
- data/lib/rubocop/config_obsoletion/rule.rb +41 -0
- data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
- data/lib/rubocop/config_validator.rb +11 -4
- data/lib/rubocop/cop/base.rb +17 -15
- data/lib/rubocop/cop/cop.rb +2 -2
- data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +26 -0
- data/lib/rubocop/cop/layout/line_length.rb +6 -16
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +64 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
- data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
- data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +1 -1
- data/lib/rubocop/cop/mixin/string_help.rb +4 -1
- data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
- data/lib/rubocop/cop/naming/variable_number.rb +3 -1
- data/lib/rubocop/cop/registry.rb +10 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
- data/lib/rubocop/cop/style/character_literal.rb +10 -11
- data/lib/rubocop/cop/style/collection_methods.rb +14 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
- data/lib/rubocop/cop/style/float_division.rb +44 -1
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/hash_except.rb +95 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
- data/lib/rubocop/cop/style/lambda_call.rb +2 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
- data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
- data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
- data/lib/rubocop/cop/style/raise_args.rb +2 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +21 -2
- data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
- data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
- data/lib/rubocop/cop/style/single_line_methods.rb +4 -0
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +24 -8
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
- data/lib/rubocop/cop/style/string_concatenation.rb +26 -1
- data/lib/rubocop/cop/style/string_literals.rb +14 -8
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
- data/lib/rubocop/cop/util.rb +3 -1
- data/lib/rubocop/ext/regexp_node.rb +31 -9
- data/lib/rubocop/ext/regexp_parser.rb +21 -3
- data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
- data/lib/rubocop/formatter/tap_formatter.rb +2 -0
- data/lib/rubocop/lockfile.rb +40 -0
- data/lib/rubocop/options.rb +9 -9
- data/lib/rubocop/rspec/cop_helper.rb +0 -4
- data/lib/rubocop/rspec/expect_offense.rb +34 -22
- data/lib/rubocop/runner.rb +16 -1
- data/lib/rubocop/target_finder.rb +4 -2
- data/lib/rubocop/util.rb +16 -0
- data/lib/rubocop/version.rb +8 -2
- metadata +33 -5
@@ -95,6 +95,7 @@ module RuboCop
|
|
95
95
|
replacement = correction_exploded_to_compact(node)
|
96
96
|
|
97
97
|
corrector.replace(node, replacement)
|
98
|
+
opposite_style_detected
|
98
99
|
end
|
99
100
|
else
|
100
101
|
correct_style_detected
|
@@ -115,6 +116,7 @@ module RuboCop
|
|
115
116
|
replacement = correction_compact_to_exploded(node)
|
116
117
|
|
117
118
|
corrector.replace(node, replacement)
|
119
|
+
opposite_style_detected
|
118
120
|
end
|
119
121
|
end
|
120
122
|
|
@@ -12,7 +12,7 @@ module RuboCop
|
|
12
12
|
# 1. This cop matches for method names only and hence cannot tell apart
|
13
13
|
# methods with same name in different classes.
|
14
14
|
# 2. This cop is limited to methods with single parameter.
|
15
|
-
# 3. This cop is unsafe if certain special global variables (e.g.
|
15
|
+
# 3. This cop is unsafe if certain special global variables (e.g. `$;`, `$/`) are set.
|
16
16
|
# That depends on the nature of the target methods, of course.
|
17
17
|
#
|
18
18
|
# Method names and their redundant arguments can be configured like this:
|
@@ -20,6 +20,8 @@ module RuboCop
|
|
20
20
|
# Methods:
|
21
21
|
# join: ''
|
22
22
|
# split: ' '
|
23
|
+
# chomp: "\n"
|
24
|
+
# chomp!: "\n"
|
23
25
|
# foo: 2
|
24
26
|
#
|
25
27
|
# @example
|
@@ -28,6 +30,8 @@ module RuboCop
|
|
28
30
|
# [1, 2, 3].join("")
|
29
31
|
# string.split(" ")
|
30
32
|
# "first\nsecond".split(" ")
|
33
|
+
# string.chomp("\n")
|
34
|
+
# string.chomp!("\n")
|
31
35
|
# A.foo(2)
|
32
36
|
#
|
33
37
|
# # good
|
@@ -35,8 +39,13 @@ module RuboCop
|
|
35
39
|
# [1, 2, 3].join
|
36
40
|
# string.split
|
37
41
|
# "first second".split
|
42
|
+
# string.chomp
|
43
|
+
# string.chomp!
|
38
44
|
# A.foo
|
39
45
|
class RedundantArgument < Base
|
46
|
+
include RangeHelp
|
47
|
+
extend AutoCorrector
|
48
|
+
|
40
49
|
MSG = 'Argument %<arg>s is redundant because it is implied by default.'
|
41
50
|
|
42
51
|
def on_send(node)
|
@@ -44,7 +53,9 @@ module RuboCop
|
|
44
53
|
return if node.arguments.count != 1
|
45
54
|
return unless redundant_argument?(node)
|
46
55
|
|
47
|
-
add_offense(node, message: format(MSG, arg: node.arguments.first.source))
|
56
|
+
add_offense(node, message: format(MSG, arg: node.arguments.first.source)) do |corrector|
|
57
|
+
corrector.remove(argument_range(node))
|
58
|
+
end
|
48
59
|
end
|
49
60
|
|
50
61
|
private
|
@@ -69,6 +80,14 @@ module RuboCop
|
|
69
80
|
Parser::CurrentRuby.new(builder).parse(buffer)
|
70
81
|
end
|
71
82
|
end
|
83
|
+
|
84
|
+
def argument_range(node)
|
85
|
+
if node.parenthesized?
|
86
|
+
range_between(node.loc.begin.begin_pos, node.loc.end.end_pos)
|
87
|
+
else
|
88
|
+
range_with_surrounding_space(range: node.first_argument.source_range, newlines: false)
|
89
|
+
end
|
90
|
+
end
|
72
91
|
end
|
73
92
|
end
|
74
93
|
end
|
@@ -3,7 +3,9 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop check for uses of Object#freeze on immutable objects.
|
6
|
+
# This cop check for uses of `Object#freeze` on immutable objects.
|
7
|
+
#
|
8
|
+
# NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
|
7
9
|
#
|
8
10
|
# @example
|
9
11
|
# # bad
|
@@ -37,8 +39,10 @@ module RuboCop
|
|
37
39
|
|
38
40
|
return true if node.immutable_literal?
|
39
41
|
|
40
|
-
FROZEN_STRING_LITERAL_TYPES.include?(node.type) &&
|
41
|
-
|
42
|
+
return true if FROZEN_STRING_LITERAL_TYPES.include?(node.type) &&
|
43
|
+
frozen_string_literals_enabled?
|
44
|
+
|
45
|
+
target_ruby_version >= 3.0 && (node.regexp_type? || node.range_type?)
|
42
46
|
end
|
43
47
|
|
44
48
|
def strip_parenthesis(node)
|
@@ -52,7 +56,7 @@ module RuboCop
|
|
52
56
|
def_node_matcher :operation_produces_immutable_object?, <<~PATTERN
|
53
57
|
{
|
54
58
|
(begin (send {float int} {:+ :- :* :** :/ :% :<<} _))
|
55
|
-
(begin (send !(str _) {:+ :- :* :** :/ :%} {float int}))
|
59
|
+
(begin (send !{(str _) array} {:+ :- :* :** :/ :%} {float int}))
|
56
60
|
(begin (send _ {:== :=== :!= :<= :>= :< :>} _))
|
57
61
|
(send (const {nil? cbase} :ENV) :[] _)
|
58
62
|
(send _ {:count :length :size} ...)
|
@@ -80,14 +80,30 @@ module RuboCop
|
|
80
80
|
delimiters.include?(char)
|
81
81
|
end
|
82
82
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
83
|
+
if Gem::Version.new(Regexp::Parser::VERSION) >= Gem::Version.new('2.0')
|
84
|
+
def each_escape(node)
|
85
|
+
node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
|
86
|
+
yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
|
87
|
+
|
88
|
+
if expr.type == :set
|
89
|
+
char_class_depth + (event == :enter ? 1 : -1)
|
90
|
+
else
|
91
|
+
char_class_depth
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
# Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
|
96
|
+
# It's for compatibility with regexp_arser 1.8 and will never be maintained.
|
97
|
+
else
|
98
|
+
def each_escape(node)
|
99
|
+
node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
|
100
|
+
yield(expr.text[1], expr.start_index, !char_class_depth.zero?) if expr.type == :escape
|
101
|
+
|
102
|
+
if expr.type == :set
|
103
|
+
char_class_depth + (event == :enter ? 1 : -1)
|
104
|
+
else
|
105
|
+
char_class_depth
|
106
|
+
end
|
91
107
|
end
|
92
108
|
end
|
93
109
|
end
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
# c + d
|
30
30
|
# end
|
31
31
|
class SingleLineBlockParams < Base
|
32
|
+
extend AutoCorrector
|
33
|
+
|
32
34
|
MSG = 'Name `%<method>s` block params `|%<params>s|`.'
|
33
35
|
|
34
36
|
def on_block(node)
|
@@ -37,20 +39,41 @@ module RuboCop
|
|
37
39
|
return unless eligible_method?(node)
|
38
40
|
return unless eligible_arguments?(node)
|
39
41
|
|
40
|
-
|
42
|
+
method_name = node.send_node.method_name
|
43
|
+
return if args_match?(method_name, node.arguments)
|
44
|
+
|
45
|
+
preferred_block_arguments = build_preferred_arguments_map(node, target_args(method_name))
|
46
|
+
joined_block_arguments = preferred_block_arguments.values.join(', ')
|
41
47
|
|
42
|
-
message =
|
48
|
+
message = format(MSG, method: method_name, params: joined_block_arguments)
|
43
49
|
|
44
|
-
add_offense(node.arguments, message: message)
|
50
|
+
add_offense(node.arguments, message: message) do |corrector|
|
51
|
+
autocorrect(corrector, node, preferred_block_arguments, joined_block_arguments)
|
52
|
+
end
|
45
53
|
end
|
46
54
|
|
47
55
|
private
|
48
56
|
|
49
|
-
def
|
50
|
-
|
51
|
-
arguments
|
57
|
+
def build_preferred_arguments_map(node, preferred_arguments)
|
58
|
+
preferred_arguments_map = {}
|
59
|
+
node.arguments.each_with_index do |current_lvar, index|
|
60
|
+
preferred_argument = preferred_arguments[index]
|
61
|
+
current_argument = current_lvar.source
|
62
|
+
preferred_argument = "_#{preferred_argument}" if current_argument.start_with?('_')
|
63
|
+
preferred_arguments_map[current_argument] = preferred_argument
|
64
|
+
end
|
65
|
+
|
66
|
+
preferred_arguments_map
|
67
|
+
end
|
68
|
+
|
69
|
+
def autocorrect(corrector, node, preferred_block_arguments, joined_block_arguments)
|
70
|
+
corrector.replace(node.arguments, "|#{joined_block_arguments}|")
|
52
71
|
|
53
|
-
|
72
|
+
node.each_descendant(:lvar) do |lvar|
|
73
|
+
if (preferred_lvar = preferred_block_arguments[lvar.source])
|
74
|
+
corrector.replace(lvar, preferred_lvar)
|
75
|
+
end
|
76
|
+
end
|
54
77
|
end
|
55
78
|
|
56
79
|
def eligible_arguments?(node)
|
@@ -6,6 +6,8 @@ module RuboCop
|
|
6
6
|
# This cop checks for single-line method definitions that contain a body.
|
7
7
|
# It will accept single-line methods with no body.
|
8
8
|
#
|
9
|
+
# Endless methods added in Ruby 3.0 are also accepted by this cop.
|
10
|
+
#
|
9
11
|
# @example
|
10
12
|
# # bad
|
11
13
|
# def some_method; body end
|
@@ -15,6 +17,7 @@ module RuboCop
|
|
15
17
|
# # good
|
16
18
|
# def self.resource_class=(klass); end
|
17
19
|
# def @table.columns; end
|
20
|
+
# def some_method() = body
|
18
21
|
#
|
19
22
|
# @example AllowIfMethodIsEmpty: true (default)
|
20
23
|
# # good
|
@@ -32,6 +35,7 @@ module RuboCop
|
|
32
35
|
|
33
36
|
def on_def(node)
|
34
37
|
return unless node.single_line?
|
38
|
+
return if node.endless?
|
35
39
|
return if allow_empty? && !node.body
|
36
40
|
|
37
41
|
add_offense(node) do |corrector|
|
@@ -68,22 +68,22 @@ module RuboCop
|
|
68
68
|
corrector.insert_before(node.condition, '!')
|
69
69
|
end
|
70
70
|
|
71
|
+
corrector.wrap(node.condition, '(', ')') if node.condition.or_type?
|
72
|
+
|
71
73
|
and_operator = if_branch.unless? ? ' && !' : ' && '
|
72
74
|
if if_branch.modifier_form?
|
73
|
-
|
75
|
+
correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
|
74
76
|
else
|
75
77
|
correct_for_basic_condition_style(corrector, node, if_branch, and_operator)
|
78
|
+
correct_for_comment(corrector, node, if_branch)
|
76
79
|
end
|
77
|
-
|
78
|
-
correct_for_comment(corrector, node, if_branch)
|
79
80
|
end
|
80
81
|
|
81
|
-
def
|
82
|
-
|
82
|
+
def correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
|
83
|
+
condition = if_branch.condition
|
84
|
+
corrector.insert_after(node.condition, replacement_condition(and_operator, condition))
|
83
85
|
|
84
|
-
range = range_between(
|
85
|
-
if_branch.loc.keyword.begin_pos, if_branch.condition.source_range.end_pos
|
86
|
-
)
|
86
|
+
range = range_between(if_branch.loc.keyword.begin_pos, condition.source_range.end_pos)
|
87
87
|
corrector.remove(range_with_surrounding_space(range: range, newlines: false))
|
88
88
|
corrector.remove(if_branch.loc.keyword)
|
89
89
|
end
|
@@ -94,15 +94,31 @@ module RuboCop
|
|
94
94
|
)
|
95
95
|
corrector.replace(range, and_operator)
|
96
96
|
corrector.remove(range_by_whole_lines(node.loc.end, include_final_newline: true))
|
97
|
+
corrector.wrap(if_branch.condition, '(', ')') if wrap_condition?(if_branch.condition)
|
97
98
|
end
|
98
99
|
|
99
100
|
def correct_for_comment(corrector, node, if_branch)
|
101
|
+
return if config.for_cop('Style/IfUnlessModifier')['Enabled']
|
102
|
+
|
100
103
|
comments = processed_source.comments_before_line(if_branch.source_range.line)
|
101
104
|
comment_text = comments.map(&:text).join("\n") << "\n"
|
102
105
|
|
103
106
|
corrector.insert_before(node.loc.keyword, comment_text) unless comments.empty?
|
104
107
|
end
|
105
108
|
|
109
|
+
def wrap_condition?(node)
|
110
|
+
node.or_type? ||
|
111
|
+
(node.send_type? && node.arguments.any? && !node.parenthesized?)
|
112
|
+
end
|
113
|
+
|
114
|
+
def replacement_condition(and_operator, condition)
|
115
|
+
if wrap_condition?(condition)
|
116
|
+
"#{and_operator}(#{condition.source})"
|
117
|
+
else
|
118
|
+
"#{and_operator}#{condition.source}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
106
122
|
def allow_modifier?
|
107
123
|
cop_config['AllowModifier']
|
108
124
|
end
|
@@ -26,10 +26,6 @@ module RuboCop
|
|
26
26
|
# puts $LAST_MATCH_INFO
|
27
27
|
# puts $IGNORECASE
|
28
28
|
# puts $ARGV # or ARGV
|
29
|
-
# puts $MATCH
|
30
|
-
# puts $PREMATCH
|
31
|
-
# puts $POSTMATCH
|
32
|
-
# puts $LAST_PAREN_MATCH
|
33
29
|
#
|
34
30
|
# @example EnforcedStyle: use_perl_names
|
35
31
|
# # good
|
@@ -51,10 +47,6 @@ module RuboCop
|
|
51
47
|
# puts $~
|
52
48
|
# puts $=
|
53
49
|
# puts $*
|
54
|
-
# puts $&
|
55
|
-
# puts $`
|
56
|
-
# puts $'
|
57
|
-
# puts $+
|
58
50
|
#
|
59
51
|
class SpecialGlobalVars < Base
|
60
52
|
include ConfigurableEnforcedStyle
|
@@ -85,11 +77,7 @@ module RuboCop
|
|
85
77
|
:$? => [:$CHILD_STATUS],
|
86
78
|
:$~ => [:$LAST_MATCH_INFO],
|
87
79
|
:$= => [:$IGNORECASE],
|
88
|
-
:$* => %i[$ARGV ARGV]
|
89
|
-
:$& => [:$MATCH],
|
90
|
-
:$` => [:$PREMATCH],
|
91
|
-
:$' => [:$POSTMATCH],
|
92
|
-
:$+ => [:$LAST_PAREN_MATCH]
|
80
|
+
:$* => %i[$ARGV ARGV]
|
93
81
|
}
|
94
82
|
|
95
83
|
PERL_VARS =
|
@@ -11,6 +11,10 @@ module RuboCop
|
|
11
11
|
# In those cases, it might be useful to extract statements to local
|
12
12
|
# variables or methods which you can then interpolate in a string.
|
13
13
|
#
|
14
|
+
# NOTE: When concatenation between two strings is broken over multiple
|
15
|
+
# lines, this cop does not register an offense; instead,
|
16
|
+
# `Style/LineEndConcatenation` will pick up the offense if enabled.
|
17
|
+
#
|
14
18
|
# @example
|
15
19
|
# # bad
|
16
20
|
# email_with_name = user.name + ' <' + user.email + '>'
|
@@ -19,6 +23,10 @@ module RuboCop
|
|
19
23
|
# email_with_name = "#{user.name} <#{user.email}>"
|
20
24
|
# email_with_name = format('%s <%s>', user.name, user.email)
|
21
25
|
#
|
26
|
+
# # accepted, line-end concatenation
|
27
|
+
# name = 'First' +
|
28
|
+
# 'Last'
|
29
|
+
#
|
22
30
|
class StringConcatenation < Base
|
23
31
|
include Util
|
24
32
|
extend AutoCorrector
|
@@ -39,6 +47,7 @@ module RuboCop
|
|
39
47
|
|
40
48
|
def on_send(node)
|
41
49
|
return unless string_concatenation?(node)
|
50
|
+
return if line_end_concatenation?(node)
|
42
51
|
|
43
52
|
topmost_plus_node = find_topmost_plus_node(node)
|
44
53
|
|
@@ -58,6 +67,16 @@ module RuboCop
|
|
58
67
|
|
59
68
|
private
|
60
69
|
|
70
|
+
def line_end_concatenation?(node)
|
71
|
+
# If the concatenation happens at the end of the line,
|
72
|
+
# and both the receiver and argument are strings, allow
|
73
|
+
# `Style/LineEndConcatenation` to handle it instead.
|
74
|
+
node.receiver.str_type? &&
|
75
|
+
node.first_argument.str_type? &&
|
76
|
+
node.multiline? &&
|
77
|
+
node.source =~ /\+\s*\n/
|
78
|
+
end
|
79
|
+
|
61
80
|
def find_topmost_plus_node(node)
|
62
81
|
current = node
|
63
82
|
while (parent = current.parent) && plus_node?(parent)
|
@@ -106,7 +125,13 @@ module RuboCop
|
|
106
125
|
end
|
107
126
|
end
|
108
127
|
|
109
|
-
"\"#{interpolated_parts.join}\""
|
128
|
+
"\"#{handle_quotes(interpolated_parts).join}\""
|
129
|
+
end
|
130
|
+
|
131
|
+
def handle_quotes(parts)
|
132
|
+
parts.map do |part|
|
133
|
+
part == '"' ? '\"' : part
|
134
|
+
end
|
110
135
|
end
|
111
136
|
|
112
137
|
def single_quoted?(str_node)
|
@@ -26,9 +26,10 @@ module RuboCop
|
|
26
26
|
# "Just some text"
|
27
27
|
# "No special chars or interpolation"
|
28
28
|
# "Every string in #{project} uses double_quotes"
|
29
|
-
class StringLiterals <
|
29
|
+
class StringLiterals < Base
|
30
30
|
include ConfigurableEnforcedStyle
|
31
31
|
include StringLiteralsHelp
|
32
|
+
extend AutoCorrector
|
32
33
|
|
33
34
|
MSG_INCONSISTENT = 'Inconsistent quote style.'
|
34
35
|
|
@@ -46,7 +47,7 @@ module RuboCop
|
|
46
47
|
quote_styles = detect_quote_styles(node)
|
47
48
|
|
48
49
|
if quote_styles.size > 1
|
49
|
-
|
50
|
+
register_offense(node, message: MSG_INCONSISTENT)
|
50
51
|
else
|
51
52
|
check_multiline_quote_style(node, quote_styles[0])
|
52
53
|
end
|
@@ -54,11 +55,17 @@ module RuboCop
|
|
54
55
|
ignore_node(node)
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
private
|
59
|
+
|
60
|
+
def autocorrect(corrector, node)
|
61
|
+
StringLiteralCorrector.correct(corrector, node, style)
|
59
62
|
end
|
60
63
|
|
61
|
-
|
64
|
+
def register_offense(node, message: nil)
|
65
|
+
add_offense(node, message: message || message(node)) do |corrector|
|
66
|
+
autocorrect(corrector, node)
|
67
|
+
end
|
68
|
+
end
|
62
69
|
|
63
70
|
def all_string_literals?(nodes)
|
64
71
|
nodes.all? { |n| n.str_type? || n.dstr_type? }
|
@@ -99,14 +106,13 @@ module RuboCop
|
|
99
106
|
end
|
100
107
|
|
101
108
|
def check_multiline_quote_style(node, quote)
|
102
|
-
range = node.source_range
|
103
109
|
children = node.children
|
104
110
|
if unexpected_single_quotes?(quote)
|
105
111
|
all_children_with_quotes = children.all? { |c| wrong_quotes?(c) }
|
106
|
-
|
112
|
+
register_offense(node) if all_children_with_quotes
|
107
113
|
elsif unexpected_double_quotes?(quote) &&
|
108
114
|
!accept_child_double_quotes?(children)
|
109
|
-
|
115
|
+
register_offense(node)
|
110
116
|
end
|
111
117
|
end
|
112
118
|
|