module ActiveAdmin class ResourceMismatchError < StandardError; end # Holds on to a collection of Resources. Is an Enumerable object # so it has some Array like qualities. # # Adding a resource assumes that the object responds to #resource_key class ResourceCollection include Enumerable def initialize @resource_hash = {} end # Add a new resource to the collection. If the resource_key already # exists, the exiting resource is returned. # # @param [Resource, Page] resource The resource to add to the collection # # @returns [Resource, Page] Either the existing resource or the new one def add(resource) if has_key?(resource.resource_key) existing_resource = find_by_key(resource.resource_key) ensure_resource_classes_match!(existing_resource, resource) existing_resource else @resource_hash[resource.resource_key] = resource end end # @returns [Array] An array of all the resources def resources @resource_hash.values end # For enumerable def each(&block) @resource_hash.values.each(&block) end # @returns [Array] An array of all the keys registered in the collection def keys @resource_hash.keys end # @returns [Boolean] If the key has been registered in the collection def has_key?(resource_key) @resource_hash.has_key?(resource_key) end # Finds a resource by a given key def find_by_key(resource_key) @resource_hash[resource_key] end # Finds a resource based on it's class. Looks up the class Heirarchy if its # a subclass of an Active Record class (ie: implementes base_class) def find_by_resource_class(resource_class) resource_class_name = resource_class.to_s match = resources_with_a_resource_class.find{|r| r.resource_class.to_s == resource_class_name } return match if match if resource_class.respond_to?(:base_class) base_class_name = resource_class.base_class.to_s resources_with_a_resource_class.find{|r| r.resource_class.to_s == base_class_name } else nil end end private def resources_with_a_resource_class select{|resource| resource.respond_to?(:resource_class) } end def ensure_resource_classes_match!(existing_resource, resource) return unless existing_resource.respond_to?(:resource_class) && resource.respond_to?(:resource_class) if existing_resource.resource_class != resource.resource_class raise ActiveAdmin::ResourceMismatchError, "Tried to register #{resource.resource_class} as #{resource.resource_key} but already registered to #{existing_resource.resource_class}" end end end end