class CachedEnumeration::Cache

provide cached access to enumeration values

usage: add cache_enumeration <params> to ActiveRecord class

parameters are

:order  order of items in cached_all (default: 'id')
:hashed list of attributes to provide hashes for (default: [ 'id', 'name' ];
:hashed list of attributes to provide hashes for (default: [ 'id', 'name' ];
        id will always be added to that list, if missing
:constantize  attribute to provide constants for (default: 'name')
            use nil, not to generate constants

cached methods are: find_from_ids( <id> ) or find_from_ids( [ <id>, <id>, … ] )

providing cached  find( <id> ) or find( [ <id>, <id>, ... ] )

find_by_XY / by_XY for all hashed attributes (by_XY is deprecated) cached_all

besides constants using the upcase name are set up providing the entries

note that all objects (arrays, maps and the models themselfs) are frozen to avoid unintentional changes.

Cachability of enumerations does not imply that all enumeration access should be cached. This is a question that needs to be well thought depending on the size of the enumeration and the number of accesses to the cached data.

The by_XY finder should be avoided as the find_by_XY will be available with and without cache.

Attributes

options[R]

Public Class Methods

new(base, params) click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 36
    def initialize(base, params)
#      p params
      @options=init_options(params)
      @cache={} #cache by keys
      @all=[] #cache of all
      @status=:uncached #can be :uncached,:cashing,:cached
      @klass=base

      #base.extend(ClassMethods)
      #base.reset_column_information
      base_singleton = class << base;
        self
      end

      patch_const_missing(base_singleton) if @options[:constantize]
#create_find_by_methods(base_singleton)
    end

Public Instance Methods

all() click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 54
def all
  ensure_caches
  @all
end
cache!() click to toggle source

forces a cache @return Boolean true is it just cached, false if it was already cached

# File lib/cached_enumeration/cached_enumeration.rb, line 74
def cache!
  #only load if loading not yet in progress
  ensure_caches if @status == :uncached
end
cached?() click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 79
def cached?
  @status==:cached
end
first() click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 87
def first
  @all.first
end
get_by(att, key) click to toggle source

returns a value from a cache @param String att name of the attribute @param String key value of the attribute

# File lib/cached_enumeration/cached_enumeration.rb, line 62
def get_by(att, key)
  ensure_caches
  key=key.to_i if att.to_s == "id"
  @cache[att.to_s][key]
end
hashed_by?(att) click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 68
def hashed_by?(att)
  options[:hashed].include?(att.to_s)
end
order() click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 83
def order
  @options[:order]
end

Private Instance Methods

caching?() click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 119
def caching?
  @status==:caching
end
create_constants() click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 140
def create_constants
  #puts "creating constants #{self.name}"
  proc=@options[:constantize].respond_to?(:call)

  @all.each do |model|
    const_name = if proc
      @options[:constantize].call(model).upcase
    else
      model.send(@options[:constantize]).upcase
    end

    @klass.const_set const_name, model
  end
end
ensure_caches() click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 93
def ensure_caches
  return false if cached? || caching?
  @status=:caching

  @cache = Hash.new do |hash, key|
    hash[key]=Hash.new
  end

  # the next line is weird but I want to have to Array so I use select
  # to dereference the relation
  @all = @klass.order(@options[:order]).all.to_a.freeze

  @all.each do |entry|
    @options[:hashed].each do |att|
      @cache[att.to_s][entry.send(att)] = entry.freeze
    end
  end

  create_constants if @options[:constantize]

  @klass.logger.try(:info, "Filled cache of #{@klass.name}: #{@options.inspect}")
  @status=:cached
  true
end
init_options(params) click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 123
def init_options(params)
  defaults = {
    :order => 'id',
    :hashed => ['id', 'name'],
    :constantize => 'name',
  }
  #params check logic
  params_diff=params.keys - defaults.keys
  raise ArgumentError.new("unexpected parameters #{params_diff.inspect}, only #{defaults.keys.inspect} are understood") unless params_diff.empty?
  params = defaults.merge(params)
  params[:hashed] << 'id' unless params[:hashed].include? 'id'
  params[:hashed].map! do |name|
    name.to_s
  end
  params
end
patch_const_missing(base_singleton) click to toggle source
# File lib/cached_enumeration/cached_enumeration.rb, line 155
def patch_const_missing(base_singleton)
  # no class caching in derived classes!
  return if @klass.parent.respond_to? :const_missing_with_cache_enumeration
  @klass.extend ConstMissing
  base_singleton.alias_method_chain :const_missing, :cache_enumeration
end