taggable_cache 0.4.2 → 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.travis.yml +15 -2
- data/CHANGELOG.md +6 -0
- data/README.rdoc +27 -12
- data/gemfiles/Gemfile.shared +3 -2
- data/lib/taggable_cache.rb +19 -0
- data/lib/taggable_cache/extensions/action_controller.rb +12 -17
- data/lib/taggable_cache/extensions/active_record.rb +9 -11
- data/lib/taggable_cache/extensions/cache_store.rb +45 -37
- data/lib/taggable_cache/railtie.rb +2 -1
- data/lib/taggable_cache/store/base.rb +9 -9
- data/lib/taggable_cache/store/redis.rb +16 -5
- data/lib/taggable_cache/version.rb +1 -1
- data/spec/integration/rails_cache_spec.rb +35 -4
- data/spec/spec_helper.rb +6 -2
- data/spec/taggable-cache/settings_spec.rb +38 -6
- data/spec/taggable-cache/store_spec.rb +36 -9
- metadata +15 -31
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cdaec20312f2c8794e73619e4abb0a2e2c7b3510
|
4
|
+
data.tar.gz: 8c3793e1730ea5081398435d07d725b1d688f9ed
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0f209d642abb7b5d4f1d8d920aae6b1ef1439ca248008e17b22c5d92a5f5ea8971eaf681185bc8ec4dd8225a34c4c989650c4086ea463b6f3c0ddfc1a223e36a
|
7
|
+
data.tar.gz: 16ef5e005b31351642da8a4953840c56c2ab432bec26103ccf2373f29a4907e88ad0ff29523008ec5363d7f5eea02e4f50aa727728a41e4d56d5178c60cfbc71
|
data/.travis.yml
CHANGED
@@ -1,11 +1,24 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
2
|
+
|
3
|
+
before_install:
|
4
|
+
- mkdir -p tmp/cache
|
5
|
+
- mkdir -p spec/internal/db
|
6
|
+
- memcached -p 11212 &
|
7
|
+
|
8
|
+
services:
|
9
|
+
- redis-server
|
10
|
+
|
3
11
|
rvm:
|
4
12
|
- 1.9.3
|
13
|
+
- 2.0.0
|
14
|
+
|
5
15
|
gemfile:
|
6
16
|
- gemfiles/Gemfile-rails.3.1.x
|
7
17
|
- gemfiles/Gemfile-rails.3.2.x
|
18
|
+
|
8
19
|
env:
|
9
20
|
- CACHE_STORE=redis
|
10
21
|
- CACHE_STORE=memcached
|
11
|
-
- CACHE_STORE=file_store
|
22
|
+
- CACHE_STORE=file_store
|
23
|
+
- CACHE_STORE=memory_store
|
24
|
+
- CACHE_STORE=dalli
|
data/CHANGELOG.md
CHANGED
data/README.rdoc
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
= Taggable cache
|
1
|
+
= Taggable cache {<img src="https://secure.travis-ci.org/brain-geek/taggable-cache.png"/>}[http://travis-ci.org/brain-geek/taggable-cache]
|
2
2
|
|
3
|
-
This gem simplifies cache expiration in rails by adding depends_on
|
3
|
+
This gem simplifies cache expiration in rails by adding depends_on parameter to rails cache setting, which makes cache element expire when depending object is changed.
|
4
4
|
|
5
|
-
= Build Status {<img src="https://secure.travis-ci.org/brain-geek/taggable-cache.png"/>}[http://travis-ci.org/brain-geek/taggable-cache]
|
6
5
|
= How to use
|
7
|
-
|
6
|
+
Taggable-cache uses redis to store cache tags data. You can use anything for an actual cache storage. {RDoc}[http://rdoc.info/github/brain-geek/taggable-cache/master/frames]
|
8
7
|
|
9
8
|
Controller(action caching):
|
10
9
|
|
@@ -13,22 +12,22 @@ Controller(action caching):
|
|
13
12
|
def index
|
14
13
|
Page.load_lot_of_data
|
15
14
|
|
16
|
-
#this depends on any Page object change - creation, deletion,
|
15
|
+
#this depends on any Page object change - creation, deletion, update
|
17
16
|
depends_on Page
|
18
17
|
end
|
19
18
|
|
20
19
|
View(fragment caching):
|
21
20
|
|
22
21
|
<%# Page.active can be AR scope, every Page object on change is checked if it is in this scope, and if is - expires cache element %>
|
23
|
-
<% cache 'cache_entry', :depends_on =>
|
22
|
+
<% cache 'cache_entry', :depends_on => Page.active do %>
|
24
23
|
<% Page.load_lot_of_data %>
|
25
24
|
<% end %>
|
26
25
|
|
27
26
|
Usage with Rails.cache:
|
28
27
|
|
29
28
|
page = Page.first
|
30
|
-
#this cache key expires only
|
31
|
-
Rails.cache.write('key', 'value', :depends_on =>
|
29
|
+
#this cache key expires only when this Page object is changed/deleted
|
30
|
+
Rails.cache.write('key', 'value', :depends_on => page)
|
32
31
|
|
33
32
|
Usage with cells gem:
|
34
33
|
|
@@ -42,14 +41,31 @@ Usage with cells gem:
|
|
42
41
|
|
43
42
|
If you are using redis for cache, it is recommended to set default expire_ttl value:
|
44
43
|
|
45
|
-
|
44
|
+
config.cache_store = ActiveSupport::Cache::RedisStore.new(:expire_in => 16.hours.to_i)
|
46
45
|
|
47
46
|
== What is supported
|
48
47
|
|
49
|
-
Rails 3.1.x and 3.2.x are supported. Tested with ruby 1.9.3
|
48
|
+
Rails 3.1.x and 3.2.x are both supported. Tested with ruby 1.9.3. Cache storage engines tested:
|
49
|
+
- {redis}[https://github.com/jodosha/redis-store]
|
50
|
+
- {dalli}[https://github.com/mperham/dalli]
|
51
|
+
- {memcached-client}[https://github.com/mperham/memcache-client]
|
52
|
+
- Rails file store
|
53
|
+
- Rails memory store
|
54
|
+
|
55
|
+
Other cache storages should work but have not been tested by author.
|
56
|
+
|
57
|
+
== Customizing store backend options
|
58
|
+
|
59
|
+
You can set custom host/port or store in taggable:
|
60
|
+
|
61
|
+
TaggableCache.settings = {
|
62
|
+
:store => :redis,
|
63
|
+
:host => '127.0.0.1',
|
64
|
+
:port => 6379
|
65
|
+
}
|
50
66
|
|
51
67
|
== Contributing to taggable-cache
|
52
|
-
|
68
|
+
|
53
69
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
54
70
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
55
71
|
* Fork the project.
|
@@ -60,4 +76,3 @@ Rails 3.1.x and 3.2.x are supported. Tested with ruby 1.9.3, but should work on
|
|
60
76
|
== Copyright
|
61
77
|
|
62
78
|
Copyright (c) 2012 Alex Rozumey. See LICENSE.txt for further details.
|
63
|
-
|
data/gemfiles/Gemfile.shared
CHANGED
data/lib/taggable_cache.rb
CHANGED
@@ -1,6 +1,25 @@
|
|
1
1
|
require 'rails'
|
2
2
|
|
3
3
|
module TaggableCache
|
4
|
+
def settings
|
5
|
+
@@settings ||= {:store => :redis, :host => '127.0.0.1', :port => 6379}
|
6
|
+
end
|
7
|
+
|
8
|
+
def settings=(value)
|
9
|
+
@@settings = value
|
10
|
+
end
|
11
|
+
|
12
|
+
# Creates new Taggable store instance based on current settings
|
13
|
+
def new_store
|
14
|
+
params = settings.dup
|
15
|
+
params.delete(:store)
|
16
|
+
|
17
|
+
cls = Store::const_get(settings[:store].to_s.camelize)
|
18
|
+
|
19
|
+
cls.send(:new, params)
|
20
|
+
end
|
21
|
+
|
22
|
+
extend self
|
4
23
|
end
|
5
24
|
|
6
25
|
require 'taggable_cache/store'
|
@@ -1,25 +1,20 @@
|
|
1
1
|
module TaggableCache
|
2
2
|
module ActionControllerExtension
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
(x.kind == :around) &&
|
9
|
-
(x.raw_filter.is_a? ActionController::Caching::Actions::ActionCacheFilter) }.each do |callback|
|
10
|
-
cache_path = callback.raw_filter.instance_variable_get('@cache_path')
|
3
|
+
def depends_on(*keys)
|
4
|
+
_process_action_callbacks.find_all{|x|
|
5
|
+
(x.kind == :around) &&
|
6
|
+
(x.raw_filter.is_a? ActionController::Caching::Actions::ActionCacheFilter) }.each do |callback|
|
7
|
+
cache_path = callback.raw_filter.instance_variable_get('@cache_path')
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
path_options = if cache_path.respond_to?(:call)
|
10
|
+
instance_exec(self, &cache_path)
|
11
|
+
else
|
12
|
+
cache_path
|
13
|
+
end
|
17
14
|
|
18
|
-
|
15
|
+
path_options = ::ActionController::Caching::Actions::ActionCachePath.new(self, path_options || {}).path
|
19
16
|
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
17
|
+
Rails.cache.add_tags(fragment_cache_key(path_options), *keys)
|
23
18
|
end
|
24
19
|
end
|
25
20
|
end
|
@@ -1,16 +1,15 @@
|
|
1
1
|
module TaggableCache
|
2
2
|
module ActiveRecordExtension
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
included do
|
5
|
-
# Future subclasses will pick up the model extension
|
6
|
-
class << self
|
7
|
-
def inherited_with_taggable(kls)
|
8
|
-
inherited_without_taggable kls
|
9
|
-
kls.send(:include, TaggableCache::ActiveRecordModelExtension) if kls.superclass == ActiveRecord::Base
|
10
|
-
end
|
11
|
-
alias_method_chain :inherited, :taggable
|
12
|
-
end
|
13
4
|
|
5
|
+
module ClassMethods
|
6
|
+
def inherited(kls)
|
7
|
+
kls.send(:include, TaggableCache::ActiveRecordModelExtension) if kls.superclass == ActiveRecord::Base
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
included do
|
14
13
|
# Existing subclasses pick up the model extension as well
|
15
14
|
self.descendants.each do |kls|
|
16
15
|
kls.send(:include, TaggableCache::ActiveRecordModelExtension) if kls.superclass == ActiveRecord::Base
|
@@ -18,13 +17,12 @@ module TaggableCache
|
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
|
-
|
22
20
|
module ActiveRecordModelExtension
|
23
21
|
extend ActiveSupport::Concern
|
24
22
|
def self.included(base)
|
25
23
|
[:after_update, :before_update, :before_destroy, :after_create].each do |event|
|
26
24
|
base.send(event, Proc.new do |model|
|
27
|
-
Rails.cache.
|
25
|
+
Rails.cache.expire_tags(model, model.class)
|
28
26
|
end)
|
29
27
|
end
|
30
28
|
end
|
@@ -1,55 +1,63 @@
|
|
1
1
|
module TaggableCache
|
2
2
|
module CacheStoreExtension
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
def self.included(base)
|
5
|
-
base.class_eval do
|
6
|
-
def taggable
|
7
|
-
@taggable ||= ::TaggableCache::Store::Redis.new
|
8
|
-
end
|
9
|
-
|
10
|
-
def write_with_taggable(name, value, options = nil)
|
11
|
-
if !options.nil? && options.has_key?(:depends_on)
|
12
|
-
add_tags(name, *options[:depends_on])
|
13
|
-
end
|
14
4
|
|
15
|
-
|
16
|
-
|
5
|
+
def taggable
|
6
|
+
@taggable ||= TaggableCache.new_store
|
7
|
+
end
|
17
8
|
|
18
|
-
|
9
|
+
# Add tag to cache element
|
10
|
+
def add_tags(key, *params)
|
11
|
+
taggable.add(key, *params)
|
12
|
+
end
|
19
13
|
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
# Expire cache elements by list of keys
|
15
|
+
def expire_tags(*params)
|
16
|
+
taggable.get(*params).each do |m|
|
17
|
+
self.delete(m)
|
18
|
+
end
|
19
|
+
end
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
# Expire all cache entries availible for taggable
|
22
|
+
# WARNING: this is expensive function and may take VERY long on big data
|
23
|
+
def expire_all
|
24
|
+
#Load all the models
|
25
|
+
Dir.glob(Rails.root + '/app/models/*.rb').each {|file| require file}
|
26
|
+
|
27
|
+
ActiveRecord::Base.subclasses.each do |cls|
|
28
|
+
expire_tags cls
|
28
29
|
|
29
|
-
|
30
|
-
self.delete(m)
|
31
|
-
end
|
32
|
-
end
|
30
|
+
pk_name = cls.primary_key
|
33
31
|
|
34
|
-
|
35
|
-
#Load all the models
|
36
|
-
Dir.glob(Rails.root + '/app/models/*.rb').each {|file| require file}
|
37
|
-
|
38
|
-
ActiveRecord::Base.subclasses.each do |cls|
|
39
|
-
delete_by_tags cls
|
32
|
+
return if cls.unscoped.first.nil? #There is no sence in continuing, if model is empty
|
40
33
|
|
41
|
-
|
34
|
+
last_id = cls.order(pk_name).last.try(pk_name.to_sym)
|
42
35
|
|
43
|
-
|
36
|
+
#hardcoded value for first record
|
37
|
+
first_id = 1
|
44
38
|
|
45
|
-
|
46
|
-
|
39
|
+
(first_id..last_id).each do |id|
|
40
|
+
expire_tags({:cls => cls, :id => id})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
47
44
|
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
included do |base|
|
46
|
+
base.class_eval do
|
47
|
+
# Returns taggable store instance
|
48
|
+
def write_with_taggable(name, value, options = {})
|
49
|
+
begin
|
50
|
+
k = namespaced_key(name, options)
|
51
|
+
rescue
|
52
|
+
k = name
|
51
53
|
end
|
54
|
+
|
55
|
+
add_tags(k, *options[:depends_on]) if options.has_key?(:depends_on)
|
56
|
+
|
57
|
+
write_without_taggable(name, value, options)
|
52
58
|
end
|
59
|
+
|
60
|
+
alias_method_chain :write, :taggable
|
53
61
|
end
|
54
62
|
end
|
55
63
|
end
|
@@ -9,8 +9,9 @@ module TaggableCache
|
|
9
9
|
::ActiveRecord::Base.send :include, TaggableCache::ActiveRecordExtension
|
10
10
|
::ActionController::Base.send :include, TaggableCache::ActionControllerExtension
|
11
11
|
|
12
|
-
::ActiveSupport::Cache::
|
12
|
+
::ActiveSupport::Cache::DalliStore.send :include, TaggableCache::CacheStoreExtension if defined? ::ActiveSupport::Cache::DalliStore
|
13
13
|
::ActiveSupport::Cache::RedisStore.send :include, TaggableCache::CacheStoreExtension if defined? ::ActiveSupport::Cache::RedisStore
|
14
|
+
::ActiveSupport::Cache::Store.send :include, TaggableCache::CacheStoreExtension
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module TaggableCache::Store
|
2
2
|
class Base
|
3
|
+
# Returns taggable cache unique id for object
|
3
4
|
def id_for(obj)
|
4
5
|
if obj.is_a? Class
|
5
6
|
obj.to_s.downcase
|
@@ -13,6 +14,8 @@ module TaggableCache::Store
|
|
13
14
|
"query-keys-#{Digest::MD5.hexdigest(obj.to_sql)}"
|
14
15
|
elsif obj.is_a? ActiveRecord::Relation
|
15
16
|
id_for(obj.arel)
|
17
|
+
elsif obj.is_a? String
|
18
|
+
"string_#{obj.to_s}"
|
16
19
|
elsif obj.is_a? Hash
|
17
20
|
if obj.include?(:cls) && obj.include?(:id)
|
18
21
|
"#{obj[:cls].to_s.downcase}-#{obj[:id]}"
|
@@ -24,10 +27,12 @@ module TaggableCache::Store
|
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
30
|
+
# Checks if this is AR scope
|
27
31
|
def is_scope?(scope)
|
28
32
|
(scope.is_a? ActiveRecord::Relation) || (scope.is_a? Arel::SelectManager)
|
29
33
|
end
|
30
34
|
|
35
|
+
# Checks if object is in given scope
|
31
36
|
def in_scope?(scope, object)
|
32
37
|
return false unless object.persisted?
|
33
38
|
|
@@ -36,24 +41,19 @@ module TaggableCache::Store
|
|
36
41
|
object.class.connection.select_all(query).length > 0
|
37
42
|
end
|
38
43
|
|
39
|
-
|
44
|
+
#:nodoc:
|
45
|
+
def initialize(attrs = {})
|
40
46
|
raise ActionController::NotImplemented.new
|
41
47
|
end
|
42
48
|
|
49
|
+
#:nodoc:
|
43
50
|
def add(tag, *members)
|
44
51
|
raise ActionController::NotImplemented.new
|
45
52
|
end
|
46
53
|
|
54
|
+
#:nodoc:
|
47
55
|
def get(*members)
|
48
56
|
raise ActionController::NotImplemented.new
|
49
57
|
end
|
50
|
-
|
51
|
-
def add_scope(tag, scope)
|
52
|
-
raise ActionController::NotImplemented.new
|
53
|
-
end
|
54
|
-
|
55
|
-
def get_scope(*members)
|
56
|
-
raise ActionController::NotImplemented.new
|
57
|
-
end
|
58
58
|
end
|
59
59
|
end
|
@@ -3,11 +3,11 @@ require "digest/md5"
|
|
3
3
|
|
4
4
|
module TaggableCache::Store
|
5
5
|
class Redis < TaggableCache::Store::Base
|
6
|
-
def initialize
|
7
|
-
@redis = ::Redis.new
|
8
|
-
:port => ENV['REDIS_PORT'] ? ENV['REDIS_PORT'].to_i : 6379
|
6
|
+
def initialize(attrs = {})
|
7
|
+
@redis = ::Redis.new attrs
|
9
8
|
end
|
10
9
|
|
10
|
+
# Add tag to multiple cache entries
|
11
11
|
def add(tag, *members)
|
12
12
|
members.each do |element|
|
13
13
|
add_scope(tag, element) if is_scope? element
|
@@ -16,13 +16,24 @@ module TaggableCache::Store
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
# Get cache entries by given keys.
|
20
|
+
# This list is cleaned up after request:
|
21
|
+
# page = Page.create
|
22
|
+
# store.add('tag_name', page)
|
23
|
+
# store.get_scope(p).should == ['tag_name']
|
24
|
+
# store.get_scope(p).should == []
|
19
25
|
def get(*members)
|
20
26
|
keys = members.map { |tag| id_for(tag) }
|
21
27
|
elements = @redis.sunion(keys)
|
22
28
|
@redis.del(keys)
|
23
|
-
|
29
|
+
|
30
|
+
scopes = members.delete_if {|a| not a.is_a? ActiveRecord::Base}
|
31
|
+
|
32
|
+
elements += get_scope(*scopes)
|
33
|
+
elements.flatten.uniq.compact
|
24
34
|
end
|
25
35
|
|
36
|
+
protected
|
26
37
|
def add_scope(tag, scope)
|
27
38
|
scope = scope.arel if scope.is_a? ActiveRecord::Relation
|
28
39
|
table_name = scope.froms.first.name
|
@@ -49,7 +60,7 @@ module TaggableCache::Store
|
|
49
60
|
end
|
50
61
|
end
|
51
62
|
|
52
|
-
keys
|
63
|
+
keys
|
53
64
|
end
|
54
65
|
end
|
55
66
|
end
|
@@ -2,8 +2,8 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
|
2
2
|
|
3
3
|
describe 'TaggableCache::Rails::Cache' do
|
4
4
|
before :all do
|
5
|
-
@object = TaggableCache
|
6
|
-
@page_object = Page.create
|
5
|
+
@object = TaggableCache.new_store
|
6
|
+
@page_object = Page.create!
|
7
7
|
end
|
8
8
|
|
9
9
|
before :each do
|
@@ -21,6 +21,16 @@ describe 'TaggableCache::Rails::Cache' do
|
|
21
21
|
Rails.cache.write 'ipsum', 'lorem'
|
22
22
|
Rails.cache.read('ipsum').should == 'lorem'
|
23
23
|
end
|
24
|
+
|
25
|
+
it "does expire for namespaced key" do
|
26
|
+
Rails.cache.write('key', 'val', :namespace => 'lorem ipsum', :depends_on => @page_object)
|
27
|
+
|
28
|
+
Rails.cache.read('key', :namespace => 'lorem ipsum').should == 'val'
|
29
|
+
|
30
|
+
@page_object.save!
|
31
|
+
|
32
|
+
Rails.cache.read('key', :namespace => 'lorem ipsum').should be_nil
|
33
|
+
end
|
24
34
|
end
|
25
35
|
|
26
36
|
describe "Rails.cache.fetch integration" do
|
@@ -39,7 +49,6 @@ describe 'TaggableCache::Rails::Cache' do
|
|
39
49
|
|
40
50
|
Rails.cache.read('ftch_ipsum').should == 'lorem ipsum'
|
41
51
|
|
42
|
-
@page_object.name = 'dfgsdgsdfgsdfg'
|
43
52
|
@page_object.save!
|
44
53
|
|
45
54
|
Rails.cache.read('ftch_ipsum').should be_nil
|
@@ -56,6 +65,29 @@ describe 'TaggableCache::Rails::Cache' do
|
|
56
65
|
|
57
66
|
Rails.cache.read('ftch_ipsum2').should be_nil
|
58
67
|
end
|
68
|
+
|
69
|
+
it "does combined expires" do
|
70
|
+
page = Page.create!
|
71
|
+
Rails.cache.fetch 'ftch_ipsum3', :depends_on => [page, @page_object] do
|
72
|
+
'lorem ipsum di'
|
73
|
+
end
|
74
|
+
|
75
|
+
Rails.cache.read('ftch_ipsum3').should == 'lorem ipsum di'
|
76
|
+
|
77
|
+
@page_object.save!
|
78
|
+
|
79
|
+
Rails.cache.read('ftch_ipsum3').should be_nil
|
80
|
+
|
81
|
+
Rails.cache.fetch 'ftch_ipsum3', :depends_on => [page, @page_object] do
|
82
|
+
'lorem ipsum di'
|
83
|
+
end
|
84
|
+
|
85
|
+
Rails.cache.read('ftch_ipsum3').should == 'lorem ipsum di'
|
86
|
+
|
87
|
+
page.save!
|
88
|
+
|
89
|
+
Rails.cache.read('ftch_ipsum3').should be_nil
|
90
|
+
end
|
59
91
|
end
|
60
92
|
|
61
93
|
describe "Activerecord integration" do
|
@@ -65,7 +97,6 @@ describe 'TaggableCache::Rails::Cache' do
|
|
65
97
|
Rails.cache.read('key').should == 'value'
|
66
98
|
|
67
99
|
#save should trigger deleting depending cache entries
|
68
|
-
@page_object.name = @page_object.name.to_s + '1'
|
69
100
|
@page_object.save!
|
70
101
|
|
71
102
|
Rails.cache.read('key').should be_nil
|
data/spec/spec_helper.rb
CHANGED
@@ -9,12 +9,16 @@ class Combustion::Application
|
|
9
9
|
when 'redis'
|
10
10
|
config.cache_store = :redis_store
|
11
11
|
when 'memcached'
|
12
|
-
config.cache_store = :mem_cache_store
|
12
|
+
config.cache_store = :mem_cache_store, "127.0.0.1:11212"
|
13
|
+
when 'memory_store'
|
14
|
+
config.cache_store = :memory_store
|
15
|
+
when 'dalli'
|
16
|
+
config.cache_store = :dalli_store, '127.0.0.1:11212'
|
13
17
|
when 'file_store'
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
17
|
-
Combustion.initialize!
|
21
|
+
Combustion.initialize! :all
|
18
22
|
|
19
23
|
require 'rspec/rails'
|
20
24
|
require 'capybara/rails'
|
@@ -1,23 +1,55 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
2
|
|
3
3
|
describe TaggableCache::Store do
|
4
|
+
before :all do
|
5
|
+
Rails.cache
|
6
|
+
@cache_settings = TaggableCache.settings
|
7
|
+
end
|
8
|
+
|
4
9
|
after :all do
|
5
|
-
|
6
|
-
|
10
|
+
TaggableCache.settings = @cache_settings
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_cache_instance
|
14
|
+
Rails.cache.class.new({})
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have default variables" do
|
18
|
+
TaggableCache.settings[:store].should == :redis
|
19
|
+
TaggableCache.settings[:host].should == '127.0.0.1'
|
20
|
+
TaggableCache.settings[:port].should == 6379
|
7
21
|
end
|
8
22
|
|
9
23
|
it "should fall back to defaults if no settings given" do
|
24
|
+
Redis.should_receive(:new) if Rails.cache.is_a? ActiveSupport::Cache::RedisStore
|
10
25
|
Redis.should_receive(:new).with(:host => '127.0.0.1', :port => 6379)
|
11
26
|
|
12
|
-
|
27
|
+
new_cache_instance.taggable
|
13
28
|
end
|
14
29
|
|
15
30
|
it "should use ENV settings" do
|
16
|
-
|
17
|
-
|
31
|
+
TaggableCache.settings = {
|
32
|
+
:store => :redis,
|
33
|
+
:host => 'hostname.lvh.me',
|
34
|
+
:port => 1234
|
35
|
+
}
|
18
36
|
|
37
|
+
Redis.should_receive(:new) if Rails.cache.is_a? ActiveSupport::Cache::RedisStore
|
19
38
|
Redis.should_receive(:new).with(:host => 'hostname.lvh.me', :port => 1234)
|
20
39
|
|
21
|
-
|
40
|
+
new_cache_instance.taggable
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should use 'store' option to detect which class to create" do
|
44
|
+
TaggableCache.settings = {
|
45
|
+
:store => :base,
|
46
|
+
:first => 'hostname.lvh.me',
|
47
|
+
:second => 1234,
|
48
|
+
:third => 'asads'
|
49
|
+
}
|
50
|
+
|
51
|
+
TaggableCache::Store::Base.should_receive(:new).with(:first => 'hostname.lvh.me', :second => 1234, :third => 'asads')
|
52
|
+
|
53
|
+
new_cache_instance.taggable
|
22
54
|
end
|
23
55
|
end
|
@@ -4,13 +4,13 @@ describe TaggableCache::Store do
|
|
4
4
|
describe "connection to redis" do
|
5
5
|
it "should use default settings" do
|
6
6
|
Redis.should_receive(:new)
|
7
|
-
TaggableCache
|
7
|
+
TaggableCache.new_store
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "adding tags" do
|
12
12
|
before :all do
|
13
|
-
@object = TaggableCache
|
13
|
+
@object = TaggableCache.new_store
|
14
14
|
@redis = Redis.new
|
15
15
|
@redis.flushall
|
16
16
|
end
|
@@ -52,6 +52,10 @@ describe TaggableCache::Store do
|
|
52
52
|
@object.id_for({:id => 543}).should be_nil
|
53
53
|
@object.id_for({:sdfasdf => 345}).should be_nil
|
54
54
|
end
|
55
|
+
|
56
|
+
it "should allow string values as keys" do
|
57
|
+
@object.id_for('lorem').should == 'string_lorem'
|
58
|
+
end
|
55
59
|
end
|
56
60
|
|
57
61
|
describe "is_scope?" do
|
@@ -100,15 +104,15 @@ describe TaggableCache::Store do
|
|
100
104
|
@object.in_scope?(Page.order(:id), Page.new).should be_false
|
101
105
|
end
|
102
106
|
|
103
|
-
describe "
|
107
|
+
describe "get" do
|
104
108
|
it "should return keys and leave nothing behind" do
|
105
109
|
#query to get all keys
|
106
110
|
p = Page.create
|
107
111
|
page = Page.order(:id)
|
108
112
|
|
109
113
|
@object.add('tag_name', page)
|
110
|
-
@object.
|
111
|
-
@object.
|
114
|
+
@object.get(p).should == ['tag_name']
|
115
|
+
@object.get(p).should == []
|
112
116
|
end
|
113
117
|
|
114
118
|
it "should do multi-get" do
|
@@ -120,9 +124,32 @@ describe TaggableCache::Store do
|
|
120
124
|
@object.add('jack', Page.where(:name => 'jack'))
|
121
125
|
@object.add('ian', Page.where(:name => 'ian'))
|
122
126
|
|
123
|
-
@object.
|
124
|
-
@object.
|
125
|
-
@object.
|
127
|
+
@object.get(bob,jack).should == ['bob', 'jack']
|
128
|
+
@object.get(bob,jack).should == []
|
129
|
+
@object.get(ian).should == ['ian']
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should be able to mix both scope and simple element results" do
|
133
|
+
bob = Page.create(:name => 'bob')
|
134
|
+
jack = Page.create(:name => 'jack')
|
135
|
+
Page.create(:name => 'ian')
|
136
|
+
|
137
|
+
@object.add('bob', Page.where(:name => 'bob'))
|
138
|
+
@object.add('jack', jack)
|
139
|
+
|
140
|
+
@object.get(bob,jack).should =~ ['bob', 'jack']
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should not duplicate keys" do
|
144
|
+
bob = Page.create(:name => 'bob')
|
145
|
+
jack = Page.create(:name => 'jack')
|
146
|
+
ian = Page.create(:name => 'ian')
|
147
|
+
|
148
|
+
@object.add('bob', Page.where('name is NOT NULL'))
|
149
|
+
@object.add('jack', Page.where(:name => 'jack'))
|
150
|
+
@object.add('ian', Page.where(:name => 'ian'))
|
151
|
+
|
152
|
+
@object.get(bob,jack,ian).should == ['bob', 'jack', 'ian']
|
126
153
|
end
|
127
154
|
end
|
128
155
|
end
|
@@ -164,7 +191,7 @@ describe TaggableCache::Store do
|
|
164
191
|
@redis.smembers("page-#{page.id}").should == ['tag_name']
|
165
192
|
@redis.smembers("page").should == ['tag2']
|
166
193
|
|
167
|
-
@object.get(page, Page).should
|
194
|
+
@object.get(page, Page).should =~ ['tag_name', 'tag2']
|
168
195
|
@redis.smembers("page-#{page.id}").should be_empty
|
169
196
|
@redis.smembers("page").should be_empty
|
170
197
|
end
|
metadata
CHANGED
@@ -1,78 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: taggable_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: '0.5'
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Alex Rozumey
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2013-06-29 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: railties
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 3.1.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 3.1.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: actionpack
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 3.1.0
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 3.1.0
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: activerecord
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 3.1.0
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 3.1.0
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: redis
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: 2.2.0
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: 2.2.0
|
78
69
|
description: It makes cache expiration in rails much simpler
|
@@ -121,32 +112,25 @@ files:
|
|
121
112
|
homepage: http://github.com/brain-geek/taggable-cache
|
122
113
|
licenses:
|
123
114
|
- MIT
|
115
|
+
metadata: {}
|
124
116
|
post_install_message:
|
125
117
|
rdoc_options: []
|
126
118
|
require_paths:
|
127
119
|
- lib
|
128
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
121
|
requirements:
|
131
|
-
- -
|
122
|
+
- - '>='
|
132
123
|
- !ruby/object:Gem::Version
|
133
124
|
version: '0'
|
134
|
-
segments:
|
135
|
-
- 0
|
136
|
-
hash: -997136803
|
137
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
-
none: false
|
139
126
|
requirements:
|
140
|
-
- -
|
127
|
+
- - '>='
|
141
128
|
- !ruby/object:Gem::Version
|
142
129
|
version: '0'
|
143
|
-
segments:
|
144
|
-
- 0
|
145
|
-
hash: -997136803
|
146
130
|
requirements: []
|
147
131
|
rubyforge_project:
|
148
|
-
rubygems_version:
|
132
|
+
rubygems_version: 2.0.3
|
149
133
|
signing_key:
|
150
|
-
specification_version:
|
134
|
+
specification_version: 4
|
151
135
|
summary: This gem simplifies cache expiration in rails by expanding rails cache methods.
|
152
136
|
test_files: []
|