class ChefAPI::Resource::CollectionProxy

Attributes

collection[R]
endpoint[R]
klass[R]
parent[R]
prefix[R]

Public Class Methods

new(parent, klass, endpoint, prefix = {}) click to toggle source

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

all() click to toggle source

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
count() click to toggle source

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
Also aliased as: size
each(&block) click to toggle source

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
exists?(id) click to toggle source

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(id) click to toggle source

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
inspect() click to toggle source

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
reload!() click to toggle source

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
size()
Alias for: count
to_s() click to toggle source

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

cache() click to toggle source

The cache…

@return [Hash]

# File lib/chef-api/resources/collection_proxy.rb, line 215
def cache
  @cache ||= {}
end
cached(key, &block) click to toggle source

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
get(id) click to toggle source

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
load_collection() click to toggle source

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