cached_resource 7.2.0 → 8.0.0

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: d1c2150c2dc21cf091c9b26674b3e52a7bd43938318704f7c2f0739a0b9756aa
4
- data.tar.gz: 2f7b9665c688f2a60b7def43cfafbe2701accded9fcf9aabc371fe91bf78362d
3
+ metadata.gz: af6263e0c63b68542a68f62371c79b057e8d9244eb4ab670cfa8956c7cdb1d54
4
+ data.tar.gz: 471295437c0567959f596cd4a8e13639dc670991632e99d01d1bbdea82123664
5
5
  SHA512:
6
- metadata.gz: c0c94c6b77f623a49a3259a69a4bb1b1d2d7fc219d590b740d5a86c71f3cfbf7eb783a2e8a2c06631c926bd2679b220341d8fbf03b77a3651d5219a70bb8d779
7
- data.tar.gz: 207c37429a14511fb788d21bc69e86b01f8f59a303b20aebafb2f07e54aba48546c03a5ac7fa4b99da0bd9b7cd53d385ddb73306c643d9044d113ea638949e61
6
+ metadata.gz: 02ee32043c70de70d3befa042ad68c0de0b71e8abf0197e477e97a1489c51ed7eb726bc38a561dd29e34763184cea026275b6a9ff4b9e20ed2c8876f90d5944e
7
+ data.tar.gz: b652cbf1e7d42adaecf1639ac01c2489a75120bb2780bdb272fef5f2be9ad93fe339521d8e0337434cc98e6eb6234164274fa446710211c8eadb3a349435af15
@@ -19,31 +19,11 @@ jobs:
19
19
 
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['1.9', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2']
23
- rails-version: ['4.2', '5.0', '5.1', '6.0', '6.1', '7.0']
22
+ ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3']
23
+ rails-version: ['4.2', '5.0', '5.1', '6.0', '6.1', '7.0', '7.1']
24
24
  exclude:
25
- # Segmentation faults during tests, but should work?
26
- - ruby-version: '2.2'
27
- rails-version: '5.0'
28
- - ruby-version: '2.2'
29
- rails-version: '5.1'
30
- # Too old
31
- - ruby-version: '1.9'
32
- rails-version: '5.0'
33
- - ruby-version: '1.9'
34
- rails-version: '5.1'
35
- - ruby-version: '1.9'
36
- rails-version: '6.0'
37
- - ruby-version: '1.9'
38
- rails-version: '6.1'
39
- - ruby-version: '1.9'
40
- rails-version: '7.0'
41
25
  # activesupport (~> 6.0.0) was resolved to 6.0.6.1, which depends on ruby (>= 2.5.0)
42
26
  # activesupport (~> 6.1.0) was resolved to 6.1.7.2, which depends on ruby (>= 2.5.0)
43
- - ruby-version: '2.2'
44
- rails-version: '6.0'
45
- - ruby-version: '2.2'
46
- rails-version: '6.1'
47
27
  - ruby-version: '2.3'
48
28
  rails-version: '6.0'
49
29
  - ruby-version: '2.3'
@@ -53,8 +33,6 @@ jobs:
53
33
  - ruby-version: '2.4'
54
34
  rails-version: '6.1'
55
35
  # activesupport (~> 7.0.0) was resolved to 7.0.4.2, which depends on Ruby (>= 2.7.0)
56
- - ruby-version: '2.2'
57
- rails-version: '7.0'
58
36
  - ruby-version: '2.3'
59
37
  rails-version: '7.0'
60
38
  - ruby-version: '2.4'
@@ -87,9 +65,25 @@ jobs:
87
65
  rails-version: '5.0'
88
66
  - ruby-version: '3.2'
89
67
  rails-version: '5.1'
68
+ # rails (~> 7.1.0) was resolved to 7.1.3.2, which depends on Ruby (>= 2.7.0)
69
+ - ruby-version: '2.3'
70
+ rails-version: '7.1'
71
+ - ruby-version: '2.4'
72
+ rails-version: '7.1'
73
+ - ruby-version: '2.5'
74
+ rails-version: '7.1'
75
+ - ruby-version: '2.6'
76
+ rails-version: '7.1'
77
+ # Because rails >= 4.0.0.beta1, < 5.0.5.rc1 depends on bundler >= 1.3.0, < 2.0
78
+ # and the current Bundler version (2.5.9) does not satisfy bundler >= 1.3.0, < 2.0,
79
+ # rails >= 4.0.0.beta1, < 5.0.5.rc1 cannot be used.
80
+ # So, because Gemfile depends on rails ~> 4.2.0,
81
+ # version solving has failed.
82
+ - ruby-version: '3.3'
83
+ rails-version: '4.2'
90
84
 
91
85
  steps:
92
- - uses: actions/checkout@v3
86
+ - uses: actions/checkout@v4
93
87
  - name: Set up Ruby ${{ matrix.ruby-version }}
94
88
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
95
89
  # change this to (see https://github.com/ruby/setup-ruby#versioning):
data/Gemfile CHANGED
@@ -24,6 +24,8 @@ when "6.1"
24
24
  eval_gemfile('../gemfiles/6.1.gemfile')
25
25
  when "7.0"
26
26
  eval_gemfile('../gemfiles/7.0.gemfile')
27
+ when "7.1"
28
+ eval_gemfile('../gemfiles/7.1.gemfile')
27
29
  else
28
30
  puts "\e[93mNo TEST_RAILS_VERSION present, letting dependency manager decide what's best.\e[0m" if ENV['DEBUG']
29
31
  end
data/README.md CHANGED
@@ -12,18 +12,17 @@ gem install cached_resource
12
12
 
13
13
  CachedResource is designed to be framework agnostic, but will hook into Rails for caching and logging if available. CachedResource supports the following ActiveSupport/Rails (right) and Ruby (down) version combinations:
14
14
 
15
- | | 🛤️ 4.2 | 🛤️ 5.0 | 🛤️ 5.1 | 🛤️ 6.0 | 🛤️ 6.1 | 🛤️ 7.0 |
16
- |-------|-----|-----|-----|-----|-----|-----|
17
- | 💎 1.9 | ✅ | | | | | |
18
- | 💎 2.2 | ✅ | | | | | |
19
- | 💎 2.3 | ✅ | ✅ | ✅ | | | |
20
- | 💎 2.4 | ✅ | ✅ | ✅ | | | |
21
- | 💎 2.5 | ✅ | ✅ | ✅ | ✅ | ✅ | |
22
- | 💎 2.6 ||| ✅ | ✅ | ✅ | |
23
- | 💎 2.7 | | ✅ | ✅ | ✅ | ✅ | |
24
- | 💎 3.0 | | | | ✅ | ✅ | ✅ |
25
- | 💎 3.1 | | | | ✅ | ✅ | ✅ |
26
- | 💎 3.2 | | | | ✅ | ✅ | ✅ |
15
+ | | 🛤️ 4.2 | 🛤️ 5.0 | 🛤️ 5.1 | 🛤️ 6.0 | 🛤️ 6.1 | 🛤️ 7.0 | 🛤️ 7.1 |
16
+ |-------|-----|-----|-----|-----|-----|-----|-----|
17
+ | 💎 2.3 | ✅ ||| | | | |
18
+ | 💎 2.4 | ✅ ||| | | | |
19
+ | 💎 2.5 | ✅ | ✅ | ✅ ||| | |
20
+ | 💎 2.6 | ✅ | | ✅ | ✅ || |
21
+ | 💎 2.7 | | ✅ | ✅ | ✅ | ✅ | ✅ |✅ |
22
+ | 💎 3.0 | | | | ✅ | ✅ | ✅ ||
23
+ | 💎 3.1 | | | | ✅ | ✅ | ✅ | ✅ |
24
+ | 💎 3.2 | | | | ✅ | ✅ | ✅ | ✅ |
25
+ | 💎 3.3 | ||| ✅ | ✅ | ✅ | ✅ |
27
26
 
28
27
  ## Limitations
29
28
 
@@ -55,15 +54,17 @@ end
55
54
  CachedResource accepts the following options:
56
55
 
57
56
  * `:enabled` Default: `true`
58
- * `:ttl` The time in seconds until the cache should expire. Default: `604800`
59
- * `:race_condition_ttl` The race condition ttl, to prevent [dog pile effect](https://en.wikipedia.org/wiki/Cache_stampede) or [cache stampede](https://en.wikipedia.org/wiki/Cache_stampede). Default: 86400
60
- * `:ttl_randomization` Enable ttl randomization. Default: `false`
61
- * `:ttl_randomization_scale` A Range from which a random value will be selected to scale the ttl. Default: `1..2`
62
- * `:collection_synchronize` Use collections to generate cache entries for individuals. Update the existing cached principal collection when retrieving subsets of the principal collection or individuals. Default: `false`
57
+ * `:cache_collections` Set to false to always remake a request for collections. Default: `true`
58
+ * `:cache` The cache store that CacheResource should use. Default: The `Rails.cache` if available, or an `ActiveSupport::Cache::MemoryStore`
63
59
  * `:collection_arguments` The arguments that identify the principal collection request. Default: `[:all]`
60
+ * `:collection_synchronize` Use collections to generate cache entries for individuals. Update the existing cached principal collection when retrieving subsets of the principal collection or individuals. Default: `false`
61
+ * `:concurrent_write` Set to true to make concurrent writes to cache after successful API response. Default: `false`
62
+ * Requires the [concurrent-ruby](https://rubygems.org/gems/concurrent-ruby) gem
64
63
  * `:logger` The logger to which CachedResource messages should be written. Default: The `Rails.logger` if available, or an `ActiveSupport::Logger`
65
- * `:cache` The cache store that CacheResource should use. Default: The `Rails.cache` if available, or an `ActiveSupport::Cache::MemoryStore`
66
- * `:cache_collections` Set to false to always remake a request for collections. Default: `true`
64
+ * `:race_condition_ttl` The race condition ttl, to prevent [dog pile effect](https://en.wikipedia.org/wiki/Cache_stampede) or [cache stampede](https://en.wikipedia.org/wiki/Cache_stampede). Default: 86400
65
+ * `:ttl_randomization_scale` A Range from which a random value will be selected to scale the ttl. Default: `1..2`
66
+ * `:ttl_randomization` Enable ttl randomization. Default: `false`
67
+ * `:ttl` The time in seconds until the cache should expire. Default: `604800`
67
68
 
68
69
  You can set them like this:
69
70
 
@@ -25,4 +25,5 @@ Gem::Specification.new do |s|
25
25
 
26
26
  s.add_development_dependency "rake"
27
27
  s.add_development_dependency "rspec"
28
+ s.add_development_dependency "concurrent-ruby", '~> 1.2', '>= 1.2.3'
28
29
  end
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rails", "~> 7.1.0"
@@ -18,6 +18,16 @@ module CachedResource
18
18
  # and establishing the necessary methods.
19
19
  def setup_cached_resource!(options)
20
20
  @cached_resource = CachedResource::Configuration.new(options)
21
+ if @cached_resource.concurrent_write
22
+ begin
23
+ send :require, 'concurrent/promise'
24
+ rescue LoadError
25
+ @cached_resource.logger.error(
26
+ "`concurrent_write` option is enabled, but `concurrent-ruby` is not an installed dependency"
27
+ )
28
+ raise
29
+ end
30
+ end
21
31
  send :include, CachedResource::Caching
22
32
  @cached_resource
23
33
  end
@@ -45,7 +45,7 @@ module CachedResource
45
45
  cache_collection_synchronize(object, *arguments) if cached_resource.collection_synchronize
46
46
  return object if !cached_resource.cache_collections && is_any_collection?(*arguments)
47
47
  cache_write(key, object, *arguments)
48
- cache_read(key)
48
+ object
49
49
  end
50
50
 
51
51
  # If this is a pure, unadulterated "all" request
@@ -82,7 +82,7 @@ module CachedResource
82
82
  # Avoid cache nil or [] objects
83
83
  def should_cache?(object)
84
84
  return false unless cached_resource.enabled
85
- object.respond_to?(:empty?) ? !object.empty? : !!object
85
+ object.present?
86
86
  end
87
87
 
88
88
  # Determine if the given arguments represent
@@ -110,7 +110,7 @@ module CachedResource
110
110
  next restored unless respond_to?(:collection_parser)
111
111
  collection_parser.new(restored).tap do |parser|
112
112
  parser.resource_class = self
113
- parser.original_params = json['original_params']
113
+ parser.original_params = json['original_params'].deep_symbolize_keys
114
114
  end
115
115
  else
116
116
  full_dup(cache)
@@ -123,6 +123,14 @@ module CachedResource
123
123
 
124
124
  # Write an entry to the cache for the given key and value.
125
125
  def cache_write(key, object, *arguments)
126
+ if cached_resource.concurrent_write
127
+ Concurrent::Promise.execute { _cache_write(key, object, *arguments) } && true
128
+ else
129
+ _cache_write(key, object, *arguments)
130
+ end
131
+ end
132
+
133
+ def _cache_write(key, object, *arguments)
126
134
  options = arguments[1] || {}
127
135
  params = options[:params]
128
136
  prefix_options, query_options = split_options(params)
@@ -24,18 +24,20 @@ module CachedResource
24
24
  # :cache, default: Rails.cache or ActiveSupport::Cache::MemoryStore.new,
25
25
  # :logger, default: Rails.logger or ActiveSupport::Logger.new(NilIO.new),
26
26
  # :cache_collections, default: true
27
+ # :concurrent_write, default: false
27
28
  def initialize(options={})
28
29
  super({
29
30
  :enabled => true,
31
+ :cache => defined?(Rails.cache) && Rails.cache || CACHE,
32
+ :cache_collections => true,
33
+ :collection_arguments => [:all],
34
+ :collection_synchronize => false,
35
+ :concurrent_write => false,
36
+ :logger => defined?(Rails.logger) && Rails.logger || LOGGER,
30
37
  :race_condition_ttl => 86400,
31
38
  :ttl => 604800,
32
39
  :ttl_randomization => false,
33
- :ttl_randomization_scale => 1..2,
34
- :collection_synchronize => false,
35
- :collection_arguments => [:all],
36
- :cache => defined?(Rails.cache) && Rails.cache || CACHE,
37
- :logger => defined?(Rails.logger) && Rails.logger || LOGGER,
38
- :cache_collections => true
40
+ :ttl_randomization_scale => 1..2
39
41
  }.merge(options))
40
42
  end
41
43
 
@@ -72,4 +74,4 @@ module CachedResource
72
74
  end
73
75
 
74
76
  end
75
- end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module CachedResource
2
- VERSION = "7.2.0"
2
+ VERSION = "8.0.0"
3
3
  end
@@ -66,19 +66,27 @@ describe CachedResource do
66
66
  end
67
67
  end
68
68
 
69
- it "should cache a response" do
70
- result = Thing.find(1)
71
- read_from_cache("thing/1").should == result
72
- end
69
+ shared_examples "caching" do
70
+ it "should cache a response" do
71
+ result = Thing.find(1)
72
+ read_from_cache("thing/1").should == result
73
+ end
74
+
75
+ it "shouldn't cache nil response" do
76
+ Thing.find(:all, :params => { :name => '42' })
77
+ read_from_cache("thing/all/name/42").should == nil
78
+ end
73
79
 
74
- it "shouldn't cache nil response" do
75
- Thing.find(:all, :params => { :name => '42' })
76
- read_from_cache("thing/all/name/42").should == nil
80
+ it "shouldn't cache blank response" do
81
+ Thing.find(:all, :params => { :name => '43' })
82
+ read_from_cache("thing/all/name/43").should == nil
83
+ end
77
84
  end
78
85
 
79
- it "shouldn't cache [] response" do
80
- Thing.find(:all, :params => { :name => '43' })
81
- read_from_cache("thing/all/name/43").should == nil
86
+ include_examples "caching"
87
+
88
+ context 'when concurrency is turned on' do
89
+ include_examples "caching"
82
90
  end
83
91
 
84
92
  it "should cache a response for a string primary key" do
@@ -234,12 +242,12 @@ describe CachedResource do
234
242
  end
235
243
 
236
244
  non_cached = Thing.where(name: 'ada')
237
- non_cached.original_params.should == { 'name' => 'ada' }
245
+ non_cached.original_params.should == { :name => 'ada' }
238
246
  non_cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
239
247
 
240
248
  cached = read_from_cache('thing/all/{:params=>{:name=>"ada"}}')
241
249
  cached.should be_instance_of(CustomCollection)
242
- cached.original_params.should == { 'name' => 'ada' }
250
+ cached.original_params.should == { :name => 'ada' }
243
251
  cached.resource_class.should == Thing
244
252
  cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
245
253
 
@@ -249,11 +257,11 @@ describe CachedResource do
249
257
  non_cached = cached.where(major: 'CS')
250
258
  end
251
259
 
252
- non_cached.original_params.should == { 'name' => 'ada', 'major' => 'CS' }
260
+ non_cached.original_params.should == { :name => 'ada', :major => 'CS' }
253
261
  non_cached.resource_class.should == Thing
254
262
  non_cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
255
- cached = read_from_cache('thing/all/{:params=>{"name"=>"ada",:major=>"cs"}}')
256
- cached.original_params.should == { 'name' => 'ada', 'major' => 'CS' }
263
+ cached = read_from_cache('thing/all/{:params=>{:name=>"ada",:major=>"cs"}}')
264
+ cached.original_params.should == { :name => 'ada', :major => 'CS' }
257
265
  cached.resource_class.should == Thing
258
266
  cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
259
267
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cached_resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 8.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Morgan Brown
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-27 00:00:00.000000000 Z
11
+ date: 2024-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeresource
@@ -80,6 +80,26 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: concurrent-ruby
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.2'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.2.3
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.2'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.2.3
83
103
  description: Enables request-based caching for ActiveResource
84
104
  email: cached_resource@email.mhgbrown.is
85
105
  executables: []
@@ -101,6 +121,7 @@ files:
101
121
  - gemfiles/6.0.gemfile
102
122
  - gemfiles/6.1.gemfile
103
123
  - gemfiles/7.0.gemfile
124
+ - gemfiles/7.1.gemfile
104
125
  - lib/cached_resource.rb
105
126
  - lib/cached_resource/cached_resource.rb
106
127
  - lib/cached_resource/caching.rb