class IDRegistry::Registry

A registry object.

Public Instance Methods

add(type_, object_) click to toggle source

Add the given object to the registry. You must specify the type of object, which is used to determine what tuples correspond to it.

# File lib/idregistry/registry.rb, line 260
def add(type_, object_)
  @config.lock

  # Some sanity checks of the arguments.
  if object_.nil?
    raise ObjectKeyError, "Attempt to add a nil object"
  end
  unless @types.has_key?(type_)
    raise ObjectKeyError, "Unrecognized type: #{type_}"
  end

  # Synchronize the actual add to protect against concurrent mutation.
  @mutex.synchronize do
    _internal_add(type_, object_, nil, nil)
  end
  self
end
categories(arg_) click to toggle source

Return all the categories for the given object or tuple.

If you pass an Array, it is interpreted as a tuple. If you pass something other than an Array or a Hash, it is interpreted as an object. Otherwise, you can explicitly specify whether you are passing a tuple or object by using hash named arguments, e.g. :tuple =>, or :object =>.

The return value is a hash. The keys are the category types relevant to this object. The values are the value arrays indicating which category the object falls under for each type.

# File lib/idregistry/registry.rb, line 150
def categories(arg_)
  @config.lock

  objdata_ = _get_objdata(arg_)
  return nil unless objdata_
  hash_ = {}
  objdata_[2].each do |tup_, tupcats_|
    tupcats_.each do |cat_|
      hash_[cat_] = @categories[cat_][1].map{ |elem_| tup_[elem_] }
    end
  end
  hash_
end
clear() click to toggle source

Clear out all cached objects from the registry.

# File lib/idregistry/registry.rb, line 389
def clear
  @mutex.synchronize do
    @tuples.clear
    @objects.clear
    @catdata.clear
  end
  self
end
config(&block_) click to toggle source

Get the configuration for this registry.

You may also configure this registry by providing a block. The configuration object will then be available as a DSL.

# File lib/idregistry/registry.rb, line 68
def config(&block_)
  ::Blockenspiel.invoke(block_, @config) if block_
  @config
end
delete(arg_) click to toggle source

Delete the given object.

If you pass an Array, it is interpreted as a tuple. If you pass something other than an Array or a Hash, it is interpreted as an object. Otherwise, you can explicitly specify whether you are passing a tuple or object by using hash named arguments, e.g. :tuple =>, or :object =>.

# File lib/idregistry/registry.rb, line 288
def delete(arg_)
  @config.lock

  @mutex.synchronize do
    if (objdata_ = _get_objdata(arg_))
      @objects.delete(objdata_[0].object_id)
      objdata_[2].each_key{ |tup_| _remove_tuple(objdata_, tup_) }
    end
  end
  self
end
delete_category(category_type_, *category_spec_) click to toggle source

Delete all objects in a given category, which is specified by the category type and the value array indicating which category of that type.

# File lib/idregistry/registry.rb, line 305
def delete_category(category_type_, *category_spec_)
  @config.lock

  if @categories.include?(category_type_)
    spec_ = category_spec_.size == 1 && category_spec_.first.is_a?(::Array) ? category_spec_.first : category_spec_
    if (tuple_hash_ = (@catdata[category_type_] ||= {})[spec_])
      @mutex.synchronize do
        tuple_hash_.values.each do |objdata_|
          @objects.delete(objdata_[0].object_id)
          objdata_[2].each_key{ |tup_| _remove_tuple(objdata_, tup_) }
        end
      end
    end
  end
  self
end
get(tuple_) click to toggle source

Retrieve the cached object corresponding to the given tuple. Returns nil if the object is not currently cached. Does not attempt to generate the object for you.

# File lib/idregistry/registry.rb, line 100
def get(tuple_)
  objdata_ = @tuples[tuple_]
  objdata_ ? objdata_[0] : nil
end
include?(arg_) click to toggle source

Returns true if the given object or tuple is present.

If you pass an Array, it is interpreted as a tuple. If you pass something other than an Array or a Hash, it is interpreted as an object. Otherwise, you can explicitly specify whether you are passing a tuple or object by using hash named arguments, e.g. :tuple =>, or :object =>.

# File lib/idregistry/registry.rb, line 132
def include?(arg_)
  _get_objdata(arg_) ? true : false
end
lookup(*args_) click to toggle source

Get the object corresponding to the given tuple. If the tuple is not present, the registry tries to generate the object for you. Returns nil if it is unable to do so.

You may pass the tuple as a single array argument, or as a set of arguments.

If the last argument is a hash, it is removed from the tuple and treated as an options hash that may be passed to an object generator block.

# File lib/idregistry/registry.rb, line 204
def lookup(*args_)
  opts_ = args_.last.is_a?(::Hash) ? args_.pop : {}
  tuple_ = args_.size == 1 && args_.first.is_a?(::Array) ? args_.first : args_

  @config.lock

  # Fast-track lookup if it's already there
  if (objdata_ = @tuples[tuple_])
    return objdata_[0]
  end

  # Not there for now. Try to create the object.
  # We want to do this before entering the synchronize block because
  # we don't want callbacks called within the synchronization.
  obj_ = nil
  type_ = nil
  pattern_ = nil
  @patterns.each do |pat_, patdata_|
    if Utils.matches?(pat_, tuple_)
      block_ = patdata_[1]
      obj_ = case block_.arity
        when 0 then block_.call
        when 1 then block_.call(tuple_)
        when 2 then block_.call(tuple_, self)
        else block_.call(tuple_, self, opts_)
      end
      unless obj_.nil?
        pattern_ = pat_
        type_ = patdata_[0]
        break
      end
    end
  end

  if obj_
    # Now attempt to insert the object.
    # This part is synchronized to protect against concurrent mutation.
    # Once in the synchronize block, we also double-check that no other
    # thread added the object in the meantime. If another thread did,
    # we throw away the object we just created, and return the other
    # thread's object instead.
    @mutex.synchronize do
      if (objdata_ = @tuples[tuple_])
        obj_ = objdata_[0]
      else
        _internal_add(type_, obj_, tuple_, pattern_)
      end
    end
  end
  obj_
end
objects_in_category(category_type_, *category_spec_) click to toggle source

Return all objects in a given category, which is specified by the category type and the value array indicating which category of that type.

# File lib/idregistry/registry.rb, line 169
def objects_in_category(category_type_, *category_spec_)
  @config.lock

  return nil unless @categories.include?(category_type_)
  spec_ = category_spec_.size == 1 && category_spec_.first.is_a?(::Array) ? category_spec_.first : category_spec_
  tuple_hash_ = (@catdata[category_type_] ||= {})[spec_]
  tuple_hash_ ? tuple_hash_.values.map{ |objdata_| objdata_[0] } : []
end
rekey(arg_) click to toggle source

Recompute the tuples for the given object, which may be identified by object or tuple. Call this when the value of the object changes in such a way that the registry should identify it differently.

If you pass an Array, it is interpreted as a tuple. If you pass something other than an Array or a Hash, it is interpreted as an object. Otherwise, you can explicitly specify whether you are passing a tuple or object by using hash named arguments, e.g. :tuple =>, or :object =>.

# File lib/idregistry/registry.rb, line 334
def rekey(arg_)
  @config.lock

  # Resolve the object.
  if (objdata_ = _get_objdata(arg_))

    # Look up tuple generators from the type, and determine the
    # new tuples for the object.
    # Do this before entering the synchronize block because we
    # don't want callbacks called within the synchronization.
    obj_ = objdata_[0]
    type_ = objdata_[1]
    new_tuple_list_ = []
    @types[type_].each do |pat_|
      if (block_ = @patterns[pat_][2])
        new_tuple_ = block_.call(obj_)
        new_tuple_list_ << new_tuple_ if new_tuple_
      else
        raise ObjectKeyError, "Not all patterns for this type can generate tuples"
      end
    end

    # Synchronize to protect against concurrent mutation.
    @mutex.synchronize do
      # One last check to ensure the object is still present
      if @objects.has_key?(obj_.object_id)
        # Ensure none of the new tuples isn't pointed elsewhere already.
        # Tuples pointed at this object, ignore them.
        # Tuples pointed at another object, raise an error.
        tuple_hash_ = objdata_[2]
        new_tuple_list_.delete_if do |tup_|
          if tuple_hash_.has_key?(tup_)
            true
          elsif @tuples.has_key?(tup_)
            raise ObjectKeyError, "Could not rekey because one of the new tuples is already present"
          else
            false
          end
        end
        # Now go through and edit the tuples
        (tuple_hash_.keys - new_tuple_list_).each do |tup_|
          _remove_tuple(objdata_, tup_)
        end
        new_tuple_list_.each do |tup_|
          _add_tuple(objdata_, tup_)
        end
      end
    end
  end
  self
end
size() click to toggle source

Return the number of objects cached in the registry.

# File lib/idregistry/registry.rb, line 91
def size
  @objects.size
end
spawn_registry(opts_={}) click to toggle source

Create a new empty registry, duplicating this registry’s configuration.

If the :unlocked option is set to true, the new registry will have an unlocked configuration that can be modified further. Otherwise, the new registry’s configuration will be locked.

Spawning a locked registry from a locked configuration is very fast because it reuses the configuration objects.

# File lib/idregistry/registry.rb, line 84
def spawn_registry(opts_={})
  config.spawn_registry(opts_)
end
tuples_for(arg_) click to toggle source

Returns an array of all tuples corresponding to the given object, or the object identified by the given tuple. Returns nil if the given object is not cached in the registry.

If you pass an Array, it is interpreted as a tuple. If you pass something other than an Array or a Hash, it is interpreted as an object. Otherwise, you can explicitly specify whether you are passing a tuple or object by using hash named arguments, e.g. :tuple =&gt;, or :object =&gt;.

# File lib/idregistry/registry.rb, line 117
def tuples_for(arg_)
  objdata_ = _get_objdata(arg_)
  objdata_ ? objdata_[2].keys : nil
end
tuples_in_category(category_type_, *category_spec_) click to toggle source

Return all tuples in a given category, which is specified by the category type and the value array indicating which category of that type.

# File lib/idregistry/registry.rb, line 183
def tuples_in_category(category_type_, *category_spec_)
  @config.lock

  return nil unless @categories.include?(category_type_)
  spec_ = category_spec_.size == 1 && category_spec_.first.is_a?(::Array) ? category_spec_.first : category_spec_
  tuple_hash_ = (@catdata[category_type_] ||= {})[spec_]
  tuple_hash_ ? tuple_hash_.keys : []
end