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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ada7260a91b22ee55210e38fced1ee123e23c2e
4
- data.tar.gz: 86e4b7113bc21f837d3b17261b6bf00f589db6b0
3
+ metadata.gz: 83bbf521df93a4a60b8a30d553026ad529de5a4a
4
+ data.tar.gz: b4c06414324517d18d7baeb121340b190784d418
5
5
  SHA512:
6
- metadata.gz: 64ab2b3303b5f27c66eef23cfe426ccc98d925995cdcc20ba631e4348d6bad53319aca7c8b311cc85a82b2fa60f76582f368579d08f2f2241e75a5a25538ea51
7
- data.tar.gz: 15c657ebc23dc4b4807423d5e0c317709cf9005ad675c9030e601f0bd86e52d834eeaa37804c1fd4c158749d49b676366ca24833b14f0a82a012ae6e61e7fab7
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
- **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`.
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' # => raises ActiveRecord::RecordNotFound
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
- I may fix this later, though, because I like scopes.
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
- klass.respond_to?(:fetch) ? klass.fetch(id) : klass.find(id) rescue nil
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) : klass.where(criteria).to_a
9
+ fetchable? ? klass.fetch_where(criteria) : object.send(association).to_a
10
10
  end
11
11
 
12
12
  def klass
@@ -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_by(criteria) : klass.find_by(criteria)
9
+ fetchable? ? klass.fetch_by(criteria) : object.send(association)
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
@@ -1,3 +1,3 @@
1
1
  module Memcacheable
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -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
- Dog.should_receive(:find_by).once
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
- Dog.should_receive(:find_by).once
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.2
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-06-30 00:00:00.000000000 Z
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