simple_cacheable 1.3.3 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b46d1110354d90d106fe5abdfed1eaa6801dd7e4
4
- data.tar.gz: 763dac9a0c34135095974d09bb2575fbc5106ed2
3
+ metadata.gz: 84641f34cae9d9da455523484d0a802851c938ed
4
+ data.tar.gz: 951f43891133aa8e58d6235d686cc2427b407dcb
5
5
  SHA512:
6
- metadata.gz: f0fd40d41856c6efb7ecdfa1d8263ab2178b98c4cc8656d5bde2f3e67d71029c8cdebacf72a9d127abd775867d1d452fe86e8b122ec8f8adb315b9fab444999b
7
- data.tar.gz: 322aad0ed21db8769cc06557df6461f8e8a29ddad18597922a4410480dc71a3d639217ea07a88b3c861db899802b4cf05c615242dc5069a9aab55325bfb0983a
6
+ metadata.gz: 99d9989b5970e995a3212583ae721802d04e1acb6e5ca4384213083926e03235f97f663027c599cdc4bbaba28ba6d0fc832813e18df2e7439e6994ead01f2985
7
+ data.tar.gz: 8dd71f349161ed02e8f63482e9a0e9dd88f98c12cdbbd7e2555fe3a217a7099c29ff5ec414dd79f98e2835a88878503a75f5cc32640129d25d691a79e5d708c8
data/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ - 2.0.0
4
5
  env: DB=sqlite
5
6
  service:
6
7
  - memcached
data/ChangeLog CHANGED
@@ -1,3 +1,9 @@
1
+ 1.4.0
2
+ * Fixed after_commit silent failure for assocations that didn't exist
3
+ * Fixed association for has_many through when there are several belongs_to relationships
4
+ * Fixed multiple calls to model_cache
5
+ * Fixed STI/inheritance use cases
6
+
1
7
  1.3.3
2
8
  * File Reorganization
3
9
  * Rails 4 Compatibility
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_cacheable (1.3.2)
4
+ simple_cacheable (1.3.3)
5
5
  rails (>= 3.0.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -4,7 +4,7 @@ cacheable
4
4
  cacheable is a simple cache implementation based on activerecord, it is
5
5
  extracted from [rails-bestpractices.com][1].
6
6
 
7
- it supports activerecord >= 3.0.0, works on 1.9.2, 1.9.3 and jruby.
7
+ it supports activerecord >= 3.0.0, tested on 1.9.3 and 2.0.0 and works with jruby.
8
8
 
9
9
  Introduction
10
10
  ------------
@@ -68,7 +68,7 @@ Install
68
68
 
69
69
  add the following code to your Gemfile
70
70
 
71
- gem "simple_cacheable", :require => "cacheable"
71
+ gem "simple_cacheable"
72
72
 
73
73
 
74
74
  Gotchas
@@ -2,7 +2,8 @@ module Cacheable
2
2
  module AssocationCache
3
3
 
4
4
  def with_association(*association_names)
5
- self.cached_associations = association_names
5
+ self.cached_associations ||= []
6
+ self.cached_associations += association_names
6
7
 
7
8
  association_names.each do |association_name|
8
9
  association = reflect_on_association(association_name)
@@ -20,8 +21,9 @@ module Cacheable
20
21
  if through_reflection_name = association.options[:through]
21
22
  through_association = self.reflect_on_association(through_reflection_name)
22
23
 
23
- # FIXME it should be the only reflection but I'm not 100% positive
24
- reverse_through_association = through_association.klass.reflect_on_all_associations(:belongs_to).first
24
+ reverse_through_association = through_association.klass.reflect_on_all_associations(:belongs_to).detect do |assoc|
25
+ assoc.klass.ancestors.include?(Cacheable) && assoc.klass.reflect_on_association(association.name)
26
+ end
25
27
 
26
28
  # In a through association it doesn't have to be a belongs_to
27
29
  reverse_association = association.klass.reflect_on_all_associations(:belongs_to).find { |reverse_association|
@@ -33,10 +35,11 @@ module Cacheable
33
35
 
34
36
  define_method("expire_#{association_name}_cache") do
35
37
  if respond_to? "expire_#{reverse_association.name}_cache".to_sym
36
- # cached_viewable.expire_association_cache
37
38
  send("cached_#{reverse_association.name}").expire_association_cache(association_name)
38
39
  else
39
- send(reverse_association.name).send(reverse_through_association.name).expire_association_cache(association_name)
40
+ if send(reverse_association.name) && send(reverse_association.name).respond_to?(reverse_through_association.name)
41
+ send(reverse_association.name).send(reverse_through_association.name).expire_association_cache(association_name)
42
+ end
40
43
  end
41
44
  end
42
45
  end
@@ -1,7 +1,10 @@
1
1
  module Cacheable
2
2
  module AttributeCache
3
3
  def with_attribute(*attributes)
4
- self.cached_indices = attributes.inject({}) { |indices, attribute| indices[attribute] = {} }
4
+ self.cached_indices ||= {}
5
+ self.cached_indices = self.cached_indices.merge(attributes.each_with_object({}) {
6
+ |attribute, indices| indices[attribute] = {}
7
+ })
5
8
 
6
9
  class_eval do
7
10
  after_commit :expire_attribute_cache, :on => :update
@@ -3,7 +3,7 @@ module Cacheable
3
3
  # Cached class method
4
4
  # Should expire on any instance save
5
5
  def with_class_method(*methods)
6
- self.cached_class_methods = methods.inject({}) { |indices, meth| indices[meth] = {} }
6
+ self.cached_class_methods = methods.each_with_object({}) { |meth, indices| indices[meth] = {} }
7
7
 
8
8
  class_eval do
9
9
  after_commit :expire_class_method_cache, on: :update
@@ -1,7 +1,8 @@
1
1
  module Cacheable
2
2
  module MethodCache
3
3
  def with_method(*methods)
4
- self.cached_methods = methods
4
+ self.cached_methods ||= []
5
+ self.cached_methods += methods
5
6
 
6
7
  class_eval do
7
8
  after_commit :expire_method_cache, :on => :update
@@ -1,3 +1,3 @@
1
1
  module Cacheable
2
- VERSION = "1.3.3"
2
+ VERSION = "1.4.0"
3
3
  end
data/lib/cacheable.rb CHANGED
@@ -8,16 +8,20 @@ module Cacheable
8
8
  base.extend(Cacheable::Caches)
9
9
  base.send :include, Cacheable::Keys
10
10
  base.send :include, Cacheable::Expiry
11
-
11
+ base.send :extend, ClassMethods
12
12
  base.class_eval do
13
- def self.model_cache(&block)
14
- class_attribute :cached_key,
13
+ class_attribute :cached_key,
15
14
  :cached_indices,
16
15
  :cached_methods,
17
16
  :cached_class_methods,
18
17
  :cached_associations
19
- instance_exec &block
20
- end
18
+ end
19
+
20
+ end
21
+
22
+ module ClassMethods
23
+ def model_cache(&block)
24
+ instance_exec &block
21
25
  end
22
26
  end
23
27
 
@@ -3,11 +3,13 @@ require 'spec_helper'
3
3
  describe Cacheable do
4
4
  let(:cache) { Rails.cache }
5
5
  let(:user) { User.create(:login => 'flyerhzm') }
6
+ let(:descendant) { Descendant.create(:login => "scotterc")}
6
7
 
7
8
  before :all do
8
9
  @post1 = user.posts.create(:title => 'post1')
9
10
  user2 = User.create(:login => 'PelegR')
10
11
  user2.posts.create(:title => 'post3')
12
+ @post3 = descendant.posts.create(:title => 'post3')
11
13
  end
12
14
 
13
15
  before :each do
@@ -68,7 +70,6 @@ describe Cacheable do
68
70
  Rails.cache.read("posts/class_method/retrieve_with_both/1+1").should be_nil
69
71
  end
70
72
 
71
- # TODO: should we cache empty arrays?
72
73
  it "should delete associations cache" do
73
74
  user.cached_images
74
75
  Rails.cache.read("users/#{user.id}/association/images").should_not be_nil
@@ -78,4 +79,89 @@ describe Cacheable do
78
79
 
79
80
  end
80
81
 
82
+ context "single table inheritance bug" do
83
+ context "user" do
84
+ it "has cached indices" do
85
+ User.cached_indices.should_not be_nil
86
+ end
87
+
88
+ it "has specific cached indices" do
89
+ User.cached_indices.keys.should include :login
90
+ User.cached_indices.keys.should_not include :email
91
+ end
92
+
93
+ it "should have cached_methods" do
94
+ User.cached_methods.should_not be_nil
95
+ User.cached_methods.should == [:last_post]
96
+ end
97
+ end
98
+
99
+ context "expiring class_method cache" do
100
+ it "expires correctly from inherited attributes" do
101
+ Rails.cache.read("users/class_method/default_name").should be_nil
102
+ User.cached_default_name
103
+ Rails.cache.read("users/class_method/default_name").should == "flyerhzm"
104
+ user.expire_model_cache
105
+ Rails.cache.read("users/class_method/default_name").should be_nil
106
+ end
107
+ end
108
+
109
+ context "descendant" do
110
+
111
+ it "should have cached indices hash" do
112
+ Descendant.cached_indices.should_not be_nil
113
+ end
114
+
115
+ it "has specific cached indices" do
116
+ Descendant.cached_indices.keys.should include :login
117
+ Descendant.cached_indices.keys.should include :email
118
+ end
119
+
120
+ it "should have cached_methods" do
121
+ Descendant.cached_methods.should_not be_nil
122
+ Descendant.cached_methods.should == [:last_post, :name]
123
+ end
124
+
125
+ context "expiring method cache" do
126
+ it "expires correctly from inherited attributes" do
127
+ Rails.cache.read("descendants/#{descendant.id}/method/last_post").should be_nil
128
+ descendant.cached_last_post.should == descendant.last_post
129
+ Rails.cache.read("descendants/#{descendant.id}/method/last_post").should == descendant.last_post
130
+ descendant.expire_model_cache
131
+ Rails.cache.read("descendants/#{descendant.id}/method/last_post").should be_nil
132
+ end
133
+ end
134
+
135
+ context "expiring attribute cache" do
136
+ it "expires correctly from inherited attributes" do
137
+ Rails.cache.read("descendants/attribute/login/scotterc").should be_nil
138
+ Descendant.find_cached_by_login("scotterc").should == descendant
139
+ Rails.cache.read("descendants/attribute/login/scotterc").should == descendant
140
+ descendant.expire_model_cache
141
+ Rails.cache.read("descendants/attribute/login/scotterc").should be_nil
142
+ end
143
+ end
144
+
145
+ context "expiring association cache" do
146
+ it "expires correctly from inherited attributes" do
147
+ Rails.cache.read("descendants/#{descendant.id}/association/posts").should be_nil
148
+ descendant.cached_posts.should == [@post3]
149
+ Rails.cache.read("descendants/#{descendant.id}/association/posts").should == [@post3]
150
+ descendant.expire_model_cache
151
+ Rails.cache.read("descendants/#{descendant.id}/association/posts").should be_nil
152
+ end
153
+ end
154
+
155
+ context "expiring class_method cache" do
156
+ it "expires correctly from inherited attributes" do
157
+ Rails.cache.read("descendants/class_method/default_name").should be_nil
158
+ Descendant.cached_default_name
159
+ Rails.cache.read("descendants/class_method/default_name").should == "ScotterC"
160
+ descendant.expire_model_cache
161
+ Rails.cache.read("descendants/class_method/default_name").should be_nil
162
+ end
163
+ end
164
+ end
165
+ end
166
+
81
167
  end
@@ -15,6 +15,7 @@ describe Cacheable do
15
15
  @tag2 = @post1.tags.create(title: "Caching")
16
16
  @group1 = Group.create(name: "Ruby On Rails")
17
17
  @account = user.create_account(group: @group1)
18
+ @location = @post1.create_location(city: "New York")
18
19
  end
19
20
 
20
21
  before :each do
@@ -163,4 +164,32 @@ describe Cacheable do
163
164
 
164
165
  end
165
166
 
167
+ describe "after_commit bug" do
168
+ it "normal" do
169
+ @image1.expects(:do_something).once
170
+ @image1.save
171
+ end
172
+
173
+ it "new image fails without association" do
174
+ image = Image.new
175
+ image.expects(:do_something).once
176
+ image.save
177
+ end
178
+
179
+ it "new image fails with missing association" do
180
+ image = @group1.images.new
181
+ image.expects(:do_something).once
182
+ image.save
183
+ end
184
+ end
185
+
186
+ describe "belongs_to bug" do
187
+
188
+ it "shouldn't hit location" do
189
+ @location.expects(:expire_association_cache).with(:images).never
190
+ user.save
191
+ end
192
+
193
+ end
194
+
166
195
  end
@@ -3,10 +3,12 @@ require 'spec_helper'
3
3
  describe Cacheable do
4
4
  let(:cache) { Rails.cache }
5
5
  let(:user) { User.create(:login => 'flyerhzm') }
6
+ let(:descendant) { Descendant.create(:login => "scotterc")}
6
7
 
7
8
  before :all do
8
9
  @post1 = user.posts.create(:title => 'post1')
9
10
  @post2 = user.posts.create(:title => 'post2')
11
+ @post3 = descendant.posts.create(:title => 'post3')
10
12
  end
11
13
 
12
14
  before :each do
@@ -57,4 +59,31 @@ describe Cacheable do
57
59
  end
58
60
  end
59
61
 
62
+ context "descendant" do
63
+ it "should not cache Descendant.find_by_login" do
64
+ Rails.cache.read("descendants/attribute/login/scotterc").should be_nil
65
+ end
66
+
67
+ it "should cache by Descendant.find_by_login" do
68
+ Descendant.find_cached_by_login("scotterc").should == descendant
69
+ Rails.cache.read("descendants/attribute/login/scotterc").should == descendant
70
+ end
71
+
72
+ it "should get cached by Descendant.find_by_login multiple times" do
73
+ Descendant.find_cached_by_login("scotterc")
74
+ Descendant.find_cached_by_login("scotterc").should == descendant
75
+ end
76
+
77
+ it "should escape whitespace" do
78
+ new_descendant = Descendant.create(:login => "descendant space")
79
+ Descendant.find_cached_by_login("descendant space").should == new_descendant
80
+ end
81
+
82
+ it "maintains cached methods" do
83
+ Rails.cache.read("descendants/#{descendant.id}/method/name").should be_nil
84
+ descendant.cached_name.should == descendant.name
85
+ Rails.cache.read("descendants/#{descendant.id}/method/name").should == descendant.name
86
+ end
87
+ end
88
+
60
89
  end
@@ -3,10 +3,12 @@ require 'spec_helper'
3
3
  describe Cacheable do
4
4
  let(:cache) { Rails.cache }
5
5
  let(:user) { User.create(:login => 'flyerhzm') }
6
+ let(:descendant) { Descendant.create(:login => "scotterc")}
6
7
 
7
8
  before :all do
8
9
  @post1 = user.posts.create(:title => 'post1')
9
10
  @post2 = user.posts.create(:title => 'post2')
11
+ @post3 = descendant.posts.create(:title => 'post3')
10
12
  end
11
13
 
12
14
  before :each do
@@ -28,6 +30,38 @@ describe Cacheable do
28
30
  user.cached_last_post
29
31
  user.cached_last_post.should == user.last_post
30
32
  end
33
+
34
+ context "descendant should inherit methods" do
35
+ it "should not cache Descendant.last_post" do
36
+ Rails.cache.read("descendants/#{descendant.id}/method/last_post").should be_nil
37
+ end
38
+
39
+ it "should cache Descendant#last_post" do
40
+ descendant.cached_last_post.should == descendant.last_post
41
+ Rails.cache.read("descendants/#{descendant.id}/method/last_post").should == descendant.last_post
42
+ end
43
+
44
+ it "should cache Descendant#last_post multiple times" do
45
+ descendant.cached_last_post
46
+ descendant.cached_last_post.should == descendant.last_post
47
+ end
48
+
49
+ context "as well as new methods" do
50
+ it "should not cache Descendant.name" do
51
+ Rails.cache.read("descendants/#{descendant.id}/method/name").should be_nil
52
+ end
53
+
54
+ it "should cache Descendant#name" do
55
+ descendant.cached_name.should == descendant.name
56
+ Rails.cache.read("descendants/#{descendant.id}/method/name").should == descendant.name
57
+ end
58
+
59
+ it "should cache Descendant#name multiple times" do
60
+ descendant.cached_name
61
+ descendant.cached_name.should == descendant.name
62
+ end
63
+ end
64
+ end
31
65
  end
32
66
 
33
67
  end
@@ -0,0 +1,20 @@
1
+ class Descendant < User
2
+
3
+ belongs_to :location
4
+
5
+ model_cache do
6
+ with_attribute :email
7
+ with_method :name
8
+ with_association :location
9
+ with_class_method :default_name
10
+ end
11
+
12
+ def name
13
+ "ScotterC"
14
+ end
15
+
16
+ def self.default_name
17
+ "ScotterC"
18
+ end
19
+
20
+ end
data/spec/models/group.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  class Group < ActiveRecord::Base
2
2
 
3
3
  has_many :accounts
4
+
5
+ has_many :images, as: :viewable
4
6
  end
data/spec/models/image.rb CHANGED
@@ -2,4 +2,9 @@ class Image < ActiveRecord::Base
2
2
 
3
3
  belongs_to :viewable, :polymorphic => true
4
4
 
5
+ after_commit :do_something
6
+
7
+ def do_something
8
+ e = 1337
9
+ end
5
10
  end
@@ -0,0 +1,3 @@
1
+ class Location < ActiveRecord::Base
2
+
3
+ end
data/spec/models/post.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  class Post < ActiveRecord::Base
2
2
  include Cacheable
3
3
 
4
+ belongs_to :location
4
5
  belongs_to :user
5
6
 
6
7
  has_many :comments, :as => :commentable
data/spec/models/user.rb CHANGED
@@ -12,9 +12,15 @@ class User < ActiveRecord::Base
12
12
  with_attribute :login
13
13
  with_method :last_post
14
14
  with_association :posts, :account, :images, :group
15
+ with_class_method :default_name
15
16
  end
16
17
 
17
18
  def last_post
18
19
  posts.last
19
20
  end
21
+
22
+ def self.default_name
23
+ "flyerhzm"
24
+ end
25
+
20
26
  end
data/spec/spec_helper.rb CHANGED
@@ -8,14 +8,11 @@ require 'mocha/api'
8
8
  require 'memcached'
9
9
  require 'cacheable'
10
10
 
11
- # MODELS = File.join(File.dirname(__FILE__), "models")
12
- # $LOAD_PATH.unshift(MODELS)
13
- # Dir[ File.join(MODELS, "*.rb") ].each { |f| require f }
14
-
15
11
  # It needs this order otherwise cacheable throws
16
12
  # errors when looking for reflection classes
17
13
  # Specifically, post can't be before tag
18
14
  # and user can't be before post
15
+ require 'models/location'
19
16
  require 'models/account'
20
17
  require 'models/group'
21
18
  require 'models/comment'
@@ -23,6 +20,7 @@ require 'models/image'
23
20
  require 'models/tag'
24
21
  require 'models/post'
25
22
  require 'models/user'
23
+ require 'models/descendant'
26
24
 
27
25
  ActiveRecord::Migration.verbose = false
28
26
  ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
@@ -45,6 +43,7 @@ RSpec.configure do |config|
45
43
  ::ActiveRecord::Schema.define(:version => 1) do
46
44
  create_table :users do |t|
47
45
  t.string :login
46
+ t.string :email
48
47
  end
49
48
 
50
49
  create_table :accounts do |t|
@@ -55,6 +54,7 @@ RSpec.configure do |config|
55
54
  create_table :posts do |t|
56
55
  t.integer :user_id
57
56
  t.string :title
57
+ t.integer :location_id
58
58
  end
59
59
 
60
60
  create_table :comments do |t|
@@ -65,6 +65,7 @@ RSpec.configure do |config|
65
65
  create_table :images do |t|
66
66
  t.integer :viewable_id
67
67
  t.string :viewable_type
68
+ t.string :name
68
69
  end
69
70
 
70
71
  create_table :tags do |t|
@@ -79,6 +80,10 @@ RSpec.configure do |config|
79
80
  create_table :groups do |t|
80
81
  t.string :name
81
82
  end
83
+
84
+ create_table :locations do |t|
85
+ t.string :city
86
+ end
82
87
  end
83
88
 
84
89
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_cacheable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-10 00:00:00.000000000 Z
12
+ date: 2013-07-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -91,8 +91,10 @@ files:
91
91
  - spec/cacheable_spec.rb
92
92
  - spec/models/account.rb
93
93
  - spec/models/comment.rb
94
+ - spec/models/descendant.rb
94
95
  - spec/models/group.rb
95
96
  - spec/models/image.rb
97
+ - spec/models/location.rb
96
98
  - spec/models/post.rb
97
99
  - spec/models/tag.rb
98
100
  - spec/models/user.rb
@@ -130,8 +132,10 @@ test_files:
130
132
  - spec/cacheable_spec.rb
131
133
  - spec/models/account.rb
132
134
  - spec/models/comment.rb
135
+ - spec/models/descendant.rb
133
136
  - spec/models/group.rb
134
137
  - spec/models/image.rb
138
+ - spec/models/location.rb
135
139
  - spec/models/post.rb
136
140
  - spec/models/tag.rb
137
141
  - spec/models/user.rb