class Familia::RedisObject

Attributes

classes[W]
db[W]
parent[RW]
ttl[W]
uri[W]
cache[R]

RedisObject instances are frozen. `cache` is a hash for you to store values retreived from Redis. This is not used anywhere by default, but you're encouraged to use it in your specific scenarios.

name[R]
parent[R]
redis[W]

Public Class Methods

classes() click to toggle source
# File lib/familia/redisobject.rb, line 19
def RedisObject.classes
  @classes
end
db(v=nil) click to toggle source
# File lib/familia/redisobject.rb, line 31
def db v=nil
  @db = v unless v.nil?
  @db || (parent ? parent.db : nil)
end
inherited(obj) click to toggle source
Calls superclass method
# File lib/familia/redisobject.rb, line 39
def inherited(obj)
  obj.db = self.db
  obj.ttl = self.ttl
  obj.uri = self.uri
  obj.parent = self
  RedisObject.classes << obj
  super(obj)
end
new(name, opts={}) click to toggle source

name: If parent is set, this will be used as the suffix for rediskey. Otherwise this becomes the value of the key. If this is an Array, the elements will be joined.

Options:

:class => A class that responds to Familia.load_method and Familia.dump_method. These will be used when loading and saving data from/to redis to unmarshal/marshal the class.

:reference => When true the index of the given value will be stored rather than the marshaled value. This assumes that the marshaled object is stored at a separate key. When read, #from_redis looks for that separate key and returns the unmarshaled object. :class must be specified. Default: false.

:extend => Extend this instance with the functionality in an other module. Literally: “self.extend opts”.

:parent => The Familia object that this redis object belongs to. This can be a class that includes Familia or an instance.

:ttl => the time to live in seconds. When not nil, this will set the redis expire for this key whenever save is called. You can also call it explicitly via update_expiration.

:quantize => append a quantized timestamp to the rediskey. Takes one of the following:

Boolean: include the default stamp (now % 10 minutes)
Integer: the number of seconds to quantize to (e.g. 1.hour)
Array: All arguments for qstamp (quantum, pattern, Time.now)

:default => the default value (String-only)

:dump_method => the instance method to call to serialize the object before sending it to Redis (default: Familia.dump_method).

:load_method => the class method to call to deserialize the object after it's read from Redis (default: Familia.load_method).

:db => the redis database to use (ignored if :redis is used).

:redis => an instance of Redis.

Uses the redis connection of the parent or the value of opts or Familia.redis (in that order).

# File lib/familia/redisobject.rb, line 104
def initialize name, opts={}
  @name, @opts = name, opts
  @name = @name.join(Familia.delim) if Array === @name
  #Familia.ld [name, opts, caller[0]].inspect
  self.extend @opts[:extend] if Module === @opts[:extend]
  @db = @opts.delete(:db)
  @parent = @opts.delete(:parent)
  @ttl ||= @opts.delete(:ttl) 
  @redis ||= @opts.delete(:redis)
  @cache = {}
  init if respond_to? :init
end
register(klass, meth) click to toggle source

To be called inside every class that inherits RedisObject meth becomes the base for the class and instances methods that are created for the given klass (e.g. Obj.list)

# File lib/familia/redisobject.rb, line 11
def RedisObject.register klass, meth
  registration[meth] = klass
end
registration() click to toggle source
# File lib/familia/redisobject.rb, line 15
def RedisObject.registration
  @registration
end
ttl(v=nil) click to toggle source
# File lib/familia/redisobject.rb, line 27
def ttl v=nil
  @ttl = v unless v.nil?
  @ttl || (parent ? parent.ttl : nil)
end
uri(v=nil) click to toggle source
# File lib/familia/redisobject.rb, line 35
def uri v=nil
  @uri = v unless v.nil?
  @uri || (parent ? parent.uri : Familia.uri)
end

Public Instance Methods

class?() click to toggle source
# File lib/familia/redisobject.rb, line 183
def class?
  !@opts[:class].to_s.empty? && @opts[:class].kind_of?(Familia)
end
clear()
Alias for: delete
clear_cache() click to toggle source
# File lib/familia/redisobject.rb, line 117
def clear_cache
  @cache.clear
end
db() click to toggle source

Returns the most likely value for db, checking (in this order):

* the value from :class if it's a Familia object
* the value from :parent
* the value self.class.db
* assumes the db is 0

After this is called once, this method will always return the same value.

# File lib/familia/redisobject.rb, line 138
def db 
  # Note it's important that we select this value at the last
  # possible moment rather than in initialize b/c the value 
  # could be modified after that but before this is called. 
  if @opts[:class] && @opts[:class].ancestors.member?(Familia)
    @opts[:class].db 
  elsif parent?
    parent.db
  else
    self.class.db || @db || 0
  end
end
del()
Alias for: delete
delete() click to toggle source
# File lib/familia/redisobject.rb, line 221
def delete 
  redis.del rediskey
end
Also aliased as: clear, del
dump_method() click to toggle source
# File lib/familia/redisobject.rb, line 252
def dump_method
  @opts[:dump_method] || Familia.dump_method
end
echo(meth, trace) click to toggle source
# File lib/familia/redisobject.rb, line 121
def echo meth, trace
  redis.echo "[#{self.class}\##{meth}] #{trace} (#{@opts[:class]}\#)"
end
exists?() click to toggle source

def destroy!

clear
# TODO: delete redis objects for this instance

end

# File lib/familia/redisobject.rb, line 232
def exists?
  redis.exists(rediskey) && !size.zero?
end
expire(sec) click to toggle source
# File lib/familia/redisobject.rb, line 240
def expire sec
  redis.expire rediskey, sec.to_i
end
expireat(unixtime) click to toggle source
# File lib/familia/redisobject.rb, line 244
def expireat unixtime
  redis.expireat rediskey, unixtime
end
from_redis(v) click to toggle source
# File lib/familia/redisobject.rb, line 332
def from_redis v
  return @opts[:default] if v.nil?
  return v unless @opts[:class]
  ret = multi_from_redis v
  ret.first unless ret.nil? # return the object or nil
end
load_method() click to toggle source
# File lib/familia/redisobject.rb, line 256
def load_method
  @opts[:load_method] || Familia.load_method
end
move(db) click to toggle source
# File lib/familia/redisobject.rb, line 205
def move db
  redis.move rediskey, db
end
multi_from_redis(*values) click to toggle source
# File lib/familia/redisobject.rb, line 291
def multi_from_redis *values
  Familia.ld "multi_from_redis: (#{@opts}) #{values}"
  return [] if values.empty?
  return values.flatten unless @opts[:class]
  ret = case @opts[:class]
  when ::String
    v.to_s
  when ::Symbol
    v.to_s.to_sym
  when ::Fixnum, ::Float
    @opts[:class].induced_from v
  else
    objs = values
    
    if @opts[:reference] == true
      objs = @opts[:class].rawmultiget *values
    end
    objs.compact!
    if @opts[:class].respond_to? load_method
      objs.collect! { |obj| 
        begin
          v = @opts[:class].send load_method, obj
          if v.nil?
            Familia.ld "[#{self.class}\#multi_from_redis] nil returned for #{@opts[:class]}\##{name}" 
          end
          v
        rescue => ex
          Familia.info v
          Familia.info "Parse error for #{rediskey} (#{load_method}): #{ex.message}"
          Familia.info ex.backtrace
          nil
        end
      }
    else
      raise Familia::Problem, "No such method: #{@opts[:class]}##{load_method}"
    end
    objs.compact # don't use compact! b/c the return value appears in ret
  end
  ret
end
parent?() click to toggle source
# File lib/familia/redisobject.rb, line 187
def parent?
  Class === parent || Module === parent || parent.kind_of?(Familia)
end
persist() click to toggle source
# File lib/familia/redisobject.rb, line 248
def persist
  redis.persist rediskey
end
qstamp(quantum=nil, pattern=nil, now=Familia.now) click to toggle source
# File lib/familia/redisobject.rb, line 191
def qstamp quantum=nil, pattern=nil, now=Familia.now
  quantum ||= ttl || 10.minutes
  pattern ||= '%H%M'
  rounded = now - (now % quantum)
  Time.at(rounded).utc.strftime(pattern)
end
realttl() click to toggle source
# File lib/familia/redisobject.rb, line 236
def realttl
  redis.ttl rediskey
end
redis() click to toggle source
# File lib/familia/redisobject.rb, line 125
def redis
  return @redis if @redis
  parent? ? parent.redis : Familia.redis(db)
end
rediskey() click to toggle source

returns a redis key based on the parent object so it will include the proper index.

# File lib/familia/redisobject.rb, line 160
def rediskey
  if parent? 
    # We need to check if the parent has a specific suffix
    # for the case where we have specified one other than :object.
    suffix = parent.kind_of?(Familia) && parent.class.suffix != :object ? parent.class.suffix : name
    k = parent.rediskey(name, nil)
  else
    k = [name].flatten.compact.join(Familia.delim)
  end
  if @opts[:quantize]
    args = case @opts[:quantize]
    when Numeric
      [@opts[:quantize]]        # :quantize => 1.minute
    when Array
      @opts[:quantize]          # :quantize => [1.day, '%m%D']
    else
      []                        # :quantize => true
    end
    k = [k, qstamp(*args)].join(Familia.delim)
  end
  k
end
rename(newkey) click to toggle source
# File lib/familia/redisobject.rb, line 209
def rename newkey
  redis.rename rediskey, newkey
end
renamenx(newkey) click to toggle source
# File lib/familia/redisobject.rb, line 213
def renamenx newkey
  redis.renamenx rediskey, newkey
end
to_redis(v) click to toggle source
# File lib/familia/redisobject.rb, line 260
def to_redis v
  return v unless @opts[:class]
  ret = case @opts[:class]
  when ::Symbol, ::String, ::Fixnum, ::Float, Gibbler::Digest
    v
  else
    if ::String === v
      v
      
    elsif @opts[:reference] == true
      unless v.respond_to? :index
        raise Familia::Problem, "#{v.class} does not have an index method"
      end
      unless v.kind_of?(Familia)
        raise Familia::Problem, "#{v.class} is not Familia (#{name})"
      end
      v.index

    elsif v.respond_to? dump_method
      v.send dump_method
      
    else
      raise Familia::Problem, "No such method: #{v.class}.#{dump_method}"
    end
  end
  if ret.nil?
    Familia.ld "[#{self.class}\#to_redis] nil returned for #{@opts[:class]}\##{name}" 
  end
  ret
end
ttl() click to toggle source
# File lib/familia/redisobject.rb, line 151
def ttl
  @ttl || 
  (parent.ttl if parent?) || 
  (@opts[:class].ttl if class?) || 
  (self.class.ttl if self.class.respond_to?(:ttl))
end
type() click to toggle source
# File lib/familia/redisobject.rb, line 217
def type 
  redis.type rediskey
end
update_expiration(ttl=nil) click to toggle source
# File lib/familia/redisobject.rb, line 198
def update_expiration(ttl=nil)
  ttl ||= self.ttl
  return if ttl.to_i.zero?  # nil will be zero
  Familia.ld "#{rediskey} to #{ttl}"
  expire ttl.to_i
end