Skip to content

Commit

Permalink
[Fix rubocop#12444] Fix false positive for Style/HashEachMethods
Browse files Browse the repository at this point in the history
Fixes rubocop#12444.

This PR fixes false positive for `Style/HashEachMethods`
when receiver literal is not a hash literal.
  • Loading branch information
koic committed Dec 10, 2023
1 parent 9879858 commit 23a9f6f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#12444](https://github.com/rubocop/rubocop/issues/12444): Fix false positive for `Style/HashEachMethods` when receiver literal is not a hash literal. ([@koic][])
17 changes: 17 additions & 0 deletions lib/rubocop/cop/style/hash_each_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class HashEachMethods < Base

# rubocop:disable Metrics/AbcSize
def on_block(node)
return unless handleable?(node)

kv_each(node) do |target, method|
register_kv_offense(target, method) and return
end
Expand Down Expand Up @@ -88,6 +90,12 @@ def on_block_pass(node)

private

def handleable?(node)
return false unless (root_receiver = root_receiver(node))

!root_receiver.literal? || root_receiver.hash_type?
end

def register_kv_offense(target, method)
return unless (parent_receiver = target.receiver.receiver)
return if allowed_receiver?(parent_receiver)
Expand Down Expand Up @@ -135,6 +143,15 @@ def register_kv_with_block_pass_offense(node, target, method)
end
end

def root_receiver(node)
receiver = node.receiver
if receiver&.receiver
root_receiver(receiver)
else
receiver
end
end

def format_message(method_name, current)
format(MSG, prefer: "each_#{method_name[0..-2]}", current: current)
end
Expand Down
17 changes: 17 additions & 0 deletions spec/rubocop/cop/style/hash_each_methods_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,23 @@
RUBY
end

it 'registers an offense and corrects when `{hash: :literal}.keys.each`' do
expect_offense(<<~RUBY)
{hash: :literal}.keys.each { |k| p k }
^^^^^^^^^ Use `each_key` instead of `keys.each`.
RUBY

expect_correction(<<~RUBY)
{hash: :literal}.each_key { |k| p k }
RUBY
end

it 'does not register an offense when `[[1, 2, 3], [4 ,5, 6]].each`' do
expect_no_offenses(<<~RUBY)
[[1, 2, 3], [4, 5, 6]].each { |a, _| p a }
RUBY
end

it 'does not register an offense for foo#each_key' do
expect_no_offenses('foo.each_key { |k| p k }')
end
Expand Down

0 comments on commit 23a9f6f

Please sign in to comment.