Class: SGS::RedisBase
- Inherits:
-
Object
- Object
- SGS::RedisBase
- Defined in:
- lib/sgs/redis_base.rb
Class Method Summary collapse
-
.load ⇒ Object
Load the instance variables for the class.
- .redis ⇒ Object
-
.redis_handle ⇒ Object
Convert the class name into something suitable for Redis.
-
.setup ⇒ Object
Initialize the (sub-)class variables in Redis.
-
.subscribe ⇒ Object
Subscribe to messages from this particular channel.
-
.to_redis(var, local_val, idx = nil) ⇒ Object
Set a variable - convert from Ruby format to Redis format.
-
.var_init(var, val, idx = nil) ⇒ Object
Initialize a Redis variable.
Instance Method Summary collapse
-
#count ⇒ Object
Retrieve the count.
-
#count_name ⇒ Object
What is the official name of the count instance variable.
-
#load ⇒ Object
Load the instance variables for the class.
-
#make_redis_name(var, opts = {}) ⇒ Object
Translate an instance variable into a Redis key name.
-
#publish ⇒ Object
Publish the count onto a Redis pub/sub channel.
-
#redis_read_var(var, klass, opts = {}) ⇒ Object
Get an instance variable value from a Redis value.
-
#save ⇒ Object
Write the instance to Redis.
-
#save_and_publish ⇒ Object
Combined save and publish.
Class Method Details
.load ⇒ Object
Load the instance variables for the class.
83 84 85 86 87 |
# File 'lib/sgs/redis_base.rb', line 83 def self.load() cls = new cls.load cls end |
.redis ⇒ Object
44 45 46 |
# File 'lib/sgs/redis_base.rb', line 44 def redis @@redis ||= Redis.new end |
.redis_handle ⇒ Object
Convert the class name into something suitable for Redis
256 257 258 |
# File 'lib/sgs/redis_base.rb', line 256 def self.redis_handle self.name.downcase.gsub(/^sgs::/, 'sgs_') end |
.setup ⇒ Object
Initialize the (sub-)class variables in Redis.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/sgs/redis_base.rb', line 56 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 ⇒ Object
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.
167 168 169 170 171 172 173 174 |
# File 'lib/sgs/redis_base.rb', line 167 def self.subscribe redis = Redis.new redis.subscribe(redis_handle) do |on| on. do |channel, count| yield count.to_i end end end |
.to_redis(var, local_val, idx = nil) ⇒ Object
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).
226 227 228 229 230 231 232 233 234 |
# File 'lib/sgs/redis_base.rb', line 226 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 |
Instance Method Details
#count ⇒ Object
Retrieve the count
184 185 186 |
# File 'lib/sgs/redis_base.rb', line 184 def count RedisBase.redis.get count_name end |
#count_name ⇒ Object
What is the official name of the count instance variable
190 191 192 |
# File 'lib/sgs/redis_base.rb', line 190 def count_name make_redis_name "@count" end |
#load ⇒ Object
Load the instance variables for the class.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/sgs/redis_base.rb', line 91 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 = {}) ⇒ Object
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
244 245 246 247 248 249 250 251 252 |
# File 'lib/sgs/redis_base.rb', line 244 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 ⇒ Object
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.
159 160 161 |
# File 'lib/sgs/redis_base.rb', line 159 def publish RedisBase.redis.publish self.class.redis_handle, count.to_s end |
#redis_read_var(var, klass, opts = {}) ⇒ Object
Get an instance variable value from a Redis value.
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/sgs/redis_base.rb', line 196 def redis_read_var(var, klass, opts = {}) redis_name = make_redis_name var, opts redis_val = 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 == Integer redis_val = redis_val.to_i when klass == Float redis_val = redis_val.to_f when klass == FalseClass redis_val = (redis_val == "true" or redis_val == "TRUE") when klass == TrueClass redis_val = (redis_val == "true" or redis_val == "TRUE") end end redis_val end |
#save ⇒ Object
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
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/sgs/redis_base.rb', line 122 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. RedisBase.redis.multi do |pipeline| var_list.each do |key, value| pipeline.set key, value end pipeline.incr count_name end true end |
#save_and_publish ⇒ Object
Combined save and publish
178 179 180 |
# File 'lib/sgs/redis_base.rb', line 178 def save_and_publish save && publish end |