Skip to content

Commit

Permalink
Make Style/MapToHash aware of safe navigation operator
Browse files Browse the repository at this point in the history
Follow up rubocop#12407 (comment).

This PR makes `Style/MapToHash` aware of safe navigation operator.
  • Loading branch information
koic committed Nov 24, 2023
1 parent 5c81b56 commit f4e4668
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#12408](https://github.com/rubocop/rubocop/pull/12408): Make `Style/MapToHash` aware of safe navigation operator. ([@koic][])
9 changes: 5 additions & 4 deletions lib/rubocop/cop/style/map_to_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,29 @@ class MapToHash < Base

minimum_target_ruby_version 2.6

MSG = 'Pass a block to `to_h` instead of calling `%<method>s.to_h`.'
MSG = 'Pass a block to `to_h` instead of calling `%<method>s%<dot>sto_h`.'
RESTRICT_ON_SEND = %i[to_h].freeze

# @!method map_to_h?(node)
def_node_matcher :map_to_h?, <<~PATTERN
{
$(send ({block numblock} $(send _ {:map :collect}) ...) :to_h)
$(send $(send _ {:map :collect} (block_pass sym)) :to_h)
$(call ({block numblock} $(call _ {:map :collect}) ...) :to_h)
$(call $(call _ {:map :collect} (block_pass sym)) :to_h)
}
PATTERN

def on_send(node)
return unless (to_h_node, map_node = map_to_h?(node))

message = format(MSG, method: map_node.loc.selector.source)
message = format(MSG, method: map_node.loc.selector.source, dot: map_node.loc.dot.source)
add_offense(map_node.loc.selector, message: message) do |corrector|
# If the `to_h` call already has a block, do not autocorrect.
next if to_h_node.block_node

autocorrect(corrector, to_h_node, map_node)
end
end
alias on_csend on_send

private

Expand Down
39 changes: 39 additions & 0 deletions spec/rubocop/cop/style/map_to_hash_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@
end
end

context "for `#{method}&.to_h` with block arity 1" do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
foo&.#{method} { |x| [x, x * 2] }&.to_h
^{method} Pass a block to `to_h` instead of calling `#{method}&.to_h`.
RUBY

expect_correction(<<~RUBY)
foo&.to_h { |x| [x, x * 2] }
RUBY
end
end

context "for `#{method}&.to_h` with block arity 2" do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
foo&.#{method} { |x, y| [x.to_s, y.to_i] }&.to_h
^{method} Pass a block to `to_h` instead of calling `#{method}&.to_h`.
RUBY

expect_correction(<<~RUBY)
foo&.to_h { |x, y| [x.to_s, y.to_i] }
RUBY
end
end

context 'when using numbered parameters', :ruby27 do
context "for `#{method}.to_h` with block arity 1" do
it 'registers an offense and corrects' do
Expand Down Expand Up @@ -70,6 +96,19 @@
end
end

context "for `#{method}&.to_h` with symbol proc" do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
foo&.#{method}(&:do_something)&.to_h
^{method} Pass a block to `to_h` instead of calling `#{method}&.to_h`.
RUBY

expect_correction(<<~RUBY)
foo&.to_h(&:do_something)
RUBY
end
end

context 'when the receiver is an array' do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
Expand Down

0 comments on commit f4e4668

Please sign in to comment.