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

Implemented Layout/SpaceInsideParens with EnforcedStyle: compact #10025

Merged
merged 3 commits into from Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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/new_space_inside_parens_compact.md
@@ -0,0 +1 @@
* [#10025](https://github.com/rubocop/rubocop/pull/10025): Changed cop `SpaceInsideParens` to include a `compact` style. ([@itay-grudev][])
3 changes: 2 additions & 1 deletion config/default.yml
Expand Up @@ -1347,10 +1347,11 @@ Layout/SpaceInsideParens:
StyleGuide: '#spaces-braces'
Enabled: true
VersionAdded: '0.49'
VersionChanged: '0.55'
VersionChanged: '<<next>>'
EnforcedStyle: no_space
SupportedStyles:
- space
- compact
- no_space

Layout/SpaceInsidePercentLiteralDelimiters:
Expand Down
98 changes: 74 additions & 24 deletions lib/rubocop/cop/layout/space_inside_parens.rb
Expand Up @@ -33,6 +33,27 @@ module Layout
# g = ( a + 3 )
# y()
#
# @example EnforcedStyle: compact
# # The `compact` style enforces that parentheses have a space at the
# # beginning with the exception that successive right parentheses are allowed.
itay-grudev marked this conversation as resolved.
Show resolved Hide resolved
# # Note: Empty parentheses should not have spaces.
#
# # bad
# f(3)
# g = (a + 3)
# y( )
# g( f( x ) )
# g( f( x( 3 ) ), 5 )
# g( ( ( 3 + 5 ) * f) ** x, 5 )
#
# # good
# f( 3 )
# g = ( a + 3 )
# y()
# g( f( x ))
# g( f( x( 3 )), 5 )
# g((( 3 + 5 ) * f ) ** x, 5 )
#
class SpaceInsideParens < Base
include SurroundingSpace
include RangeHelp
Expand All @@ -45,35 +66,37 @@ class SpaceInsideParens < Base
def on_new_investigation
tokens = processed_source.sorted_tokens

if style == :space
case style
when :space
process_with_space_style(tokens)
when :compact
process_with_compact_style(tokens)
else
each_extraneous_space(tokens) do |range|
add_offense(range) do |corrector|
corrector.remove(range)
end
end
correct_extraneous_space(tokens)
end
end

private

def process_with_space_style(tokens)
tokens.each_cons(2) do |token1, token2|
each_extraneous_space_in_empty_parens(token1, token2) do |range|
add_offense(range) do |corrector|
corrector.remove(range)
end
end
each_missing_space(token1, token2) do |range|
add_offense(range, message: MSG_SPACE) do |corrector|
corrector.insert_before(range, ' ')
end
correct_extraneous_space_in_empty_parens(token1, token2)
correct_missing_space(token1, token2)
end
end

def process_with_compact_style(tokens)
tokens.each_cons(2) do |token1, token2|
correct_extraneous_space_in_empty_parens(token1, token2)
if !left_parens?(token1, token2) && !right_parens?(token1, token2)
correct_missing_space(token1, token2)
else
correct_extaneus_space_between_consecutive_parens(token1, token2)
end
end
end

def each_extraneous_space(tokens)
def correct_extraneous_space(tokens)
tokens.each_cons(2) do |token1, token2|
next unless parens?(token1, token2)

Expand All @@ -82,25 +105,44 @@ def each_extraneous_space(tokens)
next if token2.comment?
next unless same_line?(token1, token2) && token1.space_after?

yield range_between(token1.end_pos, token2.begin_pos)
range = range_between(token1.end_pos, token2.begin_pos)
add_offense(range) do |corrector|
corrector.remove(range)
end
end
end

def correct_extaneus_space_between_consecutive_parens(token1, token2)
return if range_between(token1.end_pos, token2.begin_pos).source != ' '
itay-grudev marked this conversation as resolved.
Show resolved Hide resolved

range = range_between(token1.end_pos, token2.begin_pos)
add_offense(range) do |corrector|
corrector.remove(range)
end
end

def each_extraneous_space_in_empty_parens(token1, token2)
def correct_extraneous_space_in_empty_parens(token1, token2)
return unless token1.left_parens? && token2.right_parens?

return if range_between(token1.begin_pos, token2.end_pos).source == '()'

yield range_between(token1.end_pos, token2.begin_pos)
range = range_between(token1.end_pos, token2.begin_pos)
add_offense(range) do |corrector|
corrector.remove(range)
end
end

def each_missing_space(token1, token2)
def correct_missing_space(token1, token2)
return if can_be_ignored?(token1, token2)

if token1.left_parens?
yield range_between(token2.begin_pos, token2.begin_pos + 1)
elsif token2.right_parens?
yield range_between(token2.begin_pos, token2.end_pos)
range = if token1.left_parens?
range_between(token2.begin_pos, token2.begin_pos + 1)
elsif token2.right_parens?
range_between(token2.begin_pos, token2.end_pos)
end

add_offense(range, message: MSG_SPACE) do |corrector|
corrector.insert_before(range, ' ')
end
end

Expand All @@ -112,6 +154,14 @@ def parens?(token1, token2)
token1.left_parens? || token2.right_parens?
end

def left_parens?(token1, token2)
token1.left_parens? && token2.left_parens?
end

def right_parens?(token1, token2)
token1.right_parens? && token2.right_parens?
end

def can_be_ignored?(token1, token2)
return true unless parens?(token1, token2)

Expand Down
154 changes: 154 additions & 0 deletions spec/rubocop/cop/layout/space_inside_parens_spec.rb
Expand Up @@ -151,4 +151,158 @@
RUBY
end
end

context 'when EnforcedStyle is compact' do
let(:cop_config) { { 'EnforcedStyle' => 'compact' } }

it 'registers an offense for no spaces inside parens' do
expect_offense(<<~RUBY)
f( 3)
^ No space inside parentheses detected.
g = (a + 3 )
^ No space inside parentheses detected.
split("\\n")
^ No space inside parentheses detected.
^ No space inside parentheses detected.
RUBY

expect_correction(<<~RUBY)
f( 3 )
g = ( a + 3 )
split( "\\n" )
RUBY
end

it 'registers an offense for space inside empty parens' do
expect_offense(<<~RUBY)
f( )
^ Space inside parentheses detected.
RUBY

expect_correction(<<~RUBY)
f()
RUBY
end

it 'registers an offense in block parameter list with no spaces' do
expect_offense(<<~RUBY)
list.inject( Tms.new ) { |sum, (label, item)|
^ No space inside parentheses detected.
^ No space inside parentheses detected.
}
RUBY

expect_correction(<<~RUBY)
list.inject( Tms.new ) { |sum, ( label, item )|
}
RUBY
end

it 'registers an offense for no space around heredoc start' do
expect_offense(<<~RUBY)
f(<<~HEREDOC)
^ No space inside parentheses detected.
^ No space inside parentheses detected.
This is my text
HEREDOC
RUBY

expect_correction(<<~RUBY)
f( <<~HEREDOC )
This is my text
HEREDOC
RUBY
end

it 'accepts empty parentheses without spaces' do
expect_no_offenses('f()')
end

it 'accepts parentheses with spaces' do
expect_no_offenses(<<~RUBY)
f( 3 )
g = ( a + 3 )
split( "\\n" )
RUBY
end

it 'accepts parentheses with line break' do
expect_no_offenses(<<~RUBY)
f(
1 )
RUBY
end

it 'accepts parentheses with comment and line break' do
expect_no_offenses(<<~RUBY)
f( # Comment
1 )
RUBY
end

it 'accepts two consecutive left parentheses' do
expect_no_offenses(<<~RUBY)
f(( 3 + 5 ) * x )
RUBY
end

it 'accepts two consecutive right parentheses' do
expect_no_offenses(<<~RUBY)
f( x( 3 ))
g( f( x( 3 )), 5 )
RUBY
end

it 'accepts three consecutive left parentheses' do
expect_no_offenses(<<~RUBY)
g((( 3 + 5 ) * f ) ** x, 5 )
RUBY
end

it 'accepts three consecutive right parentheses' do
expect_no_offenses(<<~RUBY)
g( f( x( 3 )))
w( g( f( x( 3 ))), 5 )
RUBY
end

it 'registers an offense for space between consecutive brackets' do
expect_offense(<<~RUBY)
f( ( 3 + 5 ) * x )
^ Space inside parentheses detected.
g( ( ( 3 + 5 ) * f ) ** x, 5 )
^ Space inside parentheses detected.
^ Space inside parentheses detected.
f( x( 3 ) )
^ Space inside parentheses detected.
g( f( x( 3 ) ), 5 )
^ Space inside parentheses detected.
RUBY

expect_correction(<<~RUBY)
f(( 3 + 5 ) * x )
g((( 3 + 5 ) * f ) ** x, 5 )
f( x( 3 ))
g( f( x( 3 )), 5 )
RUBY
end

it 'registers multiple offense for a missing and extra space between consecutive brackets' do
expect_offense(<<~RUBY)
g( (( 3 + 5 ) * f) ** x, 5)
^ No space inside parentheses detected.
^ No space inside parentheses detected.
^ Space inside parentheses detected.
(g( f( x( 3 ) ), 5 ) )
^ Space inside parentheses detected.
^ Space inside parentheses detected.
^ No space inside parentheses detected.
RUBY

expect_correction(<<~RUBY)
g((( 3 + 5 ) * f ) ** x, 5 )
( g( f( x( 3 )), 5 ))
RUBY
end
end
end