From aad52ddce2e09da56461bea7a8366e3b355da80e Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 16 May 2020 11:26:31 +0900 Subject: [PATCH] [Fix #7976] Add ignore options for `Layout/EmptyLinesAroundAttributeAccessor` Fixes #7976 and #7981 This PR adds `AllowAliasSyntax` and `AllowedMethods` options. for `Layout/EmptyLinesAroundAttributeAccessor` cop. Users can configure a behavior for `alias` syntax using `IgnoreAliasSyntax` option. Ignored by default (true). And users can specify ignored methods using `AllowedMethods`. By default, set `alias_method`, `public`, `protected`, and `private` provided by Ruby. `cattr_accessor`, `attribute`, other methods provided by Rails (and other gems) can be set by user applications or RuboCop Rails gem. --- CHANGELOG.md | 1 + config/default.yml | 7 ++ .../empty_lines_around_attribute_accessor.rb | 60 ++++++++++++++- manual/cops_layout.md | 51 ++++++++++++- ...ty_lines_around_attribute_accessor_spec.rb | 76 ++++++++++++++++++- 5 files changed, 186 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01a4e287fde..aeb418f6f5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/config/default.yml b/config/default.yml index cfc3bb8a194..f5d292cccf2 100644 --- a/config/default.yml +++ b/config/default.yml @@ -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." diff --git a/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb b/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb index 2e4884d849e..dce9cc2b096 100644 --- a/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +++ b/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/manual/cops_layout.md b/manual/cops_layout.md index f328cb9c9f0..b283d09157f 100644 --- a/manual/cops_layout.md +++ b/manual/cops_layout.md @@ -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 @@ -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 diff --git a/spec/rubocop/cop/layout/empty_lines_around_attribute_accessor_spec.rb b/spec/rubocop/cop/layout/empty_lines_around_attribute_accessor_spec.rb index 106821be152..3bd47d4a929 100644 --- a/spec/rubocop/cop/layout/empty_lines_around_attribute_accessor_spec.rb +++ b/spec/rubocop/cop/layout/empty_lines_around_attribute_accessor_spec.rb @@ -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) @@ -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