123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Performance::CollectionLiteralInLoop

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

Overview

Identifies places where Array and Hash literals are used within loops. It is better to extract them into a local variable or constant to avoid unnecessary allocations on each iteration.

You can set the minimum number of elements to consider an offense with MinSize.

Examples:

# bad
users.select do |user|
  %i[superadmin admin].include?(user.role)
end

# good
admin_roles = %i[superadmin admin]
users.select do |user|
  admin_roles.include?(user.role)
end

# good
ADMIN_ROLES = %i[superadmin admin]
...
users.select do |user|
  ADMIN_ROLES.include?(user.role)
end

Constant Summary

Instance Method Summary

Instance Method Details

#check_literal?(node, method) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 90

def check_literal?(node, method)
  !node.nil? &&
    nonmutable_method_of_array_or_hash?(node, method) &&
    node.children.size >= min_size &&
    node.recursive_basic_literal?
end

#enumerable_method?(method_name) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 128

def enumerable_method?(method_name)
  ENUMERABLE_METHOD_NAMES.include?(method_name)
end

#keyword_loop?(type) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 110

def keyword_loop?(type)
  LOOP_TYPES.include?(type)
end

#literal_class(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 120

def literal_class(node)
  if node.array_type?
    'Array'
  elsif node.hash_type?
    'Hash'
  end
end

#loop?(ancestor, node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 106

def loop?(ancestor, node)
  keyword_loop?(ancestor.type) || kernel_loop?(ancestor) || node_within_enumerable_loop?(node, ancestor)
end

#min_size (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 132

def min_size
  Integer(cop_config['MinSize'] || 1)
end

#node_within_enumerable_loop?(node, ancestor) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 114

def node_within_enumerable_loop?(node, ancestor)
  enumerable_loop?(ancestor) do |receiver|
    receiver != node && !receiver&.descendants&.include?(node)
  end
end

#nonmutable_method_of_array_or_hash?(node, method) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 97

def nonmutable_method_of_array_or_hash?(node, method)
  (node.array_type? && ARRAY_METHODS.include?(method)) ||
    (node.hash_type? && HASH_METHODS.include?(method))
end

#on_send(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 80

def on_send(node)
  receiver, method, = *node.children
  return unless check_literal?(receiver, method) && parent_is_loop?(receiver)

  message = format(MSG, literal_class: literal_class(receiver))
  add_offense(receiver, message: message)
end

#parent_is_loop?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/collection_literal_in_loop.rb', line 102

def parent_is_loop?(node)
  node.each_ancestor.any? { |ancestor| loop?(ancestor, node) }
end