Permalink
Browse files

DRY up cache client support by using the "cache" gem

  • Loading branch information...
1 parent fe32469 commit 21faf0e382eb6ab84f2aa8f0565ef29e18d201e3 @seamusabshere committed Feb 18, 2011
View
@@ -4,3 +4,4 @@ Gemfile.lock
pkg/*
rdoc/*
secret.sh
+.DS_Store
View
@@ -1,45 +0,0 @@
-= Developer notes
-
-== Lots of cache method signatures...
-
- def get(k)
- if defined?(::Memcached) and bare_storage.is_a?(::Memcached)
- # def get(keys, marshal=true)
- begin; bare_storage.get(k.to_s); rescue ::Memcached::NotFound; nil; end
- elsif defined?(::Memcached::Rails) and bare_storage.is_a?(::Memcached::Rails)
- # def get(key, raw=false)
- bare_storage.get k.to_s
- elsif defined?(::Dalli::Client) and bare_storage.is_a?(::Dalli::Client)
- # def get(key, options=nil)
- bare_storage.get k.to_s
- elsif defined?(::MemCache) and bare_storage.is_a?(::MemCache)
- # def get(key, raw = false)
- bare_storage.get k.to_s
- elsif defined?(::ActiveSupport::Cache::Store) and bare_storage.is_a?(::ActiveSupport::Cache::Store)
- # def read(name, options = nil)
- bare_storage.read k.to_s
- else
- raise "Unknown client: #{bare_storage.inspect}"
- end
- end
-
- def set(k, v)
- if defined?(::Memcached) and bare_storage.is_a?(::Memcached)
- # def set(key, value, ttl=@default_ttl, marshal=true, flags=FLAGS)
- bare_storage.set k.to_s, v, ttl
- elsif defined?(::Memcached::Rails) and bare_storage.is_a?(::Memcached::Rails)
- # def set(key, value, ttl=@default_ttl, raw=false)
- bare_storage.set k.to_s, v, ttl
- elsif defined?(::Dalli::Client) and bare_storage.is_a?(::Dalli::Client)
- # def set(key, value, ttl=nil, options=nil)
- bare_storage.set k.to_s, v, ttl
- elsif defined?(::MemCache) and bare_storage.is_a?(::MemCache)
- # def set(key, value, expiry = 0, raw = false)
- bare_storage.set k.to_s, v, ttl
- elsif defined?(::ActiveSupport::Cache::Store) and bare_storage.is_a?(::ActiveSupport::Cache::Store)
- # def write(name, value, options = nil)
- bare_storage.write k.to_s, v, :expires_in => ttl
- else
- raise "Unknown client: #{bare_storage.inspect}"
- end
- end
View
@@ -18,13 +18,8 @@ Gem::Specification.new do |s|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.require_paths = ["lib"]
- s.add_development_dependency 'redis'
- s.add_development_dependency 'activesupport', '>=2.3.4'
- s.add_development_dependency 'i18n' # activesupport
- s.add_development_dependency 'test-unit'
+ s.add_dependency 'cache'
s.add_development_dependency 'memcached'
- s.add_development_dependency 'dalli'
- s.add_development_dependency 'memcache-client'
# if RUBY_VERSION >= '1.9'
# s.add_development_dependency 'ruby-debug19'
# else
View
@@ -1,14 +1,24 @@
+require 'cache_method/version'
# See the README.rdoc for more info!
module CacheMethod
autoload :Config, 'cache_method/config'
- autoload :Cache, 'cache_method/cache'
+ autoload :CachedResult, 'cache_method/cached_result'
+ autoload :Epoch, 'cache_method/epoch'
def self.config #:nodoc:
Config.instance
end
- def self.cache #:nodoc:
- Cache.instance
+ def self.klass_name(obj) #:nodoc:
+ obj.is_a?(::Class) ? obj.to_s : obj.class.to_s
+ end
+
+ def self.method_delimiter(obj) #:nodoc:
+ obj.is_a?(::Class) ? '.' : '#'
+ end
+
+ def self.method_signature(obj, method_id) #:nodoc:
+ [ klass_name(obj), method_id ].join method_delimiter(obj)
end
# All Objects, including instances and Classes, get the <tt>#clear_method_cache</tt> method.
@@ -20,7 +30,7 @@ module InstanceMethods
# Example:
# my_blog.clear_method_cache :get_latest_entries
def clear_method_cache(method_id)
- ::CacheMethod.cache.delete self, method_id
+ ::CacheMethod::Epoch.mark_passing :obj => self, :method_id => method_id
end
end
@@ -47,9 +57,7 @@ def cache_method(method_id, ttl = nil)
original_method_id = "_uncached_#{method_id}"
alias_method original_method_id, method_id
define_method method_id do |*args|
- ::CacheMethod.cache.fetch self, method_id, ttl, *args do
- send original_method_id, *args
- end
+ ::CacheMethod::CachedResult.fetch :obj => self, :method_id => method_id, :original_method_id => original_method_id, :args => args, :ttl => ttl
end
end
end
View
@@ -1,65 +0,0 @@
-require 'singleton'
-module CacheMethod
- # All cache requests go through a clearinghouse, allowing uncaching.
- class Cache #:nodoc: all
- autoload :Key, 'cache_method/cache/key'
- autoload :Epoch, 'cache_method/cache/epoch'
-
- include ::Singleton
-
- def fetch(obj, method_id, ttl, *args)
- k = Key.new :obj => obj, :method_id => method_id, :args => args
- if cached_v = get(k.to_s)
- return cached_v
- end
- v = yield
- set k.to_s, v, ttl
- v
- end
-
- def delete(obj, method_id)
- Epoch.mark_passing :obj => obj, :method_id => method_id
- end
-
- def get(k)
- if defined?(::Memcached) and bare_storage.is_a?(::Memcached)
- begin; bare_storage.get(k); rescue ::Memcached::NotFound; nil; end
- elsif defined?(::Redis) and bare_storage.is_a?(::Redis)
- if cached_v = bare_storage.get(k) and cached_v.is_a?(::String)
- ::Marshal.load cached_v
- end
- elsif bare_storage.respond_to?(:get)
- bare_storage.get k
- elsif bare_storage.respond_to?(:read)
- bare_storage.read k
- else
- raise "Don't know how to work with #{bare_storage.inspect}"
- end
- end
-
- def set(k, v, ttl)
- ttl ||= ::CacheMethod.config.default_ttl
- if defined?(::Redis) and bare_storage.is_a?(::Redis)
- if ttl == 0
- bare_storage.set k, ::Marshal.dump(v)
- else
- bare_storage.setex k, ttl, ::Marshal.dump(v)
- end
- elsif bare_storage.respond_to?(:set)
- bare_storage.set k, v, ttl
- elsif bare_storage.respond_to?(:write)
- if ttl == 0
- bare_storage.write k, v # never expire
- else
- bare_storage.write k, v, :expires_in => ttl
- end
- else
- raise "Don't know how to work with #{bare_storage.inspect}"
- end
- end
-
- def bare_storage
- Config.instance.storage
- end
- end
-end
@@ -1,45 +0,0 @@
-module CacheMethod
- class Cache
- class Epoch
- class << self
- def mark_passing(options = {})
- e = new options
- e.mark_passing
- end
- def current(options = {})
- e = new options
- e.current
- end
- end
-
- def initialize(options = {})
- options.each do |k, v|
- instance_variable_set "@#{k}", v
- end
- end
-
- attr_reader :obj
- attr_reader :method_id
-
- def method_signature
- @method_signature ||= Key.method_signature(obj, method_id)
- end
-
- def obj_hash
- @obj_hash ||= obj.hash
- end
-
- def cache_key
- [ 'CacheMethod', method_signature, obj_hash ].join ','
- end
-
- def current
- Cache.instance.get(cache_key).to_i
- end
-
- def mark_passing
- Cache.instance.set cache_key, (current+1), 0
- end
- end
- end
-end
@@ -1,56 +0,0 @@
-require 'digest/md5'
-module CacheMethod
- class Cache
- class Key
- class << self
- def digest(*ary)
- ::Digest::MD5.hexdigest ary.flatten.map { |i| i.to_s }.join
- end
- def parse(str)
- method_signature, epoch, obj_hash, args_digest = str.split ','
- new :method_signature => method_signature, :epoch => epoch, :obj_hash => obj_hash, :args_digest => args_digest
- end
- def klass_name(obj)
- obj.is_a?(::Class) ? obj.to_s : obj.class.to_s
- end
- def method_delimiter(obj)
- obj.is_a?(::Class) ? '.' : '#'
- end
- def method_signature(obj, method_id)
- [ klass_name(obj), method_id ].join method_delimiter(obj)
- end
- end
-
- def initialize(options = {})
- options.each do |k, v|
- instance_variable_set "@#{k}", v
- end
- end
-
- attr_reader :obj
- attr_reader :method_id
- attr_reader :args
-
- def obj_hash
- @obj_hash ||= obj.hash
- end
-
- def args_digest
- @args_digest ||= Key.digest(args)
- end
-
- def method_signature
- @method_signature ||= Key.method_signature(obj, method_id)
- end
-
- def epoch
- @epoch ||= Epoch.current(:obj => obj, :method_id => method_id)
- end
-
- def to_str
- [ method_signature, epoch, obj_hash, args_digest ].join ','
- end
- alias :to_s :to_str
- end
- end
-end
@@ -0,0 +1,56 @@
+require 'digest/md5'
+module CacheMethod
+ class CachedResult #:nodoc: all
+ class << self
+ def fetch(options = {})
+ cached_result = new options
+ cached_result.fetch
+ end
+ end
+
+ def initialize(options = {})
+ options.each do |k, v|
+ instance_variable_set "@#{k}", v
+ end
+ end
+
+ attr_reader :obj
+ attr_reader :method_id
+ attr_reader :original_method_id
+ attr_reader :args
+
+ def fetch
+ if v = Config.instance.storage.get(cache_key) and v.is_a?(::Array)
+ v[0]
+ else
+ v = obj.send original_method_id, *args
+ Config.instance.storage.set cache_key, [v], ttl
+ v
+ end
+ end
+
+ def ttl
+ @ttl ||= Config.instance.default_ttl
+ end
+
+ def cache_key
+ [ method_signature, current_epoch, obj_hash, args_digest ].join ','
+ end
+
+ def method_signature
+ @method_signature ||= ::CacheMethod.method_signature(obj, method_id)
+ end
+
+ def obj_hash
+ @obj_hash ||= obj.hash
+ end
+
+ def args_digest
+ @args_digest ||= ::Digest::MD5.hexdigest(args.flatten.join)
+ end
+
+ def current_epoch
+ @current_epoch ||= Epoch.current(:obj => obj, :method_id => method_id)
+ end
+ end
+end
@@ -1,3 +1,4 @@
+require 'cache'
require 'singleton'
module CacheMethod
# Here's where you set config options.
@@ -20,10 +21,12 @@ class Config
# Supported Redis clients:
# * redis[https://github.com/ezmobius/redis-rb]
#
+ # Uses the cache[https://github.com/seamusabshere/cache] gem to wrap these, so support depends on that gem
+ #
# Example:
# CacheMethod.config.storage = Memcached.new '127.0.0.1:11211'
- def storage=(storage)
- @storage = storage
+ def storage=(raw_client)
+ @storage = ::Cache.new raw_client
end
def storage #:nodoc:
Oops, something went wrong.

0 comments on commit 21faf0e

Please sign in to comment.