Skip to content

Commit

Permalink
[Fix rubocop#7826] Add new Layout/SpaceAroundMethodCall cop
Browse files Browse the repository at this point in the history
  • Loading branch information
Saurabh Maurya committed Apr 13, 2020
1 parent ba598be commit f6c201e
Show file tree
Hide file tree
Showing 9 changed files with 672 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -43,6 +43,7 @@
* [#7816](https://github.com/rubocop-hq/rubocop/pull/7816): Support Ruby 2.7's numbered parameter for `Style/Lambda`. ([@koic][])
* [#7829](https://github.com/rubocop-hq/rubocop/issues/7829): Fix an error for `Style/OneLineConditional` when one of the branches contains `next` keyword. ([@koic][])
* [#7384](https://github.com/rubocop-hq/rubocop/pull/7384): Add new `Style/DisableCopsWithinSourceCodeDirective` cop. ([@egze][])
* [#7826](https://github.com/rubocop-hq/rubocop/issues/7826): Add new `Layout/SpaceAroundMethodCallOperator` cop. ([@saurabhmaurya15][])

### Bug fixes

Expand Down Expand Up @@ -4449,3 +4450,4 @@
[@egze]: https://github.com/egze
[@rafaelfranca]: https://github.com/rafaelfranca
[@knu]: https://github.com/knu
[@saurabhmaurya15]: https://github.com/saurabhmaurya15
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -1088,6 +1088,11 @@ Layout/SpaceAroundKeyword:
Enabled: true
VersionAdded: '0.49'

Layout/SpaceAroundMethodCallOperator:
Description: 'Checks method call operators to not have spaces around them.'
Enabled: pending
VersionAdded: '0.81'

Layout/SpaceAroundOperators:
Description: 'Use a single space around operators.'
StyleGuide: '#spaces-operators'
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -261,6 +261,7 @@
require_relative 'rubocop/cop/layout/space_around_block_parameters'
require_relative 'rubocop/cop/layout/space_around_equals_in_parameter_default'
require_relative 'rubocop/cop/layout/space_around_keyword'
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_comma'
Expand Down
8 changes: 8 additions & 0 deletions lib/rubocop/ast/node/mixin/method_dispatch_node.rb
Expand Up @@ -121,6 +121,14 @@ def double_colon?
loc.respond_to?(:dot) && loc.dot && loc.dot.is?('::')
end

# Checks whether the dispatched method uses a safe navigation operator to
# connect the receiver and the method name.
#
# @return [Boolean] whether the method was called with a connecting dot
def safe_navigation?
loc.respond_to?(:dot) && loc.dot && loc.dot.is?('&.')
end

# Checks whether the *explicit* receiver of this method dispatch is
# `self`.
#
Expand Down
131 changes: 131 additions & 0 deletions lib/rubocop/cop/layout/space_around_method_call_operator.rb
@@ -0,0 +1,131 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Layout
# Checks method call operators to not have spaces around them.
#
# @example
# # bad
# foo. bar
# foo .bar
# foo . bar
# foo. bar .buzz
# foo
# . bar
# . buzz
# foo&. bar
# foo &.bar
# foo &. bar
# foo &. bar&. buzz
# RuboCop:: Cop
# RuboCop:: Cop:: Cop
# :: RuboCop::Cop
#
# # good
# foo.bar
# foo.bar.buzz
# foo
# .bar
# .buzz
# foo&.bar
# foo&.bar&.buzz
# RuboCop::Cop
# RuboCop::Cop::Cop
# ::RuboCop::Cop
#
class SpaceAroundMethodCallOperator < Cop
include SurroundingSpace

MSG = 'Avoid using spaces around a method call operator.'

def on_send(node)
return unless dot_or_safe_navigation_operator?(node)

check_and_add_offense(node)
end

def on_const(node)
return unless node.loc.double_colon

check_and_add_offense(node, false)
end

def autocorrect(node)
operator = operator_token(node)
left = left_token_for_auto_correction(node, operator)
right = right_token_for_auto_correction(operator)

lambda do |corrector|
SpaceCorrector.remove_space(
processed_source, corrector, left, right
)
end
end

alias on_csend on_send

private

def check_and_add_offense(node, add_left_offense = true)
operator = operator_token(node)
left = previous_token(operator)
right = next_token(operator)

if valid_right_token?(right, operator)
no_space_offenses(node, operator, right, MSG)
end
return unless valid_left_token?(left, operator)

no_space_offenses(node, left, operator, MSG) if add_left_offense
end

def operator_token(node)
operator_location =
node.const_type? ? node.loc.double_colon : node.loc.dot

processed_source.find_token do |token|
token.pos == operator_location
end
end

def previous_token(current_token)
index = processed_source.tokens.index(current_token)
index.zero? ? nil : processed_source.tokens[index - 1]
end

def next_token(current_token)
index = processed_source.tokens.index(current_token)
processed_source.tokens[index + 1]
end

def dot_or_safe_navigation_operator?(node)
node.dot? || node.safe_navigation?
end

def valid_left_token?(left, operator)
left && left.line == operator.line
end

def valid_right_token?(right, operator)
right && right.line == operator.line
end

def left_token_for_auto_correction(node, operator)
left_token = previous_token(operator)
return operator if node.const_type?
return left_token if valid_left_token?(left_token, operator)

operator
end

def right_token_for_auto_correction(operator)
right_token = next_token(operator)
return right_token if valid_right_token?(right_token, operator)

operator
end
end
end
end
end
1 change: 1 addition & 0 deletions manual/cops.md
Expand Up @@ -154,6 +154,7 @@ In the following section you find all available cops:
* [Layout/SpaceAroundBlockParameters](cops_layout.md#layoutspacearoundblockparameters)
* [Layout/SpaceAroundEqualsInParameterDefault](cops_layout.md#layoutspacearoundequalsinparameterdefault)
* [Layout/SpaceAroundKeyword](cops_layout.md#layoutspacearoundkeyword)
* [Layout/SpaceAroundMethodCallOperator](cops_layout.md#layoutspacearoundmethodcalloperator)
* [Layout/SpaceAroundOperators](cops_layout.md#layoutspacearoundoperators)
* [Layout/SpaceBeforeBlockBraces](cops_layout.md#layoutspacebeforeblockbraces)
* [Layout/SpaceBeforeComma](cops_layout.md#layoutspacebeforecomma)
Expand Down
40 changes: 40 additions & 0 deletions manual/cops_layout.md
Expand Up @@ -4075,6 +4075,46 @@ end
something = 123 if test
```
## Layout/SpaceAroundMethodCallOperator
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
--- | --- | --- | --- | ---
Pending | Yes | Yes | 0.81 | -
Checks method call operators to not have spaces around them.
### Examples
```ruby
# bad
foo. bar
foo .bar
foo . bar
foo. bar .buzz
foo
. bar
. buzz
foo&. bar
foo &.bar
foo &. bar
foo &. bar&. buzz
RuboCop:: Cop
RuboCop:: Cop:: Cop
:: RuboCop::Cop

# good
foo.bar
foo.bar.buzz
foo
.bar
.buzz
foo&.bar
foo&.bar&.buzz
RuboCop::Cop
RuboCop::Cop::Cop
::RuboCop::Cop
```
## Layout/SpaceAroundOperators
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
Expand Down
2 changes: 2 additions & 0 deletions spec/rubocop/cli/cli_options_spec.rb
Expand Up @@ -364,6 +364,8 @@ class SomeCop < Cop
Enabled: false
Style:
Enabled: false
Layout:
Enabled: false
Style/SomeCop:
Description: Something
Expand Down

0 comments on commit f6c201e

Please sign in to comment.