taggable_cache 0.2.1 → 0.3.0

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.
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'