tennpipes-memory 3.6.6

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.
@@ -0,0 +1,23 @@
1
+ module Tennpipes
2
+ module Cache
3
+ module Helpers
4
+ module ObjectCache
5
+ def cache_object(key, opts = {})
6
+ if settings.caching?
7
+ began_at = Time.now
8
+ if value = settings.cache[key.to_s]
9
+ logger.debug "GET Object", began_at, key.to_s if defined?(logger)
10
+ else
11
+ value = yield
12
+ settings.cache.store(key.to_s, value, opts)
13
+ logger.debug "SET Object", began_at, key.to_s if defined?(logger)
14
+ end
15
+ value
16
+ else
17
+ yield
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module Tennpipes
2
+ module Cache
3
+ module Helpers
4
+ module CacheStore
5
+ def expire(*key)
6
+ if key.size == 1 and (key.first.is_a?(String) or key.first.is_a?(Symbol))
7
+ settings.cache.delete(key.first)
8
+ else
9
+ settings.cache.delete(self.class.url(*key))
10
+ end
11
+ nil
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ module Tennpipes
2
+ module Cache
3
+ module Helpers
4
+ ##
5
+ # Whereas page-level caching, described in the first section of this document, works by
6
+ # grabbing the entire output of a route, fragment caching gives the developer fine-grained
7
+ # control of what gets cached. This type of caching occurs at whatever level you choose.
8
+ #
9
+ # Possible uses for fragment caching might include:
10
+ #
11
+ # - a 'feed' of some items on a page
12
+ # - output fetched (by proxy) from an API on a third-party site
13
+ # - parts of your page which are largely static/do not need re-rendering every request
14
+ # - any output which is expensive to render
15
+ #
16
+ module Fragment
17
+ include Tennpipes::Helpers::OutputHelpers
18
+
19
+ ##
20
+ # This helper is used anywhere in your application you would like to associate a fragment
21
+ # to be cached. It can be used in within a route:
22
+ #
23
+ # @param [String] key
24
+ # cache key
25
+ # @param [Hash] opts
26
+ # cache options, e.g :expires
27
+ # @param [Proc]
28
+ # Execution result to store in the cache
29
+ #
30
+ # @example
31
+ # # Caching a fragment
32
+ # class MyTweets < Tennpipes::Application
33
+ # enable :caching # turns on caching mechanism
34
+ #
35
+ # controller '/tweets' do
36
+ # get :feed, :map => '/:username' do
37
+ # username = params[:username]
38
+ #
39
+ # @feed = cache( "feed_for_#{username}", :expires => 3 ) do
40
+ # @tweets = Tweet.all( :username => username )
41
+ # render 'partials/feedcontent'
42
+ # end
43
+ #
44
+ # # Below outputs @feed somewhere in its markup.
45
+ # render 'feeds/show'
46
+ # end
47
+ # end
48
+ # end
49
+ #
50
+ # @api public
51
+ def cache(key, opts = {}, &block)
52
+ if settings.caching?
53
+ began_at = Time.now
54
+ if value = settings.cache[key.to_s]
55
+ logger.debug "GET Fragment", began_at, key.to_s if defined?(logger)
56
+ concat_content(value.html_safe)
57
+ else
58
+ value = capture_html(&block)
59
+ settings.cache.store(key.to_s, value, opts)
60
+ logger.debug "SET Fragment", began_at, key.to_s if defined?(logger)
61
+ concat_content(value)
62
+ end
63
+ else
64
+ value = capture_html(&block)
65
+ concat_content(value)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,169 @@
1
+ module Tennpipes
2
+ module Cache
3
+ ##
4
+ # Helpers supporting page or fragment caching within a request route.
5
+ #
6
+ module Helpers
7
+ ##
8
+ # Page caching is easy to integrate into your application. To turn it on, simply provide the
9
+ # <tt>:cache => true</tt> option on either a controller or one of its routes.
10
+ # By default, cached content is persisted with a "file store" --that is, in a
11
+ # subdirectory of your application root.
12
+ #
13
+ # @example
14
+ # # Setting content expiry time.
15
+ # class CachedApp < Tennpipes::Application
16
+ # enable :caching # turns on caching mechanism
17
+ #
18
+ # controller '/blog', :cache => true do
19
+ # expires 15
20
+ #
21
+ # get '/entries' do
22
+ # # expires 15 => can also be defined inside a single route
23
+ # 'Just broke up eating twinkies, lol'
24
+ # end
25
+ #
26
+ # get '/post/:id' do
27
+ # cache_key :my_name
28
+ # @post = Post.find(params[:id])
29
+ # end
30
+ # end
31
+ # end
32
+ #
33
+ # You can manually expire cache with CachedApp.cache.delete(:my_name)
34
+ #
35
+ # Note that the "latest" method call to <tt>expires</tt> determines its value: if
36
+ # called within a route, as opposed to a controller definition, the route's
37
+ # value will be assumed.
38
+ #
39
+ module Page
40
+ ##
41
+ # This helper is used within a controller or route to indicate how often content
42
+ # should persist in the cache.
43
+ #
44
+ # After <tt>seconds</tt> seconds have passed, content previously cached will
45
+ # be discarded and re-rendered. Code associated with that route will <em>not</em>
46
+ # be executed; rather, its previous output will be sent to the client with a
47
+ # 200 OK status code.
48
+ #
49
+ # @param [Integer] time
50
+ # Time til expiration (seconds)
51
+ #
52
+ # @example
53
+ # controller '/blog', :cache => true do
54
+ # expires 15
55
+ #
56
+ # get '/entries' do
57
+ # 'Just broke up eating twinkies, lol'
58
+ # end
59
+ # end
60
+ #
61
+ # @api public
62
+ def expires(time)
63
+ @route.cache_expires = time
64
+ end
65
+
66
+ ##
67
+ # This helper is used within a route or route to indicate the name in the cache.
68
+ #
69
+ # @param [Symbol] name
70
+ # cache key
71
+ # @param [Proc] block
72
+ # block to be evaluated to cache key
73
+ #
74
+ # @example
75
+ # controller '/blog', :cache => true do
76
+ #
77
+ # get '/post/:id' do
78
+ # cache_key :my_name
79
+ # @post = Post.find(params[:id])
80
+ # end
81
+ # end
82
+ #
83
+ # @example
84
+ # get '/foo', :cache => true do
85
+ # cache_key { param[:id] }
86
+ # "My id is #{param[:id}"
87
+ # end
88
+ # end
89
+ #
90
+ def cache_key(name = nil, &block)
91
+ fail "Can not provide both cache_key and a block" if name && block
92
+ @route.cache_key = name || block
93
+ end
94
+
95
+ CACHED_VERBS = { 'GET' => true, 'HEAD' => true }.freeze
96
+
97
+ def self.tennpipes_route_added(route, verb, *)
98
+ return unless route.cache && CACHED_VERBS[verb]
99
+
100
+ route.before_filters do
101
+ next unless settings.caching?
102
+ if cached_response = load_cached_response
103
+ content_type cached_response[:content_type]
104
+ halt 200, cached_response[:body]
105
+ end
106
+ end
107
+
108
+ route.after_filters do
109
+ save_cached_response(route.cache_expires) if settings.caching?
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ def load_cached_response
116
+ began_at = Time.now
117
+ route_cache_key = resolve_cache_key || env['PATH_INFO']
118
+
119
+ value = settings.cache[route_cache_key]
120
+ logger.debug "GET Cache", began_at, route_cache_key if defined?(logger) && value
121
+
122
+ value
123
+ end
124
+
125
+ def save_cached_response(cache_expires)
126
+ return unless @_response_buffer.kind_of?(String)
127
+
128
+ began_at = Time.now
129
+ route_cache_key = resolve_cache_key || env['PATH_INFO']
130
+
131
+ content = {
132
+ :body => @_response_buffer,
133
+ :content_type => @_content_type
134
+ }
135
+
136
+ settings.cache.store(route_cache_key, content, :expires => cache_expires)
137
+
138
+ logger.debug "SET Cache", began_at, route_cache_key if defined?(logger)
139
+ end
140
+
141
+ ##
142
+ # Resolve the cache_key when it's a block in the correct context.
143
+ #
144
+ def resolve_cache_key
145
+ key = @route.cache_key
146
+ key.is_a?(Proc) ? instance_eval(&key) : key
147
+ end
148
+
149
+ module ClassMethods
150
+ ##
151
+ # A method to set `expires` time inside `controller` blocks.
152
+ #
153
+ # @example
154
+ # controller :users do
155
+ # expires 15
156
+ #
157
+ # get :show do
158
+ # 'shown'
159
+ # end
160
+ # end
161
+ #
162
+ def expires(time)
163
+ @_expires = time
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,24 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+ TENNPIPES_ROOT = File.dirname(__FILE__) unless defined?(TENNPIPES_ROOT)
3
+
4
+ require 'minitest/autorun'
5
+ require 'minitest/pride'
6
+ require 'rack/test'
7
+ require 'tennpipes-memory'
8
+
9
+ require 'ext/rack-test-methods'
10
+
11
+ class MiniTest::Spec
12
+ include Rack::Test::Methods
13
+
14
+ # Sets up a Sinatra::Base subclass defined with the block
15
+ # given. Used in setup or individual spec methods to establish
16
+ # the application.
17
+ def mock_app(base=Tennpipes::Application, &block)
18
+ @app = Sinatra.new(base, &block)
19
+ end
20
+
21
+ def app
22
+ Rack::Lint.new(@app)
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
2
+
3
+ describe 'Tennpipes::Cache - Moneta store' do
4
+ def setup
5
+ @test_key = "val_#{Time.now.to_i}"
6
+ end
7
+
8
+ def teardown
9
+ Tennpipes.cache.clear
10
+ end
11
+
12
+ class Foo
13
+ def bar; "bar"; end
14
+ end
15
+
16
+ it "return nil trying to get a value that doesn't exist" do
17
+ Tennpipes.cache.clear
18
+ assert_equal nil, Tennpipes.cache[@test_key]
19
+ end
20
+
21
+ it 'set and get an object with marshal' do
22
+ Tennpipes.cache[@test_key] = Foo.new
23
+ assert_equal "bar", Tennpipes.cache[@test_key].bar
24
+ end
25
+
26
+ it 'set and get a nil value' do
27
+ Tennpipes.cache[@test_key] = nil
28
+ assert_equal '', Tennpipes.cache[@test_key].to_s
29
+ end
30
+
31
+ it 'set and get a raw value' do
32
+ Tennpipes.cache[@test_key] = 'foo'
33
+ assert_equal 'foo', Tennpipes.cache[@test_key]
34
+ end
35
+
36
+ it "set a value that expires" do
37
+ init_time = ( Time.now - 20 )
38
+ Time.stub(:now, init_time) { Tennpipes.cache.store(@test_key, 'test', :expires => 1) }
39
+ Time.stub(:now, init_time + 20) { assert_equal nil, Tennpipes.cache[@test_key] }
40
+ end
41
+
42
+ it "be able to cache forever" do
43
+ Tennpipes.cache.store('forever', 'cached', :expires => false)
44
+ 2.times { |i| assert_equal 'cached', Tennpipes.cache['forever'] }
45
+ end
46
+
47
+ it 'delete a value' do
48
+ Tennpipes.cache[@test_key] = 'test'
49
+ assert_equal 'test', Tennpipes.cache[@test_key]
50
+ Tennpipes.cache.delete(@test_key)
51
+ assert_equal nil, Tennpipes.cache[@test_key]
52
+ end
53
+ end
@@ -0,0 +1,478 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ describe "TennpipesCache" do
4
+ after do
5
+ tmp = File.expand_path("../tmp", __FILE__)
6
+ %x[rm -rf #{tmp}]
7
+ end
8
+
9
+ it 'should cache a fragment' do
10
+ called = false
11
+ mock_app do
12
+ register Tennpipes::Cache
13
+ enable :caching
14
+ get("/foo"){ cache(:test) { called ? halt(500) : (called = 'test fragment') } }
15
+ end
16
+ get "/foo"
17
+ assert_equal 200, status
18
+ assert_equal 'test fragment', body
19
+ get "/foo"
20
+ assert_equal 200, status
21
+ assert_equal 'test fragment', body
22
+ refute_equal called, false
23
+ end
24
+
25
+ it 'should cache a page' do
26
+ called = false
27
+ mock_app do
28
+ register Tennpipes::Cache
29
+ enable :caching
30
+ get('/foo', :cache => true){ called ? halt(500) : (called = 'test page') }
31
+ end
32
+ get "/foo"
33
+ assert_equal 200, status
34
+ assert_equal 'test page', body
35
+ get "/foo"
36
+ assert_equal 200, status
37
+ assert_equal 'test page', body
38
+ refute_equal false, called
39
+ end
40
+
41
+ it 'should cache HEAD verb' do
42
+ called_times = 0
43
+ mock_app do
44
+ register Tennpipes::Cache
45
+ enable :caching
46
+ get('/foo', :cache => true){ called_times += 1; called_times.to_s }
47
+ end
48
+ head "/foo"
49
+ head "/foo"
50
+ assert_equal 1, called_times
51
+ end
52
+
53
+ it 'should not cache POST verb' do
54
+ called_times = 0
55
+ mock_app do
56
+ register Tennpipes::Cache
57
+ enable :caching
58
+ post('/foo', :cache => true){ called_times += 1; called_times.to_s }
59
+ end
60
+ post "/foo"
61
+ assert_equal 1, called_times
62
+ post "/foo"
63
+ assert_equal 2, called_times
64
+ end
65
+
66
+ it 'should not cache DELETE verb' do
67
+ called_times = 0
68
+ mock_app do
69
+ register Tennpipes::Cache
70
+ enable :caching
71
+ delete('/foo', :cache => true){ called_times += 1; called_times.to_s }
72
+ end
73
+ delete "/foo"
74
+ assert_equal 1, called_times
75
+ delete "/foo"
76
+ assert_equal 2, called_times
77
+ end
78
+
79
+ it 'should not cache PUT verb' do
80
+ called_times = 0
81
+ mock_app do
82
+ register Tennpipes::Cache
83
+ enable :caching
84
+ put('/foo', :cache => true){ called_times += 1; called_times.to_s }
85
+ end
86
+ put "/foo"
87
+ assert_equal 1, called_times
88
+ put "/foo"
89
+ assert_equal 2, called_times
90
+ end
91
+
92
+ it 'should delete from the cache' do
93
+ called = false
94
+ mock_app do
95
+ register Tennpipes::Cache
96
+ enable :caching
97
+ get('/foo', :cache => true){ called ? 'test page again' : (called = 'test page') }
98
+ get('/delete_foo'){ expire('/foo') }
99
+ end
100
+ get "/foo"
101
+ assert_equal 200, status
102
+ assert_equal 'test page', body
103
+ get "/delete_foo"
104
+ get "/foo"
105
+ assert_equal 200, status
106
+ assert_equal 'test page again', body
107
+ refute_equal false, called
108
+ end
109
+
110
+ it 'should accept custom cache keys' do
111
+ called = false
112
+ mock_app do
113
+ register Tennpipes::Cache
114
+ enable :caching
115
+ get '/foo', :cache => true do
116
+ if called
117
+ "you'll never see me"
118
+ else
119
+ cache_key :foo
120
+ called = 'foo'
121
+
122
+ called
123
+ end
124
+ end
125
+
126
+ get '/bar', :cache => true do
127
+ if called
128
+ cache_key :bar
129
+ called = 'bar'
130
+
131
+ called
132
+ else
133
+ "you'll never see me"
134
+ end
135
+ end
136
+ end
137
+ get "/foo"
138
+ assert_equal 200, status
139
+ assert_equal 'foo', body
140
+ assert_equal 'foo', @app.cache[:foo][:body]
141
+ get "/foo"
142
+ assert_equal 'foo', body
143
+
144
+ get "/bar"
145
+ assert_equal 200, status
146
+ assert_equal 'bar', body
147
+ assert_equal 'bar', @app.cache[:bar][:body]
148
+ get "/bar"
149
+ assert_equal 'bar', body
150
+ end
151
+
152
+ it 'should delete based on urls' do
153
+ called = false
154
+ mock_app do
155
+ register Tennpipes::Cache
156
+ enable :caching
157
+ get(:foo, :with => :id, :cache => true) { called ? 'test page again' : (called = 'test page') }
158
+ get(:delete_foo, :with => :id) { expire(:foo, params[:id]) }
159
+ end
160
+ get "/foo/12"
161
+ assert_equal 200, status
162
+ assert_equal 'test page', body
163
+ get "/delete_foo/12"
164
+ get "/foo/12"
165
+ assert_equal 200, status
166
+ assert_equal 'test page again', body
167
+ end
168
+
169
+ it 'should allow controller-wide caching' do
170
+ called = false
171
+ mock_app do
172
+ controller :cache => true do
173
+ register Tennpipes::Cache
174
+ enable :caching
175
+ get("/foo"){ called ? halt(500) : (called = 'test') }
176
+ end
177
+ end
178
+ get "/foo"
179
+ assert_equal 200, status
180
+ assert_equal 'test', body
181
+ get "/foo"
182
+ assert_equal 200, status
183
+ assert_equal 'test', body
184
+ end
185
+
186
+ it 'should allow controller-wide expires' do
187
+ called = false
188
+ mock_app do
189
+ register Tennpipes::Cache
190
+ controller :cache => true do
191
+ enable :caching
192
+ expires 1
193
+ get("/foo"){ called ? halt(500) : (called = 'test') }
194
+ end
195
+ end
196
+ get "/foo"
197
+ assert_equal 200, status
198
+ assert_equal 'test', body
199
+ get "/foo"
200
+ assert_equal 200, status
201
+ assert_equal 'test', body
202
+ Time.stub(:now, Time.now + 2) { get "/foo" }
203
+ assert_equal 500, status
204
+ end
205
+
206
+ it 'should allow cache disabling on a per route basis' do
207
+ called = false
208
+ mock_app do
209
+ register Tennpipes::Cache
210
+ enable :caching
211
+ controller :cache => true do
212
+ get("/foo", :cache => false){ called ? 'test again' : (called = 'test') }
213
+ end
214
+ end
215
+ get "/foo"
216
+ assert_equal 200, status
217
+ assert_equal 'test', body
218
+ get "/foo"
219
+ assert_equal 200, status
220
+ assert_equal 'test again', body
221
+ end
222
+
223
+ it 'should allow expiring for pages' do
224
+ called = false
225
+ mock_app do
226
+ register Tennpipes::Cache
227
+ enable :caching
228
+ controller :cache => true do
229
+ get("/foo") {
230
+ expires 1
231
+ called ? 'test again' : (called = 'test')
232
+ }
233
+ end
234
+ end
235
+ get "/foo"
236
+ assert_equal 200, status
237
+ assert_equal 'test', body
238
+ get "/foo"
239
+ assert_equal 200, status
240
+ assert_equal 'test', body
241
+ Time.stub(:now, Time.now + 3) { get "/foo" }
242
+ assert_equal 200, status
243
+ assert_equal 'test again', body
244
+ end
245
+
246
+ it 'should allow expiring for fragments' do
247
+ called = false
248
+ mock_app do
249
+ register Tennpipes::Cache
250
+ enable :caching
251
+ controller do
252
+ get("/foo") {
253
+ expires 1
254
+ cache(:test, :expires => 2) do
255
+ called ? 'test again' : (called = 'test')
256
+ end
257
+ }
258
+ end
259
+ end
260
+ get "/foo"
261
+ assert_equal 200, status
262
+ assert_equal 'test', body
263
+ get "/foo"
264
+ assert_equal 200, status
265
+ assert_equal 'test', body
266
+ Time.stub(:now, Time.now + 3) { get "/foo" }
267
+ assert_equal 200, status
268
+ assert_equal 'test again', body
269
+ end
270
+
271
+ it 'should allow disabling of the cache' do
272
+ called = false
273
+ mock_app do
274
+ register Tennpipes::Cache
275
+ disable :caching
276
+ controller :cache => true do
277
+ get("/foo"){ called ? halt(500) : (called = 'test') }
278
+ end
279
+ end
280
+ get "/foo"
281
+ assert_equal 200, status
282
+ assert_equal 'test', body
283
+ get "/foo"
284
+ assert_equal 500, status
285
+ end
286
+
287
+ it 'should not cache integer statuses' do
288
+ mock_app do
289
+ register Tennpipes::Cache
290
+ enable :caching
291
+ get( '/404', :cache => true ) { not_found }
292
+ get( '/503', :cache => true ) { error 503 }
293
+ not_found { 'fancy 404' }
294
+ error( 503 ) { 'fancy 503' }
295
+ end
296
+ get '/404'
297
+ assert_equal 'fancy 404', body
298
+ assert_equal 404, status
299
+ assert_equal nil, @app.cache['/404']
300
+ get '/404'
301
+ assert_equal 'fancy 404', body
302
+ assert_equal 404, status
303
+ get '/503'
304
+ assert_equal 'fancy 503', body
305
+ assert_equal 503, status
306
+ assert_equal nil, @app.cache['/503']
307
+ get '/503'
308
+ assert_equal 'fancy 503', body
309
+ assert_equal 503, status
310
+ end
311
+
312
+ it 'should cache should not hit with unique params' do
313
+ call_count = 0
314
+ mock_app do
315
+ register Tennpipes::Cache
316
+ enable :caching
317
+ before do
318
+ param = params[:test] || 'none'
319
+ cache_key "foo?#{param}"
320
+ end
321
+ get '/foo/:test', :cache => true do
322
+ param = params[:test] || 'none'
323
+ call_count += 1
324
+ "foo?#{param}"
325
+ end
326
+ end
327
+
328
+ get '/foo/none'
329
+ get '/foo/none'
330
+ assert_equal 200, status
331
+ assert_equal 'foo?none', body
332
+ assert_equal 1, call_count
333
+
334
+ get '/foo/yes'
335
+ assert_equal 'foo?yes', body
336
+ assert_equal 2, call_count
337
+ end
338
+
339
+ it 'should resolve block cache keys' do
340
+ call_count = 0
341
+ mock_app do
342
+ register Tennpipes::Cache
343
+ enable :caching
344
+
345
+ get '/foo', :cache => true do
346
+ cache_key { "key #{params[:id]}" }
347
+ call_count += 1
348
+ params[:id]
349
+ end
350
+ end
351
+
352
+ get '/foo?id=1'
353
+ get '/foo?id=2'
354
+ get '/foo?id=2'
355
+ get '/foo?id=1&something_else=42'
356
+ get '/foo?id=3&something_else=42'
357
+
358
+ assert_equal 3, call_count
359
+ end
360
+
361
+ it 'should raise an error if providing both a cache_key and block' do
362
+ mock_app do
363
+ register Tennpipes::Cache
364
+ enable :caching
365
+
366
+ get '/foo', :cache => true do
367
+ cache_key(:some_key) { "key #{params[:id]}" }
368
+ end
369
+ end
370
+
371
+ assert_raises(RuntimeError) { get '/foo' }
372
+ end
373
+
374
+ it 'should cache content_type' do
375
+ called = false
376
+ mock_app do
377
+ register Tennpipes::Cache
378
+ enable :caching
379
+ get '/foo', :cache => true do
380
+ content_type :json
381
+ if called
382
+ "you'll never see me"
383
+ else
384
+ cache_key :foo
385
+ called = '{"foo":"bar"}'
386
+
387
+ called
388
+ end
389
+ end
390
+ end
391
+ get "/foo"
392
+ assert_equal 200, status
393
+ assert_equal '{"foo":"bar"}', body
394
+ assert_equal '{"foo":"bar"}', @app.cache[:foo][:body]
395
+ get "/foo"
396
+ assert_equal '{"foo":"bar"}', body
397
+ assert_match /json/, last_response.content_type
398
+ end
399
+
400
+ it 'should cache an object' do
401
+ counter = 0
402
+ mock_app do
403
+ register Tennpipes::Cache
404
+ enable :caching
405
+ get '/' do
406
+ result = ''
407
+ 2.times do
408
+ result = cache_object 'object1' do
409
+ counter += 1
410
+ { :foo => 'bar' }
411
+ end
412
+ end
413
+ result[:foo].to_s
414
+ end
415
+ end
416
+ get '/'
417
+ assert_equal 'bar', body
418
+ assert_equal 1, counter
419
+ end
420
+
421
+ it 'should allow different expiring times for different pages' do
422
+ skip
423
+ called_times_a = 0
424
+ called_times_b = 0
425
+ mock_app do
426
+ register Tennpipes::Cache
427
+ enable :caching
428
+ controller :cache => true do
429
+ get("/foo") do
430
+ expires 1
431
+ called_times_a += 1
432
+ called_times_b.to_s
433
+ end
434
+ get("/bar") do
435
+ expires 3
436
+ called_times_b += 1
437
+ called_times_b.to_s
438
+ end
439
+ end
440
+ end
441
+ Time.stub(:now, Time.now) { get "/foo"; get "/bar" }
442
+ assert_equal 1, called_times_a
443
+ assert_equal 1, called_times_b
444
+ Time.stub(:now, Time.now + 0.5) { get "/foo"; get "/bar" }
445
+ assert_equal 1, called_times_a
446
+ assert_equal 1, called_times_b
447
+ Time.stub(:now, Time.now + 2) { get "/foo"; get "/bar" }
448
+ assert_equal 2, called_times_a
449
+ assert_equal 1, called_times_b
450
+ Time.stub(:now, Time.now + 2.5) { get "/foo"; get "/bar" }
451
+ assert_equal 2, called_times_a
452
+ assert_equal 1, called_times_b
453
+ Time.stub(:now, Time.now + 4) { get "/foo"; get "/bar" }
454
+ assert_equal 3, called_times_a
455
+ assert_equal 2, called_times_b
456
+ Time.stub(:now, Time.now + 5.5) { get "/foo"; get "/bar" }
457
+ assert_equal 4, called_times_a
458
+ assert_equal 2, called_times_b
459
+ end
460
+
461
+ it "preserve the app's `caching` setting if set before registering the module" do
462
+ mock_app do
463
+ enable :caching
464
+ register Tennpipes::Cache
465
+ end
466
+
467
+ assert @app.caching
468
+ end
469
+
470
+ it "preserve the app's `cache` setting if set before registering the module" do
471
+ mock_app do
472
+ set :cache, Tennpipes::Cache.new(:Memory)
473
+ register Tennpipes::Cache
474
+ end
475
+
476
+ assert @app.cache.adapter.adapter.is_a?(Moneta::Adapters::Memory)
477
+ end
478
+ end