class SGS::RedisBase

Public Class Methods

load() click to toggle source

Load the instance variables for the class.

# File lib/sgs/redis_base.rb, line 75
def self.load()
  cls = new
  cls.load
  cls
end
redis() click to toggle source
# File lib/sgs/redis_base.rb, line 36
def redis
  @@redis ||= Redis.new
end
redis_handle() click to toggle source

Convert the class name into something suitable for Redis

# File lib/sgs/redis_base.rb, line 248
def self.redis_handle
  self.name.downcase.gsub(/^sgs::/, 'sgs_')
end
setup() click to toggle source

Initialize the (sub-)class variables in Redis.

# File lib/sgs/redis_base.rb, line 48
def self.setup
  cls = new
  cls.instance_variables.each do |var|
    val = cls.instance_variable_get var
    if val.kind_of? Array
      #
      # Arrays are handled separately. We instead
      # use the index to create a series of 'fooN'
      # variables.
      val.size.times do |idx|
        var_init var, val, idx
      end
    else
      var_init var, val
    end
  end
end
subscribe() { |to_i| ... } click to toggle source

Subscribe to messages from this particular channel. Each count is sent to the code block. It's up to the called code block to decide if the count has changed and if so, to read the data from Redis.

# File lib/sgs/redis_base.rb, line 159
def self.subscribe
  redis = Redis.new
  redis.subscribe(redis_handle) do |on|
    on.message do |channel, count|
      yield count.to_i
    end
  end
end
to_redis(var, local_val, idx = nil) click to toggle source

Set a variable - convert from Ruby format to Redis format. As of now, we only convert times. Floats and integers are dealt with by Redis (converted to strings, unfortunately).

# File lib/sgs/redis_base.rb, line 218
def self.to_redis(var, local_val, idx = nil)
  if local_val
    local_val = local_val[idx] if idx
    if local_val.class == Time
      local_val = local_val.to_f
    end
  end
  local_val
end
var_init(var, val, idx = nil) click to toggle source

Initialize a Redis variable.

# File lib/sgs/redis_base.rb, line 68
def self.var_init(var, val, idx = nil)
  cls = new
  SGS::RedisBase.redis.setnx cls.make_redis_name(var, :idx => idx), self.to_redis(var, val, idx)
end

Public Instance Methods

count() click to toggle source

Retrieve the count

# File lib/sgs/redis_base.rb, line 176
def count
  SGS::RedisBase.redis.get count_name
end
count_name() click to toggle source

What is the official name of the count instance variable

# File lib/sgs/redis_base.rb, line 182
def count_name
  make_redis_name "@count"
end
load() click to toggle source

Load the instance variables for the class.

# File lib/sgs/redis_base.rb, line 83
def load
  instance_variables.each do |var|
    lval = instance_variable_get var
    if lval.kind_of? Array
      #
      # It's an array - iterate and read the values.
      lval.size.times do |idx|
        idx_val = lval[idx]
        lval[idx] = redis_read_var var, idx_val.class, :idx => idx
      end
    elsif lval.kind_of? Location
      #
      # ::FIXME:: Yes. this is a hack.
      # This belongs in the Location class itself. It's arguable that a lot
      # of the stuff belongs in the parent class. Perhaps the thing to do
      # is ask the class to return a hash of names and values, and then
      # set them accordingly.
      lval.latitude = redis_read_var var, Float, :name => 'latitude'
      lval.longitude = redis_read_var var, Float, :name => 'longitude'
    else
      lval = redis_read_var var, lval.class
    end
    instance_variable_set var, lval
  end
  true
end
make_redis_name(var, opts = {}) click to toggle source

Translate an instance variable into a Redis key name. This is simply the class name, a dot and the instance variable. A bit of jiggery-pokery to convert the instance variable into a proper name. Probably an easier way to do this, but…

Instance method for above

# File lib/sgs/redis_base.rb, line 236
def make_redis_name(var, opts = {})
  var_name = opts[:name] || var.to_s.gsub(/^@/, '')
  prefix = opts[:prefix] || self.class.redis_handle
  if opts[:idx]
    "#{prefix}.#{var_name}#{opts[:idx] + 1}"
  else
    "#{prefix}.#{var_name}"
  end
end
publish() click to toggle source

Publish the count onto a Redis pub/sub channel. The trick to subscribing to a channel is that whenever there's a publish, the new count is published as a string. If you subscribe to the channel (usually the class name), you can remember the last received count and decide if there is fresh data. Or, you can just act anyway.

# File lib/sgs/redis_base.rb, line 151
def publish
  SGS::RedisBase.redis.publish self.class.redis_handle, count.to_s
end
redis_read_var(var, klass, opts = {}) click to toggle source

Get an instance variable value from a Redis value.

# File lib/sgs/redis_base.rb, line 188
def redis_read_var(var, klass, opts = {})
  redis_name = make_redis_name var, opts
  redis_val = SGS::RedisBase.redis.get redis_name
  redis_val = nil if redis_val == ""
  if redis_val
    if not klass or klass == NilClass
      redis_val = true if redis_val == "true"
      redis_val = false if redis_val == "false"
      klass = Float if redis_val =~ /[0-9+-\.]+/
    end
    case
    when klass == Time
      redis_val = Time.at(redis_val.to_f).gmtime
    when klass == Fixnum
      redis_val = redis_val.to_i
    when klass == Float
      redis_val = redis_val.to_f
    when klass == FalseClass
      redis_val = false
    when klass == TrueClass
      redis_val = true
    end
  end
  redis_val
end
save() click to toggle source

Write the instance to Redis. IWe produce a Hash of keys and values. From this and inside a Redis “multi” block, we set all the values and finally increment the count. @count is actually an instance variable of redis_base

# File lib/sgs/redis_base.rb, line 114
def save
  #
  # Get the Hash of settable values (including count).
  var_list = {}
  self.instance_variables.each do |var|
    lval = self.instance_variable_get var
    if lval.kind_of? Array
      lval.size.times do |idx|
        var_list[make_redis_name(var, :idx => idx)] = self.class.to_redis var, lval, idx
      end
    elsif lval.kind_of? Location
      #
      # ::FIXME:: Yes. this is a hack. see 'load' above.
      var_list[make_redis_name(var, :name => 'latitude')] = lval.latitude
      var_list[make_redis_name(var, :name => 'longitude')] = lval.longitude
    else
      var_list[make_redis_name(var)] = self.class.to_redis var, lval
    end
  end
  #
  # Inside a multi-block, set all the variables and increment
  # the count.
  SGS::RedisBase.redis.multi do
    var_list.each do |key, value|
      SGS::RedisBase.redis.set key, value
    end
    SGS::RedisBase.redis.incr count_name
  end
  true
end
save_and_publish() click to toggle source

Combined save and publish

# File lib/sgs/redis_base.rb, line 170
def save_and_publish
  save && publish
end