Skip to content

Commit

Permalink
[Fix rubocop#8354] Fix Style/CaseLikeIf to handle regexp named captures
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmytro Savochkin committed Oct 2, 2020
1 parent dab9cde commit 7512fa6
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@
* [#8801](https://github.com/rubocop-hq/rubocop/issues/8801): Fix `Layout/SpaceAroundEqualsInParameterDefault` only registered once in a line. ([@rdunlop][])
* [#8514](https://github.com/rubocop-hq/rubocop/issues/8514): Correct multiple `Style/MethodDefParentheses` per file. ([@rdunlop][])
* [#8825](https://github.com/rubocop-hq/rubocop/issues/8825): Fix crash in `Style/ExplicitBlockArgument` when code is called outside of a method. ([@ghiculescu][])
* [#8354](https://github.com/rubocop-hq/rubocop/issues/8354): Detect regexp named captures in `Style/CaseLikeIf` cop. ([@dsavochkin][])

### Changes

Expand Down
24 changes: 20 additions & 4 deletions lib/rubocop/cop/style/case_like_if.rb
Expand Up @@ -42,16 +42,16 @@ def on_if(node)
convertible = true

branch_conditions(node).each do |branch_condition|
return false if regexp_with_working_captures?(branch_condition)

conditions << []
convertible = collect_conditions(branch_condition, target, conditions.last)
break unless convertible
end

return unless convertible

add_offense(node) do |corrector|
autocorrect(corrector, node)
end
add_offense(node) { |corrector| autocorrect(corrector, node) }
end

private
Expand Down Expand Up @@ -107,7 +107,7 @@ def find_target_in_send_node(node)
when :include?, :cover?
receiver = deparenthesize(node.receiver)
node.arguments.first if receiver.range_type?
when :match, :match?
when :match, :match?, :=~
find_target_in_match_node(node)
end
end
Expand Down Expand Up @@ -230,6 +230,22 @@ def correction_range(node)
def indent(node)
' ' * node.loc.column
end

# Named captures work with `=~` (if regexp is on lhs) and with `match` (both sides)
def regexp_with_working_captures?(node)
case node.type
when :match_with_lvasgn
lhs, _rhs = *node
node.loc.selector.source == '=~' && regexp_with_named_captures?(lhs)
when :send
lhs, method, rhs = *node
method == :match && [lhs, rhs].any? { |n| regexp_with_named_captures?(n) }
end
end

def regexp_with_named_captures?(node)
node.regexp_type? && node.each_capture(named: true).count.positive?
end
end
end
end
Expand Down
74 changes: 74 additions & 0 deletions spec/rubocop/cop/style/case_like_if_spec.rb
Expand Up @@ -344,4 +344,78 @@
end
RUBY
end

context 'when using regexp with named captures' do
it 'does not register an offense with =~ and regexp on lhs' do
expect_no_offenses(<<~RUBY)
if /(?<name>.*)/ =~ foo
elsif foo == 123
end
RUBY
end

it 'registers and corrects an offense with =~ and regexp on rhs' do
expect_offense(<<~RUBY)
if foo =~ /(?<name>.*)/
^^^^^^^^^^^^^^^^^^^^^^^ Convert `if-elsif` to `case-when`.
elsif foo == 123
end
RUBY

expect_correction(<<~RUBY)
case foo
when /(?<name>.*)/
when 123
end
RUBY
end

it 'does not register an offense with match and regexp on lhs' do
expect_no_offenses(<<~RUBY)
if /(?<name>.*)/.match(foo)
elsif foo == 123
end
RUBY
end

it 'does not register an offense with match and regexp on rhs' do
expect_no_offenses(<<~RUBY)
if foo.match(/(?<name>.*)/)
elsif foo == 123
end
RUBY
end

it 'registers and corrects an offense with match? and regexp on lhs' do
expect_offense(<<~RUBY)
if /(?<name>.*)/.match?(foo)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Convert `if-elsif` to `case-when`.
elsif foo == 123
end
RUBY

expect_correction(<<~RUBY)
case foo
when /(?<name>.*)/
when 123
end
RUBY
end

it 'registers and corrects an offense with match? and regexp on rhs' do
expect_offense(<<~RUBY)
if foo.match?(/(?<name>.*)/)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Convert `if-elsif` to `case-when`.
elsif foo == 123
end
RUBY

expect_correction(<<~RUBY)
case foo
when /(?<name>.*)/
when 123
end
RUBY
end
end
end

0 comments on commit 7512fa6

Please sign in to comment.