Skip to content

Commit

Permalink
Update Style/SingleLineMethods to correct to an endless method defi…
Browse files Browse the repository at this point in the history
…nition if they are allowed.
  • Loading branch information
dvandersluis authored and bbatsov committed Jan 7, 2021
1 parent 1063b4e commit 9eb5daf
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#9295](https://github.com/rubocop-hq/rubocop/pull/9295): Update `Style/SingleLineMethods` to correct to an endless method definition if they are allowed. ([@dvandersluis][])
2 changes: 1 addition & 1 deletion config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4382,7 +4382,7 @@ Style/SingleLineMethods:
StyleGuide: '#no-single-line-methods'
Enabled: true
VersionAdded: '0.9'
VersionChanged: '1.7'
VersionChanged: <<next>>
AllowIfMethodIsEmpty: true

Style/SlicingWithRange:
Expand Down
31 changes: 29 additions & 2 deletions lib/rubocop/cop/style/single_line_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ module Style
#
# Endless methods added in Ruby 3.0 are also accepted by this cop.
#
# If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow` or
# `allow_always`, single-line methods will be auto-corrected to endless
# methods if there is only one statement in the body.
#
# @example
# # bad
# def some_method; body end
Expand Down Expand Up @@ -47,6 +51,28 @@ def on_def(node)
private

def autocorrect(corrector, node)
if correct_to_endless?(node.body)
correct_to_endless(corrector, node)
else
correct_to_multiline(corrector, node)
end
end

def allow_empty?
cop_config['AllowIfMethodIsEmpty']
end

def correct_to_endless?(body_node)
endless_method_config = config.for_cop('Style/EndlessMethod')

return false unless endless_method_config['Enabled']
return false if endless_method_config['EnforcedStyle'] == 'disallow'
return false unless body_node

!(body_node.begin_type? || body_node.kwbegin_type?)
end

def correct_to_multiline(corrector, node)
each_part(node.body) do |part|
LineBreakCorrector.break_line_before(
range: part, node: node, corrector: corrector,
Expand All @@ -62,8 +88,9 @@ def autocorrect(corrector, node)
move_comment(node, corrector)
end

def allow_empty?
cop_config['AllowIfMethodIsEmpty']
def correct_to_endless(corrector, node)
replacement = "def #{node.method_name}(#{node.arguments.source}) = #{node.body.source}"
corrector.replace(node, replacement)
end

def each_part(body)
Expand Down
4 changes: 4 additions & 0 deletions spec/rubocop/cli/cli_autocorrect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,10 @@ module B
end

it 'can correct single line methods' do
create_file('.rubocop.yml', <<~YAML)
Style/EndlessMethod:
EnforcedStyle: disallow
YAML
create_file('example.rb', <<~RUBY)
def func1; do_something end # comment
def func2() do_1; do_2; end
Expand Down
86 changes: 85 additions & 1 deletion spec/rubocop/cop/style/single_line_methods_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

let(:config) do
RuboCop::Config.new('Style/SingleLineMethods' => cop_config,
'Layout/IndentationWidth' => { 'Width' => 2 })
'Layout/IndentationWidth' => { 'Width' => 2 },
'Style/EndlessMethod' => { 'Enabled' => false })
end
let(:cop_config) { { 'AllowIfMethodIsEmpty' => true } }

Expand Down Expand Up @@ -157,4 +158,87 @@ def some_method() = x
RUBY
end
end

context 'when `Style/EndlessMethod` is enabled' do
before { config['Style/EndlessMethod'] = { 'Enabled' => true }.merge(endless_method_config) }

shared_examples 'convert to endless method' do
it 'corrects to an endless method definition' do
expect_correction(<<~RUBY.strip, source: 'def some_method; body end')
def some_method() = body
RUBY
end

it 'retains comments' do
source = 'def some_method; body end # comment'
expect_correction(<<~RUBY.strip, source: source)
def some_method() = body # comment
RUBY
end

it 'does not correct to an endless method if the method body contains multiple statements' do
expect_correction(<<~RUBY.strip, source: 'def some_method; foo; bar end')
def some_method;#{trailing_whitespace}
foo;#{trailing_whitespace}
bar#{trailing_whitespace}
end
RUBY
end

context 'with AllowIfMethodIsEmpty: false' do
let(:cop_config) { { 'AllowIfMethodIsEmpty' => false } }

it 'does not turn a method with no body into an endless method' do
expect_correction(<<~RUBY.strip, source: 'def some_method; end')
def some_method;#{trailing_whitespace}
end
RUBY
end
end

context 'with AllowIfMethodIsEmpty: true' do
let(:cop_config) { { 'AllowIfMethodIsEmpty' => true } }

it 'does not correct' do
expect_no_offenses('def some_method; end')
end
end
end

context 'with `disallow` style' do
let(:endless_method_config) { { 'EnforcedStyle' => 'disallow' } }

it 'corrects to an normal method' do
expect_correction(<<~RUBY.strip, source: 'def some_method; body end')
def some_method;#{trailing_whitespace}
body#{trailing_whitespace}
end
RUBY
end
end

context 'with `allow` style' do
let(:endless_method_config) { { 'EnforcedStyle' => 'allow' } }

it_behaves_like 'convert to endless method'
end

context 'with `allow_always` style' do
let(:endless_method_config) { { 'EnforcedStyle' => 'allow_always' } }

it_behaves_like 'convert to endless method'
end
end

context 'when `Style/EndlessMethod` is disabled' do
before { config['Style/EndlessMethod'] = { 'Enabled' => false } }

it 'corrects to an normal method' do
expect_correction(<<~RUBY.strip, source: 'def some_method; body end')
def some_method;#{trailing_whitespace}
body#{trailing_whitespace}
end
RUBY
end
end
end

0 comments on commit 9eb5daf

Please sign in to comment.