module MultiCache

Constants

CACHE_KEY_MASTER_PREFIX

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

After installation:

Create config/initializers/init_multi_cache.rb
and add the lines

    MultiCache.configure do |config|
      config.redis_instance "<redis-instance>"
    end

  where <redis-instance> is the Redis::Namespace object to be used by 
  MultiCache for caching
  Please ensure that the <redis-instance> is wrapped in quotes

All models where you want to use MultiCache must:

[mandatory]   Define a CLASS method
              MULTI_CACHE_PREFIXES
                that returns an array of allowed cache prefixes used by
                the class   

[mandatory]   Define a CLASS method 
              GEN_CACHE_CONTENT(ID_OR_OBJ, CACHE_PREFIX)
                that generates a hash that will be cached
                ID_OR_OBJ is a hash that contains 
                  {:id => obj_id, :obj => actual_obj_if_available}
              CACHE_PREFIX is an optional string that can be used to 
                distinguish between different cached info for the same
                object.

[optional]    Define a CLASS method 
              PARSE_CACHE_CONTENT(CONTENT, CACHE_PREFIX)
                that parses the cached content once it is read from 
                redis. Sometimes some JSON.parses are required. If not
                defined, the default method is called (which simply returns
                the cached value as-is)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

CACHE_KEY_SEPARATOR
MULTICACHE_DEFAULT_TTL

Three months in seconds

VERSION

Public Class Methods

configure() { |self| ... } click to toggle source
# File lib/multi_cache.rb, line 53
def self.configure
  raise ArgumentError, "requires a block" unless block_given?
  yield self
end
del_from_redis(prefix, category) click to toggle source
# File lib/multi_cache.rb, line 162
def self.del_from_redis(prefix, category)
  if category.nil?
    MultiCache.get_redis.del(prefix)
  else
    MultiCache.get_redis.hdel(prefix, Array.wrap(category).compact)
  end
end
destroy_obj_cache(id, category = nil) click to toggle source
# File lib/multi_cache.rb, line 128
def self.destroy_obj_cache(id, category = nil)
  # Delete cache for one object only
  prefix = self.fixed_cache_prefix(id)
  MultiCache.del_from_redis(prefix, category)
end
fixed_cache_prefix(id = nil) click to toggle source
# File lib/multi_cache.rb, line 114
def self.fixed_cache_prefix(id = nil)
  chain = [CACHE_KEY_MASTER_PREFIX, self.name.to_s]
  chain.push(id.to_s.strip) if id.present?
  chain.join(CACHE_KEY_SEPARATOR)
end
get_cached(id_or_obj, cache_category) click to toggle source
# File lib/multi_cache.rb, line 74
def self.get_cached(id_or_obj, cache_category)
  id_and_obj = get_id_and_obj(id_or_obj)

  validate_cache_category(cache_category)

  cache_key = obj_cache_key(id_and_obj[:id])
  cached_json = MultiCache.get_redis.hget(cache_key, cache_category)

  if cached_json.nil?
    # Not found in cache
    cached_hash = gen_cache_content(id_or_obj, cache_category)
    self.write_to_cache(cached_hash, cache_key, cache_category)
  else
    cached_hash = JSON.parse(cached_json)
  end

  parse_cache_content(cached_hash, cache_category)
end
get_id_and_obj(id_or_obj) click to toggle source
# File lib/multi_cache.rb, line 142
def self.get_id_and_obj(id_or_obj)
  id_and_obj = {}
  if id_or_obj.class == self
    id_and_obj[:obj] = id_or_obj
    id_and_obj[:id] = obj.id.to_s
  else
    id_and_obj[:id] = id_or_obj.to_s
    # obj = nil # Load it when necessary
  end
  id_and_obj
end
get_redis() click to toggle source
# File lib/multi_cache.rb, line 62
def self.get_redis
  if @redis.blank?
    @redis = eval(@@multicache_redis_name)
  end
  @redis
end
obj_cache_key(id) click to toggle source
# File lib/multi_cache.rb, line 108
def self.obj_cache_key(id)
  # Do not change ordering since we match keys using this
  raise ArgumentError.new 'Key can not be blank' if id.blank?
  [fixed_cache_prefix(id)].join(CACHE_KEY_SEPARATOR)
end
parse_cache_content(content, cache_prefix) click to toggle source

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Misc # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# File lib/multi_cache.rb, line 137
def self.parse_cache_content(content, cache_prefix)
  # Default method. Override in including class.
  content
end
redis_instance(redis_inst_str) click to toggle source
# File lib/multi_cache.rb, line 58
def self.redis_instance(redis_inst_str)
  @@multicache_redis_name = redis_inst_str
end
validate_cache_category(cache_category) click to toggle source
# File lib/multi_cache.rb, line 154
def self.validate_cache_category(cache_category)
  if !(multi_cache_prefixes.include? cache_category)
    raise "#{self} Class: cache category '#{cache_category}' " +
              "must be among #{multi_cache_prefixes}"
  end
end
write_to_cache(cached_hash, cache_key, cache_category) click to toggle source
# File lib/multi_cache.rb, line 93
def self.write_to_cache(cached_hash, cache_key, cache_category)
  raise "the output of GEN_CACHE_CONTENT must be a hash" if !(cached_hash.is_a? Hash)
  if !cached_hash.nil?
    created = MultiCache.get_redis.hset(cache_key, cache_category, cached_hash.to_json)
    MultiCache.get_redis.expire(cache_key, MULTICACHE_DEFAULT_TTL) if created
  end
end

Public Instance Methods

destroy_obj_cache(category = nil) click to toggle source

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Cache destruction # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# File lib/multi_cache.rb, line 124
def destroy_obj_cache(category = nil)
  self.class.destroy_obj_cache(self.id, category)
end
obj_cache_key(id = self.id) click to toggle source

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Cache key determination # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# File lib/multi_cache.rb, line 104
def obj_cache_key(id = self.id)
  self.class.obj_cache_key(id)
end