Class: Rubocop::Cop::Style::HashTransformation

Inherits:
RuboCop::Cop::Base
  • Object
show all
Extended by:
RuboCop::Cop::AutoCorrector
Includes:
RuboCop::Cop::RangeHelp
Defined in:
lib/rubocop/cop/style/hash_transformation.rb

Overview

Identifies places where ‘map { … }.to_h` or `Hash[map { … }]` can be replaced with `to_h { … }`, saving an intermediate array allocation.

Full credit: github.com/eugeneius/rubocop-performance/blob/hash_transformation/lib/rubocop/cop/performance/hash_transformation.rb

Examples:

# bad
hash.map { |k, v| [v.upcase, k.downcase] }.to_h
hash.collect { |k, v| [v.upcase, k.downcase] }.to_h
Hash[hash.map { |k, v| [v.upcase, k.downcase] }]
Hash[hash.collect { |k, v| [v.upcase, k.downcase] }]
array.map { |x| [x, x + 1] }.to_h

# good
hash.to_h { |k, v| [v.upcase, k.downcase] }
array.to_h { |x| [x, x + 1] }

Constant Summary collapse

MSG =
'Use `to_h { ... }` instead of `%<current>s`.'

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rubocop/cop/style/hash_transformation.rb', line 39

def on_send(node)
  to_h_candidate?(node) do |_block, call|
    range = offense_range(node, call)
    message = message(node, call)
    add_offense(range, message: message) do |corrector|
      block, call = to_h_candidate?(node)

      corrector.remove(after_block(node, block))
      corrector.replace(call.loc.selector, 'to_h')
      corrector.remove(before_block(node, block))
    end
  end
end

#to_h_candidate?(node) ⇒ Object



30
31
32
33
34
35
36
37
# File 'lib/rubocop/cop/style/hash_transformation.rb', line 30

def_node_matcher :to_h_candidate?, <<~PATTERN
  {
    [(send
      $(block $(send _ {:map :collect}) ...) :to_h) !block_literal?]
    (send (const nil? :Hash) :[]
      $(block $(send _ {:map :collect}) ...))
  }
PATTERN