Skip to content

Commit

Permalink
[Fix rubocop#3019] Add Style/EmptyCaseCondition cop (rubocop#3044)
Browse files Browse the repository at this point in the history
  • Loading branch information
owst authored and Neodelf committed Oct 15, 2016
1 parent 2bb8a64 commit 14b514d
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
* [#3052](https://github.com/bbatsov/rubocop/pull/3052): `Style/MultilineHashBraceLayout` enforced style supports `same_line` option. ([@panthomakos][])
* [#3052](https://github.com/bbatsov/rubocop/pull/3052): `Style/MultilineMethodCallBraceLayout` enforced style supports `same_line` option. ([@panthomakos][])
* [#3052](https://github.com/bbatsov/rubocop/pull/3052): `Style/MultilineMethodDefinitionBraceLayout` enforced style supports `same_line` option. ([@panthomakos][])
* [#3019](https://github.com/bbatsov/rubocop/issues/3019): Add new `Style/EmptyCaseCondition` cop. ([@owst][])

### Bug fixes

* [#3032](https://github.com/bbatsov/rubocop/issues/3032): Fix autocorrecting parentheses for predicate methods without space before args. ([@graemeboy][])
* [#3000](https://github.com/bbatsov/rubocop/pull/3000): Fix encoding crash on HTML output. ([@gerrywastaken][])
* [#2983](https://github.com/bbatsov/rubocop/pull/2983): `Style/AlignParameters` message was clarified for `with_fixed_indentation` style. ([@dylanahsmith][])
Expand Down
4 changes: 4 additions & 0 deletions config/enabled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ Style/EmptyElse:
Description: 'Avoid empty else-clauses.'
Enabled: true

Style/EmptyCaseCondition:
Description: 'Avoid empty condition in case statements.'
Enabled: true

Style/EmptyLineBetweenDefs:
Description: 'Use empty lines between defs.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#empty-lines-between-methods'
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
require 'rubocop/cop/style/double_negation'
require 'rubocop/cop/style/each_with_object'
require 'rubocop/cop/style/else_alignment'
require 'rubocop/cop/style/empty_case_condition'
require 'rubocop/cop/style/empty_else'
require 'rubocop/cop/style/empty_line_between_defs'
require 'rubocop/cop/style/empty_lines'
Expand Down
89 changes: 89 additions & 0 deletions lib/rubocop/cop/style/empty_case_condition.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# encoding: utf-8
# frozen_string_literal: true

module RuboCop
module Cop
module Style
# This cop checks for case statements with an empty condition.
#
# @example
#
# # bad:
# case
# when x == 0
# puts 'x is 0'
# when y == 0
# puts 'y is 0'
# else
# puts 'neither is 0'
# end
#
# # good:
# if x == 0
# puts 'x is 0'
# elsif y == 0
# puts 'y is 0'
# else
# puts 'neither is 0'
# end
#
# # good: (the case condition node is not empty)
# case n
# when 0
# puts 'zero'
# when 1
# puts 'one'
# else
# puts 'more'
# end
class EmptyCaseCondition < Cop
MSG = 'Do not use empty `case` condition, instead use an `if` '\
'expression.'.freeze

def on_case(case_node)
condition_node = case_node.children.first

add_offense(case_node, :keyword, MSG) if condition_node.nil?
end

private

def autocorrect(case_node)
lambda do |corrector|
_cond_node, *when_nodes, _else_node = *case_node

correct_case_whens(corrector, case_node, when_nodes)

correct_multiple_alternative_whens(corrector, when_nodes)
end
end

def correct_case_whens(corrector, case_node, when_nodes)
case_to_first_when =
case_node.loc.keyword.join(when_nodes.first.loc.keyword)

corrector.replace(case_to_first_when, 'if')

when_nodes.drop(1).each do |when_node|
corrector.replace(when_node.loc.keyword, 'elsif')
end
end

# Since an if condition containing commas is not syntactically valid, we
# correct `when x,y` to `if [x,y].any?`.
def correct_multiple_alternative_whens(corrector, when_nodes)
when_nodes.each do |when_node|
children = when_node.children

# In `when a; r` we have two children: [a, r].
# In `when a, b, c; r` we have 4.
next unless children.count > 2

corrector.insert_before(children.first.loc.expression, '[')
corrector.insert_after(children[-2].loc.expression, '].any?')
end
end
end
end
end
end
132 changes: 132 additions & 0 deletions spec/rubocop/cop/style/empty_case_condition_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# encoding: utf-8
# frozen_string_literal: true

require 'spec_helper'

describe RuboCop::Cop::Style::EmptyCaseCondition do
subject(:cop) { described_class.new }

shared_examples 'detect/correct empty case, accept non-empty case' do
it 'registers an offense' do
inspect_source(cop, source)
expect(cop.messages).to eq [described_class::MSG]
end

it 'correctly autocorrects' do
expect(autocorrect_source(cop, source)).to eq corrected_source.join("\n")
end

let(:source_with_case) { source.map { |s| s.gsub(/case/, 'case :a') } }

it 'accepts the source with case' do
inspect_source(cop, source_with_case)
expect(cop.messages).to be_empty
end
end

context 'given a case statement with an empty case' do
context 'with multiple when branches and an else' do
let(:source) do
['case',
'when 1 == 2',
' foo',
'when 1 == 1',
' bar',
'else',
' baz',
'end']
end
let(:corrected_source) do
['if 1 == 2',
' foo',
'elsif 1 == 1',
' bar',
'else',
' baz',
'end']
end

it_behaves_like 'detect/correct empty case, accept non-empty case'
end

context 'with multiple when branches and no else' do
let(:source) do
['case',
'when 1 == 2',
' foo',
'when 1 == 1',
' bar',
'end']
end
let(:corrected_source) do
['if 1 == 2',
' foo',
'elsif 1 == 1',
' bar',
'end']
end

it_behaves_like 'detect/correct empty case, accept non-empty case'
end

context 'with a single when branch and an else' do
let(:source) do
['case',
'when 1 == 2',
' foo',
'else',
' bar',
'end']
end
let(:corrected_source) do
['if 1 == 2',
' foo',
'else',
' bar',
'end']
end

it_behaves_like 'detect/correct empty case, accept non-empty case'
end

context 'with a single when branch and no else' do
let(:source) do
['case',
'when 1 == 2',
' foo',
'end']
end
let(:corrected_source) do
['if 1 == 2',
' foo',
'end']
end

it_behaves_like 'detect/correct empty case, accept non-empty case'
end

context 'with a when branch including comma-delimited alternatives' do
let(:source) do
['case',
'when false',
' foo',
'when nil, false, 1',
' bar',
'when false, 1',
' baz',
'end']
end
let(:corrected_source) do
['if false',
' foo',
'elsif [nil, false, 1].any?',
' bar',
'elsif [false, 1].any?',
' baz',
'end']
end

it_behaves_like 'detect/correct empty case, accept non-empty case'
end
end
end

0 comments on commit 14b514d

Please sign in to comment.