taggable_cache 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -5,6 +5,5 @@ before_install:
5
5
  rvm:
6
6
  - 1.9.3
7
7
  gemfile:
8
- - gemfiles/Gemfile-rails.3.0.x
9
8
  - gemfiles/Gemfile-rails.3.1.x
10
- - gemfiles/Gemfile-rails.3.2.x
9
+ - gemfiles/Gemfile-rails.3.2.x
data/Gemfile CHANGED
@@ -11,7 +11,7 @@ gem 'rake'
11
11
  gem 'rspec-rails', :require => false
12
12
  gem 'rspec'
13
13
  gem 'capybara'
14
- gem 'combustion', :git => 'https://brain-geek@github.com/brain-geek/combustion.git' #, '~> 0.3.1'
14
+ gem 'combustion'
15
15
  gem 'sqlite3'
16
16
 
17
17
  gem 'rails', '~> 3.2.0'
data/Gemfile.lock CHANGED
@@ -1,16 +1,8 @@
1
- GIT
2
- remote: https://brain-geek@github.com/brain-geek/combustion.git
3
- revision: 3574c523d1ce6d8805ab2218c8d52257b5848640
4
- specs:
5
- combustion (0.3.2)
6
- rails (>= 3.0.0)
7
- thor (>= 0.14.6)
8
-
9
1
  PATH
10
2
  remote: .
11
3
  specs:
12
- taggable_cache (0.2.1)
13
- rails (>= 3.0.8)
4
+ taggable_cache (0.3.0)
5
+ rails (>= 3.1.0)
14
6
  redis (>= 2.2.2)
15
7
 
16
8
  GEM
@@ -55,6 +47,9 @@ GEM
55
47
  childprocess (0.3.1)
56
48
  ffi (~> 1.0.6)
57
49
  coderay (1.0.5)
50
+ combustion (0.3.2)
51
+ rails (>= 3.0.0)
52
+ thor (>= 0.14.6)
58
53
  diff-lcs (1.1.3)
59
54
  erubis (2.7.0)
60
55
  ffi (1.0.11)
@@ -142,7 +137,7 @@ PLATFORMS
142
137
 
143
138
  DEPENDENCIES
144
139
  capybara
145
- combustion!
140
+ combustion
146
141
  pry
147
142
  pry-nav
148
143
  rails (~> 3.2.0)
@@ -6,7 +6,7 @@ gem 'rake'
6
6
  gem 'rspec-rails', :require => false
7
7
  gem 'rspec'
8
8
  gem 'capybara'
9
- gem 'combustion', :git => 'https://brain-geek@github.com/brain-geek/combustion.git'
9
+ gem 'combustion'
10
10
  gem 'sqlite3'
11
11
 
12
12
 
@@ -6,7 +6,7 @@ gem 'rake'
6
6
  gem 'rspec-rails', :require => false
7
7
  gem 'rspec'
8
8
  gem 'capybara'
9
- gem 'combustion', :git => 'https://brain-geek@github.com/brain-geek/combustion.git'
9
+ gem 'combustion'
10
10
  gem 'sqlite3'
11
11
 
12
12
 
@@ -0,0 +1,5 @@
1
+ require "redis"
2
+
3
+ class TaggableCache::DynamicStore < TaggableCache::Store
4
+
5
+ end
@@ -27,6 +27,10 @@ ActiveSupport::Cache::Store.class_eval do
27
27
  taggable.get(*params).each do |m|
28
28
  self.delete(m)
29
29
  end
30
+
31
+ taggable.get_scope(*(params.delete_if{|a| not a.is_a? ActiveRecord::Base})).each do |m|
32
+ self.delete(m)
33
+ end
30
34
  end
31
35
  end
32
36
 
@@ -40,7 +44,6 @@ end
40
44
  module TaggableCache
41
45
  class Railtie < ::Rails::Railtie
42
46
  initializer "taggable_cache" do |app|
43
- # binding.pry
44
47
  ActiveRecord::Base.observers << TaggableCache::Spectator
45
48
  ActiveRecord::Base.add_observer TaggableCache::Spectator.instance
46
49
  end
@@ -4,6 +4,7 @@ class TaggableCache::Spectator < ActiveRecord::Observer
4
4
  end
5
5
 
6
6
  alias :after_update :event
7
- alias :after_destroy :event
7
+ alias :before_update :event
8
+ alias :before_destroy :event
8
9
  alias :after_create :event
9
10
  end
@@ -1,4 +1,5 @@
1
1
  require "redis"
2
+ require "digest/md5"
2
3
 
3
4
  class TaggableCache::Store
4
5
  def initialize
@@ -14,6 +15,10 @@ class TaggableCache::Store
14
15
  else
15
16
  id_for(obj.class)
16
17
  end
18
+ elsif obj.is_a? Arel::SelectManager
19
+ "query-keys-#{Digest::MD5.hexdigest(obj.to_sql)}"
20
+ elsif obj.is_a? ActiveRecord::Relation
21
+ id_for(obj.arel)
17
22
  else
18
23
  nil
19
24
  end
@@ -21,6 +26,7 @@ class TaggableCache::Store
21
26
 
22
27
  def add(tag, *members)
23
28
  members.each do |element|
29
+ add_scope(tag, element) if is_scope? element
24
30
  ident = id_for(element)
25
31
  @redis.sadd ident, tag unless ident.nil?
26
32
  end
@@ -34,4 +40,45 @@ class TaggableCache::Store
34
40
  elements
35
41
  end.flatten.compact
36
42
  end
43
+
44
+ def is_scope?(scope)
45
+ (scope.is_a? ActiveRecord::Relation) || (scope.is_a? Arel::SelectManager)
46
+ end
47
+
48
+ def add_scope(tag, scope)
49
+ scope = scope.arel if scope.is_a? ActiveRecord::Relation
50
+ table_name = scope.froms.first.name
51
+ query_fingerprint = Digest::MD5.hexdigest(scope.to_sql)
52
+
53
+ @redis.sadd "#{table_name}-scopes", "#{query_fingerprint}"
54
+ @redis.set "query-#{query_fingerprint}", Marshal.dump(scope)
55
+ end
56
+
57
+ def in_scope(scope, object)
58
+ return false unless object.persisted?
59
+
60
+ query = scope.where(scope.froms.first[:id].eq(object.id)).to_sql
61
+
62
+ object.class.connection.select_all(query).length > 0
63
+ end
64
+
65
+ def get_scope(*members)
66
+ keys = members.delete_if{|a| not a.is_a? ActiveRecord::Base }.map do |object|
67
+
68
+ table_redis_key = "#{object.class.table_name}-scopes"
69
+
70
+ @redis.smembers(table_redis_key).map do |scope_key|
71
+ scope = Marshal.restore(@redis.get("query-#{scope_key}"))
72
+
73
+ if in_scope(scope, object)
74
+ ident = "query-keys-#{scope_key}"
75
+ elements = @redis.smembers(ident)
76
+ @redis.del(ident)
77
+ elements
78
+ end
79
+ end
80
+ end
81
+
82
+ keys.flatten.compact
83
+ end
37
84
  end
@@ -1,3 +1,3 @@
1
1
  module TaggableCache
2
- VERSION = "0.2.1" # This is for the gem and does not conflict with the rest of the functionality
2
+ VERSION = "0.3.0" # This is for the gem and does not conflict with the rest of the functionality
3
3
  end
@@ -46,7 +46,7 @@ describe 'TaggableCache::Rails::Cache' do
46
46
  Rails.cache.read('lorem').should be_nil
47
47
  end
48
48
 
49
- pending "scope change" do
49
+ describe "scope change" do
50
50
  it "should not drop if changes are unrelated" do
51
51
  Rails.cache.write('lorem', 'impsum', :depends_on => [Page.where(:name => 'bob')])
52
52
  Rails.cache.read('lorem').should == 'impsum'
@@ -80,7 +80,7 @@ describe 'TaggableCache::Rails::Cache' do
80
80
  page.name = 'jack'
81
81
  page.save!
82
82
 
83
- Rails.cache.read('lorem').should be_nil
83
+ Rails.cache.read('lorem').should be_nil
84
84
  end
85
85
  end
86
86
  end
@@ -32,6 +32,86 @@ describe TaggableCache::Store do
32
32
  it "should return nil if unknown is passed" do
33
33
  @object.id_for(123).should be_nil
34
34
  end
35
+
36
+ it "should make hash of arel/AR::relation object" do
37
+ @object.id_for(Page.order(:id)).should == @object.id_for(Page.order(:id).arel)
38
+ @object.id_for(Page.order(:id)).should_not be_nil
39
+
40
+ @object.id_for(Page.order(:id)).should_not == @object.id_for(Page.order(:name).arel)
41
+ end
42
+ end
43
+
44
+ describe "is_scope?" do
45
+ it "is not AR object or class" do
46
+ @object.is_scope?(Page).should be_false
47
+ @object.is_scope?(Page.create).should be_false
48
+ end
49
+
50
+ it "is arel object or AR relation" do
51
+ @object.is_scope?(Page.order(:id)).should be_true
52
+ @object.is_scope?(Page.order(:id).arel).should be_true
53
+ end
54
+ end
55
+
56
+ describe "scope flow" do
57
+ before :each do
58
+ @redis.flushall
59
+ end
60
+
61
+ it "should add scope to model-specific set" do
62
+ @redis.smembers('pages-scopes').should == []
63
+ @object.add('tag_name', Page.where('name' => 'bob'))
64
+ @redis.smembers('pages-scopes').count.should == 1
65
+ end
66
+
67
+ it "should be a marshalized arel object in model-specific set" do
68
+ Page.create(:name => 'bob')
69
+ @object.add('tag_scoped', Page.where('name' => 'bob'))
70
+ key = @redis.smembers('pages-scopes').first
71
+ query = @redis.get("query-#{key}")
72
+ Marshal.restore(query).should be_kind_of Arel::SelectManager
73
+
74
+ @redis.smembers("query-keys-#{key}").should == ['tag_scoped']
75
+ end
76
+
77
+ it "should process 'in_scope' right way" do
78
+ bob = Page.create(:name => 'bob')
79
+ jack = Page.create(:name => 'jack')
80
+
81
+ @object.in_scope(Page.where(:name => 'bob'), bob).should be_true
82
+ @object.in_scope(Page.where(:name => 'bob'), jack).should be_false
83
+
84
+ @object.in_scope(Page.order(:id), Page.create).should be_true
85
+
86
+ #unsaved obj(without id)
87
+ @object.in_scope(Page.order(:id), Page.new).should be_false
88
+ end
89
+
90
+ describe "get_scope" do
91
+ it "should return keys and leave nothing behind" do
92
+ #query to get all keys
93
+ p = Page.create
94
+ page = Page.order(:id)
95
+
96
+ @object.add('tag_name', page)
97
+ @object.get_scope(p).should == ['tag_name']
98
+ @object.get_scope(p).should == []
99
+ end
100
+
101
+ it "should do multi-get" do
102
+ bob = Page.create(:name => 'bob')
103
+ jack = Page.create(:name => 'jack')
104
+ ian = Page.create(:name => 'ian')
105
+
106
+ @object.add('bob', Page.where(:name => 'bob'))
107
+ @object.add('jack', Page.where(:name => 'jack'))
108
+ @object.add('ian', Page.where(:name => 'ian'))
109
+
110
+ @object.get_scope(bob,jack).should == ['bob', 'jack']
111
+ @object.get_scope(bob,jack).should == []
112
+ @object.get_scope(ian).should == ['ian']
113
+ end
114
+ end
35
115
  end
36
116
 
37
117
  describe "Redis interaction" do
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
28
28
  s.rubygems_version = "1.8.15"
29
29
  s.summary = "This gem simplifies cache expiration in rails by providing depends_on option to rails cache."
30
30
 
31
- s.add_dependency(%q<rails>, [">= 3.0.8"])
31
+ s.add_dependency(%q<rails>, [">= 3.1.0"])
32
32
  s.add_dependency(%q<redis>, [">= 2.2.2"])
33
33
  end
34
34
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: taggable_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,18 +13,18 @@ date: 2012-02-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &81044650 !ruby/object:Gem::Requirement
16
+ requirement: &71322420 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 3.0.8
21
+ version: 3.1.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *81044650
24
+ version_requirements: *71322420
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis
27
- requirement: &81044090 !ruby/object:Gem::Requirement
27
+ requirement: &71321470 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: 2.2.2
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *81044090
35
+ version_requirements: *71321470
36
36
  description: This gem simplifies cache expiration in rails
37
37
  email: brain-geek@yandex.ua
38
38
  executables: []
@@ -48,10 +48,10 @@ files:
48
48
  - LICENSE.txt
49
49
  - README.rdoc
50
50
  - Rakefile
51
- - gemfiles/Gemfile-rails.3.0.x
52
51
  - gemfiles/Gemfile-rails.3.1.x
53
52
  - gemfiles/Gemfile-rails.3.2.x
54
53
  - lib/taggable_cache.rb
54
+ - lib/taggable_cache/dynamic_store.rb
55
55
  - lib/taggable_cache/railtie.rb
56
56
  - lib/taggable_cache/spectator.rb
57
57
  - lib/taggable_cache/store.rb
@@ -85,7 +85,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
85
  version: '0'
86
86
  segments:
87
87
  - 0
88
- hash: -685870733
88
+ hash: -516926623
89
89
  required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  none: false
91
91
  requirements:
@@ -94,10 +94,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
94
  version: '0'
95
95
  segments:
96
96
  - 0
97
- hash: -685870733
97
+ hash: -516926623
98
98
  requirements: []
99
99
  rubyforge_project:
100
- rubygems_version: 1.8.10
100
+ rubygems_version: 1.8.17
101
101
  signing_key:
102
102
  specification_version: 3
103
103
  summary: This gem simplifies cache expiration in rails by providing depends_on option
@@ -1,13 +0,0 @@
1
- source :rubygems
2
-
3
- gem 'taggable_cache', :path => '..'
4
-
5
- gem 'rake'
6
- gem 'rspec-rails', :require => false
7
- gem 'rspec'
8
- gem 'capybara'
9
- gem 'combustion', :git => 'https://brain-geek@github.com/brain-geek/combustion.git'
10
- gem 'sqlite3'
11
-
12
-
13
- gem 'rails', '~> 3.0.0'