cache_fu 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +18 -0
- data/README +18 -0
- data/defaults/extensions.rb.default +40 -0
- data/defaults/memcached.yml.default +34 -0
- data/defaults/memcached_ctl.default +81 -0
- data/lib/acts_as_cached/benchmarking.rb +82 -0
- data/lib/acts_as_cached/cache_methods.rb +307 -0
- data/lib/acts_as_cached/config.rb +111 -0
- data/lib/acts_as_cached/disabled.rb +30 -0
- data/lib/acts_as_cached/fragment_cache.rb +102 -0
- data/lib/acts_as_cached/local_cache.rb +44 -0
- data/lib/acts_as_cached/railtie.rb +13 -0
- data/lib/acts_as_cached/recipes.rb +8 -0
- data/lib/cache_fu.rb +62 -0
- data/lib/cache_fu.rb~ +61 -0
- data/lib/cache_fu.rb~5453d1247ce57bb1ea5ad70936b97707d5dbdab0 +1 -0
- data/lib/cache_fu.rb~5453d1247ce57bb1ea5ad70936b97707d5dbdab0_0 +1 -0
- data/lib/tasks/memcached.rake +59 -0
- data/rails/init.rb +34 -0
- data/test/benchmarking_test.rb +36 -0
- data/test/cache_test.rb +281 -0
- data/test/config_test.rb +128 -0
- data/test/disabled_test.rb +40 -0
- data/test/extensions_test.rb +33 -0
- data/test/fragment_cache_test.rb +250 -0
- data/test/helper.rb +215 -0
- data/test/local_cache_test.rb +43 -0
- data/test/sti_test.rb +36 -0
- metadata +103 -0
@@ -0,0 +1,250 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
require 'test/unit'
|
3
|
+
require 'action_controller/test_process'
|
4
|
+
|
5
|
+
ActionController::Routing::Routes.draw do |map|
|
6
|
+
map.connect ':controller/:action/:id'
|
7
|
+
end
|
8
|
+
|
9
|
+
class FooController < ActionController::Base
|
10
|
+
def url_for(*args)
|
11
|
+
"http://#{Time.now.to_i}.foo.com"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BarController < ActionController::Base
|
16
|
+
def page
|
17
|
+
render :text => "give me my bongos"
|
18
|
+
end
|
19
|
+
|
20
|
+
def index
|
21
|
+
render :text => "doop!"
|
22
|
+
end
|
23
|
+
|
24
|
+
def edit
|
25
|
+
render :text => "rawk"
|
26
|
+
end
|
27
|
+
|
28
|
+
def trees_are_swell?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def rescue_action(e)
|
33
|
+
raise e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class FooTemplate
|
38
|
+
include ::ActionView::Helpers::CacheHelper
|
39
|
+
|
40
|
+
attr_reader :controller
|
41
|
+
|
42
|
+
def initialize
|
43
|
+
@controller = FooController.new
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "Fragment caching (when used with memcached)" do
|
48
|
+
include FragmentCacheSpecSetup
|
49
|
+
|
50
|
+
setup do
|
51
|
+
@view = FooTemplate.new
|
52
|
+
end
|
53
|
+
|
54
|
+
specify "should be able to cache with a normal, non-keyed Rails cache calls" do
|
55
|
+
_erbout = ""
|
56
|
+
content = "Caching is fun!"
|
57
|
+
|
58
|
+
ActsAsCached.config[:store].expects(:set).with(@view.controller.url_for.gsub('http://',''), content, ActsAsCached.config[:ttl])
|
59
|
+
|
60
|
+
@view.cache { _erbout << content }
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "should be able to cache with a normal cache call when we don't have a default ttl" do
|
64
|
+
begin
|
65
|
+
_erbout = ""
|
66
|
+
content = "Caching is fun!"
|
67
|
+
|
68
|
+
original_ttl = ActsAsCached.config.delete(:ttl)
|
69
|
+
ActsAsCached.config[:store].expects(:set).with(@view.controller.url_for.gsub('http://',''), content, 25.minutes)
|
70
|
+
|
71
|
+
@view.cache { _erbout << content }
|
72
|
+
ensure
|
73
|
+
ActsAsCached.config[:ttl] = original_ttl
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "should be able to cache with a normal, keyed Rails cache calls" do
|
78
|
+
_erbout = ""
|
79
|
+
content = "Wow, even a key?!"
|
80
|
+
key = "#{Time.now.to_i}_wow_key"
|
81
|
+
|
82
|
+
ActsAsCached.config[:store].expects(:set).with(key, content, ActsAsCached.config[:ttl])
|
83
|
+
|
84
|
+
@view.cache(key) { _erbout << content }
|
85
|
+
end
|
86
|
+
|
87
|
+
specify "should be able to cache with new time-to-live option" do
|
88
|
+
_erbout = ""
|
89
|
+
content = "Time to live? TIME TO DIE!!"
|
90
|
+
key = "#{Time.now.to_i}_death_key"
|
91
|
+
|
92
|
+
ActsAsCached.config[:store].expects(:set).with(key, content, 60)
|
93
|
+
@view.cache(key, { :ttl => 60 }) { _erbout << content }
|
94
|
+
end
|
95
|
+
|
96
|
+
specify "should ignore everything but time-to-live when options are present" do
|
97
|
+
_erbout = ""
|
98
|
+
content = "Don't mess around, here, sir."
|
99
|
+
key = "#{Time.now.to_i}_mess_key"
|
100
|
+
|
101
|
+
ActsAsCached.config[:store].expects(:set).with(key, content, 60)
|
102
|
+
@view.cache(key, { :other_options => "for the kids", :ttl => 60 }) { _erbout << content }
|
103
|
+
end
|
104
|
+
|
105
|
+
specify "should be able to skip cache gets" do
|
106
|
+
ActsAsCached.skip_cache_gets = true
|
107
|
+
ActsAsCached.config[:store].expects(:get).never
|
108
|
+
_erbout = ""
|
109
|
+
@view.cache { _erbout << "Caching is fun!" }
|
110
|
+
ActsAsCached.skip_cache_gets = false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "Action caching (when used with memcached)" do
|
115
|
+
include FragmentCacheSpecSetup
|
116
|
+
page_content = "give me my bongos"
|
117
|
+
index_content = "doop!"
|
118
|
+
edit_content = "rawk"
|
119
|
+
|
120
|
+
setup do
|
121
|
+
@controller = BarController.new
|
122
|
+
@request = ActionController::TestRequest.new
|
123
|
+
@response = ActionController::TestResponse.new
|
124
|
+
end
|
125
|
+
|
126
|
+
teardown do # clear the filter chain between specs to avoid chaos
|
127
|
+
BarController.write_inheritable_attribute('filter_chain', [])
|
128
|
+
end
|
129
|
+
|
130
|
+
# little helper for prettier expections on the cache
|
131
|
+
def cache_expects(method, expected_times = 1)
|
132
|
+
ActsAsCached.config[:store].expects(method).times(expected_times)
|
133
|
+
end
|
134
|
+
|
135
|
+
specify "should cache using default ttl for a normal action cache without ttl" do
|
136
|
+
BarController.caches_action :page
|
137
|
+
|
138
|
+
key = 'test.host/bar/page'
|
139
|
+
cache_expects(:set).with(key, page_content, ActsAsCached.config[:ttl])
|
140
|
+
get :page
|
141
|
+
@response.body.should == page_content
|
142
|
+
|
143
|
+
cache_expects(:read).with(key, nil).returns(page_content)
|
144
|
+
get :page
|
145
|
+
@response.body.should == page_content
|
146
|
+
end
|
147
|
+
|
148
|
+
specify "should cache using defaul ttl for normal, multiple action caches" do
|
149
|
+
BarController.caches_action :page, :index
|
150
|
+
|
151
|
+
cache_expects(:set).with('test.host/bar/page', page_content, ActsAsCached.config[:ttl])
|
152
|
+
get :page
|
153
|
+
cache_expects(:set).with('test.host/bar', index_content, ActsAsCached.config[:ttl])
|
154
|
+
get :index
|
155
|
+
end
|
156
|
+
|
157
|
+
specify "should be able to action cache with ttl" do
|
158
|
+
BarController.caches_action :page => { :ttl => 2.minutes }
|
159
|
+
|
160
|
+
cache_expects(:set).with('test.host/bar/page', page_content, 2.minutes)
|
161
|
+
get :page
|
162
|
+
@response.body.should == page_content
|
163
|
+
end
|
164
|
+
|
165
|
+
specify "should be able to action cache multiple actions with ttls" do
|
166
|
+
BarController.caches_action :index, :page => { :ttl => 5.minutes }
|
167
|
+
|
168
|
+
cache_expects(:set).with('test.host/bar/page', page_content, 5.minutes)
|
169
|
+
cache_expects(:set).with('test.host/bar', index_content, ActsAsCached.config[:ttl])
|
170
|
+
|
171
|
+
get :page
|
172
|
+
@response.body.should == page_content
|
173
|
+
|
174
|
+
get :index
|
175
|
+
@response.body.should == index_content
|
176
|
+
cache_expects(:read).with('test.host/bar', nil).returns(index_content)
|
177
|
+
|
178
|
+
get :index
|
179
|
+
end
|
180
|
+
|
181
|
+
specify "should be able to action cache conditionally when passed something that returns true" do
|
182
|
+
BarController.caches_action :page => { :if => :trees_are_swell? }
|
183
|
+
|
184
|
+
cache_expects(:set).with('test.host/bar/page', page_content, ActsAsCached.config[:ttl])
|
185
|
+
|
186
|
+
get :page
|
187
|
+
@response.body.should == page_content
|
188
|
+
|
189
|
+
cache_expects(:read).with('test.host/bar/page', nil).returns(page_content)
|
190
|
+
|
191
|
+
get :page
|
192
|
+
end
|
193
|
+
|
194
|
+
#check for edginess
|
195
|
+
if [].respond_to?(:extract_options!)
|
196
|
+
specify "should not break cache_path overrides" do
|
197
|
+
BarController.caches_action :page, :cache_path => 'http://test.host/some/custom/path'
|
198
|
+
cache_expects(:set).with('test.host/some/custom/path', page_content, ActsAsCached.config[:ttl])
|
199
|
+
get :page
|
200
|
+
end
|
201
|
+
|
202
|
+
specify "should not break cache_path block overrides" do
|
203
|
+
BarController.caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]}/edit" : "http://test.host/edit" }
|
204
|
+
cache_expects(:set).with('test.host/edit', edit_content, ActsAsCached.config[:ttl])
|
205
|
+
get :edit
|
206
|
+
|
207
|
+
get :index
|
208
|
+
cache_expects(:set).with('test.host/5/edit', edit_content, ActsAsCached.config[:ttl])
|
209
|
+
get :edit, :id => 5
|
210
|
+
end
|
211
|
+
|
212
|
+
specify "should play nice with custom ttls and cache_path overrides" do
|
213
|
+
BarController.caches_action :page => { :ttl => 5.days }, :cache_path => 'http://test.host/my/custom/path'
|
214
|
+
cache_expects(:set).with('test.host/my/custom/path', page_content, 5.days)
|
215
|
+
get :page
|
216
|
+
end
|
217
|
+
|
218
|
+
specify "should play nice with custom ttls and cache_path block overrides" do
|
219
|
+
BarController.caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]}/edit" : "http://test.host/edit" }
|
220
|
+
cache_expects(:set).with('test.host/5/edit', edit_content, ActsAsCached.config[:ttl])
|
221
|
+
get :edit, :id => 5
|
222
|
+
end
|
223
|
+
|
224
|
+
specify "should play nice with the most complicated thing i can throw at it" do
|
225
|
+
BarController.caches_action :index => { :ttl => 24.hours }, :page => { :ttl => 5.seconds }, :edit => { :ttl => 5.days }, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]}/#{c.params[:action]}" : "http://test.host/#{c.params[:action]}" }
|
226
|
+
cache_expects(:set).with('test.host/index', index_content, 24.hours)
|
227
|
+
get :index
|
228
|
+
cache_expects(:set).with('test.host/5/edit', edit_content, 5.days)
|
229
|
+
get :edit, :id => 5
|
230
|
+
cache_expects(:set).with('test.host/5/page', page_content, 5.seconds)
|
231
|
+
get :page, :id => 5
|
232
|
+
|
233
|
+
cache_expects(:read).with('test.host/5/page', nil).returns(page_content)
|
234
|
+
get :page, :id => 5
|
235
|
+
cache_expects(:read).with('test.host/5/edit', nil).returns(edit_content)
|
236
|
+
get :edit, :id => 5
|
237
|
+
cache_expects(:read).with('test.host/index', nil).returns(index_content)
|
238
|
+
get :index
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
specify "should be able to skip action caching when passed something that returns false" do
|
243
|
+
BarController.caches_action :page => { :if => Proc.new {|c| !c.trees_are_swell?} }
|
244
|
+
|
245
|
+
cache_expects(:set, 0).with('test.host/bar/page', page_content, ActsAsCached.config[:ttl])
|
246
|
+
|
247
|
+
get :page
|
248
|
+
@response.body.should == page_content
|
249
|
+
end
|
250
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
##
|
2
|
+
# This file exists to fake out all the Railsisms we use so we can run the
|
3
|
+
# tests in isolation.
|
4
|
+
$LOAD_PATH.unshift 'lib/'
|
5
|
+
#
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
gem 'mocha', '>= 0.4.0'
|
10
|
+
require 'mocha'
|
11
|
+
gem 'test-spec', '= 0.3.0'
|
12
|
+
require 'test/spec'
|
13
|
+
require 'multi_rails_init'
|
14
|
+
rescue LoadError
|
15
|
+
puts '=> acts_as_cached tests depend on the following gems: mocha (0.4.0+), test-spec (0.3.0), multi_rails (0.0.2), and rails.'
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'redgreen'
|
20
|
+
rescue LoadError
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
Test::Spec::Should.send :alias_method, :have, :be
|
25
|
+
Test::Spec::ShouldNot.send :alias_method, :have, :be
|
26
|
+
|
27
|
+
##
|
28
|
+
# real men test without mocks
|
29
|
+
if $with_memcache = ARGV.include?('with-memcache')
|
30
|
+
require 'memcache'
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# init.rb hacks
|
35
|
+
RAILS_ROOT = '.' unless defined? RAILS_ROOT
|
36
|
+
RAILS_ENV = 'test' unless defined? RAILS_ENV
|
37
|
+
|
38
|
+
##
|
39
|
+
# get the default config using absolute path, so tests all play nice when run in isolation
|
40
|
+
DEFAULT_CONFIG_FILE = File.expand_path(File.dirname(__FILE__) + '/../defaults/memcached.yml.default')
|
41
|
+
|
42
|
+
##
|
43
|
+
# aac
|
44
|
+
require 'acts_as_cached'
|
45
|
+
Object.send :include, ActsAsCached::Mixin
|
46
|
+
|
47
|
+
##
|
48
|
+
# i need you.
|
49
|
+
module Enumerable
|
50
|
+
def index_by
|
51
|
+
inject({}) do |accum, elem|
|
52
|
+
accum[yield(elem)] = elem
|
53
|
+
accum
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# mocky.
|
60
|
+
class HashStore < Hash
|
61
|
+
alias :get :[]
|
62
|
+
|
63
|
+
def get_multi(*values)
|
64
|
+
reject { |k,v| !values.include? k }
|
65
|
+
end
|
66
|
+
|
67
|
+
def set(key, value, *others)
|
68
|
+
self[key] = value
|
69
|
+
end
|
70
|
+
|
71
|
+
def namespace
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
$cache = HashStore.new
|
77
|
+
|
78
|
+
class Story
|
79
|
+
acts_as_cached($with_memcache ? {} : { :store => $cache })
|
80
|
+
|
81
|
+
attr_accessor :id, :title
|
82
|
+
|
83
|
+
def initialize(attributes = {})
|
84
|
+
attributes.each { |key, value| instance_variable_set("@#{key}", value) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def attributes
|
88
|
+
{ :id => id, :title => title }
|
89
|
+
end
|
90
|
+
|
91
|
+
def ==(other)
|
92
|
+
return false unless other.respond_to? :attributes
|
93
|
+
attributes == other.attributes
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.find(*args)
|
97
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
98
|
+
|
99
|
+
if (ids = args.flatten).size > 1
|
100
|
+
ids.map { |id| $stories[id.to_i] }
|
101
|
+
elsif (id = args.flatten.first).to_i.to_s == id.to_s
|
102
|
+
$stories[id.to_i]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.find_by_title(*args)
|
107
|
+
title = args.shift
|
108
|
+
find(args).select { |s| s.title == title }
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.base_class
|
112
|
+
Story
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.something_cool; :redbull end
|
116
|
+
def something_flashy; :molassy end
|
117
|
+
|
118
|
+
def self.block_on(target = nil)
|
119
|
+
target || :something
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.pass_through(target)
|
123
|
+
target
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.two_params(first, second)
|
127
|
+
"first: #{first} | second: #{second}"
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.find_live(*args) false end
|
131
|
+
end
|
132
|
+
|
133
|
+
class Feature < Story; end
|
134
|
+
class Interview < Story; end
|
135
|
+
|
136
|
+
module ActionController
|
137
|
+
class Base
|
138
|
+
def rendering_runtime(*args) '' end
|
139
|
+
def self.silence; yield end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class MemCache
|
144
|
+
attr_accessor :servers
|
145
|
+
def initialize(*args) end
|
146
|
+
class MemCacheError < StandardError; end unless defined? MemCacheError
|
147
|
+
end unless $with_memcache
|
148
|
+
|
149
|
+
module StoryCacheSpecSetup
|
150
|
+
def self.included(base)
|
151
|
+
base.setup do
|
152
|
+
setup_cache_spec
|
153
|
+
Story.instance_eval { @max_key_length = nil }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def setup_cache_spec
|
158
|
+
@story = Story.new(:id => 1, :title => "acts_as_cached 2 released!")
|
159
|
+
@story2 = Story.new(:id => 2, :title => "BDD is something you can use")
|
160
|
+
@story3 = Story.new(:id => 3, :title => "RailsConf is overrated.")
|
161
|
+
$stories = { 1 => @story, 2 => @story2, 3 => @story3 }
|
162
|
+
|
163
|
+
$with_memcache ? with_memcache : with_mock
|
164
|
+
end
|
165
|
+
|
166
|
+
def with_memcache
|
167
|
+
unless $mc_setup_for_story_cache_spec
|
168
|
+
ActsAsCached.config.clear
|
169
|
+
config = YAML.load_file(DEFAULT_CONFIG_FILE)
|
170
|
+
config['test'] = config['development'].merge('benchmarking' => false, 'disabled' => false)
|
171
|
+
ActsAsCached.config = config
|
172
|
+
$mc_setup_for_story_cache_spec = true
|
173
|
+
end
|
174
|
+
|
175
|
+
Story.send :acts_as_cached
|
176
|
+
Story.expire_cache(1)
|
177
|
+
Story.expire_cache(2)
|
178
|
+
Story.expire_cache(3)
|
179
|
+
Story.expire_cache(:block)
|
180
|
+
Story.set_cache(2, @story2)
|
181
|
+
end
|
182
|
+
|
183
|
+
def with_mock
|
184
|
+
$cache.clear
|
185
|
+
|
186
|
+
Story.send :acts_as_cached, :store => $cache
|
187
|
+
$cache['Story:2'] = @story2
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
module FragmentCacheSpecSetup
|
192
|
+
def self.included(base)
|
193
|
+
base.setup { setup_fragment_spec }
|
194
|
+
end
|
195
|
+
|
196
|
+
def setup_fragment_spec
|
197
|
+
unless $mc_setup_for_fragment_cache_spec
|
198
|
+
ActsAsCached.config.clear
|
199
|
+
config = YAML.load_file(DEFAULT_CONFIG_FILE)
|
200
|
+
|
201
|
+
if $with_memcache
|
202
|
+
other_options = { 'fragments' => true }
|
203
|
+
else
|
204
|
+
Object.const_set(:CACHE, $cache) unless defined? CACHE
|
205
|
+
other_options = { 'fragments' => true, 'store' => $cache }
|
206
|
+
end
|
207
|
+
|
208
|
+
config['test'] = config['development'].merge other_options
|
209
|
+
|
210
|
+
ActsAsCached.config = config
|
211
|
+
ActsAsCached::FragmentCache.setup!
|
212
|
+
$mc_setup_for_fragment_cache_spec = true
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
context "When local_cache_for_request is called" do
|
4
|
+
include StoryCacheSpecSetup
|
5
|
+
|
6
|
+
setup do
|
7
|
+
ActionController::Base.new.local_cache_for_request
|
8
|
+
$cache = CACHE if $with_memcache
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "get_cache should pull from the local cache on a second hit" do
|
12
|
+
$cache.expects(:get).with('Story:2').returns(@story2)
|
13
|
+
@story2.get_cache
|
14
|
+
$cache.expects(:get).never
|
15
|
+
@story2.get_cache
|
16
|
+
end
|
17
|
+
|
18
|
+
specify "set_cache should set to the local cache" do
|
19
|
+
$cache.expects(:set).at_least_once.returns(@story)
|
20
|
+
ActsAsCached::LocalCache.local_cache.expects(:[]=).with('Story:1', @story).returns(@story)
|
21
|
+
@story.set_cache
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "expire_cache should clear from the local cache" do
|
25
|
+
@story2.get_cache
|
26
|
+
$cache.expects(:delete).at_least_once
|
27
|
+
ActsAsCached::LocalCache.local_cache.expects(:delete).with('Story:2')
|
28
|
+
@story2.expire_cache
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "clear_cache should clear from the local cache" do
|
32
|
+
@story2.get_cache
|
33
|
+
$cache.expects(:delete).at_least_once
|
34
|
+
ActsAsCached::LocalCache.local_cache.expects(:delete).with('Story:2')
|
35
|
+
@story2.clear_cache
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "cached? should check the local cache" do
|
39
|
+
@story2.get_cache
|
40
|
+
$cache.expects(:get).never
|
41
|
+
@story2.cached?
|
42
|
+
end
|
43
|
+
end
|
data/test/sti_test.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
context "An STI subclass acting as cached" do
|
4
|
+
include StoryCacheSpecSetup
|
5
|
+
|
6
|
+
setup do
|
7
|
+
@feature = Feature.new(:id => 3, :title => 'Behind the scenes of acts_as_cached')
|
8
|
+
@interview = Interview.new(:id => 4, :title => 'An interview with the Arcade Fire')
|
9
|
+
@feature.expire_cache
|
10
|
+
@interview.expire_cache
|
11
|
+
$stories.update 3 => @feature, 4 => @interview
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "should be just as retrievable as any other cachable Ruby object" do
|
15
|
+
Feature.cached?(3).should.equal false
|
16
|
+
Feature.get_cache(3)
|
17
|
+
Feature.cached?(3).should.equal true
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should have a key corresponding to its parent class" do
|
21
|
+
@feature.cache_key.should.equal "Story:3"
|
22
|
+
@interview.cache_key.should.equal "Story:4"
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should be able to get itself from the cache via its parent class" do
|
26
|
+
Story.get_cache(3).should.equal @feature
|
27
|
+
Story.get_cache(4).should.equal @interview
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "should take on its parents cache options but be able to set its own" do
|
31
|
+
@feature.cache_key.should.equal "Story:3"
|
32
|
+
Feature.cache_config[:version] = 1
|
33
|
+
@feature.cache_key.should.equal "Story:1:3"
|
34
|
+
@story.cache_key.should.equal "Story:1"
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cache_fu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.2
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- ""
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-23 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "3.0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rails
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "3.0"
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
description: This gem is kreetitech's fork (http://github.com/kreetitech/cache_fu).
|
38
|
+
email:
|
39
|
+
- ""
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
files:
|
47
|
+
- rails/init.rb
|
48
|
+
- lib/acts_as_cached/benchmarking.rb
|
49
|
+
- lib/acts_as_cached/cache_methods.rb
|
50
|
+
- lib/acts_as_cached/config.rb
|
51
|
+
- lib/acts_as_cached/disabled.rb
|
52
|
+
- lib/acts_as_cached/fragment_cache.rb
|
53
|
+
- lib/acts_as_cached/local_cache.rb
|
54
|
+
- lib/acts_as_cached/railtie.rb
|
55
|
+
- lib/acts_as_cached/recipes.rb
|
56
|
+
- lib/cache_fu.rb
|
57
|
+
- lib/cache_fu.rb~
|
58
|
+
- lib/cache_fu.rb~5453d1247ce57bb1ea5ad70936b97707d5dbdab0
|
59
|
+
- lib/cache_fu.rb~5453d1247ce57bb1ea5ad70936b97707d5dbdab0_0
|
60
|
+
- lib/tasks/memcached.rake
|
61
|
+
- test/benchmarking_test.rb
|
62
|
+
- test/cache_test.rb
|
63
|
+
- test/config_test.rb
|
64
|
+
- test/disabled_test.rb
|
65
|
+
- test/extensions_test.rb
|
66
|
+
- test/fragment_cache_test.rb
|
67
|
+
- test/helper.rb
|
68
|
+
- test/local_cache_test.rb
|
69
|
+
- test/sti_test.rb
|
70
|
+
- defaults/extensions.rb.default
|
71
|
+
- defaults/memcached.yml.default
|
72
|
+
- defaults/memcached_ctl.default
|
73
|
+
- LICENSE
|
74
|
+
- README
|
75
|
+
homepage: http://github.com/kreetitech/cache_fu
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.8.3
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Makes caching easy for ActiveRecord models
|
102
|
+
test_files: []
|
103
|
+
|