Skip to content

Commit

Permalink
Merge pull request #11328 from fatkodima/concat_array_literals-autoco…
Browse files Browse the repository at this point in the history
…rrection

Support autocorrection for percent literals in `Style/ConcatArrayLiterals`
  • Loading branch information
koic committed Dec 25, 2022
2 parents 239abcf + 62d38f5 commit 43cd246
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#11325](https://github.com/rubocop/rubocop/issues/11325): Support autocorrection for percent literals in `Style/ConcatArrayLiterals`. ([@fatkodima][])
24 changes: 22 additions & 2 deletions lib/rubocop/cop/style/concat_array_literals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ConcatArrayLiterals < Base
'Use `push` with elements as arguments without array brackets instead of `%<current>s`.'
RESTRICT_ON_SEND = %i[concat].freeze

# rubocop:disable Metrics
def on_send(node)
return if node.arguments.empty?
return unless node.arguments.all?(&:array_type?)
Expand All @@ -38,7 +39,12 @@ def on_send(node)
current = offense.source

if node.arguments.any?(&:percent_literal?)
message = format(MSG_FOR_PERCENT_LITERALS, current: current)
if percent_literals_includes_only_basic_literals?(node)
prefer = preferred_method(node)
message = format(MSG, prefer: prefer, current: current)
else
message = format(MSG_FOR_PERCENT_LITERALS, current: current)
end
else
prefer = preferred_method(node)
message = format(MSG, prefer: prefer, current: current)
Expand All @@ -48,6 +54,7 @@ def on_send(node)
corrector.replace(offense, prefer)
end
end
# rubocop:enable Metrics

private

Expand All @@ -56,10 +63,23 @@ def offense_range(node)
end

def preferred_method(node)
new_arguments = node.arguments.map { |arg| arg.children.map(&:source) }.join(', ')
new_arguments =
node.arguments.map do |arg|
if arg.percent_literal?
arg.children.map(&:value).map(&:inspect)
else
arg.children.map(&:source)
end
end.join(', ')

"push(#{new_arguments})"
end

def percent_literals_includes_only_basic_literals?(node)
node.arguments.select(&:percent_literal?).all? do |arg|
arg.children.all? { |child| child.str_type? || child.sym_type? }
end
end
end
end
end
Expand Down
60 changes: 41 additions & 19 deletions spec/rubocop/cop/style/concat_array_literals_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,82 +3,104 @@
RSpec.describe RuboCop::Cop::Style::ConcatArrayLiterals, :config do
it 'registers an offense when using `concat` with single element array literal argument' do
expect_offense(<<~RUBY)
item.concat([item])
^^^^^^^^^^^^^^ Use `push(item)` instead of `concat([item])`.
arr.concat([item])
^^^^^^^^^^^^^^ Use `push(item)` instead of `concat([item])`.
RUBY

expect_correction(<<~RUBY)
item.push(item)
arr.push(item)
RUBY
end

it 'registers an offense when using `concat` with multiple elements array literal argument' do
expect_offense(<<~RUBY)
item.concat([foo, bar])
^^^^^^^^^^^^^^^^^^ Use `push(foo, bar)` instead of `concat([foo, bar])`.
arr.concat([foo, bar])
^^^^^^^^^^^^^^^^^^ Use `push(foo, bar)` instead of `concat([foo, bar])`.
RUBY

expect_correction(<<~RUBY)
item.push(foo, bar)
arr.push(foo, bar)
RUBY
end

it 'registers an offense when using `concat` with multiple array literal arguments' do
expect_offense(<<~RUBY)
item.concat([foo, bar], [baz])
^^^^^^^^^^^^^^^^^^^^^^^^^ Use `push(foo, bar, baz)` instead of `concat([foo, bar], [baz])`.
arr.concat([foo, bar], [baz])
^^^^^^^^^^^^^^^^^^^^^^^^^ Use `push(foo, bar, baz)` instead of `concat([foo, bar], [baz])`.
RUBY

expect_correction(<<~RUBY)
item.push(foo, bar, baz)
arr.push(foo, bar, baz)
RUBY
end

it 'registers an offense when using `concat` with single element `%i` array literal argument' do
expect_offense(<<~RUBY)
item.concat(%i[item])
^^^^^^^^^^^^^^^^ Use `push` with elements as arguments without array brackets instead of `concat(%i[item])`.
arr.concat(%i[item])
^^^^^^^^^^^^^^^^ Use `push(:item)` instead of `concat(%i[item])`.
RUBY

expect_correction(<<~RUBY)
arr.push(:item)
RUBY
end

it 'registers an offense when using `concat` with `%I` array literal argument consisting of non basic literals' do
expect_offense(<<~RUBY)
arr.concat(%I[item \#{foo}])
^^^^^^^^^^^^^^^^^^^^^^^ Use `push` with elements as arguments without array brackets instead of `concat(%I[item \#{foo}])`.
RUBY

expect_no_corrections
end

it 'registers an offense when using `concat` with single element `%w` array literal argument' do
it 'registers an offense when using `concat` with `%W` array literal argument consisting of non basic literals' do
expect_offense(<<~RUBY)
item.concat(%w[item])
^^^^^^^^^^^^^^^^ Use `push` with elements as arguments without array brackets instead of `concat(%w[item])`.
arr.concat(%W[item \#{foo}])
^^^^^^^^^^^^^^^^^^^^^^^ Use `push` with elements as arguments without array brackets instead of `concat(%W[item \#{foo}])`.
RUBY

expect_no_corrections
end

it 'registers an offense when using `concat` with single element `%w` array literal argument' do
expect_offense(<<~RUBY)
arr.concat(%w[item])
^^^^^^^^^^^^^^^^ Use `push("item")` instead of `concat(%w[item])`.
RUBY

expect_correction(<<~RUBY)
arr.push("item")
RUBY
end

it 'does not register an offense when using `concat` with variable argument' do
expect_no_offenses(<<~RUBY)
item.concat(items)
arr.concat(items)
RUBY
end

it 'does not register an offense when using `concat` with array literal and variable arguments' do
expect_no_offenses(<<~RUBY)
item.concat([foo, bar], baz)
arr.concat([foo, bar], baz)
RUBY
end

it 'does not register an offense when using `concat` with no arguments' do
expect_no_offenses(<<~RUBY)
item.concat
arr.concat
RUBY
end

it 'does not register an offense when using `push`' do
expect_no_offenses(<<~RUBY)
item.push(item)
arr.push(item)
RUBY
end

it 'does not register an offense when using `<<`' do
expect_no_offenses(<<~RUBY)
item << item
arr << item
RUBY
end
end

0 comments on commit 43cd246

Please sign in to comment.