/
word_array.rb
155 lines (137 loc) · 4.23 KB
/
word_array.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# frozen_string_literal: true
module RuboCop
module Cop
module Style
# Checks for array literals made up of word-like
# strings, that are not using the %w() syntax.
#
# Alternatively, it can check for uses of the %w() syntax, in projects
# which do not want to include that syntax.
#
# NOTE: When using the `percent` style, %w() arrays containing a space
# will be registered as offenses.
#
# Configuration option: MinSize
# If set, arrays with fewer elements than this value will not trigger the
# cop. For example, a `MinSize` of `3` will not enforce a style on an
# array of 2 or fewer elements.
#
# @example EnforcedStyle: percent (default)
# # good
# %w[foo bar baz]
#
# # bad
# ['foo', 'bar', 'baz']
#
# # bad (contains spaces)
# %w[foo\ bar baz\ quux]
#
# # bad
# [
# ['one', 'One'],
# ['two', 'Two']
# ]
#
# # good
# [
# %w[one One],
# %w[two Two]
# ]
#
# # good (2d array containing spaces)
# [
# ['one', 'One'],
# ['two', 'Two'],
# ['forty two', 'Forty Two']
# ]
#
# @example EnforcedStyle: brackets
# # good
# ['foo', 'bar', 'baz']
#
# # bad
# %w[foo bar baz]
#
# # good (contains spaces)
# ['foo bar', 'baz quux']
#
# # good
# [
# ['one', 'One'],
# ['two', 'Two']
# ]
#
# # bad
# [
# %w[one One],
# %w[two Two]
# ]
#
class WordArray < Base
include ArrayMinSize
include ArraySyntax
include ConfigurableEnforcedStyle
include PercentArray
extend AutoCorrector
PERCENT_MSG = 'Use `%w` or `%W` for an array of words.'
ARRAY_MSG = 'Use %<prefer>s for an array of words.'
class << self
attr_accessor :largest_brackets
end
def on_new_investigation
super
# Prevent O(n2) checks (checking the entire matrix once for each child array) by caching
@matrix_of_complex_content_cache = Hash.new do |cache, node|
cache[node] = matrix_of_complex_content?(node)
end
end
def on_array(node)
if bracketed_array_of?(:str, node)
return if complex_content?(node.values)
return if within_matrix_of_complex_content?(node)
check_bracketed_array(node, 'w')
elsif node.percent_literal?(:string)
check_percent_array(node)
end
end
private
def within_matrix_of_complex_content?(node)
return false unless (parent = node.parent)
parent.array_type? && @matrix_of_complex_content_cache[parent]
end
def matrix_of_complex_content?(array)
array.values.all?(&:array_type?) &&
array.values.any? { |subarray| complex_content?(subarray.values) }
end
def complex_content?(strings, complex_regex: word_regex)
strings.any? do |s|
next unless s.str_content
string = s.str_content.dup.force_encoding(::Encoding::UTF_8)
!string.valid_encoding? ||
(complex_regex && !complex_regex.match?(string)) ||
string.include?(' ')
end
end
def invalid_percent_array_contents?(node)
# Disallow %w() arrays that contain invalid encoding or spaces
complex_content?(node.values, complex_regex: false)
end
def word_regex
Regexp.new(cop_config['WordRegex'])
end
def build_bracketed_array(node)
return '[]' if node.children.empty?
words = node.children.map do |word|
if word.dstr_type?
string_literal = to_string_literal(word.source)
trim_string_interpolation_escape_character(string_literal)
else
to_string_literal(word.children[0])
end
end
build_bracketed_array_with_appropriate_whitespace(elements: words, node: node)
end
end
end
end
end