Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix #9962] Update Style/WordArray to register an offense in percent style if any values contain spaces #9981

Merged
merged 1 commit into from Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/change_update_stylewordarray_to_register_an.md
@@ -0,0 +1 @@
* [#9962](https://github.com/rubocop/rubocop/issues/9962): Update `Style/WordArray` to register an offense in `percent` style if any values contain spaces. ([@dvandersluis][])
2 changes: 1 addition & 1 deletion config/default.yml
Expand Up @@ -4921,7 +4921,7 @@ Style/WordArray:
StyleGuide: '#percent-w'
Enabled: true
VersionAdded: '0.9'
VersionChanged: '0.36'
VersionChanged: '<<next>>'
EnforcedStyle: percent
SupportedStyles:
# percent style: %w(word1 word2)
Expand Down
17 changes: 10 additions & 7 deletions lib/rubocop/cop/mixin/percent_array.rb
Expand Up @@ -18,15 +18,16 @@ def invalid_percent_array_context?(node)
!parent.parenthesized? && parent&.block_literal?
end

# Override to determine values that are invalid in a percent array
def invalid_percent_array_contents?(_node)
false
end

def allowed_bracket_array?(node)
comments_in_array?(node) || below_array_length?(node) ||
invalid_percent_array_context?(node)
end

def message(_node)
style == :percent ? self.class::PERCENT_MSG : self.class::ARRAY_MSG
end

def comments_in_array?(node)
line_span = node.source_range.first_line...node.source_range.last_line
processed_source.each_comment_in_lines(line_span).any?
Expand All @@ -35,9 +36,11 @@ def comments_in_array?(node)
def check_percent_array(node)
array_style_detected(:percent, node.values.size)

return unless style == :brackets
return unless style == :brackets || invalid_percent_array_contents?(node)

add_offense(node) { |corrector| correct_bracketed(corrector, node) }
add_offense(node, message: self.class::ARRAY_MSG) do |corrector|
correct_bracketed(corrector, node)
end
end

def check_bracketed_array(node, literal_prefix)
Expand All @@ -47,7 +50,7 @@ def check_bracketed_array(node, literal_prefix)

return unless style == :percent

add_offense(node) do |corrector|
add_offense(node, message: self.class::PERCENT_MSG) do |corrector|
percent_literal_corrector = PercentLiteralCorrector.new(@config, @preferred_delimiters)
percent_literal_corrector.correct(corrector, node, literal_prefix)
end
Expand Down
22 changes: 20 additions & 2 deletions lib/rubocop/cop/style/word_array.rb
Expand Up @@ -9,6 +9,9 @@ module Style
# 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
Expand All @@ -21,12 +24,18 @@ module Style
# # bad
# ['foo', 'bar', 'baz']
#
# # bad (contains spaces)
# %w[foo\ bar baz\ quux]
#
# @example EnforcedStyle: brackets
# # good
# ['foo', 'bar', 'baz']
#
# # bad
# %w[foo bar baz]
#
# # good (contains spaces)
# ['foo bar', 'baz quux']
class WordArray < Base
include ArrayMinSize
include ArraySyntax
Expand All @@ -53,13 +62,22 @@ def on_array(node)

private

def complex_content?(strings)
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? || !word_regex.match?(string) || / /.match?(string)
!string.valid_encoding? ||
(complex_regex && !complex_regex.match?(string)) ||
/ /.match?(string)
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
Expand Down
32 changes: 32 additions & 0 deletions spec/rubocop/cop/style/word_array_spec.rb
Expand Up @@ -317,6 +317,34 @@
_investigate(cop2, parse_source('%w(a b c)'))
expect(cop2.config_to_allow_offenses).to eq('EnforcedStyle' => 'percent', 'MinSize' => 3)
end

it 'registers an offense for a %w() array containing spaces' do
expect_offense(<<~'RUBY')
%w(one\ two three\ four)
^^^^^^^^^^^^^^^^^^^^^^^^ Use `[]` for an array of words.
RUBY

expect_correction(<<~RUBY)
['one two', 'three four']
RUBY
end

it 'does not register an offense for a %w() array containing non word characters' do
expect_no_offenses(<<~RUBY)
%w(% %i %I %q %Q %r %s %w %W %x)
RUBY
end

it 'corrects properly when there is an extra trailing comma' do
expect_offense(<<~RUBY)
A = ["one", "two",]
^^^^^^^^^^^^^^^ Use `%w` or `%W` for an array of words.
RUBY

expect_correction(<<~RUBY)
A = %w(one two)
RUBY
end
end

context 'when EnforcedStyle is array' do
Expand All @@ -338,6 +366,10 @@
expect_no_offenses("['foo', 'bar', 'foo-bar']")
end

it 'does not register an offense for arrays of strings with spaces' do
expect_no_offenses("['foo bar', 'baz quux']")
end

it 'registers an offense for a %w() array' do
expect_offense(<<~RUBY)
%w(one two three)
Expand Down