123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Performance::InefficientHashSearch

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, AutoCorrector, Base
Instance Chain:
self, Base
Inherits: Base
  • Object
Defined in: lib/rubocop/cop/performance/inefficient_hash_search.rb

Overview

Checks for inefficient searching of keys and values within hashes.

Hash#keys.include? is less efficient than Hash#key? because the former allocates a new array and then performs an O(n) search through that array, while Hash#key? does not allocate any array and performs a faster O(1) search for the key.

Hash#values.include? is less efficient than Hash#value?. While they both perform an O(n) search through all of the values, calling values allocates a new array while using value? does not.

Examples:

# bad
{ a: 1, b: 2 }.keys.include?(:a)
{ a: 1, b: 2 }.keys.include?(:z)
h = { a: 1, b: 2 }; h.keys.include?(100)

# good
{ a: 1, b: 2 }.key?(:a)
{ a: 1, b: 2 }.has_key?(:z)
h = { a: 1, b: 2 }; h.key?(100)

# bad
{ a: 1, b: 2 }.values.include?(2)
{ a: 1, b: 2 }.values.include?('garbage')
h = { a: 1, b: 2 }; h.values.include?(nil)

# good
{ a: 1, b: 2 }.value?(2)
{ a: 1, b: 2 }.has_value?('garbage')
h = { a: 1, b: 2 }; h.value?(nil)

Cop Safety Information:

  • This cop is unsafe because it can’t tell whether the receiver is a hash object.

Constant Summary

Instance Method Summary

Instance Method Details

#correct_argument(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 91

def correct_argument(node)
  node.first_argument.source
end

#correct_dot(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 99

def correct_dot(node)
  node.receiver.loc.dot.source
end

#correct_hash_expression(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 95

def correct_hash_expression(node)
  node.receiver.receiver.source
end

#correct_method(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 75

def correct_method(node)
  case current_method(node)
  when :keys then use_long_method ? 'has_key?' : 'key?'
  when :values then use_long_method ? 'has_value?' : 'value?'
  end
end

#current_method(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 82

def current_method(node)
  node.receiver.method_name
end

#message(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 67

def message(node)
  "Use `##{correct_method(node)}` instead of `##{current_method(node)}.include?`."
end

#on_csend(node)

Alias for #on_send.

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 63

alias on_csend on_send

#on_send(node) Also known as: #on_csend

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 51

def on_send(node)
  inefficient_include?(node) do |receiver|
    return if receiver.nil?

    message = message(node)
    add_offense(node, message: message) do |corrector|
      # Replace `keys.include?` or `values.include?` with the appropriate
      # `key?`/`value?` method.
      corrector.replace(node, replacement(node))
    end
  end
end

#replacement(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 71

def replacement(node)
  "#{correct_hash_expression(node)}#{correct_dot(node)}#{correct_method(node)}(#{correct_argument(node)})"
end

#use_long_method (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/inefficient_hash_search.rb', line 86

def use_long_method
  preferred_config = config.for_all_cops['Style/PreferredHashMethods']
  preferred_config && preferred_config['EnforcedStyle'] == 'long' && preferred_config['Enabled']
end