Skip to content

Commit

Permalink
Support Ruby 2.7's pattern matching for Style/ConditionalAssignment
Browse files Browse the repository at this point in the history
This PR supports Ruby 2.7's pattern matching for `Style/ConditionalAssignment`.

This `Style/IdenticalConditionalBranches` cop is detecting for `if` and `case`.
Therefore, I think about detecting `case-match` with the cop instead of a new cop.
  • Loading branch information
koic authored and bbatsov committed Jul 27, 2021
1 parent b5f3438 commit 39fcf1c
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 5 deletions.
@@ -0,0 +1 @@
* [#9948](https://github.com/rubocop/rubocop/pull/9948): Support Ruby 2.7's pattern matching for `Style/ConditionalAssignment` cop. ([@koic][])
24 changes: 19 additions & 5 deletions lib/rubocop/cop/style/conditional_assignment.rb
Expand Up @@ -26,7 +26,7 @@ def expand_elses(branch)
# `when` nodes contain the entire branch including the condition.
# We only need the contents of the branch, not the condition.
def expand_when_branches(when_branches)
when_branches.map { |branch| branch.children[1] }
when_branches.map(&:body)
end

def tail(branch)
Expand Down Expand Up @@ -272,6 +272,16 @@ def on_case(node)
check_node(node, branches)
end

def on_case_match(node)
return unless style == :assign_to_condition
return unless node.else_branch

in_pattern_branches = expand_when_branches(node.in_pattern_branches)
branches = [*in_pattern_branches, node.else_branch]

check_node(node, branches)
end

private

def check_assignment_to_condition(node)
Expand All @@ -297,7 +307,7 @@ def candidate_node?(node)
end

# @!method candidate_condition?(node)
def_node_matcher :candidate_condition?, '[{if case} !#allowed_ternary?]'
def_node_matcher :candidate_condition?, '[{if case case_match} !#allowed_ternary?]'

def allowed_ternary?(assignment)
assignment.if_type? && assignment.ternary? && !include_ternary?
Expand All @@ -319,7 +329,7 @@ def assignment_node(node)
end

def move_assignment_outside_condition(corrector, node)
if node.case_type?
if node.case_type? || node.case_match_type?
CaseCorrector.correct(corrector, self, node)
elsif node.ternary?
TernaryCorrector.correct(corrector, node)
Expand All @@ -333,7 +343,7 @@ def move_assignment_inside_condition(corrector, node)

if ternary_condition?(condition)
TernaryCorrector.move_assignment_inside_condition(corrector, node)
elsif condition.case_type?
elsif condition.case_type? || condition.case_match_type?
CaseCorrector.move_assignment_inside_condition(corrector, node)
elsif condition.if_type?
IfCorrector.move_assignment_inside_condition(corrector, node)
Expand Down Expand Up @@ -631,7 +641,11 @@ def extract_tail_branches(node)
end

def extract_branches(case_node)
when_branches = expand_when_branches(case_node.when_branches)
when_branches = if case_node.case_type?
expand_when_branches(case_node.when_branches)
else
expand_when_branches(case_node.in_pattern_branches)
end

[when_branches, case_node.else_branch]
end
Expand Down
Expand Up @@ -126,6 +126,33 @@
RUBY
end

context '>= Ruby 2.7', :ruby27 do
it 'registers an offense for assigning any variable type to case in' do
expect_offense(<<~RUBY, variable: variable)
%{variable} = case foo
^{variable}^^^^^^^^^^^ Assign variables inside of conditionals
in "a"
1
in "b"
2
else
3
end
RUBY

expect_correction(<<~RUBY)
case foo
in "a"
#{variable} = 1
in "b"
#{variable} = 2
else
#{variable} = 3
end
RUBY
end
end

it 'does not crash for rescue assignment' do
expect_no_offenses(<<~RUBY)
begin
Expand Down
Expand Up @@ -271,6 +271,30 @@
#{indent}end
RUBY
end

context '>= Ruby 2.7', :ruby27 do
it 'corrects comparison methods in case in' do
expect_offense(<<~RUBY)
case foo
^^^^^^^^ Use the return of the conditional for variable assignment and comparison.
in bar
a #{method} b
else
a #{method} d
end
RUBY

indent = ' ' * "a #{method} ".length if indent_end
expect_correction(<<~RUBY)
a #{method} case foo
in bar
b
else
d
#{indent}end
RUBY
end
end
end
end
end
Expand Down

0 comments on commit 39fcf1c

Please sign in to comment.