Skip to content

Commit

Permalink
merged caching_memcached and caching plugins in one file according to…
Browse files Browse the repository at this point in the history
… Jeremy

starting to write a spec supporting memcached (last test FAILED, I don't know why yet)
  • Loading branch information
Florent authored and Florent committed Oct 22, 2009
1 parent 8b9131e commit b99a1fa
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 133 deletions.
53 changes: 38 additions & 15 deletions lib/sequel/plugins/caching.rb
@@ -1,8 +1,8 @@
module Sequel
module Plugins
# Sequel's built-in caching plugin supports caching to any object that
# implements the Ruby-Memcache API. You can add caching for any model
# or for all models via:
# implements the Ruby-Memcache API (or memcached API with the :ignore_exceptions
# option). You can add caching for any model or for all models via:
#
# Model.plugin :caching, store # Cache all models
# MyModel.plugin :caching, store # Just cache MyModel
Expand All @@ -11,23 +11,32 @@ module Plugins
#
# cache_store.set(key, obj, time) # Associate the obj with the given key
# # in the cache for the time (specified
# # in seconds)
# cache_store.get(key) => obj # Returns object set with same key
# cache_store.get(key2) => nil # nil returned if there isn't an object
# # currently in the cache with that key
# # in seconds).
# cache_store.get(key) => obj # Returns object set with same key.
# cache_store.get(key2) => nil # nil returned if there isn't an object
# # currently in the cache with that key.
#
# If the :ignore_exceptions option is true, exceptions raised by cache_store.get
# are ignored and nil is returned instead. The memcached API is to
# raise an exception for a missing record, so if you use memcached, you will
# want to use this option.
module Caching
# Set the cache_store and cache_ttl attributes for the given model.
# If the :ttl option is not given, 3600 seconds is the default.
def self.configure(model, store, opts={})
model.instance_eval do
@cache_store = store
@cache_ttl = opts[:ttl] || 3600
@cache_ignore_exceptions = opts[:ignore_exceptions]
end
end

module ClassMethods
# If true, ignores exceptions when gettings cached records (the memcached API).
attr_reader :cache_ignore_exceptions

# The cache store object for the model, which should implement the
# Ruby-Memcache API
# Ruby-Memcache (or memcached) API
attr_reader :cache_store

# The time to live for the cache store, in seconds.
Expand All @@ -38,38 +47,52 @@ def set_cache_ttl(ttl)
@cache_ttl = ttl
end

# Copy the cache_store and cache_ttl to the subclass.
# Copy the necessary class instance variables to the subclass.
def inherited(subclass)
super
store = @cache_store
ttl = @cache_ttl
cache_ignore_exceptions = @cache_ignore_exceptions
subclass.instance_eval do
@cache_store = store
@cache_ttl = ttl
@cache_ignore_exceptions = cache_ignore_exceptions
end
end

private

# Delete the entry with the matching key from the cache
def cache_delete(key)
@cache_store.delete(key)
def cache_delete(ck)
@cache_store.delete(ck)
nil
end

def cache_get(ck)
if @cache_ignore_exceptions
@cache_store.get(ck) rescue nil
else
@cache_store.get(ck)
end
end

# Return a key string for the pk
def cache_key(pk)
"#{self}:#{Array(pk).join(',')}"
end

# Set the object in the cache_store with the given key for cache_ttl seconds.
def cache_set(ck, obj)
@cache_store.set(ck, obj, @cache_ttl)
end

# Check the cache before a database lookup unless a hash is supplied.
def primary_key_lookup(pk)
ck = cache_key(pk)
if obj = @cache_store.get(ck)
return obj
end
if obj = super(pk)
@cache_store.set(ck, obj, @cache_ttl)
unless obj = cache_get(ck)
if obj = super(pk)
cache_set(ck, obj)
end
end
obj
end
Expand Down
118 changes: 0 additions & 118 deletions lib/sequel/plugins/caching_memcached.rb

This file was deleted.

33 changes: 33 additions & 0 deletions spec/extensions/caching_spec.rb
Expand Up @@ -12,6 +12,14 @@ def get(k); self[k]; end
cache = @cache_class.new
@cache = cache

@memcached_class = Class.new(Hash) do
attr_accessor :ttl
def set(k, v, ttl); self[k] = v; @ttl = ttl; end
def get(k); if self[k] then return self[k]; else raise; end end
end
cache2 = @memcached_class.new
@memcached = cache2

@c = Class.new(Sequel::Model(:items))
@c.class_eval do
plugin :caching, cache
Expand All @@ -38,9 +46,18 @@ def delete
$sqls << delete_sql
end
})

@c2 = Class.new(@c) do
def self.name; 'SubItem' end
end

@c3 = Class.new(Sequel::Model(:items))
@c3.class_eval do
plugin :caching, @memcached
def self.name; 'Item' end

columns :name, :id
end
end

it "should set the model's cache store" do
Expand Down Expand Up @@ -205,4 +222,20 @@ def self.name; 'SubItem' end
"SELECT * FROM items WHERE (id = 1) LIMIT 1", \
"SELECT * FROM items WHERE (id = 4) LIMIT 1"]
end

it "should support ignore_exception option" do
c = Class.new(Sequel::Model(:items))
c.plugin :caching, @cache, :ignore_exceptions => true
Class.new(c).cache_ignore_exceptions.should == true
end

it "should raise an exception if cache_store is not memcached and ignore_exception is enabled" do
@c3[:id => 1].should raise_error
end

it "should rescue an exception if cache_store is memcached and ignore_exception is enabled" do
c = Class.new(Sequel::Model(:items))
c.plugin :caching, @memcached, :ignore_exceptions => true
c[:id => 1].should be_nil
end
end

0 comments on commit b99a1fa

Please sign in to comment.