Skip to content

Commit

Permalink
Update Style/NilLambda to handle procs as well.
Browse files Browse the repository at this point in the history
  • Loading branch information
dvandersluis committed May 5, 2021
1 parent 5ba77b9 commit f5a571b
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 12 deletions.
@@ -0,0 +1 @@
* [#9776](https://github.com/rubocop/rubocop/pull/9776): Update `Style/NilLambda` to handle procs as well. ([@dvandersluis][])
41 changes: 29 additions & 12 deletions lib/rubocop/cop/style/nil_lambda.rb
Expand Up @@ -3,8 +3,8 @@
module RuboCop
module Cop
module Style
# This cop checks for lambdas that always return nil, which can be replaced
# with an empty lambda instead.
# This cop checks for lambdas and procs that always return nil,
# which can be replaced with an empty lambda or proc instead.
#
# @example
# # bad
Expand All @@ -14,6 +14,12 @@ module Style
# next nil
# end
#
# proc { nil }
#
# Proc.new do
# break nil
# end
#
# # good
# -> {}
#
Expand All @@ -22,31 +28,42 @@ module Style
#
# -> (x) { nil if x }
#
# proc {}
#
# Proc.new { nil if x }
#
class NilLambda < Base
extend AutoCorrector
include RangeHelp

MSG = 'Use an empty lambda instead of always returning nil.'
MSG = 'Use an empty %<type>s instead of always returning nil.'

# @!method nil_return?(node)
def_node_matcher :nil_return?, <<~PATTERN
{ ({return next break} nil) (nil) }
PATTERN

def on_block(node)
return unless node.lambda?
return unless node.lambda? || node.proc?
return unless nil_return?(node.body)

add_offense(node) do |corrector|
range = if node.single_line?
range_with_surrounding_space(range: node.body.loc.expression)
else
range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
end

corrector.remove(range)
message = format(MSG, type: node.lambda? ? 'lambda' : 'proc')
add_offense(node, message: message) do |corrector|
autocorrect(corrector, node)
end
end

private

def autocorrect(corrector, node)
range = if node.single_line?
range_with_surrounding_space(range: node.body.loc.expression)
else
range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
end

corrector.remove(range)
end
end
end
end
Expand Down
198 changes: 198 additions & 0 deletions spec/rubocop/cop/style/nil_lambda_spec.rb
Expand Up @@ -171,4 +171,202 @@
RUBY
end
end

context 'proc' do
it 'registers an offense when returning nil implicitly' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'registers an offense when returning nil with `return`' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
return nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'registers an offense when returning nil with `break`' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
break nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'registers an offense when returning nil with `next`' do
expect_offense(<<~RUBY)
proc do
^^^^^^^ Use an empty proc instead of always returning nil.
next nil
end
RUBY

expect_correction(<<~RUBY)
proc do
end
RUBY
end

it 'does not register an offense when not returning nil' do
expect_no_offenses(<<~RUBY)
proc do
6
end
RUBY
end

it 'does not register an offense when doing more than returning nil' do
expect_no_offenses(<<~RUBY)
proc do |x|
x ? x.method : nil
end
RUBY
end

it 'does not remove block params or change spacing' do
expect_offense(<<~RUBY)
fn = proc do |x|
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
fn = proc do |x|
end
RUBY
end

it 'properly corrects single line' do
expect_offense(<<~RUBY)
proc { nil }
^^^^^^^^^^^^ Use an empty proc instead of always returning nil.
RUBY

expect_correction(<<~RUBY)
proc {}
RUBY
end
end

context 'Proc.new' do
it 'registers an offense when returning nil implicitly' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'registers an offense when returning nil with `return`' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
return nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'registers an offense when returning nil with `break`' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
break nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'registers an offense when returning nil with `next`' do
expect_offense(<<~RUBY)
Proc.new do
^^^^^^^^^^^ Use an empty proc instead of always returning nil.
next nil
end
RUBY

expect_correction(<<~RUBY)
Proc.new do
end
RUBY
end

it 'does not register an offense when not returning nil' do
expect_no_offenses(<<~RUBY)
Proc.new do
6
end
RUBY
end

it 'does not register an offense when doing more than returning nil' do
expect_no_offenses(<<~RUBY)
Proc.new do |x|
x ? x.method : nil
end
RUBY
end

it 'does not remove block params or change spacing' do
expect_offense(<<~RUBY)
fn = Proc.new do |x|
^^^^^^^^^^^^^^^ Use an empty proc instead of always returning nil.
nil
end
RUBY

expect_correction(<<~RUBY)
fn = Proc.new do |x|
end
RUBY
end

it 'properly corrects single line' do
expect_offense(<<~RUBY)
Proc.new { nil }
^^^^^^^^^^^^^^^^ Use an empty proc instead of always returning nil.
RUBY

expect_correction(<<~RUBY)
Proc.new {}
RUBY
end
end
end

0 comments on commit f5a571b

Please sign in to comment.