lib/active_admin/resource_collection.rb
# frozen_string_literal: true
module ActiveAdmin
# This is a container for resources, which acts much like a Hash.
# It's assumed that an added resource responds to `resource_name`.
class ResourceCollection
include Enumerable
extend Forwardable
def_delegators :@collection, :empty?, :has_key?, :keys, :values, :size
def initialize
@collection = {}
end
def add(resource)
if match = @collection[resource.resource_name]
raise_if_mismatched! match, resource
match
else
@collection[resource.resource_name] = resource
end
end
# Changes `each` to pass in the value, instead of both the key and value.
def each(&block)
values.each &block
end
def [](obj)
@collection[obj] || find_resource(obj)
end
private
# Finds a resource based on the resource name, resource class, or base class.
def find_resource(obj)
resources.detect do |r|
r.resource_name.to_s == obj.to_s
end || resources.detect do |r|
r.resource_class.to_s == obj.to_s
end ||
if obj.respond_to? :base_class
resources.detect { |r| r.resource_class.to_s == obj.base_class.to_s }
end
end
def resources
select { |r| r.class <= Resource } # can otherwise be a Page
end
def raise_if_mismatched!(existing, given)
if existing.class != given.class
raise IncorrectClass.new existing, given
elsif given.class <= Resource && existing.resource_class != given.resource_class
raise ConfigMismatch.new existing, given
end
end
class IncorrectClass < StandardError
def initialize(existing, given)
super "You're trying to register #{given.resource_name} which is a #{given.class}, " +
"but #{existing.resource_name}, a #{existing.class} has already claimed that name."
end
end
class ConfigMismatch < StandardError
def initialize(existing, given)
super "You're trying to register #{given.resource_class} as #{given.resource_name}, " +
"but the existing #{existing.class} config was built for #{existing.resource_class}!"
end
end
end
end