Skip to content

Commit 2a4f895

Browse files
tejasbubanebbatsov
authored andcommitted
[Fix rubocop#9064] Add three new config options for Layout/EmptyLineBetweenDefs cop
* EmptyLineBetweenMethodDefs * EmptyLineBetweenClassDefs * EmptyLineBetweenModuleDefs This cop previous had ability to check for empty lines between method definitions only. This commit allows the cop to check for empty lines between class and module definitions as well. All three configs are enabled by default. Closes rubocop#9064
1 parent 218409d commit 2a4f895

File tree

5 files changed

+204
-7
lines changed

5 files changed

+204
-7
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
### New features
1616

1717
* [#7737](https://github.com/rubocop-hq/rubocop/issues/7737): Add new `Style/RedundantArgument` cop. ([@tejasbubane][])
18+
* [#9064](https://github.com/rubocop-hq/rubocop/issues/9064): Add `EmptyLineBetweenMethodDefs`, `EmptyLineBetweenClassDefs` and `EmptyLineBetweenModuleDefs` config options for `Layout/EmptyLineBetweenDefs` cop. ([@tejasbubane][])
1819

1920
## 1.3.1 (2020-11-16)
2021

config/default.yml

+4
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,10 @@ Layout/EmptyLineBetweenDefs:
463463
StyleGuide: '#empty-lines-between-methods'
464464
Enabled: true
465465
VersionAdded: '0.49'
466+
VersionChanged: <<next>>
467+
EmptyLineBetweenMethodDefs: true
468+
EmptyLineBetweenClassDefs: true
469+
EmptyLineBetweenModuleDefs: true
466470
# If `true`, this parameter means that single line method definitions don't
467471
# need an empty line between them.
468472
AllowAdjacentOneLineDefs: false

lib/rubocop/cop/layout/empty_line_between_defs.rb

+77-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ module Layout
1313
# `AllowAdjacentOneLineDefs` configures whether adjacent
1414
# one-line method definitions are considered an offense.
1515
#
16-
# @example
16+
# @example EmptyLineBetweenMethodDefs: true (default)
17+
# # checks for empty lines between method definitions.
1718
#
1819
# # bad
1920
# def a
@@ -29,11 +30,57 @@ module Layout
2930
#
3031
# def b
3132
# end
33+
#
34+
# @example EmptyLineBetweenClassDefs: true (default)
35+
# # checks for empty lines between class definitions.
36+
#
37+
# # bad
38+
# class A
39+
# end
40+
# class B
41+
# end
42+
# def b
43+
# end
44+
#
45+
# @example
46+
#
47+
# # good
48+
# class A
49+
# end
50+
#
51+
# class B
52+
# end
53+
#
54+
# def b
55+
# end
56+
#
57+
# @example EmptyLineBetweenModuleDefs: true (default)
58+
# # checks for empty lines between module definitions.
59+
#
60+
# # bad
61+
# module A
62+
# end
63+
# module B
64+
# end
65+
# def b
66+
# end
67+
#
68+
# @example
69+
#
70+
# # good
71+
# module A
72+
# end
73+
#
74+
# module B
75+
# end
76+
#
77+
# def b
78+
# end
3279
class EmptyLineBetweenDefs < Base
3380
include RangeHelp
3481
extend AutoCorrector
3582

36-
MSG = 'Use empty lines between method definitions.'
83+
MSG = 'Use empty lines between %<type>s definitions.'
3784

3885
def self.autocorrect_incompatible_with
3986
[Layout::EmptyLines]
@@ -47,7 +94,7 @@ def self.autocorrect_incompatible_with
4794
def on_begin(node)
4895
node.children.each_cons(2) do |prev, n|
4996
nodes = [prev, n]
50-
check_defs(nodes) if nodes.all? { |def_candidate| def_node?(def_candidate) }
97+
check_defs(nodes) if nodes.all? { |def_candidate| candidate?(def_candidate) }
5198
end
5299
end
53100

@@ -57,8 +104,9 @@ def check_defs(nodes)
57104
return if nodes.all?(&:single_line?) &&
58105
cop_config['AllowAdjacentOneLineDefs']
59106

60-
location = nodes.last.loc.keyword.join(nodes.last.loc.name)
61-
add_offense(location) do |corrector|
107+
correction_node = nodes.last
108+
location = correction_node.loc.keyword.join(correction_node.loc.name)
109+
add_offense(location, message: message(correction_node)) do |corrector|
62110
autocorrect(corrector, *nodes)
63111
end
64112
end
@@ -83,10 +131,32 @@ def autocorrect(corrector, prev_def, node)
83131

84132
private
85133

86-
def def_node?(node)
134+
def candidate?(node)
87135
return unless node
88136

89-
node.def_type? || node.defs_type?
137+
method_candidate?(node) || class_candidate?(node) || module_candidate?(node)
138+
end
139+
140+
def method_candidate?(node)
141+
cop_config['EmptyLineBetweenMethodDefs'] && (node.def_type? || node.defs_type?)
142+
end
143+
144+
def class_candidate?(node)
145+
cop_config['EmptyLineBetweenClassDefs'] && node.class_type?
146+
end
147+
148+
def module_candidate?(node)
149+
cop_config['EmptyLineBetweenModuleDefs'] && node.module_type?
150+
end
151+
152+
def message(node)
153+
type = case node.type
154+
when :def, :defs
155+
:method
156+
else
157+
node.type
158+
end
159+
format(MSG, type: type)
90160
end
91161

92162
def multiple_blank_lines_groups?(first_def_node, second_def_node)

lib/rubocop/options.rb

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
module RuboCop
77
class IncorrectCopNameError < StandardError; end
8+
89
class OptionArgumentError < StandardError; end
910

1011
# This class handles command line options.

spec/rubocop/cop/layout/empty_line_between_defs_spec.rb

+121
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
class K
99
def m
1010
end
11+
1112
class J
1213
def n
1314
end
1415
def o
1516
^^^^^ Use empty lines between method definitions.
1617
end
1718
end
19+
1820
# checks something
1921
def p
2022
end
@@ -411,4 +413,123 @@ def o
411413
RUBY
412414
end
413415
end
416+
417+
context 'EmptyLineBetweenClassDefs' do
418+
it 'registers offense when no empty lines between class and method definitions' do
419+
expect_offense(<<~RUBY)
420+
class Foo
421+
end
422+
class Baz
423+
^^^^^^^^^ Use empty lines between class definitions.
424+
end
425+
def example
426+
^^^^^^^^^^^ Use empty lines between method definitions.
427+
end
428+
RUBY
429+
430+
expect_correction(<<~RUBY)
431+
class Foo
432+
end
433+
434+
class Baz
435+
end
436+
437+
def example
438+
end
439+
RUBY
440+
end
441+
442+
context 'when disabled' do
443+
let(:cop_config) { { 'EmptyLineBetweenClassDefs' => false } }
444+
445+
it 'does not register offense' do
446+
expect_no_offenses(<<~RUBY)
447+
class Foo
448+
end
449+
class Baz
450+
end
451+
def example
452+
end
453+
RUBY
454+
end
455+
end
456+
457+
context 'with AllowAdjacentOneLineDefs enabled' do
458+
let(:cop_config) { { 'AllowAdjacentOneLineDefs' => true } }
459+
460+
it 'does not register offense' do
461+
expect_no_offenses(<<~RUBY)
462+
class Foo; end
463+
class Baz; end
464+
RUBY
465+
end
466+
end
467+
end
468+
469+
context 'EmptyLineBetweenModuleDefs' do
470+
it 'registers offense when no empty lines between module and method definitions' do
471+
expect_offense(<<~RUBY)
472+
module Foo
473+
end
474+
module Baz
475+
^^^^^^^^^^ Use empty lines between module definitions.
476+
end
477+
def example
478+
^^^^^^^^^^^ Use empty lines between method definitions.
479+
end
480+
RUBY
481+
482+
expect_correction(<<~RUBY)
483+
module Foo
484+
end
485+
486+
module Baz
487+
end
488+
489+
def example
490+
end
491+
RUBY
492+
end
493+
494+
context 'when disabled' do
495+
let(:cop_config) { { 'EmptyLineBetweenModuleDefs' => false } }
496+
497+
it 'does not register offense' do
498+
expect_no_offenses(<<~RUBY)
499+
module Foo
500+
end
501+
module Baz
502+
end
503+
def example
504+
end
505+
RUBY
506+
end
507+
end
508+
end
509+
510+
context 'when empty lines between classes and modules together' do
511+
it 'registers offense when no empty lines between module and method definitions' do
512+
expect_offense(<<~RUBY)
513+
class Foo
514+
end
515+
module Baz
516+
^^^^^^^^^^ Use empty lines between module definitions.
517+
end
518+
def example
519+
^^^^^^^^^^^ Use empty lines between method definitions.
520+
end
521+
RUBY
522+
523+
expect_correction(<<~RUBY)
524+
class Foo
525+
end
526+
527+
module Baz
528+
end
529+
530+
def example
531+
end
532+
RUBY
533+
end
534+
end
414535
end

0 commit comments

Comments
 (0)