Module: Cachely::Mechanics
- Defined in:
- lib/cachely/mechanics.rb
Class Method Summary collapse
-
.connect(opts = {}) ⇒ Boolean
Connects to the Redis store you want to use for a cache.
-
.flush_all_keys ⇒ String
Flush the Redis store of all keys.
-
.get(obj, method, *args) ⇒ Object
Gets a cached response to a method.
-
.map_array_to_s(p) ⇒ String
Map array to s, calls recursively on elements then to json.
-
.map_hash_to_s(p) ⇒ String
Maps hash to s, basically does recursive call to map_param_to_s to get everythign inside and then to_jsons.
-
.map_param_to_s(p) ⇒ String
Turns any parameter into a string.
-
.map_s_to_obj(s) ⇒ Object
Turns String into an actual object.
-
.map_s_to_param(s) ⇒ Object
Turns any string into a parameter.
-
.redis ⇒ Redis
Grab current redis instance.
-
.redis_key(context, method, *args) ⇒ String
Converts method name and arguments into a coherent key.
-
.setup_method(klazz, name, time_to_expire_in_s, is_class_method = false) ⇒ Object
Defines the method using my hacky eval script.
-
.store(obj, method, result, time_to_exp_in_sec, *args) ⇒ String
Stores the result in it’s proper cached location on redis by getting the redis key and parsing The result into a storable string, mostly made up of recursive json.
Instance Method Summary collapse
-
#context([Object, Symbol, Args], methodnamesymbol) ⇒ String
Converts method name and arguments into a coherent key.
-
#obj([Symbol]) ⇒ String
Stores the result in it’s proper cached location on redis by getting the redis key and parsing The result into a storable string, mostly made up of recursive json.
Class Method Details
.connect(opts = {}) ⇒ Boolean
Connects to the Redis store you want to use for a cache.
9 10 11 12 13 14 15 |
# File 'lib/cachely/mechanics.rb', line 9 def self.connect(opts = {}) @redis ||= Redis.new( :host => opts[:host], :port => opts[:port], :password => opts[:password], :driver => opts[:driver]) end |
.flush_all_keys ⇒ String
Flush the Redis store of all keys.
20 21 22 |
# File 'lib/cachely/mechanics.rb', line 20 def self.flush_all_keys redis.flushdb end |
.get(obj, method, *args) ⇒ Object
Gets a cached response to a method.
66 67 68 69 70 71 72 |
# File 'lib/cachely/mechanics.rb', line 66 def self.get(obj, method, *args) result = redis.get(redis_key(obj, method, *args)) #return an array, bc if the result stored was nil, it looks the same as if #we got no result back(which we would return nil) so we differentiate by putting #our return value always in an array. Easy to check. result.nil? ? nil : [map_s_to_param(result)] end |
.map_array_to_s(p) ⇒ String
Map array to s, calls recursively on elements then to json
219 220 221 222 223 |
# File 'lib/cachely/mechanics.rb', line 219 def self.map_array_to_s(p) p.map do |part| map_param_to_s(part) end.to_json end |
.map_hash_to_s(p) ⇒ String
Maps hash to s, basically does recursive call to map_param_to_s to get everythign inside and then to_jsons.
208 209 210 211 212 213 |
# File 'lib/cachely/mechanics.rb', line 208 def self.map_hash_to_s(p) p.inject(Hash.new) do |hash, entry| hash[map_param_to_s(entry[0])] = map_param_to_s(entry[1]) hash end.to_json end |
.map_param_to_s(p) ⇒ String
Turns any parameter into a string. Current supported types are primitives, orm models That respond to id and have an updated_at field, and objects that have a to_json method.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/cachely/mechanics.rb', line 169 def self.map_param_to_s(p) if(p.is_a?(Hash)) return map_hash_to_s(p) elsif(p.is_a?(Array)) return map_array_to_s(p) elsif(p.respond_to?("to_json")) translated = nil if p.is_a?(String) translated = "instance|"+p.class.to_s+"|"+p elsif p.is_a?(Symbol) translated = "instance|"+p.class.to_s+"|"+p.to_s elsif p.nil? translated = "instance|NilClass|nil" elsif p.is_a?(TrueClass) translated = "instance|TrueClass|true" elsif p.is_a?(FalseClass) translated = "instance|FalseClass|false" elsif p.is_a?(Fixnum) translated = "instance|Fixnum|" + p.to_s elsif p.is_a?(Float) translated = "instance|Float|" + p.to_s elsif p.is_a?(ActiveRecord::Base) #don't want { "dummy_model" = > {:attributes => 1}} #want {:attributes => 1} translated = "instance|#{p.class.to_s}|#{JSON.parse(p.to_json)[p.class.to_s.underscore].to_json}" else translated = (p.to_s.match(/^#</) ? "instance|#{p.class}" : "class|#{p.to_s}") + "|"+ p.to_json end return translated end end |
.map_s_to_obj(s) ⇒ Object
Turns String into an actual object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/cachely/mechanics.rb', line 133 def self.map_s_to_obj(s) class_or_instance = s.split("|").first type = s.split("|")[1] data = s.gsub(/^#{class_or_instance}\|#{type}\|/,'') case type when "TrueClass" return true when "FalseClass" return false when "Symbol" return data.to_sym when "Fixnum" return data.to_i when "Float" return data.to_f when "String" return data when "NilClass" return nil else class_or_instance == "instance" ? obj = Object.const_get(type).new : obj = Object.const_get(type) JSON.parse(data).each do |key, value| obj.send(key+"=",value) if obj.respond_to?(key+"=") end return obj end end |
.map_s_to_param(s) ⇒ Object
Turns any string into a parameter. Current supported types are primitives, orm models That respond to id and have an updated_at field, and objects that have a to_json method.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/cachely/mechanics.rb', line 104 def self.map_s_to_param(s) begin respawned_hash = JSON.parse(s) if respawned_hash.is_a?(Array) respawned_hash.map! do |piece| map_s_to_param(piece) end elsif respawned_hash.is_a?(Hash) respawned_hash = respawned_hash.inject(Hash.new) do |new_hash, entry| new_hash[map_s_to_param(entry[0])] = map_s_to_param(entry[1]) new_hash end end return respawned_hash rescue JSON::ParserError => e #The only times the string isn't json is if it is a primitive, or an ORM object #This exception happens then, we catch it, and check orm signature. return map_s_to_obj(s) end end |
.redis ⇒ Redis
Grab current redis instance. Has ability to reconnect for you if it fails.
27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/cachely/mechanics.rb', line 27 def self.redis @tries = 0 unless @tries begin @redis.get("test") #tests to see if we're still authed. @tries = 0 #means we can reset our trymeter. rescue Exception => e @tries+=1 if @tries if @tries<5 connect end end return @redis end |
.redis_key(context, method, *args) ⇒ String
Converts method name and arguments into a coherent key. Creates a hash and to_jsons it And that becomes the redis key. Spiffy, I know.
91 92 93 94 95 96 97 |
# File 'lib/cachely/mechanics.rb', line 91 def self.redis_key(context, method, *args) map_param_to_s({ :context => context, :method => method, :args => args }) end |
.setup_method(klazz, name, time_to_expire_in_s, is_class_method = false) ⇒ Object
Defines the method using my hacky eval script. So far, this is the only way I’ve found that allows me to define variable argument length definitions. If you have a better idea, please refactor it!
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/cachely/mechanics.rb', line 47 def self.setup_method(klazz, name, time_to_expire_in_s, is_class_method = false) context = (is_class_method ? klazz : klazz.new) args_str = context.method("#{name.to_s}_old".to_sym).parameters.map { |k| k.last}.join(',') args_to_use_in_def = args_str.empty? ? "" : "," + args_str eval("klazz.define_#{is_class_method ? "singleton_" : ""}method(:#{name}) do #{args_str.empty? ? "" : "|#{args_str}|"}; " + "result = Cachely::Mechanics.get(context,:#{name}#{args_to_use_in_def});" + "return result.first if result.is_a?(Array);" + "result = context.send(:#{"#{name.to_s}_old"}#{args_to_use_in_def});" + "Cachely::Mechanics.store(context,:#{"#{name.to_s}"}, result#{time_to_expire_in_s.nil? ? ",nil": ",#{time_to_expire_in_s}"}#{args_to_use_in_def});" + "return result;" + "end" ) end |
.store(obj, method, result, time_to_exp_in_sec, *args) ⇒ String
Stores the result in it’s proper cached location on redis by getting the redis key and parsing The result into a storable string, mostly made up of recursive json.
81 82 83 84 |
# File 'lib/cachely/mechanics.rb', line 81 def self.store(obj, method, result, time_to_exp_in_sec, *args) redis.set(redis_key(obj, method, *args), map_param_to_s(result)) redis.expire(redis_key(obj, method, *args), time_to_exp_in_sec) if time_to_exp_in_sec end |
Instance Method Details
#context([Object, Symbol, Args], methodnamesymbol) ⇒ String
Converts method name and arguments into a coherent key. Creates a hash and to_jsons it And that becomes the redis key. Spiffy, I know.
91 92 93 94 95 96 97 |
# File 'lib/cachely/mechanics.rb', line 91 def self.redis_key(context, method, *args) map_param_to_s({ :context => context, :method => method, :args => args }) end |
#obj([Symbol]) ⇒ String
Stores the result in it’s proper cached location on redis by getting the redis key and parsing The result into a storable string, mostly made up of recursive json.
66 67 68 69 70 71 72 |
# File 'lib/cachely/mechanics.rb', line 66 def self.get(obj, method, *args) result = redis.get(redis_key(obj, method, *args)) #return an array, bc if the result stored was nil, it looks the same as if #we got no result back(which we would return nil) so we differentiate by putting #our return value always in an array. Easy to check. result.nil? ? nil : [map_s_to_param(result)] end |