Skip to content

Commit

Permalink
Add new Layout/SpaceBeforeBrackets cop
Browse files Browse the repository at this point in the history
Follow rubocop/ruby-style-guide#856.

This PR adds new `Layout/SpaceBeforeBrackets` cop.

```ruby
# bad
collection [index_or_key]

# good
collection[index_or_key]
```

This cop is marked as unsafe because it can occur false positives
for `do_something [this_is_an_array_literal_argument]` that take
an array without parentheses as an argument.

I noticed this issue below.
https://github.com/rsim/oracle-enhanced/pull/2076/files#
diff-0d21136da5aee9b25213dcf874f62418fa24a06a90237e069642a5af54e7b2efL494-R494
  • Loading branch information
koic committed Dec 15, 2020
1 parent 5cfb001 commit 9cfced1
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog/new_layout_space_before_brackets.md
@@ -0,0 +1 @@
* [#9231](https://github.com/rubocop-hq/rubocop/pull/9231): Add new `Layout/SpaceBeforeBrackets` cop. ([@koic][])
7 changes: 7 additions & 0 deletions config/default.yml
Expand Up @@ -1192,6 +1192,13 @@ Layout/SpaceBeforeBlockBraces:
- no_space
VersionChanged: '0.52'

Layout/SpaceBeforeBrackets:
Description: 'Checks for receiver with a space before the opening brackets.'
StyleGuide: '#space-in-brackets-access'
Enabled: pending
VersionAdded: '<<next>>'
Safe: false

Layout/SpaceBeforeComma:
Description: 'No spaces before commas.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -230,6 +230,7 @@
require_relative 'rubocop/cop/layout/space_around_method_call_operator'
require_relative 'rubocop/cop/layout/space_around_operators'
require_relative 'rubocop/cop/layout/space_before_block_braces'
require_relative 'rubocop/cop/layout/space_before_brackets'
require_relative 'rubocop/cop/layout/space_before_comma'
require_relative 'rubocop/cop/layout/space_before_comment'
require_relative 'rubocop/cop/layout/space_before_first_arg'
Expand Down
68 changes: 68 additions & 0 deletions lib/rubocop/cop/layout/space_before_brackets.rb
@@ -0,0 +1,68 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Layout
# Checks for space between the name of a receiver and a left
# brackets.
#
# This cop is marked as unsafe because it can occur false positives
# for `do_something [this_is_an_array_literal_argument]` that take
# an array without parentheses as an argument.
#
# @example
#
# # bad
# collection [index_or_key]
#
# # good
# collection[index_or_key]
#
class SpaceBeforeBrackets < Base
include RangeHelp
extend AutoCorrector

MSG = 'Remove the space before the opening brackets.'

def_node_matcher :bad_method?, <<~PATTERN
(send nil? :bad_method ...)
PATTERN

def on_send(node)
return if node.parenthesized? || node.parent&.send_type?
return unless (first_argument = node.first_argument)

begin_pos = first_argument.source_range.begin_pos

return unless (range = offense_range(node, first_argument, begin_pos))

register_offense(range)
end

private

def offense_range(node, first_argument, begin_pos)
if space_before_brackets?(node, first_argument)
range_between(node.loc.selector.end_pos, begin_pos)
elsif node.method?(:[]=)
end_pos = node.receiver.source_range.end_pos

return if begin_pos - end_pos == 1

range_between(end_pos, begin_pos - 1)
end
end

def register_offense(range)
add_offense(range) do |corrector|
corrector.remove(range)
end
end

def space_before_brackets?(node, first_argument)
node.receiver.nil? && first_argument.array_type? && node.arguments.size == 1
end
end
end
end
end
73 changes: 73 additions & 0 deletions spec/rubocop/cop/layout/space_before_brackets_spec.rb
@@ -0,0 +1,73 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Layout::SpaceBeforeBrackets, :config do
subject(:cop) { described_class.new(config) }

context 'when referencing' do
it 'registers an offense and corrects when using space between receiver and left brackets' do
expect_offense(<<~RUBY)
collection [index_or_key]
^ Remove the space before the opening brackets.
RUBY

expect_correction(<<~RUBY)
collection[index_or_key]
RUBY
end

it 'does not register an offense when not using space between receiver and left brackets' do
expect_no_offenses(<<~RUBY)
collection[index_or_key]
RUBY
end

it 'does not register an offense when array literal argument is enclosed in parentheses' do
expect_no_offenses(<<~RUBY)
collection([index_or_key])
RUBY
end

it 'does not register an offense when it is used as a method argument' do
expect_no_offenses(<<~RUBY)
expect(offenses).to eq []
RUBY
end

it 'does not register an offense when using multiple arguments' do
expect_no_offenses(<<~RUBY)
do_something [foo], bar
RUBY
end

it 'does not register an offense when without receiver' do
expect_no_offenses(<<~RUBY)
[index_or_key]
RUBY
end
end

context 'when assigning' do
it 'registers an offense and corrects when using space between receiver and left brackets' do
expect_offense(<<~RUBY)
@correction [index_or_key] = :value
^ Remove the space before the opening brackets.
RUBY

expect_correction(<<~RUBY)
@correction[index_or_key] = :value
RUBY
end

it 'does not register an offense when not using space between receiver and left brackets' do
expect_no_offenses(<<~RUBY)
@correction[index_or_key] = :value
RUBY
end
end

it 'does not register an offense when assigning an array' do
expect_no_offenses(<<~RUBY)
task.options = ['--no-output']
RUBY
end
end

0 comments on commit 9cfced1

Please sign in to comment.