rubocop 1.18.3 → 1.20.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 +46 -7
- data/lib/rubocop/cli.rb +18 -0
- data/lib/rubocop/config_loader.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +21 -6
- data/lib/rubocop/config_validator.rb +18 -5
- data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/require_library_corrector.rb +23 -0
- data/lib/rubocop/cop/documentation.rb +1 -1
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +34 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +71 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/class_structure.rb +5 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +10 -2
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +22 -18
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +0 -7
- data/lib/rubocop/cop/layout/indentation_style.rb +2 -2
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +33 -14
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +22 -9
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -1
- data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +5 -5
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +24 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +105 -0
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -2
- data/lib/rubocop/cop/lint/debugger.rb +2 -2
- data/lib/rubocop/cop/lint/duplicate_branch.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +8 -5
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
- data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +14 -1
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +6 -1
- data/lib/rubocop/cop/mixin/heredoc.rb +7 -0
- data/lib/rubocop/cop/mixin/percent_array.rb +13 -7
- data/lib/rubocop/cop/mixin/require_library.rb +59 -0
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +18 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +39 -6
- data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
- data/lib/rubocop/cop/style/commented_keyword.rb +2 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +19 -5
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -7
- data/lib/rubocop/cop/style/double_negation.rb +12 -1
- data/lib/rubocop/cop/style/encoding.rb +26 -15
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +32 -7
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
- data/lib/rubocop/cop/style/hash_except.rb +4 -3
- data/lib/rubocop/cop/style/hash_transform_keys.rb +0 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +30 -5
- data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -1
- data/lib/rubocop/cop/style/missing_else.rb +7 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +73 -13
- data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +4 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +83 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
- data/lib/rubocop/cop/style/semicolon.rb +32 -24
- data/lib/rubocop/cop/style/single_line_block_params.rb +3 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +14 -9
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +21 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +3 -0
- data/lib/rubocop/cop/style/symbol_array.rb +3 -3
- data/lib/rubocop/cop/style/word_array.rb +23 -5
- data/lib/rubocop/cop/util.rb +7 -2
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -1
- data/lib/rubocop/magic_comment.rb +44 -15
- data/lib/rubocop/options.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +6 -1
- metadata +12 -5
@@ -84,6 +84,7 @@ module RuboCop
|
|
84
84
|
|
85
85
|
def on_kwbegin(node)
|
86
86
|
return if empty_begin?(node) ||
|
87
|
+
begin_block_has_multiline_statements?(node) ||
|
87
88
|
contain_rescue_or_ensure?(node) ||
|
88
89
|
valid_context_using_only_begin?(node)
|
89
90
|
|
@@ -102,6 +103,9 @@ module RuboCop
|
|
102
103
|
corrector.remove(offense_range)
|
103
104
|
end
|
104
105
|
|
106
|
+
if use_modifier_form_after_multiline_begin_block?(node)
|
107
|
+
correct_modifier_form_after_multiline_begin_block(corrector, node)
|
108
|
+
end
|
105
109
|
corrector.remove(node.loc.end)
|
106
110
|
end
|
107
111
|
end
|
@@ -127,10 +131,31 @@ module RuboCop
|
|
127
131
|
corrector.insert_before(node.parent, comments) unless comments.blank?
|
128
132
|
end
|
129
133
|
|
134
|
+
def use_modifier_form_after_multiline_begin_block?(node)
|
135
|
+
return unless (parent = node.parent)
|
136
|
+
|
137
|
+
node.multiline? && parent.if_type? && parent.modifier_form?
|
138
|
+
end
|
139
|
+
|
140
|
+
def correct_modifier_form_after_multiline_begin_block(corrector, node)
|
141
|
+
condition_range = condition_range(node.parent)
|
142
|
+
|
143
|
+
corrector.insert_after(node.children.first, " #{condition_range.source}")
|
144
|
+
corrector.remove(range_by_whole_lines(condition_range, include_final_newline: true))
|
145
|
+
end
|
146
|
+
|
147
|
+
def condition_range(node)
|
148
|
+
range_between(node.loc.keyword.begin_pos, node.condition.source_range.end_pos)
|
149
|
+
end
|
150
|
+
|
130
151
|
def empty_begin?(node)
|
131
152
|
node.children.empty?
|
132
153
|
end
|
133
154
|
|
155
|
+
def begin_block_has_multiline_statements?(node)
|
156
|
+
node.children.count >= 2
|
157
|
+
end
|
158
|
+
|
134
159
|
def contain_rescue_or_ensure?(node)
|
135
160
|
first_child = node.children.first
|
136
161
|
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
|
9
9
|
#
|
10
|
+
# NOTE: From Ruby 3.0, this cop allows explicit freezing of interpolated
|
11
|
+
# string literals when `# frozen-string-literal: true` is used.
|
12
|
+
#
|
10
13
|
# @example
|
11
14
|
# # bad
|
12
15
|
# CONST = 1.freeze
|
@@ -37,9 +40,7 @@ module RuboCop
|
|
37
40
|
node = strip_parenthesis(node)
|
38
41
|
|
39
42
|
return true if node.immutable_literal?
|
40
|
-
|
41
|
-
return true if FROZEN_STRING_LITERAL_TYPES.include?(node.type) &&
|
42
|
-
frozen_string_literals_enabled?
|
43
|
+
return true if frozen_string_literal?(node)
|
43
44
|
|
44
45
|
target_ruby_version >= 3.0 && (node.regexp_type? || node.range_type?)
|
45
46
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for places where conditional branch makes redundant self-assignment.
|
7
|
+
#
|
8
|
+
# It only detects local variable because it may replace state of instance variable,
|
9
|
+
# class variable, and global variable that have state across methods with `nil`.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# foo = condition ? bar : foo
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# foo = bar if condition
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# foo = condition ? foo : bar
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# foo = bar unless condition
|
24
|
+
#
|
25
|
+
class RedundantSelfAssignmentBranch < Base
|
26
|
+
include RangeHelp
|
27
|
+
extend AutoCorrector
|
28
|
+
|
29
|
+
MSG = 'Remove the self-assignment branch.'
|
30
|
+
|
31
|
+
# @!method bad_method?(node)
|
32
|
+
def_node_matcher :bad_method?, <<~PATTERN
|
33
|
+
(send nil? :bad_method ...)
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_lvasgn(node)
|
37
|
+
variable, expression = *node
|
38
|
+
return unless use_if_and_else_branch?(expression)
|
39
|
+
|
40
|
+
if_branch = expression.if_branch
|
41
|
+
else_branch = expression.else_branch
|
42
|
+
return if inconvertible_to_modifier?(if_branch, else_branch)
|
43
|
+
|
44
|
+
if self_assign?(variable, if_branch)
|
45
|
+
register_offense(expression, if_branch, else_branch, 'unless')
|
46
|
+
elsif self_assign?(variable, else_branch)
|
47
|
+
register_offense(expression, else_branch, if_branch, 'if')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def use_if_and_else_branch?(expression)
|
54
|
+
return false unless expression&.if_type?
|
55
|
+
|
56
|
+
!expression.ternary? || !expression.else?
|
57
|
+
end
|
58
|
+
|
59
|
+
def inconvertible_to_modifier?(if_branch, else_branch)
|
60
|
+
multiple_statements?(if_branch) || multiple_statements?(else_branch) ||
|
61
|
+
else_branch.respond_to?(:elsif?) && else_branch.elsif?
|
62
|
+
end
|
63
|
+
|
64
|
+
def multiple_statements?(branch)
|
65
|
+
branch && branch.children.compact.count > 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def self_assign?(variable, branch)
|
69
|
+
variable.to_s == branch&.source
|
70
|
+
end
|
71
|
+
|
72
|
+
def register_offense(if_node, offense_branch, opposite_branch, keyword)
|
73
|
+
add_offense(offense_branch) do |corrector|
|
74
|
+
assignment_value = opposite_branch ? opposite_branch.source : 'nil'
|
75
|
+
replacement = "#{assignment_value} #{keyword} #{if_node.condition.source}"
|
76
|
+
|
77
|
+
corrector.replace(if_node, replacement)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -60,8 +60,8 @@ module RuboCop
|
|
60
60
|
# @!method redundant_sort?(node)
|
61
61
|
def_node_matcher :redundant_sort?, <<~MATCHER
|
62
62
|
{
|
63
|
-
(send $(send _ $:sort
|
64
|
-
(send $(send _ $:sort
|
63
|
+
(send $(send _ $:sort) ${:last :first})
|
64
|
+
(send $(send _ $:sort) ${:[] :at :slice} {(int 0) (int -1)})
|
65
65
|
|
66
66
|
(send $(send _ $:sort_by _) ${:last :first})
|
67
67
|
(send $(send _ $:sort_by _) ${:[] :at :slice} {(int 0) (int -1)})
|
@@ -32,38 +32,29 @@ module RuboCop
|
|
32
32
|
|
33
33
|
MSG = 'Do not use semicolons to terminate expressions.'
|
34
34
|
|
35
|
+
def self.autocorrect_incompatible_with
|
36
|
+
[Style::SingleLineMethods]
|
37
|
+
end
|
38
|
+
|
35
39
|
def on_new_investigation
|
36
40
|
return if processed_source.blank?
|
37
41
|
|
38
|
-
@processed_source = processed_source
|
39
|
-
|
40
42
|
check_for_line_terminator_or_opener
|
41
43
|
end
|
42
44
|
|
43
|
-
def on_begin(node)
|
45
|
+
def on_begin(node)
|
44
46
|
return if cop_config['AllowAsExpressionSeparator']
|
45
47
|
|
46
48
|
exprs = node.children
|
47
49
|
|
48
50
|
return if exprs.size < 2
|
49
51
|
|
50
|
-
|
51
|
-
exprs_lines = exprs.map(&:first_line)
|
52
|
-
lines = exprs_lines.group_by(&:itself)
|
53
|
-
|
54
|
-
lines.each do |line, expr_on_line|
|
52
|
+
expressions_per_line(exprs).each do |line, expr_on_line|
|
55
53
|
# Every line with more than one expression on it is a
|
56
54
|
# potential offense
|
57
55
|
next unless expr_on_line.size > 1
|
58
56
|
|
59
|
-
|
60
|
-
# if the first semicolon on the line is a separator of
|
61
|
-
# expressions. It's just a guess.
|
62
|
-
column = @processed_source[line - 1].index(';')
|
63
|
-
|
64
|
-
next unless column
|
65
|
-
|
66
|
-
convention_on(line, column, false)
|
57
|
+
find_semicolon_positions(line) { |pos| register_semicolon(line, pos, true) }
|
67
58
|
end
|
68
59
|
end
|
69
60
|
|
@@ -71,9 +62,9 @@ module RuboCop
|
|
71
62
|
|
72
63
|
def check_for_line_terminator_or_opener
|
73
64
|
# Make the obvious check first
|
74
|
-
return unless
|
65
|
+
return unless processed_source.raw_source.include?(';')
|
75
66
|
|
76
|
-
each_semicolon { |line, column|
|
67
|
+
each_semicolon { |line, column| register_semicolon(line, column, false) }
|
77
68
|
end
|
78
69
|
|
79
70
|
def each_semicolon
|
@@ -84,15 +75,32 @@ module RuboCop
|
|
84
75
|
end
|
85
76
|
|
86
77
|
def tokens_for_lines
|
87
|
-
|
78
|
+
processed_source.tokens.group_by(&:line)
|
88
79
|
end
|
89
80
|
|
90
|
-
def
|
91
|
-
range = source_range(
|
92
|
-
|
93
|
-
# on the same line
|
81
|
+
def register_semicolon(line, column, after_expression)
|
82
|
+
range = source_range(processed_source.buffer, line, column)
|
83
|
+
|
94
84
|
add_offense(range) do |corrector|
|
95
|
-
|
85
|
+
if after_expression
|
86
|
+
corrector.replace(range, "\n")
|
87
|
+
else
|
88
|
+
corrector.remove(range)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def expressions_per_line(exprs)
|
94
|
+
# create a map matching lines to the number of expressions on them
|
95
|
+
exprs_lines = exprs.map(&:first_line)
|
96
|
+
exprs_lines.group_by(&:itself)
|
97
|
+
end
|
98
|
+
|
99
|
+
def find_semicolon_positions(line)
|
100
|
+
# Scan for all the semicolons on the line
|
101
|
+
semicolons = processed_source[line - 1].enum_for(:scan, ';')
|
102
|
+
semicolons.each do
|
103
|
+
yield Regexp.last_match.begin(0)
|
96
104
|
end
|
97
105
|
end
|
98
106
|
end
|
@@ -109,7 +109,9 @@ module RuboCop
|
|
109
109
|
# we remove any leading underscores before comparing.
|
110
110
|
actual_args_no_underscores = actual_args.map { |arg| arg.to_s.sub(/^_+/, '') }
|
111
111
|
|
112
|
-
|
112
|
+
# Allow the arguments if the names match but not all are given
|
113
|
+
expected_args = target_args(method_name).first(actual_args_no_underscores.size)
|
114
|
+
actual_args_no_underscores == expected_args
|
113
115
|
end
|
114
116
|
end
|
115
117
|
end
|
@@ -72,17 +72,15 @@ module RuboCop
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def correct_to_multiline(corrector, node)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
if (body = node.body) && body.begin_type? && body.parenthesized_call?
|
76
|
+
break_line_before(corrector, node, body)
|
77
|
+
else
|
78
|
+
each_part(body) do |part|
|
79
|
+
break_line_before(corrector, node, part)
|
80
|
+
end
|
80
81
|
end
|
81
82
|
|
82
|
-
|
83
|
-
range: node.loc.end, node: node, corrector: corrector,
|
84
|
-
indent_steps: 0, configured_width: configured_indentation_width
|
85
|
-
)
|
83
|
+
break_line_before(corrector, node, node.loc.end, indent_steps: 0)
|
86
84
|
|
87
85
|
move_comment(node, corrector)
|
88
86
|
end
|
@@ -96,6 +94,13 @@ module RuboCop
|
|
96
94
|
corrector.replace(node, replacement)
|
97
95
|
end
|
98
96
|
|
97
|
+
def break_line_before(corrector, node, range, indent_steps: 1)
|
98
|
+
LineBreakCorrector.break_line_before(
|
99
|
+
range: range, node: node, corrector: corrector,
|
100
|
+
configured_width: configured_indentation_width, indent_steps: indent_steps
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
99
104
|
def each_part(body)
|
100
105
|
return unless body
|
101
106
|
|
@@ -38,6 +38,10 @@ module RuboCop
|
|
38
38
|
|
39
39
|
MSG = 'Consider merging nested conditions into outer `%<conditional_type>s` conditions.'
|
40
40
|
|
41
|
+
def self.autocorrect_incompatible_with
|
42
|
+
[Style::NegatedIf, Style::NegatedUnless]
|
43
|
+
end
|
44
|
+
|
41
45
|
def on_if(node)
|
42
46
|
return if node.ternary? || node.else? || node.elsif?
|
43
47
|
|
@@ -5,9 +5,14 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
#
|
7
7
|
# This cop looks for uses of Perl-style global variables.
|
8
|
+
# Correcting to global variables in the 'English' library
|
9
|
+
# will add a require statement to the top of the file if
|
10
|
+
# enabled by RequireEnglish config.
|
8
11
|
#
|
9
12
|
# @example EnforcedStyle: use_english_names (default)
|
10
13
|
# # good
|
14
|
+
# require 'English' # or this could be in another file.
|
15
|
+
#
|
11
16
|
# puts $LOAD_PATH
|
12
17
|
# puts $LOADED_FEATURES
|
13
18
|
# puts $PROGRAM_NAME
|
@@ -50,6 +55,8 @@ module RuboCop
|
|
50
55
|
#
|
51
56
|
class SpecialGlobalVars < Base
|
52
57
|
include ConfigurableEnforcedStyle
|
58
|
+
include RangeHelp
|
59
|
+
include RequireLibrary
|
53
60
|
extend AutoCorrector
|
54
61
|
|
55
62
|
MSG_BOTH = 'Prefer `%<prefer>s` from the stdlib \'English\' ' \
|
@@ -90,6 +97,8 @@ module RuboCop
|
|
90
97
|
# Anything *not* in this set is provided by the English library.
|
91
98
|
NON_ENGLISH_VARS = Set.new(%i[$LOAD_PATH $LOADED_FEATURES $PROGRAM_NAME ARGV]).freeze
|
92
99
|
|
100
|
+
LIBRARY_NAME = 'English'
|
101
|
+
|
93
102
|
def on_gvar(node)
|
94
103
|
global_var, = *node
|
95
104
|
|
@@ -117,6 +126,8 @@ module RuboCop
|
|
117
126
|
def autocorrect(corrector, node, global_var)
|
118
127
|
node = node.parent while node.parent&.begin_type? && node.parent.children.one?
|
119
128
|
|
129
|
+
ensure_required(corrector, node, LIBRARY_NAME) if should_require_english?(global_var)
|
130
|
+
|
120
131
|
corrector.replace(node, replacement(node, global_var))
|
121
132
|
end
|
122
133
|
|
@@ -172,6 +183,16 @@ module RuboCop
|
|
172
183
|
|
173
184
|
"{#{preferred_name}}"
|
174
185
|
end
|
186
|
+
|
187
|
+
def add_require_english?
|
188
|
+
cop_config['RequireEnglish']
|
189
|
+
end
|
190
|
+
|
191
|
+
def should_require_english?(global_var)
|
192
|
+
style == :use_english_names &&
|
193
|
+
add_require_english? &&
|
194
|
+
!NON_ENGLISH_VARS.include?(preferred_names(global_var).first)
|
195
|
+
end
|
175
196
|
end
|
176
197
|
end
|
177
198
|
end
|
@@ -5,6 +5,9 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for inheritance from Struct.new.
|
7
7
|
#
|
8
|
+
# It is marked as unsafe auto-correction because it will change the
|
9
|
+
# inheritance tree (e.g. return value of `Module#ancestors`).
|
10
|
+
#
|
8
11
|
# @example
|
9
12
|
# # bad
|
10
13
|
# class Person < Struct.new(:first_name, :last_name)
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
extend AutoCorrector
|
36
36
|
|
37
37
|
PERCENT_MSG = 'Use `%i` or `%I` for an array of symbols.'
|
38
|
-
ARRAY_MSG = 'Use `
|
38
|
+
ARRAY_MSG = 'Use `%<prefer>s` for an array of symbols.'
|
39
39
|
|
40
40
|
class << self
|
41
41
|
attr_accessor :largest_brackets
|
@@ -60,7 +60,7 @@ module RuboCop
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
63
|
+
def build_bracketed_array(node)
|
64
64
|
syms = node.children.map do |c|
|
65
65
|
if c.dsym_type?
|
66
66
|
string_literal = to_string_literal(c.source)
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
"[#{syms.join(', ')}]"
|
75
75
|
end
|
76
76
|
|
77
77
|
def to_symbol_literal(string)
|
@@ -9,6 +9,9 @@ module RuboCop
|
|
9
9
|
# Alternatively, it can check for uses of the %w() syntax, in projects
|
10
10
|
# which do not want to include that syntax.
|
11
11
|
#
|
12
|
+
# NOTE: When using the `percent` style, %w() arrays containing a space
|
13
|
+
# will be registered as offenses.
|
14
|
+
#
|
12
15
|
# Configuration option: MinSize
|
13
16
|
# If set, arrays with fewer elements than this value will not trigger the
|
14
17
|
# cop. For example, a `MinSize` of `3` will not enforce a style on an
|
@@ -21,12 +24,18 @@ module RuboCop
|
|
21
24
|
# # bad
|
22
25
|
# ['foo', 'bar', 'baz']
|
23
26
|
#
|
27
|
+
# # bad (contains spaces)
|
28
|
+
# %w[foo\ bar baz\ quux]
|
29
|
+
#
|
24
30
|
# @example EnforcedStyle: brackets
|
25
31
|
# # good
|
26
32
|
# ['foo', 'bar', 'baz']
|
27
33
|
#
|
28
34
|
# # bad
|
29
35
|
# %w[foo bar baz]
|
36
|
+
#
|
37
|
+
# # good (contains spaces)
|
38
|
+
# ['foo bar', 'baz quux']
|
30
39
|
class WordArray < Base
|
31
40
|
include ArrayMinSize
|
32
41
|
include ArraySyntax
|
@@ -35,7 +44,7 @@ module RuboCop
|
|
35
44
|
extend AutoCorrector
|
36
45
|
|
37
46
|
PERCENT_MSG = 'Use `%w` or `%W` for an array of words.'
|
38
|
-
ARRAY_MSG = 'Use `
|
47
|
+
ARRAY_MSG = 'Use `%<prefer>s` for an array of words.'
|
39
48
|
|
40
49
|
class << self
|
41
50
|
attr_accessor :largest_brackets
|
@@ -53,18 +62,27 @@ module RuboCop
|
|
53
62
|
|
54
63
|
private
|
55
64
|
|
56
|
-
def complex_content?(strings)
|
65
|
+
def complex_content?(strings, complex_regex: word_regex)
|
57
66
|
strings.any? do |s|
|
67
|
+
next unless s.str_content
|
68
|
+
|
58
69
|
string = s.str_content.dup.force_encoding(::Encoding::UTF_8)
|
59
|
-
!string.valid_encoding? ||
|
70
|
+
!string.valid_encoding? ||
|
71
|
+
(complex_regex && !complex_regex.match?(string)) ||
|
72
|
+
/ /.match?(string)
|
60
73
|
end
|
61
74
|
end
|
62
75
|
|
76
|
+
def invalid_percent_array_contents?(node)
|
77
|
+
# Disallow %w() arrays that contain invalid encoding or spaces
|
78
|
+
complex_content?(node.values, complex_regex: false)
|
79
|
+
end
|
80
|
+
|
63
81
|
def word_regex
|
64
82
|
Regexp.new(cop_config['WordRegex'])
|
65
83
|
end
|
66
84
|
|
67
|
-
def
|
85
|
+
def build_bracketed_array(node)
|
68
86
|
words = node.children.map do |word|
|
69
87
|
if word.dstr_type?
|
70
88
|
string_literal = to_string_literal(word.source)
|
@@ -75,7 +93,7 @@ module RuboCop
|
|
75
93
|
end
|
76
94
|
end
|
77
95
|
|
78
|
-
|
96
|
+
"[#{words.join(', ')}]"
|
79
97
|
end
|
80
98
|
end
|
81
99
|
end
|