From cd748fd695ee0cb42e75d223e086130274c68fc7 Mon Sep 17 00:00:00 2001 From: Itay Grudev Date: Wed, 18 Aug 2021 22:19:16 +0300 Subject: [PATCH 1/3] Implemented Layout/SpaceInsideParens with EnforcedStyle: compact --- changelog/new_space_inside_parens_compact.md | 1 + config/default.yml | 3 +- lib/rubocop/cop/layout/space_inside_parens.rb | 49 ++++++- .../cop/layout/space_inside_parens_spec.rb | 130 ++++++++++++++++++ 4 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 changelog/new_space_inside_parens_compact.md diff --git a/changelog/new_space_inside_parens_compact.md b/changelog/new_space_inside_parens_compact.md new file mode 100644 index 00000000000..2ef073f5463 --- /dev/null +++ b/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][]) diff --git a/config/default.yml b/config/default.yml index 53e201581c4..9063293f053 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1347,10 +1347,11 @@ Layout/SpaceInsideParens: StyleGuide: '#spaces-braces' Enabled: true VersionAdded: '0.49' - VersionChanged: '0.55' + VersionChanged: '<>' EnforcedStyle: no_space SupportedStyles: - space + - compact - no_space Layout/SpaceInsidePercentLiteralDelimiters: diff --git a/lib/rubocop/cop/layout/space_inside_parens.rb b/lib/rubocop/cop/layout/space_inside_parens.rb index 52aa118112f..e1ce4ff7ccd 100644 --- a/lib/rubocop/cop/layout/space_inside_parens.rb +++ b/lib/rubocop/cop/layout/space_inside_parens.rb @@ -33,6 +33,25 @@ 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. + # # Note: Empty parentheses should not have spaces. + # + # # bad + # f(3) + # g = (a + 3) + # y( ) + # g( f( x ) ) + # g( f( x( 3 ) ), 5 ) + # + # # good + # f( 3 ) + # g = ( a + 3 ) + # y() + # g( f( x )) + # g( f( x( 3 )), 5 ) + # class SpaceInsideParens < Base include SurroundingSpace include RangeHelp @@ -45,8 +64,11 @@ 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| @@ -73,6 +95,17 @@ def process_with_space_style(tokens) end end + def process_with_compact_style(tokens) + process_with_space_style(tokens) + tokens.each_cons(2) do |token1, token2| + each_extaneus_space_between_right_parents(token1, token2) do |range| + add_offense(range) do |corrector| + corrector.remove(range) + end + end + end + end + def each_extraneous_space(tokens) tokens.each_cons(2) do |token1, token2| next unless parens?(token1, token2) @@ -86,6 +119,14 @@ def each_extraneous_space(tokens) end end + def each_extaneus_space_between_right_parents(token1, token2) + return unless right_parens?(token1, token2) + + return if range_between(token1.end_pos, token2.begin_pos).source != ' ' + + yield range_between(token1.end_pos, token2.begin_pos) + end + def each_extraneous_space_in_empty_parens(token1, token2) return unless token1.left_parens? && token2.right_parens? @@ -97,6 +138,8 @@ def each_extraneous_space_in_empty_parens(token1, token2) def each_missing_space(token1, token2) return if can_be_ignored?(token1, token2) + return if style == :compact && token1.right_parens? && token2.right_parens? + if token1.left_parens? yield range_between(token2.begin_pos, token2.begin_pos + 1) elsif token2.right_parens? @@ -112,6 +155,10 @@ def parens?(token1, token2) token1.left_parens? || token2.right_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) diff --git a/spec/rubocop/cop/layout/space_inside_parens_spec.rb b/spec/rubocop/cop/layout/space_inside_parens_spec.rb index e60917dc79d..00f3dbb9f18 100644 --- a/spec/rubocop/cop/layout/space_inside_parens_spec.rb +++ b/spec/rubocop/cop/layout/space_inside_parens_spec.rb @@ -151,4 +151,134 @@ 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 right parentheses' do + expect_no_offenses(<<~RUBY) + f( x( 3 )) + g( f( x( 3 )), 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( x( 3 ) ) + ^ Space inside parentheses detected. + g( f( x( 3 ) ), 5 ) + ^ Space inside parentheses detected. + RUBY + + expect_correction(<<~RUBY) + 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( f( x( 3 ) ), 5 ) ) + ^ Space inside parentheses detected. + ^ Space inside parentheses detected. + ^ No space inside parentheses detected. + RUBY + + expect_correction(<<~RUBY) + ( g( f( x( 3 )), 5 )) + RUBY + end + end end From 8cc5b290525660f1ad6873f4234cf7dc8bac5e4a Mon Sep 17 00:00:00 2001 From: Itay Grudev Date: Fri, 24 Sep 2021 03:02:37 +0300 Subject: [PATCH 2/3] Implemented left compaction for SpaceInsideParens Compact style --- lib/rubocop/cop/layout/space_inside_parens.rb | 71 ++++++++++--------- .../cop/layout/space_inside_parens_spec.rb | 24 +++++++ 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/lib/rubocop/cop/layout/space_inside_parens.rb b/lib/rubocop/cop/layout/space_inside_parens.rb index e1ce4ff7ccd..5f02d517d55 100644 --- a/lib/rubocop/cop/layout/space_inside_parens.rb +++ b/lib/rubocop/cop/layout/space_inside_parens.rb @@ -44,6 +44,7 @@ module Layout # y( ) # g( f( x ) ) # g( f( x( 3 ) ), 5 ) + # g( ( ( 3 + 5 ) * f) ** x, 5 ) # # # good # f( 3 ) @@ -51,6 +52,7 @@ module Layout # y() # g( f( x )) # g( f( x( 3 )), 5 ) + # g((( 3 + 5 ) * f ) ** x, 5 ) # class SpaceInsideParens < Base include SurroundingSpace @@ -70,11 +72,7 @@ def on_new_investigation 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 @@ -82,31 +80,23 @@ def on_new_investigation 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 - end + correct_extraneous_space_in_empty_parens(token1, token2) + correct_missing_space(token1, token2) end end def process_with_compact_style(tokens) - process_with_space_style(tokens) tokens.each_cons(2) do |token1, token2| - each_extaneus_space_between_right_parents(token1, token2) do |range| - add_offense(range) do |corrector| - corrector.remove(range) - end + 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) @@ -115,35 +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 each_extaneus_space_between_right_parents(token1, token2) - return unless right_parens?(token1, token2) - + def correct_extaneus_space_between_consecutive_parens(token1, token2) return if range_between(token1.end_pos, token2.begin_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_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) - return if style == :compact && token1.right_parens? && token2.right_parens? + 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 - 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) + add_offense(range, message: MSG_SPACE) do |corrector| + corrector.insert_before(range, ' ') end end @@ -155,6 +154,10 @@ 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 diff --git a/spec/rubocop/cop/layout/space_inside_parens_spec.rb b/spec/rubocop/cop/layout/space_inside_parens_spec.rb index 00f3dbb9f18..2190da6024d 100644 --- a/spec/rubocop/cop/layout/space_inside_parens_spec.rb +++ b/spec/rubocop/cop/layout/space_inside_parens_spec.rb @@ -240,6 +240,12 @@ 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 )) @@ -247,6 +253,12 @@ 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 ))) @@ -256,6 +268,11 @@ 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 ) @@ -263,6 +280,8 @@ RUBY expect_correction(<<~RUBY) + f(( 3 + 5 ) * x ) + g((( 3 + 5 ) * f ) ** x, 5 ) f( x( 3 )) g( f( x( 3 )), 5 ) RUBY @@ -270,6 +289,10 @@ 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. @@ -277,6 +300,7 @@ RUBY expect_correction(<<~RUBY) + g((( 3 + 5 ) * f ) ** x, 5 ) ( g( f( x( 3 )), 5 )) RUBY end From 97b4bedd7a3547d1f98987f9d350b94bebd36573 Mon Sep 17 00:00:00 2001 From: Itay Grudev Date: Mon, 27 Sep 2021 12:44:01 +0300 Subject: [PATCH 3/3] Corrected Layout/SpaceInsideParens compact style documentation --- lib/rubocop/cop/layout/space_inside_parens.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/layout/space_inside_parens.rb b/lib/rubocop/cop/layout/space_inside_parens.rb index 5f02d517d55..bcde717e469 100644 --- a/lib/rubocop/cop/layout/space_inside_parens.rb +++ b/lib/rubocop/cop/layout/space_inside_parens.rb @@ -35,7 +35,7 @@ module Layout # # @example EnforcedStyle: compact # # The `compact` style enforces that parentheses have a space at the - # # beginning with the exception that successive right parentheses are allowed. + # # beginning with the exception that successive parentheses are allowed. # # Note: Empty parentheses should not have spaces. # # # bad