class ChefAPI::Resource::CollectionProxy
Attributes
Public Class Methods
Create a new collection proxy from the given parent class and collection information. The collection proxy aims to make working with nested resource collections a bit easier. The proxy waits until non-existing data is requested before making another HTTP request. In this way, it helps reduce bandwidth and API requets.
Additionally, the collection proxy caches the results of an object request in memory by id
, so additional requests for the same object will hit the cache, again reducing HTTP requests.
@param [Resource::Base] parent
the parent resource that created the collection
@param [Class] klass
the class the resulting objects should be
@param [String] endpoint
the relative path for the RESTful endpoint
@return [CollectionProxy]
# File lib/chef-api/resources/collection_proxy.rb, line 25 def initialize(parent, klass, endpoint, prefix = {}) @parent = parent @klass = klass @endpoint = "#{parent.resource_path}/#{endpoint}" @prefix = prefix @collection = load_collection end
Public Instance Methods
Get the full list of all entries in the collection. This method is incredibly expensive and should only be used when you absolutely need all resources. If you need a specific resource, you should use an iterator such as select
or find
instead, since it will minimize HTTP requests. Once all the objects are requested, they are cached, reducing the number of HTTP requests.
@return [Array<Resource::Base>]
# File lib/chef-api/resources/collection_proxy.rb, line 93 def all entries end
The total number of items in this collection. This method does not make an API request, but rather counts the number of keys in the given collection.
# File lib/chef-api/resources/collection_proxy.rb, line 113 def count collection.length end
The custom iterator for looping over each object in this collection. For more information, please see the Enumerator
module in Ruby core.
# File lib/chef-api/resources/collection_proxy.rb, line 101 def each(&block) collection.each do |id, url| object = cached(id) { klass.from_url(url, prefix) } block.call(object) if block end end
Determine if the resource with the given id exists on the remote Chef Server. This method does not actually query the Chef Server, but rather delegates to the cached collection. To guarantee the most fresh set of data, you should call reload!
before exists?
to ensure you have the most up-to-date collection of resources.
@param [String, Symbol] id
the unique id of the resource to find.
@return [Boolean]
true if the resource exists, false otherwise
# File lib/chef-api/resources/collection_proxy.rb, line 79 def exists?(id) collection.key?(id.to_s) end
Fetch a specific resource in the collection by id.
@example Fetch a resource
Bacon.first.items.fetch('crispy')
@param [String, Symbol] id
the id of the resource to fetch
@return [Resource::Base, nil]
the fetched class, or nil if it does not exists
# File lib/chef-api/resources/collection_proxy.rb, line 60 def fetch(id) return nil unless exists?(id) cached(id) { klass.from_url(get(id), prefix) } end
The detailed string representation of this collection proxy.
@return [String]
# File lib/chef-api/resources/collection_proxy.rb, line 132 def inspect objects = collection .map { |id, _| cached(id) || klass.new(klass.schema.primary_key => id) } .map(&:to_s) "#<#{self.class.name} [#{objects.join(", ")}]>" end
Force a reload of this collection proxy and all its elements. This is useful if you think additional items have been added to the remote collection and need access to them locally. This will also clear any existing cached responses, so use with caution.
@return [self]
# File lib/chef-api/resources/collection_proxy.rb, line 41 def reload! cache.clear @collection = load_collection self end
The string representation of this collection proxy.
@return [String]
# File lib/chef-api/resources/collection_proxy.rb, line 123 def to_s "#<#{self.class.name}>" end
Private Instance Methods
The cache…
@return [Hash]
# File lib/chef-api/resources/collection_proxy.rb, line 215 def cache @cache ||= {} end
Retrieve a cached value. This method helps significantly reduce the number of HTTP requests made against the remote server.
@param [String, Symbol] key
the cache key (typically the +name+ of the resource)
@param [Proc] block
the block to evaluate to set the value if it doesn't exist
@return [Object]
the value at the cache
# File lib/chef-api/resources/collection_proxy.rb, line 206 def cached(key, &block) cache[key.to_sym] ||= block ? block.call : nil end
Retrieve a specific item in the collection. Note, this will always return the original raw record (with the key => URL pairing), not a cached resource.
@param [String, Symbol] id
the id of the resource to fetch
@return [String, nil]
the URL to retrieve the item in the collection, or nil if it does not exist
# File lib/chef-api/resources/collection_proxy.rb, line 231 def get(id) collection[id.to_s] end
Fetch the object collection from the Chef Server. Since the Chef Server's API is completely insane and all over the place, it might return a Hash where the key is the id of the resource and the value is the url for that item on the Chef Server:
{ "key" => "url" }
Or if the Chef Server's fancy is tickled, it might just return an array of the list of items:
["item_1", "item_2"]
Or if the Chef Server is feeling especially magical, it might return the actual objects, but prefixed with the JSON id:
[{"organization" => {"_id" => "..."}}, {"organization" => {...}}]
So, this method attempts to intelligent handle these use cases. That being said, I can almost guarantee that someone is going to do some crazy strange edge case with this library and hit a bug here, so it will likely be changed in the future. For now, it “works on my machine”.
@return [Hash]
# File lib/chef-api/resources/collection_proxy.rb, line 173 def load_collection case response = Resource::Base.connection.get(endpoint) when Array if response.first.is_a?(Hash) key = klass.schema.primary_key.to_s {}.tap do |hash| response.each do |results| results.each do |_, info| hash[key] = klass.resource_path(info[key]) end end end else Hash[*response.map { |item| [item, klass.resource_path(item)] }.flatten] end when Hash response end end