From 7dd734fe332e87dbf91a0471211412375ff05d71 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Fri, 4 Jun 2021 20:44:15 +0900 Subject: [PATCH] Support pattern matching for `Style/IdenticalConditionalBranches` cop This PR supports Ruby 2.7's pattern matching syntax for `Style/IdenticalConditionalBranches` cop. 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. It may also be suitable for the cop's role of detecting duplicated conditional branches. --- ...or_style_identical_conditional_branches.md | 1 + .../style/identical_conditional_branches.rb | 29 ++++ .../identical_conditional_branches_spec.rb | 138 ++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 changelog/new_support_pattern_matching_for_style_identical_conditional_branches.md diff --git a/changelog/new_support_pattern_matching_for_style_identical_conditional_branches.md b/changelog/new_support_pattern_matching_for_style_identical_conditional_branches.md new file mode 100644 index 00000000000..b7b712ff156 --- /dev/null +++ b/changelog/new_support_pattern_matching_for_style_identical_conditional_branches.md @@ -0,0 +1 @@ +* [#9855](https://github.com/rubocop/rubocop/pull/9855): Support Ruby 2.7's pattern matching for `Style/IdenticalConditionalBranches` cop. ([@koic][]) diff --git a/lib/rubocop/cop/style/identical_conditional_branches.rb b/lib/rubocop/cop/style/identical_conditional_branches.rb index 5961764c475..dfdd226ad2f 100644 --- a/lib/rubocop/cop/style/identical_conditional_branches.rb +++ b/lib/rubocop/cop/style/identical_conditional_branches.rb @@ -67,6 +67,28 @@ module Style # do_x # do_z # end + # + # # bad + # case foo + # in 1 + # do_x + # in 2 + # do_x + # else + # do_x + # end + # + # # good + # case foo + # in 1 + # do_x + # do_y + # in 2 + # # nothing + # else + # do_x + # do_z + # end class IdenticalConditionalBranches < Base include RangeHelp extend AutoCorrector @@ -87,6 +109,13 @@ def on_case(node) check_branches(node, branches) end + def on_case_match(node) + return unless node.else? && node.else_branch + + branches = node.in_pattern_branches.map(&:body).push(node.else_branch) + check_branches(node, branches) + end + private def check_branches(node, branches) diff --git a/spec/rubocop/cop/style/identical_conditional_branches_spec.rb b/spec/rubocop/cop/style/identical_conditional_branches_spec.rb index b5be664900c..61caf99e867 100644 --- a/spec/rubocop/cop/style/identical_conditional_branches_spec.rb +++ b/spec/rubocop/cop/style/identical_conditional_branches_spec.rb @@ -233,6 +233,144 @@ end end + context 'when using pattern matching', :ruby27 do + context 'on case-match with identical bodies' do + it 'registers an offense and corrects' do + expect_offense(<<~RUBY) + case something + in :a + do_x + ^^^^ Move `do_x` out of the conditional. + in :b + do_x + ^^^^ Move `do_x` out of the conditional. + else + do_x + ^^^^ Move `do_x` out of the conditional. + end + RUBY + + expect_correction(<<~RUBY) + case something + in :a + in :b + else + end + do_x + RUBY + end + end + + context 'when one of the case-match branches is empty' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + case value + in cond1 + else + if cond2 + else + end + end + RUBY + end + end + + context 'on case-match with identical trailing lines' do + it 'registers and corrects an offense' do + expect_offense(<<~RUBY) + case something + in :a + x1 + do_x + ^^^^ Move `do_x` out of the conditional. + in :b + x2 + do_x + ^^^^ Move `do_x` out of the conditional. + else + x3 + do_x + ^^^^ Move `do_x` out of the conditional. + end + RUBY + + expect_correction(<<~RUBY) + case something + in :a + x1 + in :b + x2 + else + x3 + end + do_x + RUBY + end + end + + context 'on case-match with identical leading lines' do + it 'registers and corrects an offense' do + expect_offense(<<~RUBY) + case something + in :a + do_x + ^^^^ Move `do_x` out of the conditional. + x1 + in :b + do_x + ^^^^ Move `do_x` out of the conditional. + x2 + else + do_x + ^^^^ Move `do_x` out of the conditional. + x3 + end + RUBY + + expect_correction(<<~RUBY) + do_x + case something + in :a + x1 + in :b + x2 + else + x3 + end + RUBY + end + end + + context 'on case-match without else' do + it "doesn't register an offense" do + expect_no_offenses(<<~RUBY) + case something + in :a + do_x + in :b + do_x + end + RUBY + end + end + + context 'on case-match with empty when' do + it "doesn't register an offense" do + expect_no_offenses(<<~RUBY) + case something + in :a + do_x + do_y + in :b + else + do_x + do_z + end + RUBY + end + end + end + context 'with empty brace' do it 'does not raise any error' do expect_no_offenses(<<~RUBY)