Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
156 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Style | ||
# This cop enforces the use of `Array()` instead of explicit `Array` check or `[*var]`. | ||
# | ||
# @example | ||
# # bad | ||
# paths = [paths] unless paths.is_a?(Array) | ||
# paths.each { |path| do_something(path) } | ||
# | ||
# # bad (always creates a new Array instance) | ||
# [*paths].each { |path| do_something(path) } | ||
# | ||
# # good (and a bit more readable) | ||
# Array(paths).each { |path| do_something(path) } | ||
# | ||
class ArrayCoercion < Base | ||
extend AutoCorrector | ||
|
||
SPLAT_MSG = 'Use `Array(%<arg>s)` instead of `[*%<arg>s]`.' | ||
CHECK_MSG = 'Use `Array(%<arg>s)` instead of explicit `Array` check.' | ||
|
||
def_node_matcher :array_splat?, <<~PATTERN | ||
(array (splat $_)) | ||
PATTERN | ||
|
||
def_node_matcher :unless_array?, <<~PATTERN | ||
(if | ||
(send | ||
(lvar $_) :is_a? | ||
(const nil? :Array)) nil? | ||
(lvasgn $_ | ||
(array | ||
(lvar $_)))) | ||
PATTERN | ||
|
||
def on_array(node) | ||
return unless node.square_brackets? | ||
|
||
array_splat?(node) do |arg_node| | ||
message = format(SPLAT_MSG, arg: arg_node.source) | ||
add_offense(node, message: message) do |corrector| | ||
corrector.replace(node, "Array(#{arg_node.source})") | ||
end | ||
end | ||
end | ||
|
||
def on_if(node) | ||
unless_array?(node) do |var_a, var_b, var_c| | ||
if var_a == var_b && var_c == var_b | ||
message = format(CHECK_MSG, arg: var_a) | ||
add_offense(node, message: message) do |corrector| | ||
corrector.replace(node, "#{var_a} = Array(#{var_a})") | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Style::ArrayCoercion do | ||
subject(:cop) { described_class.new } | ||
|
||
it 'registers an offense and corrects when splatting variable into array' do | ||
expect_offense(<<~RUBY) | ||
[*paths].each { |path| do_something(path) } | ||
^^^^^^^^ Use `Array(paths)` instead of `[*paths]`. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
Array(paths).each { |path| do_something(path) } | ||
RUBY | ||
end | ||
|
||
it 'registers an offense and corrects when converting variable into array with check' do | ||
expect_offense(<<~RUBY) | ||
paths = [paths] unless paths.is_a?(Array) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `Array(paths)` instead of explicit `Array` check. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
paths = Array(paths) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when splat is not in array' do | ||
expect_no_offenses(<<~RUBY) | ||
first_path, rest = *paths | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when splatting multiple variables into array' do | ||
expect_no_offenses(<<~RUBY) | ||
[*paths, '/root'].each { |path| do_something(path) } | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when converting variable into other named array variable with check' do | ||
expect_no_offenses(<<~RUBY) | ||
other_paths = [paths] unless paths.is_a?(Array) | ||
RUBY | ||
end | ||
end |