api_cache 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 04d4fca20574868e21c48d50e07ae2d6cc78f493
4
+ data.tar.gz: a8b1f69f0a0fe9d9c5ee30a6fa5becffe3bcb4e7
5
+ SHA512:
6
+ metadata.gz: 9df4d242de81e51b02398ca4781a18ae83460e3b059f14410d438334423928a533c7025fea819258d5a3fc1338b928ef3085092826cc6ea521b47d9645fc8189
7
+ data.tar.gz: 23e2d15510a671df5f6ca4d488890165785cce3df10ab67b12b4502d0f85bb456d17c9e706c717c3ae7db47226b4e9f4f726231c296c95ded2baab99a16b27d4
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 – 2014-07-16
4
+
5
+ * [NEW] Allow keys to be deleted [Doug Puchalski]
6
+ * [UPDATED] Updated Moneta dependency - works with 0.7.x & 0.8.x
7
+ * [FIX] Fixed long standing bug in the case that the `created_at` key was evicted before the data key (for example when using memcached)
data/README.md CHANGED
@@ -16,8 +16,7 @@ APICache allows any API client library to be easily wrapped with a robust cachin
16
16
 
17
17
  # Use a proper store
18
18
  require 'moneta'
19
- require 'moneta/memcache'
20
- APICache.store = Moneta::Memcache.new(:server => "localhost")
19
+ APICache.store = Moneta.new(:Memcached)
21
20
 
22
21
  # Wrap an API, and handle the failure case
23
22
 
@@ -94,8 +93,7 @@ You can send any of the following options to `APICache.get(url, options = {}, &b
94
93
 
95
94
  Before using the APICache you should set the cache to use. By default an in memory hash is used - obviously not a great idea. Thankfully APICache can use any moneta store, so for example if you wanted to use memcache you'd do this:
96
95
 
97
- require 'moneta/memcache'
98
- APICache.store = Moneta::Memcache.new(:server => "localhost")
96
+ APICache.store = Moneta.new(:Memcached)
99
97
 
100
98
  Please be liberal with the github issue tracker, more so with pull requests, or drop me a mail to me [at] mloughran [dot] com. I'd love to hear from you.
101
99
 
data/Rakefile CHANGED
@@ -1,10 +1,7 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
- require 'spec/rake/spectask'
5
- Spec::Rake::SpecTask.new(:spec) do |t|
6
- t.libs << 'lib' << 'spec'
7
- t.spec_files = FileList['spec/**/*_spec.rb']
8
- end
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
9
6
 
10
7
  task :default => :spec
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "api_cache"
6
- s.version = "0.2.3"
6
+ s.version = "0.3.0"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Martyn Loughran"]
9
9
  s.email = ["me@mloughran.com"]
@@ -16,10 +16,9 @@ Gem::Specification.new do |s|
16
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
17
  s.require_paths = ["lib"]
18
18
 
19
- s.add_development_dependency('rspec', "~> 1.0")
19
+ s.add_development_dependency('rspec', "~> 2.7")
20
20
  s.add_development_dependency('webmock')
21
21
  s.add_development_dependency('rake')
22
- s.add_development_dependency('moneta', "~> 0.6.0")
22
+ s.add_development_dependency('moneta', "~> 0.7")
23
23
  s.add_development_dependency('dalli')
24
- s.add_development_dependency('memcache-client')
25
24
  end
@@ -128,6 +128,13 @@ class APICache
128
128
  end
129
129
  end
130
130
  end
131
+
132
+ # Manually delete data from the cache.
133
+ #
134
+ def self.delete(key)
135
+ APICache::Cache.new(key, {}).delete
136
+ end
137
+
131
138
  end
132
139
 
133
140
  require 'api_cache/cache'
@@ -14,14 +14,30 @@ class APICache
14
14
  raise "Method not implemented. Called abstract class."
15
15
  end
16
16
 
17
+ # Delete the given key. The return value is not used.
18
+ def delete(key)
19
+ raise "Method not implemented. Called abstract class."
20
+ end
21
+
17
22
  # Does a given key exist in the cache?
18
23
  def exists?(key)
19
24
  raise "Method not implemented. Called abstract class."
20
25
  end
21
26
 
22
- # Has a given time passed since the key was set?
23
- def expired?(key, timeout)
27
+ # created_at returns the time when the key was last set
28
+ def created_at(key)
24
29
  raise "Method not implemented. Called abstract class."
25
30
  end
31
+
32
+ # expired? returns true if the given timeout has passed since the key was
33
+ # set. It has nothing to say about the existence or otherwise of said key.
34
+ def expired?(key, timeout)
35
+ if (created_at = created_at(key))
36
+ Time.now - created_at > timeout
37
+ else
38
+ # If the created_at data is missing assume expired
39
+ true
40
+ end
41
+ end
26
42
  end
27
43
  end
@@ -47,6 +47,11 @@ class APICache
47
47
  true
48
48
  end
49
49
 
50
+ def delete
51
+ store.delete(hash)
52
+ return nil
53
+ end
54
+
50
55
  private
51
56
 
52
57
  def hash
@@ -16,14 +16,18 @@ class APICache
16
16
  @dalli.get(key)
17
17
  end
18
18
 
19
+ # Delete value.
20
+ def delete(key)
21
+ @dalli.delete(key)
22
+ end
23
+
19
24
  # Does a given key exist in the cache?
20
25
  def exists?(key)
21
26
  !get(key).nil?
22
27
  end
23
28
 
24
- # Has a given time passed since the key was set?
25
- def expired?(key, timeout)
26
- Time.now - @dalli.get("#{key}_created_at") > timeout
29
+ def created_at(key)
30
+ @dalli.get("#{key}_created_at")
27
31
  end
28
32
  end
29
33
  end
@@ -1,8 +1,8 @@
1
1
  class APICache
2
2
  class MemoryStore < APICache::AbstractStore
3
- def initialize
3
+ def initialize(cache = {})
4
4
  APICache.logger.debug "Using memory store"
5
- @cache = {}
5
+ @cache = cache
6
6
  true
7
7
  end
8
8
 
@@ -13,23 +13,21 @@ class APICache
13
13
  end
14
14
 
15
15
  def get(key)
16
- data = @cache[key][1]
16
+ data = exists?(key) ? @cache[key][1] : nil
17
17
  APICache.logger.debug("cache: #{data.nil? ? "miss" : "hit"} (#{key})")
18
18
  data
19
19
  end
20
20
 
21
- def exists?(key)
22
- !@cache[key].nil?
21
+ def delete(key)
22
+ @cache.delete(key)
23
23
  end
24
24
 
25
- def expired?(key, timeout)
26
- Time.now - created(key) > timeout
25
+ def exists?(key)
26
+ !@cache[key].nil?
27
27
  end
28
28
 
29
- private
30
-
31
- def created(key)
32
- @cache[key][0]
29
+ def created_at(key)
30
+ @cache[key] && @cache[key][0]
33
31
  end
34
32
  end
35
33
  end
@@ -16,14 +16,18 @@ class APICache
16
16
  @moneta[key]
17
17
  end
18
18
 
19
+ # Delete value.
20
+ def delete(key)
21
+ @moneta.delete(key)
22
+ end
23
+
19
24
  # Does a given key exist in the cache?
20
25
  def exists?(key)
21
26
  @moneta.key?(key)
22
27
  end
23
28
 
24
- # Has a given time passed since the key was set?
25
- def expired?(key, timeout)
26
- Time.now - @moneta["#{key}_created_at"] > timeout
29
+ def created_at(key)
30
+ @moneta["#{key}_created_at"]
27
31
  end
28
32
  end
29
33
  end
@@ -4,17 +4,24 @@ class APICache
4
4
  class NullStore < APICache::AbstractStore
5
5
  def initialize
6
6
  end
7
-
8
- def exists?(key)
9
- false
10
- end
11
7
 
12
8
  def set(key, value)
13
9
  true
14
10
  end
15
11
 
16
- def expired?(key, timeout)
17
- true
12
+ def get(key)
13
+ nil
14
+ end
15
+
16
+ def delete(key)
17
+ end
18
+
19
+ def exists?(key)
20
+ false
21
+ end
22
+
23
+ def created_at(key)
24
+ nil
18
25
  end
19
26
  end
20
27
  end
@@ -23,8 +23,7 @@ describe APICache do
23
23
 
24
24
  it "should allow moneta instances to be passed" do
25
25
  require 'moneta'
26
- require 'moneta/memory'
27
- APICache.store = Moneta::Memory.new
26
+ APICache.store = Moneta.new(:Memory)
28
27
  APICache.store.should be_kind_of(APICache::MonetaStore)
29
28
  end
30
29
 
@@ -40,62 +39,96 @@ describe APICache do
40
39
  end
41
40
 
42
41
  describe "get method" do
43
- before :each do
44
- @api = mock(APICache::API, :get => @api_data)
45
- @cache = mock(APICache::Cache, :get => @cache_data, :set => true)
46
-
47
- APICache::API.stub!(:new).and_return(@api)
48
- APICache::Cache.stub!(:new).and_return(@cache)
49
- end
50
-
51
- it "should fetch data from the cache if the state is :current" do
52
- @cache.stub!(:state).and_return(:current)
53
-
54
- APICache.get(@key).should == @cache_data
55
- end
56
-
57
- it "should make new request to API if the state is :refetch and store result in cache" do
58
- @cache.stub!(:state).and_return(:refetch)
59
- @cache.should_receive(:set).with(@api_data)
60
-
61
- APICache.get(@key).should == @api_data
62
- end
63
-
64
- it "should return the cached value if the state is :refetch but the api is not accessible" do
65
- @cache.stub!(:state).and_return(:refetch)
66
- @api.should_receive(:get).with.and_raise(APICache::CannotFetch)
67
-
68
- APICache.get(@key).should == @cache_data
69
- end
70
-
71
- it "should make new request to API if the state is :invalid" do
72
- @cache.stub!(:state).and_return(:invalid)
73
-
74
- APICache.get(@key).should == @api_data
75
- end
76
-
77
- it "should raise CannotFetch if the api cannot fetch data and the cache state is :invalid" do
78
- @cache.stub!(:state).and_return(:invalid)
79
- @api.should_receive(:get).with.and_raise(APICache::CannotFetch)
80
-
81
- lambda {
82
- APICache.get(@key).should
83
- }.should raise_error(APICache::CannotFetch)
84
- end
85
-
86
- it "should make new request to API if the state is :missing" do
87
- @cache.stub!(:state).and_return(:missing)
88
-
89
- APICache.get(@key).should == @api_data
42
+
43
+ context "when cache is mocked" do
44
+ before :each do
45
+ @api = mock(APICache::API, :get => @api_data)
46
+ @cache = mock(APICache::Cache, :get => @cache_data, :set => true)
47
+
48
+ APICache::API.stub!(:new).and_return(@api)
49
+ APICache::Cache.stub!(:new).and_return(@cache)
50
+ end
51
+
52
+ it "should fetch data from the cache if the state is :current" do
53
+ @cache.stub!(:state).and_return(:current)
54
+
55
+ APICache.get(@key).should == @cache_data
56
+ end
57
+
58
+ it "should make new request to API if the state is :refetch and store result in cache" do
59
+ @cache.stub!(:state).and_return(:refetch)
60
+ @cache.should_receive(:set).with(@api_data)
61
+
62
+ APICache.get(@key).should == @api_data
63
+ end
64
+
65
+ it "should return the cached value if the state is :refetch but the api is not accessible" do
66
+ @cache.stub!(:state).and_return(:refetch)
67
+ @api.should_receive(:get).with.and_raise(APICache::CannotFetch)
68
+
69
+ APICache.get(@key).should == @cache_data
70
+ end
71
+
72
+ it "should make new request to API if the state is :invalid" do
73
+ @cache.stub!(:state).and_return(:invalid)
74
+
75
+ APICache.get(@key).should == @api_data
76
+ end
77
+
78
+ it "should raise CannotFetch if the api cannot fetch data and the cache state is :invalid" do
79
+ @cache.stub!(:state).and_return(:invalid)
80
+ @api.should_receive(:get).with.and_raise(APICache::CannotFetch)
81
+
82
+ lambda {
83
+ APICache.get(@key).should
84
+ }.should raise_error(APICache::CannotFetch)
85
+ end
86
+
87
+ it "should make new request to API if the state is :missing" do
88
+ @cache.stub!(:state).and_return(:missing)
89
+
90
+ APICache.get(@key).should == @api_data
91
+ end
92
+
93
+ it "should raise an exception if the api cannot fetch data and the cache state is :missing" do
94
+ @cache.stub!(:state).and_return(:missing)
95
+ @api.should_receive(:get).with.and_raise(APICache::CannotFetch)
96
+
97
+ lambda {
98
+ APICache.get(@key).should
99
+ }.should raise_error(APICache::CannotFetch)
100
+ end
90
101
  end
91
-
92
- it "should raise an exception if the api cannot fetch data and the cache state is :missing" do
93
- @cache.stub!(:state).and_return(:missing)
94
- @api.should_receive(:get).with.and_raise(APICache::CannotFetch)
95
-
96
- lambda {
97
- APICache.get(@key).should
98
- }.should raise_error(APICache::CannotFetch)
102
+
103
+
104
+ context "when cache is not mocked" do
105
+
106
+ before :each do
107
+ APICache.store = APICache::MemoryStore.new
108
+ @api = mock(APICache::API, :get => @api_data)
109
+ APICache::API.stub!(:new).and_return(@api)
110
+ end
111
+
112
+ #it "should initially fetch" do
113
+ # @api.should_receive(:get)
114
+ # APICache.get(@key)
115
+ #end
116
+
117
+ it "should only fetch once" do
118
+ @api.should_receive(:get).once
119
+ APICache.get(@key)
120
+ APICache.get(@key)
121
+ end
122
+
123
+ it "should refetch if deleted" do
124
+ @api.should_receive(:get).twice
125
+ APICache.get(@key)
126
+ APICache.delete(@key)
127
+ APICache.get(@key)
128
+ end
129
+
99
130
  end
131
+
100
132
  end
133
+
101
134
  end
@@ -33,4 +33,10 @@ describe APICache::Cache do
33
33
  sleep 1
34
34
  cache.state.should == :invalid
35
35
  end
36
+
37
+ it "should initially have invalid state" do
38
+ cache = APICache::Cache.new('foo', @options)
39
+ cache.state.should == :invalid
40
+ end
41
+
36
42
  end
@@ -3,28 +3,8 @@ require 'spec_helper'
3
3
  require 'dalli'
4
4
 
5
5
  describe APICache::DalliStore do
6
- before :each do
7
- @dalli = Dalli::Client.new('localhost:11211')
8
- @dalli.delete('foo')
9
- @store = APICache::DalliStore.new(@dalli)
10
- end
6
+ let(:cache) { Dalli::Client.new("localhost:11211") }
7
+ let(:store) { APICache::DalliStore.new(cache) }
11
8
 
12
- it 'should set and get' do
13
- @store.set('key', 'value')
14
- @store.get('key').should == 'value'
15
- end
16
-
17
- it 'should allow checking whether a key exists' do
18
- @store.exists?('foo').should be_false
19
- @store.set('foo', 'bar')
20
- @store.exists?('foo').should be_true
21
- end
22
-
23
- it 'should allow checking whether a given amount of time has passed since the key was set' do
24
- @store.expired?('foo', 1).should be_false
25
- @store.set('foo', 'bar')
26
- @store.expired?('foo', 1).should be_false
27
- sleep 1
28
- @store.expired?('foo', 1).should be_true
29
- end
9
+ include_examples "generic store"
30
10
  end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe APICache::MemoryStore do
4
+ let(:cache) { {} }
5
+ let(:store) { APICache::MemoryStore.new(cache) }
6
+
7
+ # Deleting created_at makes no sense given the way MemoryStore stores data
8
+ @skip_created_at_deletion = true
9
+ include_examples "generic store"
10
+ end
@@ -1,31 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  require 'moneta'
4
- require 'moneta/memcache'
5
4
 
6
5
  describe APICache::MonetaStore do
7
- before :each do
8
- @moneta = Moneta::Memcache.new(:server => "localhost")
9
- @moneta.delete('foo')
10
- @store = APICache::MonetaStore.new(@moneta)
11
- end
6
+ let(:cache) { Moneta.new(:Memcached) }
7
+ let(:store) { APICache::MonetaStore.new(cache) }
12
8
 
13
- it "should set and get" do
14
- @store.set("key", "value")
15
- @store.get("key").should == "value"
16
- end
17
-
18
- it "should allow checking whether a key exists" do
19
- @store.exists?('foo').should be_false
20
- @store.set('foo', 'bar')
21
- @store.exists?('foo').should be_true
22
- end
23
-
24
- it "should allow checking whether a given amount of time has passed since the key was set" do
25
- @store.expired?('foo', 1).should be_false
26
- @store.set('foo', 'bar')
27
- @store.expired?('foo', 1).should be_false
28
- sleep 1
29
- @store.expired?('foo', 1).should be_true
30
- end
9
+ include_examples "generic store"
31
10
  end
@@ -11,7 +11,7 @@ describe APICache::NullStore do
11
11
  @store.exists?('foo').should be_false
12
12
  end
13
13
 
14
- it "should allows say keys are expired" do
14
+ it "should always say keys are expired" do
15
15
  @store.expired?('foo', 1).should be_true
16
16
  @store.set('foo', 'bar')
17
17
  @store.expired?('foo', 1).should be_true
@@ -0,0 +1,42 @@
1
+ shared_examples "generic store" do
2
+ before :each do
3
+ cache.delete("foo")
4
+ end
5
+
6
+ it "should allow set and get" do
7
+ store.set("foo", "bar")
8
+ store.get("foo").should == "bar"
9
+ end
10
+
11
+ it "should report existence" do
12
+ store.exists?("foo").should == false
13
+ store.set("foo", "bar")
14
+ store.exists?("foo").should == true
15
+ end
16
+
17
+ it "should allow checking expiration" do
18
+ store.set("foo", "bar")
19
+ store.expired?("foo", 1).should == false
20
+ store.expired?("foo", 0).should == true
21
+ end
22
+
23
+ it "should return nil if not found" do
24
+ store.get("nothing").should == nil
25
+ end
26
+
27
+ it "should be possible to delete" do
28
+ store.set("foo", "bar")
29
+ store.delete("key")
30
+ store.exists?("key").should == false
31
+ store.get("key").should == nil
32
+ end
33
+
34
+ unless @skip_created_at_deletion
35
+ it "should claim that key has expired if _created_at key is missing" do
36
+ store.set("key", "bar")
37
+ store.expired?("foo", 10).should == false
38
+ cache.delete("foo_created_at")
39
+ store.expired?("foo", 10).should == true
40
+ end
41
+ end
42
+ end
@@ -1,7 +1,9 @@
1
- require "spec"
1
+ require "rspec"
2
2
  require 'webmock/rspec'
3
3
 
4
4
  $:.push File.join(File.dirname(__FILE__), '..', 'lib')
5
5
  require "api_cache"
6
6
 
7
7
  APICache.logger.level = Logger::FATAL
8
+
9
+ require "shared_store_specs"
metadata CHANGED
@@ -1,95 +1,97 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: api_cache
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.2.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
6
5
  platform: ruby
7
- authors:
6
+ authors:
8
7
  - Martyn Loughran
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
-
13
- date: 2011-03-28 00:00:00 +01:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
11
+ date: 2014-07-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
17
14
  name: rspec
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
20
- none: false
21
- requirements:
22
- - - ~>
23
- - !ruby/object:Gem::Version
24
- version: "1.0"
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
25
20
  type: :development
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
28
- name: webmock
29
21
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
31
- none: false
32
- requirements:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: webmock
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
33
31
  - - ">="
34
- - !ruby/object:Gem::Version
35
- version: "0"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
36
34
  type: :development
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
39
- name: rake
40
35
  prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
42
- none: false
43
- requirements:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
44
45
  - - ">="
45
- - !ruby/object:Gem::Version
46
- version: "0"
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
47
48
  type: :development
48
- version_requirements: *id003
49
- - !ruby/object:Gem::Dependency
50
- name: moneta
51
49
  prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
53
- none: false
54
- requirements:
55
- - - ~>
56
- - !ruby/object:Gem::Version
57
- version: 0.6.0
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: moneta
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.7'
58
62
  type: :development
59
- version_requirements: *id004
60
- - !ruby/object:Gem::Dependency
61
- name: dalli
62
63
  prerelease: false
63
- requirement: &id005 !ruby/object:Gem::Requirement
64
- none: false
65
- requirements:
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: dalli
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
66
73
  - - ">="
67
- - !ruby/object:Gem::Version
68
- version: "0"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
69
76
  type: :development
70
- version_requirements: *id005
71
- - !ruby/object:Gem::Dependency
72
- name: memcache-client
73
77
  prerelease: false
74
- requirement: &id006 !ruby/object:Gem::Requirement
75
- none: false
76
- requirements:
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
77
80
  - - ">="
78
- - !ruby/object:Gem::Version
79
- version: "0"
80
- type: :development
81
- version_requirements: *id006
82
- description: APICache allows any API client library to be easily wrapped with a robust caching layer. It supports caching (obviously), serving stale data and limits on the number of API calls. It's also got a handy syntax if all you want to do is cache a bothersome url.
83
- email:
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: APICache allows any API client library to be easily wrapped with a robust
84
+ caching layer. It supports caching (obviously), serving stale data and limits on
85
+ the number of API calls. It's also got a handy syntax if all you want to do is cache
86
+ a bothersome url.
87
+ email:
84
88
  - me@mloughran.com
85
89
  executables: []
86
-
87
90
  extensions: []
88
-
89
91
  extra_rdoc_files: []
90
-
91
- files:
92
- - .gitignore
92
+ files:
93
+ - ".gitignore"
94
+ - CHANGELOG.md
93
95
  - Gemfile
94
96
  - LICENSE
95
97
  - README.md
@@ -110,43 +112,42 @@ files:
110
112
  - spec/cache_spec.rb
111
113
  - spec/dalli_store_spec.rb
112
114
  - spec/integration_spec.rb
115
+ - spec/memory_store_spec.rb
113
116
  - spec/monteta_store_spec.rb
114
117
  - spec/null_store_spec.rb
118
+ - spec/shared_store_specs.rb
115
119
  - spec/spec_helper.rb
116
- has_rdoc: true
117
120
  homepage: http://mloughran.github.com/api_cache/
118
121
  licenses: []
119
-
122
+ metadata: {}
120
123
  post_install_message:
121
124
  rdoc_options: []
122
-
123
- require_paths:
125
+ require_paths:
124
126
  - lib
125
- required_ruby_version: !ruby/object:Gem::Requirement
126
- none: false
127
- requirements:
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
128
129
  - - ">="
129
- - !ruby/object:Gem::Version
130
- version: "0"
131
- required_rubygems_version: !ruby/object:Gem::Requirement
132
- none: false
133
- requirements:
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
134
  - - ">="
135
- - !ruby/object:Gem::Version
136
- version: "0"
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
137
  requirements: []
138
-
139
138
  rubyforge_project:
140
- rubygems_version: 1.5.3
139
+ rubygems_version: 2.2.2
141
140
  signing_key:
142
- specification_version: 3
141
+ specification_version: 4
143
142
  summary: API Cache allows advanced caching of APIs
144
- test_files:
143
+ test_files:
145
144
  - spec/api_cache_spec.rb
146
145
  - spec/api_spec.rb
147
146
  - spec/cache_spec.rb
148
147
  - spec/dalli_store_spec.rb
149
148
  - spec/integration_spec.rb
149
+ - spec/memory_store_spec.rb
150
150
  - spec/monteta_store_spec.rb
151
151
  - spec/null_store_spec.rb
152
+ - spec/shared_store_specs.rb
152
153
  - spec/spec_helper.rb