lib/rubocop/cop/metrics/collection_literal_length.rb
# frozen_string_literal: true
module RuboCop
module Cop
module Metrics
# Checks for literals with extremely many entries. This is indicative of
# configuration or data that may be better extracted somewhere else, like
# a database, fetched from an API, or read from a non-code file (CSV,
# JSON, YAML, etc.).
#
# @example
# # bad
# # Huge Array literal
# [1, 2, '...', 999_999_999]
#
# # bad
# # Huge Hash literal
# { 1 => 1, 2 => 2, '...' => '...', 999_999_999 => 999_999_999}
#
# # bad
# # Huge Set "literal"
# Set[1, 2, '...', 999_999_999]
#
# # good
# # Reasonably sized Array literal
# [1, 2, '...', 10]
#
# # good
# # Reading huge Array from external data source
# # File.readlines('numbers.txt', chomp: true).map!(&:to_i)
#
# # good
# # Reasonably sized Hash literal
# { 1 => 1, 2 => 2, '...' => '...', 10 => 10}
#
# # good
# # Reading huge Hash from external data source
# CSV.foreach('numbers.csv', headers: true).each_with_object({}) do |row, hash|
# hash[row["key"].to_i] = row["value"].to_i
# end
#
# # good
# # Reasonably sized Set "literal"
# Set[1, 2, '...', 10]
#
# # good
# # Reading huge Set from external data source
# SomeFramework.config_for(:something)[:numbers].to_set
#
class CollectionLiteralLength < Base
MSG = 'Avoid hard coding large quantities of data in code. ' \
'Prefer reading the data from an external source.'
RESTRICT_ON_SEND = [:[]].freeze
def on_array(node)
add_offense(node) if node.children.length >= collection_threshold
end
alias on_hash on_array
def on_index(node)
add_offense(node) if node.arguments.length >= collection_threshold
end
def on_send(node)
on_index(node) if node.method?(:[])
end
private
def collection_threshold
cop_config.fetch('LengthThreshold', Float::INFINITY)
end
end
end
end
end