padrino-cache 0.17.0 → 0.18.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: debf35ad318b1406cca39e13b78606d3a6c907871c86f80f3597dd8f3e102f7b
4
- data.tar.gz: 6d0348ce0bb9c75715968b52c45cbf0f3ddfba3ccfd6c46bfc5788efe8bcb47a
3
+ metadata.gz: ba34b4d72a0a4f039038801633b094117edb2548332855bfe6348700c1c4ed4f
4
+ data.tar.gz: 3f6382fa84609a885528064148e3b77674745bb2e14c3ed4f40f34da6972ef8b
5
5
  SHA512:
6
- metadata.gz: '08d3aff0107b8308cbef75f856c186210843d0338b0948376c859817b20961ec37dc86bba22f05a99012cb8d4f4fd8d907e8d34d6cfddd822c5d1a55e597e844'
7
- data.tar.gz: 69227bd4456285c96c3074c0b55dd839a7ce4f22eeef12b5c8514606db18bc5a70710f41de316a419ec7ac786d8d80bca90f5c45eb10bd372430e15df4373c2f
6
+ metadata.gz: 36573ec3921e7ff49e5cdeaddf9cd98eecd60e70272c51247821015e5115ebcea88a79de2ba954a599386cb0df32b00fd34b1afd537103565a18ddd7365bbaf9
7
+ data.tar.gz: 8bb374c1341562a7dcc2101e2e28bb38fe2eb76efa8c6cc6cf017c5d1855510cac823671f70218089846239f7fc633e7005b2d9199e5de526a154d82752f0869
@@ -60,7 +60,7 @@ module Padrino
60
60
  #
61
61
  # @api public
62
62
  def expires(time)
63
- @route.cache_expires = time
63
+ @_cache_expires = time
64
64
  end
65
65
 
66
66
  ##
@@ -89,7 +89,11 @@ module Padrino
89
89
  #
90
90
  def cache_key(name = nil, &block)
91
91
  raise 'Can not provide both cache_key and a block' if name && block
92
- @route.cache_key = name || block
92
+
93
+ @_cache_key = name || block
94
+ # A Symbol or a block is the same for every request, so later requests can look it up before the
95
+ # handler runs. Any other key (a String built from params) belongs to this request only.
96
+ @route.cache_key = @_cache_key if @_cache_key.is_a?(Symbol) || @_cache_key.is_a?(Proc)
93
97
  end
94
98
 
95
99
  CACHED_VERBS = { 'GET' => true, 'HEAD' => true }.freeze
@@ -97,21 +101,29 @@ module Padrino
97
101
  def self.padrino_route_added(route, verb, *)
98
102
  return unless route.cache && CACHED_VERBS[verb]
99
103
 
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
104
+ # Remember the key and expiry set before this route (by an app-level before filter), so a route
105
+ # reached through pass starts from them rather than from this route's.
106
+ route.before_filters { @_cache_outer = [@_cache_key, @_cache_expires] }
107
+ # The lookup is the route's last condition: it runs after every before filter and condition, so
108
+ # access checks written there apply to cached pages too.
109
+ route.custom_conditions << instance_method(:serve_cached_response)
107
110
 
108
111
  route.after_filters do
109
- save_cached_response(route.cache_expires) if settings.caching?
112
+ save_cached_response(@_cache_expires.nil? ? route.cache_expires : @_cache_expires) if settings.caching?
113
+ @_cache_key, @_cache_expires = @_cache_outer
110
114
  end
111
115
  end
112
116
 
113
117
  private
114
118
 
119
+ def serve_cached_response
120
+ if settings.caching? && (cached_response = load_cached_response)
121
+ content_type cached_response[:content_type]
122
+ halt 200, cached_response[:body]
123
+ end
124
+ true
125
+ end
126
+
115
127
  def load_cached_response
116
128
  began_at = Time.now
117
129
  route_cache_key = resolve_cache_key || env['PATH_INFO']
@@ -142,7 +154,7 @@ module Padrino
142
154
  # Resolve the cache_key when it's a block in the correct context.
143
155
  #
144
156
  def resolve_cache_key
145
- key = @route.cache_key
157
+ key = @_cache_key || @route.cache_key
146
158
  key.is_a?(Proc) ? instance_eval(&key) : key
147
159
  end
148
160
 
@@ -381,6 +381,150 @@ describe 'PadrinoCache' do
381
381
  assert_equal 2, call_count
382
382
  end
383
383
 
384
+ it 'should not reuse a string cache key from another request' do
385
+ mock_app do
386
+ register Padrino::Cache
387
+ enable :caching
388
+ get '/post/:id', cache: true do
389
+ cache_key "post-#{params[:id]}"
390
+ "post #{params[:id]}"
391
+ end
392
+ end
393
+
394
+ get '/post/1'
395
+ assert_equal 'post 1', body
396
+ get '/post/2'
397
+ assert_equal 'post 2', body
398
+ get '/post/1'
399
+ assert_equal 'post 1', body
400
+ end
401
+
402
+ it 'should run controller before filters on a cached response' do
403
+ mock_app do
404
+ register Padrino::Cache
405
+ enable :caching
406
+ controller :secret, cache: true do
407
+ before { halt 403, 'denied' unless params[:ok] }
408
+ get(:index) { 'secret page' }
409
+ end
410
+ end
411
+
412
+ get '/secret?ok=1'
413
+ assert_equal 'secret page', body
414
+ get '/secret'
415
+ assert_equal 403, status
416
+ assert_equal 'denied', body
417
+ end
418
+
419
+ it 'should use a cache key set in a controller before filter for the lookup' do
420
+ calls = 0
421
+ mock_app do
422
+ register Padrino::Cache
423
+ enable :caching
424
+ controller :users, cache: true do
425
+ before { cache_key "user-#{params[:u]}" }
426
+ get(:show, with: :u) { calls += 1; "user #{params[:u]}" }
427
+ end
428
+ end
429
+
430
+ get '/users/show/a'
431
+ get '/users/show/b'
432
+ get '/users/show/a'
433
+ assert_equal 'user a', body
434
+ assert_equal 2, calls
435
+ end
436
+
437
+ it 'should not apply a cache key to the next route after pass' do
438
+ mock_app do
439
+ register Padrino::Cache
440
+ enable :caching
441
+ get '/x/:id', cache: true do
442
+ cache_key :shared
443
+ pass if params[:id] == 'skip'
444
+ "A #{params[:id]}"
445
+ end
446
+ get('/x/:id', cache: true) { "B #{params[:id]}" }
447
+ end
448
+
449
+ get '/x/skip'
450
+ assert_equal 'B skip', body
451
+ get '/x/1'
452
+ assert_equal 'A 1', body
453
+ end
454
+
455
+ it 'should check route conditions on a cached response' do
456
+ mock_app do
457
+ register Padrino::Cache
458
+ enable :caching
459
+ def self.protect(protected)
460
+ condition { halt 403, 'No secrets for you!' unless params[:key] == 's3cr3t' } if protected
461
+ end
462
+ controller cache: true, conditions: { protect: true } do
463
+ get('/private') { 'secret stuff' }
464
+ end
465
+ end
466
+
467
+ get '/private?key=s3cr3t'
468
+ assert_equal 'secret stuff', body
469
+ get '/private'
470
+ assert_equal 403, status
471
+ assert_equal 'No secrets for you!', body
472
+ end
473
+
474
+ it 'should keep a cache key from an app-level before filter for the route reached through pass' do
475
+ mock_app do
476
+ register Padrino::Cache
477
+ enable :caching
478
+ before { cache_key "u-#{params[:u]}" }
479
+ get('/z', cache: true) { pass }
480
+ get('/z', cache: true) { "B for #{params[:u]}" }
481
+ end
482
+
483
+ get '/z?u=alice'
484
+ assert_equal 'B for alice', body
485
+ get '/z?u=bob'
486
+ assert_equal 'B for bob', body
487
+ end
488
+
489
+ it 'should keep expires to the request that set it' do
490
+ stored = []
491
+ store = Object.new
492
+ store.define_singleton_method(:[]) { |_key| nil }
493
+ store.define_singleton_method(:store) { |key, _value, options| stored << [key, options[:expires]] }
494
+ mock_app do
495
+ register Padrino::Cache
496
+ enable :caching
497
+ set :cache, store
498
+ get '/foo', cache: true do
499
+ expires 100 if params[:long]
500
+ 'foo'
501
+ end
502
+ end
503
+
504
+ get '/foo?long=1'
505
+ get '/foo'
506
+ assert_equal [['/foo', 100], ['/foo', nil]], stored
507
+ end
508
+
509
+ it 'should let expires false in a handler override the route expiry' do
510
+ stored = []
511
+ store = Object.new
512
+ store.define_singleton_method(:[]) { |_key| nil }
513
+ store.define_singleton_method(:store) { |key, _value, options| stored << [key, options[:expires]] }
514
+ mock_app do
515
+ register Padrino::Cache
516
+ enable :caching
517
+ set :cache, store
518
+ get '/ef', cache: true, expires: 60 do
519
+ expires false
520
+ 'ef'
521
+ end
522
+ end
523
+
524
+ get '/ef'
525
+ assert_equal [['/ef', false]], stored
526
+ end
527
+
384
528
  it 'should resolve block cache keys' do
385
529
  call_count = 0
386
530
  mock_app do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: padrino-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Padrino Team
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2026-10-14 00:00:00.000000000 Z
14
+ date: 2026-10-31 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: padrino-core
@@ -19,28 +19,28 @@ dependencies:
19
19
  requirements:
20
20
  - - '='
21
21
  - !ruby/object:Gem::Version
22
- version: 0.17.0
22
+ version: 0.18.1
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 0.17.0
29
+ version: 0.18.1
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: padrino-helpers
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - '='
35
35
  - !ruby/object:Gem::Version
36
- version: 0.17.0
36
+ version: 0.18.1
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - '='
42
42
  - !ruby/object:Gem::Version
43
- version: 0.17.0
43
+ version: 0.18.1
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: moneta
46
46
  requirement: !ruby/object:Gem::Requirement
@@ -97,11 +97,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
97
  - !ruby/object:Gem::Version
98
98
  version: 1.3.6
99
99
  requirements: []
100
- rubygems_version: 3.5.23
100
+ rubygems_version: 3.5.22
101
101
  signing_key:
102
102
  specification_version: 4
103
103
  summary: Page and fragment caching for Padrino
104
- test_files:
105
- - test/helper.rb
106
- - test/test_moneta_store.rb
107
- - test/test_padrino_cache.rb
104
+ test_files: []