cached_resource 5.1.1 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2b25cc83718d786c0441bc7cb082944ac7aa4fe3d379792cacb96e87df668eb
4
- data.tar.gz: 8fa4f263faee071d9e7361f27b8927113bb36e76b1e5e765e993935cadad8c22
3
+ metadata.gz: 7102fd60421cc8ddea333b62047f5bf15dcc07e1ac38444084f8815d728ad386
4
+ data.tar.gz: 51e3b4a15b4094cdcfeda312a10b44aaff7f1da7143020c5100cd55b7f8dd22e
5
5
  SHA512:
6
- metadata.gz: 0523763d1f6d1dd9eb1d68ddb2a196e8f737d5660c91bcb244374804b0ddc31f50037ebb19c0dc1a25b891586cf3b5025df60b16a11c209e03f0510147e78514
7
- data.tar.gz: 8ae89f1cd8fcf8dccedc053c7acc15b76ea84853240b0998ee31b5a17f837d001696866262182787d315d4f432f67d87b1ef4d9ef918b530b4e884f4e2f88363
6
+ metadata.gz: 789e3ab01ffa4dd155a7587cab2d6f92455c0e9a8e2d8ce429b562c626be43eaadbfda3a44d13e09cb998c5e51805042eb7cd7463adc6b7f1e8cc25e2e77628e
7
+ data.tar.gz: 636d931d7de4ab7068d3f68704c4832f6216be8b0d7d50cc28797fb55389e8d2b0199b78685b57d5c48f8d596c6bf0e96a58f24d75a2a9b89467688de90140b3
data/.travis.yml CHANGED
@@ -1,5 +1,7 @@
1
1
  language: ruby
2
2
  sudo: false
3
+ before_install:
4
+ - gem install bundler:1.17.3
3
5
  cache: bundler
4
6
 
5
7
  rvm:
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # CachedResource [![Build Status](https://secure.travis-ci.org/mhgbrown/cached_resource.png)](http://travis-ci.org/mhgbrown/cached_resource)
1
+ # CachedResource [![Build Status](https://travis-ci.org/mhgbrown/cached_resource.svg?branch=master)](http://travis-ci.org/mhgbrown/cached_resource)
2
2
  CachedResource is a Ruby gem whose goal is to increase the performance of interacting with web services via ActiveResource by caching responses based on request parameters. It can help reduce the lag created by making repeated requests across a network.
3
3
 
4
4
  ## Installation
@@ -53,6 +53,7 @@ CachedResource accepts the following options:
53
53
  * `:collection_arguments` The arguments that identify the principal collection request. Default: `[:all]`
54
54
  * `:logger` The logger to which CachedResource messages should be written. Default: The `Rails.logger` if available, or an `ActiveSupport::Logger`
55
55
  * `:cache` The cache store that CacheResource should use. Default: The `Rails.cache` if available, or an `ActiveSupport::Cache::MemoryStore`
56
+ * `:cache_collections` Set to false to always remake a request for collections. Default: `true`
56
57
 
57
58
  You can set them like this:
58
59
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- cached_resource (5.1.0)
4
+ cached_resource (5.3.0)
5
5
  activeresource (>= 4.0)
6
6
  activesupport (>= 4.0)
7
7
  nilio (>= 1.0)
@@ -93,7 +93,7 @@ GEM
93
93
  rails-deprecated_sanitizer (>= 1.0.1)
94
94
  rails-html-sanitizer (1.0.3)
95
95
  loofah (~> 2.0)
96
- rails-observers (0.1.4)
96
+ rails-observers (0.1.5)
97
97
  activemodel (>= 4.0)
98
98
  railties (4.2.9)
99
99
  actionpack (= 4.2.9)
@@ -137,4 +137,4 @@ DEPENDENCIES
137
137
  rspec
138
138
 
139
139
  BUNDLED WITH
140
- 1.17.1
140
+ 1.17.3
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- cached_resource (5.1.0)
4
+ cached_resource (5.3.0)
5
5
  activeresource (>= 4.0)
6
6
  activesupport (>= 4.0)
7
7
  nilio (>= 1.0)
@@ -37,19 +37,18 @@ GEM
37
37
  globalid (>= 0.3.6)
38
38
  activemodel (5.0.2)
39
39
  activesupport (= 5.0.2)
40
- activemodel-serializers-xml (1.0.1)
40
+ activemodel-serializers-xml (1.0.2)
41
41
  activemodel (> 5.x)
42
- activerecord (> 5.x)
43
42
  activesupport (> 5.x)
44
43
  builder (~> 3.1)
45
44
  activerecord (5.0.2)
46
45
  activemodel (= 5.0.2)
47
46
  activesupport (= 5.0.2)
48
47
  arel (~> 7.0)
49
- activeresource (5.0.0)
50
- activemodel (>= 5.0, < 6)
48
+ activeresource (5.1.1)
49
+ activemodel (>= 5.0, < 7)
51
50
  activemodel-serializers-xml (~> 1.0)
52
- activesupport (>= 5.0, < 6)
51
+ activesupport (>= 5.0, < 7)
53
52
  activesupport (5.0.2)
54
53
  concurrent-ruby (~> 1.0, >= 1.0.2)
55
54
  i18n (~> 0.7)
@@ -147,4 +146,4 @@ DEPENDENCIES
147
146
  rspec
148
147
 
149
148
  BUNDLED WITH
150
- 1.17.1
149
+ 1.17.3
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- cached_resource (5.1.0)
4
+ cached_resource (5.3.0)
5
5
  activeresource (>= 4.0)
6
6
  activesupport (>= 4.0)
7
7
  nilio (>= 1.0)
@@ -37,19 +37,18 @@ GEM
37
37
  globalid (>= 0.3.6)
38
38
  activemodel (5.1.2)
39
39
  activesupport (= 5.1.2)
40
- activemodel-serializers-xml (1.0.1)
40
+ activemodel-serializers-xml (1.0.2)
41
41
  activemodel (> 5.x)
42
- activerecord (> 5.x)
43
42
  activesupport (> 5.x)
44
43
  builder (~> 3.1)
45
44
  activerecord (5.1.2)
46
45
  activemodel (= 5.1.2)
47
46
  activesupport (= 5.1.2)
48
47
  arel (~> 8.0)
49
- activeresource (5.0.0)
50
- activemodel (>= 5.0, < 6)
48
+ activeresource (5.1.1)
49
+ activemodel (>= 5.0, < 7)
51
50
  activemodel-serializers-xml (~> 1.0)
52
- activesupport (>= 5.0, < 6)
51
+ activesupport (>= 5.0, < 7)
53
52
  activesupport (5.1.2)
54
53
  concurrent-ruby (~> 1.0, >= 1.0.2)
55
54
  i18n (~> 0.7)
@@ -147,4 +146,4 @@ DEPENDENCIES
147
146
  rspec
148
147
 
149
148
  BUNDLED WITH
150
- 1.17.1
149
+ 1.17.3
@@ -17,6 +17,7 @@ module CachedResource
17
17
  def find_with_cache(*arguments)
18
18
  arguments << {} unless arguments.last.is_a?(Hash)
19
19
  should_reload = arguments.last.delete(:reload) || !cached_resource.enabled
20
+ should_reload = true if !cached_resource.cache_collections && is_any_collection?(*arguments)
20
21
  arguments.pop if arguments.last.empty?
21
22
  key = cache_key(arguments)
22
23
 
@@ -24,8 +25,8 @@ module CachedResource
24
25
  end
25
26
 
26
27
  # Clear the cache.
27
- def clear_cache
28
- cache_clear
28
+ def clear_cache(options=nil)
29
+ cache_clear(options)
29
30
  end
30
31
 
31
32
  private
@@ -41,6 +42,7 @@ module CachedResource
41
42
  def find_via_reload(key, *arguments)
42
43
  object = find_without_cache(*arguments)
43
44
  cache_collection_synchronize(object, *arguments) if cached_resource.collection_synchronize
45
+ return object if !cached_resource.cache_collections && is_any_collection?(*arguments)
44
46
  cache_write(key, object)
45
47
  cache_read(key)
46
48
  end
@@ -82,16 +84,27 @@ module CachedResource
82
84
  arguments == cached_resource.collection_arguments
83
85
  end
84
86
 
87
+ # Determine if the given arguments represent
88
+ # any collection of objects
89
+ def is_any_collection?(*arguments)
90
+ cached_resource.collection_arguments.all?{ |arg| arguments.include?(arg) } || arguments.include?(:all)
91
+ end
92
+
85
93
  # Read a entry from the cache for the given key.
86
94
  def cache_read(key)
87
95
  object = cached_resource.cache.read(key).try do |json_cache|
88
- cache = json_to_object(JSON.parse(json_cache, :symbolize_names => true))
89
- if cache.is_a? Enumerable
90
- restored = cache.map { |record| full_dup(record) }
91
- next restored unless respond_to?(:collection_parser)
92
- collection_parser.new(restored)
93
- else
94
- full_dup(cache)
96
+
97
+ json = ActiveSupport::JSON.decode(json_cache)
98
+
99
+ unless json.nil?
100
+ cache = json_to_object(json)
101
+ if cache.is_a? Enumerable
102
+ restored = cache.map { |record| full_dup(record) }
103
+ next restored unless respond_to?(:collection_parser)
104
+ collection_parser.new(restored)
105
+ else
106
+ full_dup(cache)
107
+ end
95
108
  end
96
109
  end
97
110
  object && cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} READ #{key}")
@@ -106,15 +119,26 @@ module CachedResource
106
119
  end
107
120
 
108
121
  # Clear the cache.
109
- def cache_clear
110
- cached_resource.cache.clear.tap do |result|
111
- cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} CLEAR")
122
+ def cache_clear(options=nil)
123
+ # Memcache doesn't support delete_matched, which can also be computationally expensive
124
+ if cached_resource.cache.class.to_s == 'ActiveSupport::Cache::MemCacheStore' || options.try(:fetch,:all)
125
+ cached_resource.cache.clear.tap do |result|
126
+ cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} CLEAR ALL")
127
+ end
128
+ else
129
+ cached_resource.cache.delete_matched("^#{name_key}/*").tap do |result|
130
+ cached_resource.logger.info("#{CachedResource::Configuration::LOGGER_PREFIX} CLEAR #{name_key}/*")
131
+ end
112
132
  end
113
133
  end
114
134
 
115
135
  # Generate the request cache key.
116
136
  def cache_key(*arguments)
117
- "#{name.parameterize.gsub("-", "/")}/#{arguments.join('/')}".downcase.delete(' ')
137
+ "#{name_key}/#{arguments.join('/')}".downcase.delete(' ')
138
+ end
139
+
140
+ def name_key
141
+ name.parameterize.gsub("-", "/")
118
142
  end
119
143
 
120
144
  # Make a full duplicate of an ActiveResource record.
@@ -128,15 +152,17 @@ module CachedResource
128
152
  def json_to_object(json)
129
153
  if json.is_a? Array
130
154
  json.map { |attrs|
131
- self.new(attrs[:object], attrs[:persistence]) }
155
+ self.new(attrs["object"], attrs["persistence"]) }
132
156
  else
133
- self.new(json[:object], json[:persistence])
157
+ self.new(json["object"], json["persistence"])
134
158
  end
135
159
  end
136
160
 
137
161
  def object_to_json(object)
138
162
  if object.is_a? Enumerable
139
163
  object.map { |o| { :object => o, :persistence => o.persisted? } }.to_json
164
+ elsif object.nil?
165
+ nil.to_json
140
166
  else
141
167
  { :object => object, :persistence => object.persisted? }.to_json
142
168
  end
@@ -22,7 +22,8 @@ module CachedResource
22
22
  # :collection_synchronize, default: false,
23
23
  # :collection_arguments, default: [:all]
24
24
  # :cache, default: Rails.cache or ActiveSupport::Cache::MemoryStore.new,
25
- # :logger, default: Rails.logger or ActiveSupport::Logger.new(NilIO.new)
25
+ # :logger, default: Rails.logger or ActiveSupport::Logger.new(NilIO.new),
26
+ # :cache_collections, default: true
26
27
  def initialize(options={})
27
28
  super({
28
29
  :enabled => true,
@@ -33,7 +34,8 @@ module CachedResource
33
34
  :collection_synchronize => false,
34
35
  :collection_arguments => [:all],
35
36
  :cache => defined?(Rails.cache) && Rails.cache || CACHE,
36
- :logger => defined?(Rails.logger) && Rails.logger || LOGGER
37
+ :logger => defined?(Rails.logger) && Rails.logger || LOGGER,
38
+ :cache_collections => true
37
39
  }.merge(options))
38
40
  end
39
41
 
@@ -1,3 +1,3 @@
1
1
  module CachedResource
2
- VERSION = "5.1.1"
2
+ VERSION = "5.3.0"
3
3
  end
@@ -12,6 +12,11 @@ describe CachedResource do
12
12
  cached_resource
13
13
  end
14
14
 
15
+ class NotTheThing < ActiveResource::Base
16
+ self.site = "http://api.notthething.com"
17
+ cached_resource
18
+ end
19
+
15
20
  @thing = {:thing => {:id => 1, :name => "Ada"}}
16
21
  @other_thing = {:thing => {:id => 1, :name => "Ari"}}
17
22
  @thing2 = {:thing => {:id => 2, :name => "Joe"}}
@@ -19,15 +24,22 @@ describe CachedResource do
19
24
  @thing3 = {:thing => {:id => 3, :name => "Stu"}}
20
25
  @string_thing = {:thing => {:id => "fded", :name => "Lev"}}
21
26
  @other_string_thing = {:thing => {:id => "fded", :name => "Lon"}}
27
+ @date_thing = {:thing => {:id => 4, :created_at => Time.utc(2020).iso8601}}
22
28
  @thing_json = @thing.to_json
23
29
  @other_thing_json = @other_thing.to_json
24
30
  @string_thing_json = @string_thing.to_json
25
31
  @other_string_thing_json = @other_string_thing.to_json
32
+ @date_thing_json = @date_thing.to_json
33
+ @nil_thing = nil.to_json
34
+ @not_the_thing = {:not_the_thing => {:id => 1, :name => "Not"}}
35
+ @not_the_thing_json = @not_the_thing.to_json
26
36
  end
27
37
 
28
38
  after(:each) do
29
39
  Thing.cached_resource.cache.clear
30
40
  Object.send(:remove_const, :Thing)
41
+ NotTheThing.cached_resource.cache.clear
42
+ Object.send(:remove_const, :NotTheThing)
31
43
  end
32
44
 
33
45
  describe "when enabled" do
@@ -36,12 +48,17 @@ describe CachedResource do
36
48
  # to make sure it works
37
49
  Thing.cached_resource.cache.clear
38
50
  Thing.cached_resource.on!
51
+ NotTheThing.cached_resource.cache.clear
52
+ NotTheThing.cached_resource.on!
39
53
 
40
54
  ActiveResource::HttpMock.reset!
41
55
  ActiveResource::HttpMock.respond_to do |mock|
42
56
  mock.get "/things/1.json", {}, @thing_json
43
57
  mock.get "/things/1.json?foo=bar", {}, @thing_json
44
58
  mock.get "/things/fded.json", {}, @string_thing_json
59
+ mock.get "/things.json?name=42", {}, @nil_thing, 404
60
+ mock.get "/things/4.json", {}, @date_thing_json
61
+ mock.get "/not_the_things/1.json", {}, @not_the_thing_json
45
62
  end
46
63
  end
47
64
 
@@ -51,6 +68,11 @@ describe CachedResource do
51
68
  read_from_cache("thing/1").should == result
52
69
  end
53
70
 
71
+ it "should cache a nil response" do
72
+ result = Thing.find(:all, :params => { :name => '42' })
73
+ read_from_cache("thing/all/name/42").should == nil
74
+ end
75
+
54
76
  it "should cache a response for a string primary key" do
55
77
  result = Thing.find("fded")
56
78
  read_from_cache("thing/fded").should == result
@@ -67,6 +89,20 @@ describe CachedResource do
67
89
  read_from_cache("thing/1").should == nil
68
90
  end
69
91
 
92
+ it "should not empty the cache of NotTheThing when clear_cache is called on the Thing" do
93
+ result1 = Thing.find(1)
94
+ result2 = NotTheThing.find(1)
95
+ Thing.clear_cache
96
+ NotTheThing.send(:cache_read, 'notthething/1').should == result2
97
+ end
98
+
99
+ it "should empty all the cache when clear_cache is called on the Thing with :all option set" do
100
+ result1 = Thing.find(1)
101
+ result2 = NotTheThing.find(1)
102
+ Thing.clear_cache(all: true)
103
+ NotTheThing.send(:cache_read, 'notthething/1').should == nil
104
+ end
105
+
70
106
  it "should cache a response with the same persistence" do
71
107
  result1 = Thing.find(1)
72
108
  result1.persisted?.should be true
@@ -159,6 +195,19 @@ describe CachedResource do
159
195
  result1.should_not be_frozen
160
196
  end
161
197
 
198
+ describe "when ActiveSupport.parse_json_times is enabled" do
199
+ before(:all) do
200
+ Time.zone = 'UTC'
201
+ ActiveSupport.parse_json_times = true
202
+ end
203
+
204
+ it "should convert date times to objects when reading from cache" do
205
+ Thing.find(4)
206
+
207
+ read_from_cache("thing/4").created_at.should == @date_thing[:thing][:created_at]
208
+ end
209
+ end
210
+
162
211
  shared_examples "collection_return_type" do
163
212
  if ActiveResource::VERSION::MAJOR >= 4
164
213
  it "should return an ActiveResource::Collection" do
@@ -516,4 +565,37 @@ describe CachedResource do
516
565
  new_result.name.should_not == old_result.name
517
566
  end
518
567
  end
568
+
569
+ describe "when cache_collections is disabled" do
570
+ before(:each) do
571
+ Thing.cached_resource.cache.clear
572
+ Thing.cached_resource.cache_collections = false
573
+
574
+ ActiveResource::HttpMock.reset!
575
+ ActiveResource::HttpMock.respond_to do |mock|
576
+ mock.get "/things.json", {}, [@thing[:thing],@string_thing[:thing]].to_json(:root => :thing)
577
+ mock.get "/things/1.json", {}, @thing_json
578
+ mock.get "/things/fded.json", {}, @string_thing_json
579
+ end
580
+ end
581
+
582
+ it "should cache a response" do
583
+ result = Thing.find(1)
584
+ read_from_cache("thing/1").should == result
585
+ end
586
+
587
+ it "should not remake a single request" do
588
+ result = Thing.find(1)
589
+ ActiveResource::HttpMock.requests.length.should == 1
590
+ result = Thing.find(1)
591
+ ActiveResource::HttpMock.requests.length.should == 1
592
+ end
593
+
594
+ it "should always remake the request for collections" do
595
+ Thing.all
596
+ ActiveResource::HttpMock.requests.length.should == 1
597
+ Thing.all
598
+ ActiveResource::HttpMock.requests.length.should == 2
599
+ end
600
+ end
519
601
  end
@@ -22,6 +22,10 @@ describe "CachedResource::Configuration" do
22
22
  configuration.collection_arguments.should == [:all]
23
23
  end
24
24
 
25
+ it "should cache collections" do
26
+ configuration.cache_collections == true
27
+ end
28
+
25
29
  describe "outside a Rails environment" do
26
30
  it "should be logging to a buffered logger attached to a NilIO" do
27
31
  configuration.logger.class.should == default_logger
@@ -72,7 +76,8 @@ describe "CachedResource::Configuration" do
72
76
  :enabled => false,
73
77
  :collection_synchronize => true,
74
78
  :collection_arguments => [:every],
75
- :custom => "irrelevant"
79
+ :custom => "irrelevant",
80
+ :cache_collections => true
76
81
  end
77
82
  end
78
83
 
@@ -90,6 +95,7 @@ describe "CachedResource::Configuration" do
90
95
  cr.collection_synchronize.should == true
91
96
  cr.collection_arguments.should == [:every]
92
97
  cr.custom.should == "irrelevant"
98
+ cr.cache_collections.should == true
93
99
  end
94
100
  end
95
101
 
@@ -130,7 +136,8 @@ describe "CachedResource::Configuration" do
130
136
  :enabled => false,
131
137
  :collection_synchronize => true,
132
138
  :collection_arguments => [:every],
133
- :custom => "irrelevant"
139
+ :custom => "irrelevant",
140
+ :cache_collections => true
134
141
  end
135
142
 
136
143
  class Foo < Bar
@@ -158,7 +165,8 @@ describe "CachedResource::Configuration" do
158
165
  :enabled => false,
159
166
  :collection_synchronize => true,
160
167
  :collection_arguments => [:every],
161
- :custom => "irrelevant"
168
+ :custom => "irrelevant",
169
+ :cache_collections => true
162
170
  end
163
171
 
164
172
  class Foo < Bar
@@ -186,6 +194,7 @@ describe "CachedResource::Configuration" do
186
194
  cr.custom.should == nil
187
195
  cr.ttl_randomization.should == false
188
196
  cr.ttl_randomization_scale.should == (1..2)
197
+ cr.cache_collections.should == true
189
198
  expect(cr.race_condition_ttl).to eq(86400)
190
199
  end
191
200
 
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: 5.1.1
4
+ version: 5.3.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: 2018-11-12 00:00:00.000000000 Z
11
+ date: 2021-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeresource
@@ -143,13 +143,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
143
  - !ruby/object:Gem::Version
144
144
  version: '0'
145
145
  requirements: []
146
- rubyforge_project:
147
- rubygems_version: 2.7.6
146
+ rubygems_version: 3.0.9
148
147
  signing_key:
149
148
  specification_version: 4
150
149
  summary: Caching for ActiveResource
151
- test_files:
152
- - spec/cached_resource/cached_resource_spec.rb
153
- - spec/cached_resource/caching_spec.rb
154
- - spec/cached_resource/configuration_spec.rb
155
- - spec/spec_helper.rb
150
+ test_files: []