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

[Fix #7976] Add ignore options for Layout/EmptyLinesAroundAttributeAccessor #7982

Merged
Show file tree
Hide file tree
Changes from all 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.md
Expand Up @@ -6,6 +6,7 @@

* [#7735](https://github.com/rubocop-hq/rubocop/issues/7735): `NodePattern` and `AST` classes have been moved to the [`rubocop-ast` gem](https://github.com/rubocop-hq/rubocop-ast). ([@marcandre][])
* [#7950](https://github.com/rubocop-hq/rubocop/pull/7950): Add new `Lint/DeprecatedOpenSSLConstant` cop. ([@bdewater][])
* [#7976](https://github.com/rubocop-hq/rubocop/issues/7976): Add `IgnoreAliasSyntax` and` IgnoredMethods` options for `Layout/EmptyLinesAroundAttributeAccessor`. ([@koic][])

### Bug fixes

Expand Down
7 changes: 7 additions & 0 deletions config/default.yml
Expand Up @@ -468,6 +468,13 @@ Layout/EmptyLinesAroundAttributeAccessor:
StyleGuide: '#empty-lines-around-attribute-accessor'
Enabled: pending
VersionAdded: '0.83'
VersionChanged: '0.84'
AllowAliasSyntax: true
AllowedMethods:
- alias_method
- public
- protected
- private

Layout/EmptyLinesAroundBeginBody:
Description: "Keeps track of empty lines around begin-end bodies."
Expand Down
60 changes: 56 additions & 4 deletions lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb
Expand Up @@ -3,7 +3,9 @@
module RuboCop
module Cop
module Layout
# Checks for a newline after attribute accessor.
# Checks for a newline after an attribute accessor or a group of them.
# `alias` syntax and `alias_method`, `public`, `protected`, and `private` methods are allowed by default.
# These are customizable with `AllowAliasSyntax` and `AllowedMethods` options.
#
# @example
# # bad
Expand All @@ -26,6 +28,38 @@ module Layout
# def do_something
# end
#
# @example AllowAliasSyntax: true (default)
# # good
# attr_accessor :foo
# alias :foo? :foo
#
# def do_something
# end
#
# @example AllowAliasSyntax: false
# # bad
# attr_accessor :foo
# alias :foo? :foo
#
# def do_something
# end
#
# # good
# attr_accessor :foo
#
# alias :foo? :foo
#
# def do_something
# end
#
# @example AllowedMethods: ['private']
# # good
# attr_accessor :foo
# private :foo
#
# def do_something
# end
#
class EmptyLinesAroundAttributeAccessor < Cop
include RangeHelp

Expand All @@ -36,7 +70,7 @@ def on_send(node)
return if next_line_empty?(node.last_line)

next_line_node = next_line_node(node)
return if next_line_node.nil? || attribute_accessor?(next_line_node)
return if next_line_node.nil? || allow_alias?(next_line_node) || attribute_or_allowed_method?(next_line_node)

add_offense(node)
end
Expand All @@ -59,8 +93,26 @@ def next_line_node(node)
node.parent.children[node.sibling_index + 1]
end

def attribute_accessor?(node)
node.send_type? && node.attribute_accessor?
def allow_alias?(node)
allow_alias_syntax? && node.alias_type?
end

def attribute_or_allowed_method?(node)
return false unless node.send_type?

node.attribute_accessor? || allowed_method?(node.method_name)
end

def allow_alias_syntax?
cop_config.fetch('AllowAliasSyntax', true)
end

def allowed_method?(name)
allowed_methods.include?(name.to_s)
end

def allowed_methods
cop_config.fetch('AllowedMethods', [])
end
end
end
Expand Down
51 changes: 49 additions & 2 deletions manual/cops_layout.md
Expand Up @@ -1203,9 +1203,11 @@ some_method(

Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
--- | --- | --- | --- | ---
Pending | Yes | Yes | 0.83 | -
Pending | Yes | Yes | 0.83 | 0.84

Checks for a newline after attribute accessor.
Checks for a newline after an attribute accessor or a group of them.
`alias` syntax and `alias_method`, `public`, `protected`, and `private` methods are allowed by default.
These are customizable with `AllowAliasSyntax` and `AllowedMethods` options.

### Examples

Expand All @@ -1230,6 +1232,51 @@ attr :qux
def do_something
end
```
#### AllowAliasSyntax: true (default)

```ruby
# good
attr_accessor :foo
alias :foo? :foo

def do_something
end
```
#### AllowAliasSyntax: false

```ruby
# bad
attr_accessor :foo
alias :foo? :foo

def do_something
end

# good
attr_accessor :foo

alias :foo? :foo

def do_something
end
```
#### AllowedMethods: ['private']

```ruby
# good
attr_accessor :foo
private :foo

def do_something
end
```

### Configurable attributes

Name | Default value | Configurable values
--- | --- | ---
AllowAliasSyntax | `true` | Boolean
AllowedMethods | `alias_method`, `public`, `protected`, `private` | Array

### References

Expand Down
@@ -1,10 +1,8 @@
# frozen_string_literal: true

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

let(:config) { RuboCop::Config.new }

it 'registers an offense and corrects for code ' \
'that immediately follows accessor' do
expect_offense(<<~RUBY)
Expand Down Expand Up @@ -68,4 +66,76 @@ class Foo
end
RUBY
end

context 'when `AllowAliasSyntax: true`' do
let(:cop_config) do
{ 'AllowAliasSyntax' => true }
end

it 'does not register an offense for code that immediately `alias` syntax after accessor' do
expect_no_offenses(<<~RUBY)
attr_accessor :foo
alias foo? foo

def do_something
end
RUBY
end
end

context 'when `AllowAliasSyntax: false`' do
let(:cop_config) do
{ 'AllowAliasSyntax' => false }
end

it 'registers an offense for code that immediately `alias` syntax after accessor' do
expect_offense(<<~RUBY)
attr_accessor :foo
^^^^^^^^^^^^^^^^^^ Add an empty line after attribute accessor.
alias foo? foo

def do_something
end
RUBY
end
end

context 'when `AllowedMethods: private`' do
let(:cop_config) do
{
'AllowedMethods' => [
'private'
]
}
end

it 'does not register an offense for code that immediately ignored methods after accessor' do
expect_no_offenses(<<~RUBY)
attr_accessor :foo
private :foo

def do_something
end
RUBY
end
end

context 'when `AllowedMethods: []`' do
let(:cop_config) do
{
'AllowedMethods' => []
}
end

it 'registers an offense for code that immediately ignored methods after accessor' do
expect_offense(<<~RUBY)
attr_accessor :foo
^^^^^^^^^^^^^^^^^^ Add an empty line after attribute accessor.
private :foo

def do_something
end
RUBY
end
end
end