scoped_cache_keys 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 599264adc7feb1e042fde17a4473126615907cfd03e27172d9355f9c5dfc6308
4
+ data.tar.gz: bd9335f025963374103c7fd8a0a897606e977b02568ba1a5816cc55a7f8f9afd
5
+ SHA512:
6
+ metadata.gz: 9740614f52aeb1c14a7462ac11c1c4a496146402a7973f76991651bd3480ebf2e95754af17962ebecb2f1dab544fe56c7555f86b0d578be7032f374acbe26bf2
7
+ data.tar.gz: 9d2dc9a88572ef4991280a50bd9c764041d96d9996f8bc548b07cde2ecc614d7e5a619979099cc92c33af497b79816cfc5c8691fa0f56bd681261bd49bc058fc
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .ruby-version
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
+
2
3
  gemspec
3
4
 
4
5
  gem 'rake'
data/Gemfile.lock CHANGED
@@ -1,39 +1,41 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scoped_cache_keys (0.1.1)
4
+ scoped_cache_keys (0.3.0)
5
5
 
6
6
  GEM
7
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
8
8
  specs:
9
- activemodel (3.2.3)
10
- activesupport (= 3.2.3)
11
- builder (~> 3.0.0)
12
- activerecord (3.2.3)
13
- activemodel (= 3.2.3)
14
- activesupport (= 3.2.3)
15
- arel (~> 3.0.2)
16
- tzinfo (~> 0.3.29)
17
- activesupport (3.2.3)
18
- i18n (~> 0.6)
19
- multi_json (~> 1.0)
20
- arel (3.0.2)
21
- builder (3.0.0)
22
- diff-lcs (1.1.3)
23
- i18n (0.6.0)
24
- multi_json (1.3.4)
25
- rake (0.9.2)
26
- rspec (2.6.0)
27
- rspec-core (~> 2.6.0)
28
- rspec-expectations (~> 2.6.0)
29
- rspec-mocks (~> 2.6.0)
30
- rspec-core (2.6.4)
31
- rspec-expectations (2.6.0)
32
- diff-lcs (~> 1.1.2)
33
- rspec-mocks (2.6.0)
34
- sqlite3 (1.3.6)
35
- timecop (0.3.5)
36
- tzinfo (0.3.33)
9
+ activemodel (7.0.4)
10
+ activesupport (= 7.0.4)
11
+ activerecord (7.0.4)
12
+ activemodel (= 7.0.4)
13
+ activesupport (= 7.0.4)
14
+ activesupport (7.0.4)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (>= 1.6, < 2)
17
+ minitest (>= 5.1)
18
+ tzinfo (~> 2.0)
19
+ concurrent-ruby (1.1.10)
20
+ diff-lcs (1.5.0)
21
+ i18n (1.12.0)
22
+ concurrent-ruby (~> 1.0)
23
+ mini_portile2 (2.8.0)
24
+ minitest (5.16.3)
25
+ rake (13.0.6)
26
+ rspec (2.99.0)
27
+ rspec-core (~> 2.99.0)
28
+ rspec-expectations (~> 2.99.0)
29
+ rspec-mocks (~> 2.99.0)
30
+ rspec-core (2.99.2)
31
+ rspec-expectations (2.99.2)
32
+ diff-lcs (>= 1.1.3, < 2.0)
33
+ rspec-mocks (2.99.4)
34
+ sqlite3 (1.5.3)
35
+ mini_portile2 (~> 2.8.0)
36
+ timecop (0.9.5)
37
+ tzinfo (2.0.5)
38
+ concurrent-ruby (~> 1.0)
37
39
 
38
40
  PLATFORMS
39
41
  ruby
@@ -45,3 +47,6 @@ DEPENDENCIES
45
47
  scoped_cache_keys!
46
48
  sqlite3
47
49
  timecop
50
+
51
+ BUNDLED WITH
52
+ 2.3.12
data/Readme.md CHANGED
@@ -1,25 +1,104 @@
1
- Add scoped_cache_key / expire_scoped_cache_key to your models for caching/sweeping of model-related caches.
1
+ scoped_cache_keys
2
+ =================
3
+
4
+ Add `scoped_cache_key` / `expire_scoped_cache_key` to your models for caching/sweeping of model-related caches.
5
+
6
+ Overview
7
+ --------
8
+
9
+ `scoped_cache_keys` enables you to "scope" multiple cache entries together, such that they can be expired
10
+ together in a single operation.
11
+
12
+ This saves the trouble of having to delete several individual cache entries, and improves the consistency
13
+ of your cache entries by having them all expire together.
14
+
15
+ Model-related caches in a Rails application often consist of multiple cache entries, which should be
16
+ consistent with each other.
17
+
18
+ For instance, you might have a cache entry which is a key->value mapping for a model, but another
19
+ cache entry which is a value->key mapping.
2
20
 
3
21
  Install
4
- =======
5
- sudo gem install scoped_cache_keys
6
- Or
22
+ -------
7
23
 
8
- rails plugin install git://github.com/grosser/scoped_cache_keys.git
24
+ ```bash
25
+ gem "scoped_cache_keys"
26
+ ```
9
27
 
10
28
  Usage
11
- =====
29
+ -----
30
+
31
+ To use `scoped_cached_keys`, use `include ScopedCacheKeys` in your model declaration:
32
+
33
+ ```ruby
34
+ class User < ActiveRecord::Base
35
+ include ScopedCacheKeys
36
+ ...
37
+ end
38
+ ```
39
+
40
+ ### scoped_cache_key ###
41
+
42
+ The `scoped_cache_key` method returns a key that will change whenever `expire_scoped_cache_key` is called.
43
+ The cache key will be scoped to the model object that `scoped_cache_key` is invoked on, along with
44
+ whatever scope is passed:
45
+
46
+ ```ruby
47
+ account.scoped_cache_key(:orders)
48
+ ```
49
+
50
+ Options: Any caching options that are passed to `Rails.cache` methods may be passed to `scoped_cache_key`.
51
+ For example:
52
+
53
+ ```ruby
54
+ account.scoped_cache_key(:orders, expires_in: 10.minutes)
55
+ ```
56
+
57
+ The key that is returned can be treated as a "base key," that is, concatenated with other strings to form
58
+ other cache keys. All such cache keys will become unreachable, and thus "expired," when
59
+ `expire_scoped_cache_key` is called.
60
+
61
+ ### expire_scoped_cache_key ###
62
+
63
+ The `expire_scoped_cache_key` method will expire a scoped cache key obtained with `scoped_cache_key`.
64
+ Example:
65
+
66
+ ```ruby
67
+ account.expire_scoped_cache_key(:orders)
68
+ ```
69
+
70
+ Options: The optional `delay` parameter specifies an amount of time to delay before actually expiring
71
+ the scoped cache key. Example:
72
+
73
+ ```ruby
74
+ account.expire_scoped_cache_key(:orders, delay: 5.seconds)
75
+ ```
76
+
77
+ The `delay` parameter can be useful for contending with database replication lag. When many concurrent
78
+ processes access the scoped cache entries, one or more may immediately try to rebuild the cache
79
+ the instant that `expire_scoped_cache_key` completes. This could happen so quickly that the database
80
+ replicas may not be caught up with the model changes that were just committed. Alternately, one
81
+ could force the models to be queried from the primary database to avoid such race conditions.
82
+
83
+ The expiration delay may also be set at a global level:
84
+
85
+ ```ruby
86
+ ScopedCacheKeys.expire_scoped_cache_key_delay = 10.seconds
87
+ ```
12
88
 
13
- Gives you a key that will change whenever expire_scoped_cache_key is called.
89
+ ### Example ###
14
90
 
91
+ ```
15
92
  <% cache user.scoped_cache_key :products do %>
16
93
  ... user.products.each ...
17
94
  <% end %>
18
95
 
19
- <% cache "something-else-" + user.scoped_cache_key :products %>
96
+ <% cache "something-else-" + user.scoped_cache_key(:products) do %>
20
97
  ... will also be expired ...
21
98
  <% end %>
99
+ ```
22
100
 
101
+ ```ruby
23
102
  # app/sweepers/product_sweeper.rb
24
103
  class ProductSweeper < ActionController::Caching::Sweeper
25
104
  observe Product
@@ -28,10 +107,10 @@ Gives you a key that will change whenever expire_scoped_cache_key is called.
28
107
  record.user.expire_scoped_cache_key :products
29
108
  end
30
109
  end
110
+ ```
31
111
 
32
112
  Author
33
- ======
113
+ ------
34
114
  [Zendesk](http://zendesk.com)<br/>
35
115
  michael@grosser.it<br/>
36
- License: MIT<br/>
37
- [![Build Status](https://secure.travis-ci.org/grosser/scoped_cache_keys.png)](http://travis-ci.org/grosser/scoped_cache_keys)
116
+ License: MIT
@@ -1,3 +1,3 @@
1
1
  module ScopedCacheKeys
2
- VERSION = '0.1.1'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -1,13 +1,26 @@
1
1
  require 'scoped_cache_keys/version'
2
2
 
3
3
  module ScopedCacheKeys
4
- def scoped_cache_key(scope)
5
- base_key = Rails.cache.fetch(build_scoped_cache_key([scope])){ Time.now.to_f }
4
+ class << self
5
+ # If set, expire_scoped_cache_key will delay expiration by this many seconds
6
+ # globally.
7
+ attr_accessor :expire_scoped_cache_key_delay
8
+ end
9
+
10
+ def scoped_cache_key(scope, options = nil)
11
+ base_key = Rails.cache.fetch(build_scoped_cache_key([scope]), options) { Time.now.to_f }
6
12
  build_scoped_cache_key [scope, base_key]
7
13
  end
8
14
 
9
- def expire_scoped_cache_key(scope)
10
- Rails.cache.delete(build_scoped_cache_key(scope))
15
+ def expire_scoped_cache_key(scope, delay: nil)
16
+ delay ||= ScopedCacheKeys.expire_scoped_cache_key_delay
17
+ key = build_scoped_cache_key(scope)
18
+ if delay
19
+ entry = Rails.cache.read(key)
20
+ Rails.cache.write(key, entry, expires_in: delay) if entry
21
+ else
22
+ Rails.cache.delete(key)
23
+ end
11
24
  end
12
25
 
13
26
  private
@@ -45,6 +45,12 @@ describe ScopedCacheKeys do
45
45
  user.updated_at = 1.week.ago
46
46
  }.to_not change{ user.scoped_cache_key(:foo) }
47
47
  end
48
+
49
+ it "accepts cache options such as expired_in" do
50
+ key = user.scoped_cache_key(:foo, expires_in: 10.seconds)
51
+ Timecop.travel(11.seconds.from_now)
52
+ user.scoped_cache_key(:foo).should_not == key
53
+ end
48
54
  end
49
55
 
50
56
  describe "#expire_scoped_cache_key" do
@@ -59,5 +65,25 @@ describe ScopedCacheKeys do
59
65
  user.expire_scoped_cache_key :bar
60
66
  }.to_not change{ user.scoped_cache_key(:foo) }
61
67
  end
68
+
69
+ it "expires a specific scope after a specified delay" do
70
+ key = user.scoped_cache_key :foo
71
+ user.expire_scoped_cache_key :foo, delay: 5.seconds
72
+ Timecop.travel(4.seconds.from_now)
73
+ user.scoped_cache_key(:foo).should == key
74
+ Timecop.travel(2.seconds.from_now)
75
+ user.scoped_cache_key(:foo).should_not == key
76
+ end
77
+
78
+ it "expires a specific scope after a specified global delay" do
79
+ ScopedCacheKeys.expire_scoped_cache_key_delay = 10.seconds
80
+ key = user.scoped_cache_key :foo
81
+ user.expire_scoped_cache_key :foo
82
+ Timecop.travel(9.seconds.from_now)
83
+ user.scoped_cache_key(:foo).should == key
84
+ Timecop.travel(2.seconds.from_now)
85
+ user.scoped_cache_key(:foo).should_not == key
86
+ ScopedCacheKeys.expire_scoped_cache_key_delay = nil
87
+ end
62
88
  end
63
89
  end
metadata CHANGED
@@ -1,33 +1,22 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: scoped_cache_keys
3
- version: !ruby/object:Gem::Version
4
- hash: 25
5
- prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Michael Grosser
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2012-05-04 00:00:00 Z
11
+ date: 2022-12-02 00:00:00.000000000 Z
19
12
  dependencies: []
20
-
21
13
  description:
22
14
  email: michael@grosser.it
23
15
  executables: []
24
-
25
16
  extensions: []
26
-
27
17
  extra_rdoc_files: []
28
-
29
- files:
30
- - .travis.yml
18
+ files:
19
+ - ".gitignore"
31
20
  - Gemfile
32
21
  - Gemfile.lock
33
22
  - Rakefile
@@ -38,37 +27,27 @@ files:
38
27
  - spec/scoped_cache_keys_spec.rb
39
28
  - spec/spec_helper.rb
40
29
  homepage: http://github.com/grosser/scoped_cache_keys
41
- licenses:
30
+ licenses:
42
31
  - MIT
32
+ metadata: {}
43
33
  post_install_message:
44
34
  rdoc_options: []
45
-
46
- require_paths:
35
+ require_paths:
47
36
  - lib
48
- required_ruby_version: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
51
39
  - - ">="
52
- - !ruby/object:Gem::Version
53
- hash: 3
54
- segments:
55
- - 0
56
- version: "0"
57
- required_rubygems_version: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
60
44
  - - ">="
61
- - !ruby/object:Gem::Version
62
- hash: 3
63
- segments:
64
- - 0
65
- version: "0"
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
66
47
  requirements: []
67
-
68
- rubyforge_project:
69
- rubygems_version: 1.8.24
48
+ rubygems_version: 3.1.6
70
49
  signing_key:
71
- specification_version: 3
72
- summary: Add scoped_cache_key / expire_scoped_cache_key to your models for caching/sweeping of model-related caches + touch_if_necessary
50
+ specification_version: 4
51
+ summary: Add scoped_cache_key / expire_scoped_cache_key to your models for caching/sweeping
52
+ of model-related caches + touch_if_necessary
73
53
  test_files: []
74
-
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- script: "bundle exec rake"
2
- rvm:
3
- - ree
4
- - 1.9.2
5
- - 1.9.3