memcacheable 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -3
- data/lib/memcacheable.rb +9 -0
- data/lib/memcacheable/fetch_belongs_to.rb +8 -3
- data/lib/memcacheable/fetch_has_many.rb +1 -1
- data/lib/memcacheable/fetch_has_one.rb +1 -1
- data/lib/memcacheable/fetch_method.rb +23 -0
- data/lib/memcacheable/version.rb +1 -1
- data/spec/lib/memcacheable_spec.rb +33 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83bbf521df93a4a60b8a30d553026ad529de5a4a
|
4
|
+
data.tar.gz: b4c06414324517d18d7baeb121340b190784d418
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70da4d0ccb557357110e24298fc01b41995b3da99ead6ebd23d85101ea45cecfdeb26e7476d303a2e2894d5154ca3fc1cd6ea0d5900b1e4cecc3aa6376a36bd6
|
7
|
+
data.tar.gz: 0365dced8c66ecd9f3a9e0577a187ef7e62d9de21dc88816c7f17737943be9f7a706c5678ace823b50ae9837b17bc60c4466c046ef811e3daff5d9750d7e314b
|
data/README.md
CHANGED
@@ -26,7 +26,7 @@ class Person < ActiveRecord::Base
|
|
26
26
|
end
|
27
27
|
```
|
28
28
|
|
29
|
-
|
29
|
+
Boom! Now you can `fetch` a person by their id, like below. When the person gets updated or touched, it will flush the cache, and the person will be reloaded on the next `fetch`.
|
30
30
|
|
31
31
|
```ruby
|
32
32
|
person = Person.fetch id # caches the person
|
@@ -62,7 +62,7 @@ person = Person.fetch_by weight: 175, height: 71 # fetched and cached with new
|
|
62
62
|
Like noise in your life? Try `fetch_by!` (hard to say: "fetch-by-bang!").
|
63
63
|
|
64
64
|
```ruby
|
65
|
-
person = Person.fetch_by! name: 'Mork' # =>
|
65
|
+
person = Person.fetch_by! name: 'Mork' # => ActiveRecord::RecordNotFound
|
66
66
|
```
|
67
67
|
|
68
68
|
While `fetch_by` just pulls back just one record, you can fetch a collection with `fetch_where`:
|
@@ -88,7 +88,7 @@ Btw, don't do something stupid like trying to call scope methods on the result o
|
|
88
88
|
Person.fetch_where(height: 60).limit(5)
|
89
89
|
```
|
90
90
|
|
91
|
-
|
91
|
+
If you want something very similar to scopes, keep reading to learn about [caching methods](https://github.com/flintinatux/memcacheable#cache-methods).
|
92
92
|
|
93
93
|
### Cache associations
|
94
94
|
|
@@ -138,6 +138,31 @@ person.touch # association cache is flushed, but not the fetch_where
|
|
138
138
|
person.fetch_kittens # reloads the kittens from the cache, and caches as an association
|
139
139
|
```
|
140
140
|
|
141
|
+
### Cache methods
|
142
|
+
|
143
|
+
Does your model have a method that eats up lots of calculation time, or perhaps a scope-like method that requires a database query? Cache that bad boy!
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
class Person < ActiveRecord::Base
|
147
|
+
has_many :kittens
|
148
|
+
|
149
|
+
include Memcacheable
|
150
|
+
cache_method :random_kitten
|
151
|
+
|
152
|
+
def random_kitten(seed=Random.new_seed)
|
153
|
+
kittens.sample(Random.new seed)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
**Voila!** Now you get a nice fetch method to cache the results:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
person.fetch_random_kitten(12345) # => gets your random kitty, and then caches it
|
162
|
+
```
|
163
|
+
|
164
|
+
Notice that the fetch method accepts the same args as the original. **Caveat:** blocks are not accepted, unfortunately. I love blocks, but they don't have a consistent identifier to include in a cache key. So feel free to get creative with args, but not blocks.
|
165
|
+
|
141
166
|
## Inspiration
|
142
167
|
|
143
168
|
None of the caching options out there really satisfied my needs, so I wrote this gem. But I was not without inspiration. I learned the basics of Rails caching from the [RailsCasts](http://railscasts.com/) episode on [Model Caching](http://railscasts.com/episodes/115-model-caching-revised), and I borrowed a lot of syntax from the very popular [IdentityCache gem](https://github.com/Shopify/identity_cache) from our friends at [Shopify](http://www.shopify.com/).
|
data/lib/memcacheable.rb
CHANGED
@@ -10,6 +10,7 @@ module Memcacheable
|
|
10
10
|
autoload :FetchByCriteria
|
11
11
|
autoload :FetchHasMany
|
12
12
|
autoload :FetchHasOne
|
13
|
+
autoload :FetchMethod
|
13
14
|
autoload :FetchOne
|
14
15
|
autoload :FetchWhere
|
15
16
|
autoload :Fetcher
|
@@ -52,6 +53,14 @@ module Memcacheable
|
|
52
53
|
self.cached_indexes << fields.map(&:to_sym).sort
|
53
54
|
end
|
54
55
|
|
56
|
+
def cache_method(*methods)
|
57
|
+
methods.each do |method|
|
58
|
+
define_method "fetch_#{method}" do |*args|
|
59
|
+
FetchMethod.new(self, method, args).fetch
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
55
64
|
def fetch(id)
|
56
65
|
FetchOne.new(self, id).fetch
|
57
66
|
end
|
@@ -1,11 +1,16 @@
|
|
1
1
|
module Memcacheable
|
2
2
|
class FetchBelongsTo < FetchAssociation
|
3
|
+
def fetchable?
|
4
|
+
klass.respond_to?(:fetch)
|
5
|
+
end
|
3
6
|
|
4
7
|
def find_on_cache_miss
|
5
|
-
klass = association.to_s.camelize.constantize
|
6
8
|
id = object.send "#{association}_id"
|
7
|
-
|
9
|
+
fetchable? ? klass.fetch(id) : object.send(association) rescue nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def klass
|
13
|
+
@klass ||= association.to_s.camelize.constantize
|
8
14
|
end
|
9
|
-
|
10
15
|
end
|
11
16
|
end
|
@@ -6,7 +6,7 @@ module Memcacheable
|
|
6
6
|
|
7
7
|
def find_on_cache_miss
|
8
8
|
criteria = { "#{class_name}_id" => object.id }
|
9
|
-
fetchable? ? klass.fetch_where(criteria) :
|
9
|
+
fetchable? ? klass.fetch_where(criteria) : object.send(association).to_a
|
10
10
|
end
|
11
11
|
|
12
12
|
def klass
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Memcacheable
|
2
|
+
class FetchMethod < Fetcher
|
3
|
+
attr_accessor :object, :method, :args
|
4
|
+
|
5
|
+
def initialize(object, method, args)
|
6
|
+
self.object = object
|
7
|
+
self.method = method
|
8
|
+
self.args = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def cache_key
|
12
|
+
[object, method, args]
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"method #{cache_key.to_param}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_on_cache_miss
|
20
|
+
object.send method, *args
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/memcacheable/version.rb
CHANGED
@@ -20,6 +20,11 @@ class Kitten < FakeModel
|
|
20
20
|
include Memcacheable
|
21
21
|
cache_index :person_id
|
22
22
|
cache_belongs_to :person
|
23
|
+
cache_method :meow
|
24
|
+
|
25
|
+
def meow(how_many=1)
|
26
|
+
how_many.times.map{ 'meow' }.join ' '
|
27
|
+
end
|
23
28
|
end
|
24
29
|
|
25
30
|
describe Memcacheable do
|
@@ -175,6 +180,7 @@ describe Memcacheable do
|
|
175
180
|
describe '::cache_has_one' do
|
176
181
|
let(:dog) { Dog.new person_id: id }
|
177
182
|
before do
|
183
|
+
person.stub(:dog).and_return dog
|
178
184
|
Dog.stub(:find_by) do |criteria|
|
179
185
|
criteria.all?{ |k,v| dog.send(k) == v } ? dog : nil
|
180
186
|
end
|
@@ -189,7 +195,7 @@ describe Memcacheable do
|
|
189
195
|
end
|
190
196
|
|
191
197
|
it "only queries once and then caches" do
|
192
|
-
|
198
|
+
person.should_receive(:dog).once
|
193
199
|
person.fetch_dog
|
194
200
|
person.fetch_dog
|
195
201
|
end
|
@@ -197,7 +203,7 @@ describe Memcacheable do
|
|
197
203
|
it "flushes when touched by association" do
|
198
204
|
person.fetch_dog
|
199
205
|
person.touch
|
200
|
-
|
206
|
+
person.should_receive(:dog).once
|
201
207
|
person.fetch_dog
|
202
208
|
end
|
203
209
|
end
|
@@ -269,4 +275,29 @@ describe Memcacheable do
|
|
269
275
|
person.fetch_kittens
|
270
276
|
end
|
271
277
|
end
|
278
|
+
|
279
|
+
describe '::cache_method' do
|
280
|
+
let(:kitten) { Kitten.new }
|
281
|
+
|
282
|
+
it "defines a new fetch method" do
|
283
|
+
kitten.should.respond_to?(:fetch_meow)
|
284
|
+
end
|
285
|
+
|
286
|
+
it "calls down to the method correctly on cache miss" do
|
287
|
+
kitten.fetch_meow(3) { |sound| sound.upcase }.should eq 'meow meow meow'
|
288
|
+
end
|
289
|
+
|
290
|
+
it "only queries once and then caches" do
|
291
|
+
kitten.should_receive(:meow).once
|
292
|
+
kitten.fetch_meow
|
293
|
+
kitten.fetch_meow
|
294
|
+
end
|
295
|
+
|
296
|
+
it "flushed when touched by an association" do
|
297
|
+
kitten.fetch_meow
|
298
|
+
kitten.touch
|
299
|
+
kitten.should_receive(:meow).once
|
300
|
+
kitten.fetch_meow
|
301
|
+
end
|
302
|
+
end
|
272
303
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: memcacheable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott McCormack
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- lib/memcacheable/fetch_by_criteria.rb
|
117
117
|
- lib/memcacheable/fetch_has_many.rb
|
118
118
|
- lib/memcacheable/fetch_has_one.rb
|
119
|
+
- lib/memcacheable/fetch_method.rb
|
119
120
|
- lib/memcacheable/fetch_one.rb
|
120
121
|
- lib/memcacheable/fetch_where.rb
|
121
122
|
- lib/memcacheable/fetcher.rb
|