redis-rack-cache 0.0.0 → 1.1.rc

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.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ tmp/*
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
  gemspec
3
+
4
+ gem 'redis-store', '1.1.0.rc', :path => File.expand_path('../../redis-store', __FILE__)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 - 2011 Luca Guidi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Redis stores for Rack::Cache
2
+
3
+ __`redis-rack-cache`__ provides a Redis backed store for __Rack::Cache__. It natively supports object marshalling, timeouts, single or multiple nodes and namespaces.
4
+
5
+ ## Redis Installation
6
+
7
+ ### Option 1: Homebrew
8
+
9
+ MacOS X users should use [Homebrew](https://github.com/mxcl/homebrew) to install Redis:
10
+
11
+ brew install redis
12
+
13
+ ### Option 2: From Source
14
+
15
+ Download and install Redis from [http://redis.io](http://redis.io/)
16
+
17
+ wget http://redis.googlecode.com/files/redis-2.4.5.tar.gz
18
+ tar -zxf redis-2.4.5.tar.gz
19
+ mv redis-2.4.5 redis
20
+ cd redis
21
+ make
22
+
23
+ ## Usage
24
+
25
+ # Gemfile
26
+ gem 'redis-rack-cache'
27
+
28
+ ### HTTP Cache Store:
29
+
30
+ # config.ru
31
+ require 'rack'
32
+ require 'rack/cache'
33
+ require 'redis-rack-cache'
34
+
35
+ use Rack::Cache,
36
+ :metastore => 'redis://localhost:6379/0/metastore',
37
+ :entitystore => 'redis://localhost:6380/0/entitystore'
38
+
39
+ #### Configuration
40
+
41
+ For advanced configuration options, please check the [Redis Store Wiki](https://github.com/jodosha/redis-store/wiki).
42
+
43
+ ## Running tests
44
+
45
+ git clone git://github.com/jodosha/redis-store.git
46
+ cd redis-store/redis-rack-cache
47
+ gem install bundler --pre # required version: 1.1.rc
48
+ bundle exec rake
49
+
50
+ If you are on **Snow Leopard** you have to run `env ARCHFLAGS="-arch x86_64" bundle exec rake`
51
+
52
+ ## Copyright
53
+
54
+ (c) 2009 - 2011 Luca Guidi - [http://lucaguidi.com](http://lucaguidi.com), released under the MIT license
data/Rakefile CHANGED
@@ -1 +1,13 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler'
2
+ Bundler.setup
3
+ require 'rake'
4
+ require 'bundler/gem_tasks'
5
+
6
+ begin
7
+ require 'rdoc/task'
8
+ rescue LoadError
9
+ require 'rake/rdoctask'
10
+ end
11
+
12
+ load 'tasks/redis.tasks.rb'
13
+ task :default => 'redis:test:suite'
@@ -0,0 +1,55 @@
1
+ require 'rack/cache/entitystore'
2
+
3
+ module Rack
4
+ module Cache
5
+ class EntityStore
6
+ class RedisBase < self
7
+ # The underlying ::Redis instance used to communicate with the Redis daemon.
8
+ attr_reader :cache
9
+
10
+ extend Rack::Utils
11
+
12
+ def open(key)
13
+ data = read(key)
14
+ data && [data]
15
+ end
16
+
17
+ def self.resolve(uri)
18
+ new ::Redis::Factory.resolve(uri.to_s)
19
+ end
20
+ end
21
+
22
+ class Redis < RedisBase
23
+ def initialize(server, options = {})
24
+ @cache = ::Redis.new server
25
+ end
26
+
27
+ def exist?(key)
28
+ cache.exists key
29
+ end
30
+
31
+ def read(key)
32
+ cache.get key
33
+ end
34
+
35
+ def write(body, ttl=0)
36
+ buf = StringIO.new
37
+ key, size = slurp(body){|part| buf.write(part) }
38
+
39
+ if ttl.zero?
40
+ [key, size] if cache.set(key, buf.string)
41
+ else
42
+ [key, size] if cache.setex(key, ttl, buf.string)
43
+ end
44
+ end
45
+
46
+ def purge(key)
47
+ cache.del key
48
+ nil
49
+ end
50
+ end
51
+
52
+ REDIS = Redis
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,45 @@
1
+ require 'digest/sha1'
2
+ require 'rack/utils'
3
+ require 'rack/cache/key'
4
+ require 'rack/cache/metastore'
5
+
6
+ module Rack
7
+ module Cache
8
+ class MetaStore
9
+ class RedisBase < self
10
+ extend Rack::Utils
11
+
12
+ # The Redis::Store object used to communicate with the Redis daemon.
13
+ attr_reader :cache
14
+
15
+ def self.resolve(uri)
16
+ new ::Redis::Factory.resolve(uri.to_s)
17
+ end
18
+ end
19
+
20
+ class Redis < RedisBase
21
+ # The Redis instance used to communicated with the Redis daemon.
22
+ attr_reader :cache
23
+
24
+ def initialize(server, options = {})
25
+ @cache = ::Redis::Factory.create(server)
26
+ end
27
+
28
+ def read(key)
29
+ cache.get(hexdigest(key)) || []
30
+ end
31
+
32
+ def write(key, entries)
33
+ cache.set(hexdigest(key), entries)
34
+ end
35
+
36
+ def purge(key)
37
+ cache.del(hexdigest(key))
38
+ nil
39
+ end
40
+ end
41
+
42
+ REDIS = Redis
43
+ end
44
+ end
45
+ end
@@ -1,7 +1,7 @@
1
- module Redis
1
+ class Redis
2
2
  module Rack
3
3
  module Cache
4
- VERSION = "0.0.0"
4
+ VERSION = '1.1.rc'
5
5
  end
6
6
  end
7
7
  end
@@ -1,9 +1,5 @@
1
- require "redis-rack-cache/version"
2
-
3
- module Redis
4
- module Rack
5
- module Cache
6
- # Your code goes here...
7
- end
8
- end
9
- end
1
+ require 'redis-store'
2
+ require 'rack/cache'
3
+ require 'rack/cache/redis_entitystore'
4
+ require 'rack/cache/redis_metastore'
5
+ require 'redis-rack-cache/version'
@@ -18,7 +18,12 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
23
- # s.add_runtime_dependency "rest-client"
21
+ s.add_dependency 'redis-store', '1.1.0.rc'
22
+ s.add_dependency 'rack-cache', '1.1'
23
+
24
+ s.add_development_dependency 'rake', '~> 0.9.2.2'
25
+ s.add_development_dependency 'bundler', '~> 1.1.rc'
26
+ s.add_development_dependency 'mocha', '~> 0.10.0'
27
+ s.add_development_dependency 'minitest', '~> 2.8.0'
28
+ s.add_development_dependency 'purdytest', '~> 1.0.0'
24
29
  end
Binary file
Binary file
@@ -0,0 +1,121 @@
1
+ require 'test_helper'
2
+
3
+ class Object
4
+ def sha_like?
5
+ length == 40 && self =~ /^[0-9a-z]+$/
6
+ end
7
+ end
8
+
9
+ describe Rack::Cache::EntityStore::Redis do
10
+ before do
11
+ @store = ::Rack::Cache::EntityStore::Redis.new :host => 'localhost'
12
+ end
13
+
14
+ it 'has the class referenced by homonym constant' do
15
+ ::Rack::Cache::EntityStore::REDIS.must_equal(::Rack::Cache::EntityStore::Redis)
16
+ end
17
+
18
+ it 'resolves the connection uri' do
19
+ cache = ::Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1")).cache
20
+ cache.must_be_kind_of(::Redis)
21
+ cache.id.must_equal("redis://127.0.0.1:6379/0")
22
+
23
+ cache = ::Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1:6380")).cache
24
+ cache.id.must_equal("redis://127.0.0.1:6380/0")
25
+
26
+ cache = ::Rack::Cache::EntityStore::Redis.resolve(uri("redis://127.0.0.1/13")).cache
27
+ cache.id.must_equal("redis://127.0.0.1:6379/13")
28
+
29
+ cache = ::Rack::Cache::EntityStore::Redis.resolve(uri("redis://:secret@127.0.0.1")).cache
30
+ cache.id.must_equal("redis://127.0.0.1:6379/0")
31
+ cache.client.password.must_equal('secret')
32
+ end
33
+
34
+ it 'responds to all required messages' do
35
+ %w[read open write exist?].each do |message|
36
+ @store.must_respond_to message
37
+ end
38
+ end
39
+
40
+ it 'stores bodies with #write' do
41
+ key, size = @store.write(['My wild love went riding,'])
42
+ key.wont_be_nil
43
+ key.must_be :sha_like?
44
+
45
+ data = @store.read(key)
46
+ data.must_equal('My wild love went riding,')
47
+ end
48
+
49
+ it 'takes a ttl parameter for #write' do
50
+ key, size = @store.write(['My wild love went riding,'], 0)
51
+ key.wont_be_nil
52
+ key.must_be :sha_like?
53
+
54
+ data = @store.read(key)
55
+ data.must_equal('My wild love went riding,')
56
+ end
57
+
58
+ it 'correctly determines whether cached body exists for key with #exist?' do
59
+ key, size = @store.write(['She rode to the devil,'])
60
+ assert @store.exist?(key)
61
+ assert ! @store.exist?('938jasddj83jasdh4438021ksdfjsdfjsdsf')
62
+ end
63
+
64
+ it 'can read data written with #write' do
65
+ key, size = @store.write(['And asked him to pay.'])
66
+ data = @store.read(key)
67
+ data.must_equal('And asked him to pay.')
68
+ end
69
+
70
+ it 'gives a 40 character SHA1 hex digest from #write' do
71
+ key, size = @store.write(['she rode to the sea;'])
72
+ key.wont_be_nil
73
+ key.length.must_equal(40)
74
+ key.must_match(/^[0-9a-z]+$/)
75
+ key.must_equal('90a4c84d51a277f3dafc34693ca264531b9f51b6')
76
+ end
77
+
78
+ it 'returns the entire body as a String from #read' do
79
+ key, size = @store.write(['She gathered together'])
80
+ @store.read(key).must_equal('She gathered together')
81
+ end
82
+
83
+ it 'returns nil from #read when key does not exist' do
84
+ @store.read('87fe0a1ae82a518592f6b12b0183e950b4541c62').must_be_nil
85
+ end
86
+
87
+ it 'returns a Rack compatible body from #open' do
88
+ key, size = @store.write(['Some shells for her hair.'])
89
+ body = @store.open(key)
90
+ body.must_respond_to :each
91
+ buf = ''
92
+ body.each { |part| buf << part }
93
+ buf.must_equal('Some shells for her hair.')
94
+ end
95
+
96
+ it 'returns nil from #open when key does not exist' do
97
+ @store.open('87fe0a1ae82a518592f6b12b0183e950b4541c62').must_be_nil
98
+ end
99
+
100
+ if RUBY_VERSION < '1.9'
101
+ it 'can store largish bodies with binary data' do
102
+ pony = File.open(File.dirname(__FILE__) + '/pony.jpg', 'rb') { |f| f.read }
103
+ key, size = @store.write([pony])
104
+ key.must_equal('d0f30d8659b4d268c5c64385d9790024c2d78deb')
105
+ data = @store.read(key)
106
+ data.length.must_equal(pony.length)
107
+ data.hash.must_equal(pony.hash)
108
+ end
109
+ end
110
+
111
+ it 'deletes stored entries with #purge' do
112
+ key, size = @store.write(['My wild love went riding,'])
113
+ @store.purge(key).must_be_nil
114
+ @store.read(key).must_be_nil
115
+ end
116
+
117
+ private
118
+ define_method :uri do |uri|
119
+ URI.parse uri
120
+ end
121
+ end
@@ -0,0 +1,266 @@
1
+ require 'test_helper'
2
+
3
+ describe Rack::Cache::MetaStore::Redis do
4
+ before do
5
+ @store = ::Rack::Cache::MetaStore::Redis.resolve uri('redis://127.0.0.1')
6
+ @entity_store = ::Rack::Cache::EntityStore::Redis.resolve uri('redis://127.0.0.1:6380')
7
+ @request = mock_request('/', {})
8
+ @response = mock_response(200, {}, ['hello world'])
9
+ end
10
+
11
+ after do
12
+ @store.cache.flushall
13
+ @entity_store.cache.flushall
14
+ end
15
+
16
+ it "has the class referenced by homonym constant" do
17
+ ::Rack::Cache::MetaStore::REDIS.must_equal(::Rack::Cache::MetaStore::Redis)
18
+ end
19
+
20
+ it "instantiates the store" do
21
+ @store.must_be_kind_of(::Rack::Cache::MetaStore::Redis)
22
+ end
23
+
24
+ it "resolves the connection uri" do
25
+ cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1")).cache
26
+ cache.must_be_kind_of(::Redis::Store)
27
+ cache.to_s.must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0")
28
+
29
+ cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1:6380")).cache
30
+ cache.to_s.must_equal("Redis Client connected to 127.0.0.1:6380 against DB 0")
31
+
32
+ cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://127.0.0.1/13")).cache
33
+ cache.to_s.must_equal("Redis Client connected to 127.0.0.1:6379 against DB 13")
34
+
35
+ cache = Rack::Cache::MetaStore::Redis.resolve(uri("redis://:secret@127.0.0.1")).cache
36
+ cache.id.must_equal("redis://127.0.0.1:6379/0")
37
+ cache.client.password.must_equal('secret')
38
+ end
39
+
40
+ # Low-level implementation methods ===========================================
41
+
42
+ it 'writes a list of negotation tuples with #write' do
43
+ # lambda {
44
+ @store.write('/test', [[{}, {}]])
45
+ # }.wont_raise Exception
46
+ end
47
+
48
+ it 'reads a list of negotation tuples with #read' do
49
+ @store.write('/test', [[{},{}],[{},{}]])
50
+ tuples = @store.read('/test')
51
+ tuples.must_equal([ [{},{}], [{},{}] ])
52
+ end
53
+
54
+ it 'reads an empty list with #read when nothing cached at key' do
55
+ @store.read('/nothing').must_be_empty
56
+ end
57
+
58
+ it 'removes entries for key with #purge' do
59
+ @store.write('/test', [[{},{}]])
60
+ @store.read('/test').wont_be_empty
61
+
62
+ @store.purge('/test')
63
+ @store.read('/test').must_be_empty
64
+ end
65
+
66
+ it 'succeeds when purging non-existing entries' do
67
+ @store.read('/test').must_be_empty
68
+ @store.purge('/test')
69
+ end
70
+
71
+ it 'returns nil from #purge' do
72
+ @store.write('/test', [[{},{}]])
73
+ @store.purge('/test').must_be_nil
74
+ @store.read('/test').must_equal([])
75
+ end
76
+
77
+ %w[/test http://example.com:8080/ /test?x=y /test?x=y&p=q].each do |key|
78
+ it "can read and write key: '#{key}'" do
79
+ # lambda {
80
+ @store.write(key, [[{},{}]])
81
+ # }.wont_raise Exception
82
+ @store.read(key).must_equal([[{},{}]])
83
+ end
84
+ end
85
+
86
+ it "can read and write fairly large keys" do
87
+ key = "b" * 4096
88
+ # lambda {
89
+ @store.write(key, [[{},{}]])
90
+ # }.wont_raise Exception
91
+ @store.read(key).must_equal([[{},{}]])
92
+ end
93
+
94
+ it "allows custom cache keys from block" do
95
+ request = mock_request('/test', {})
96
+ request.env['rack-cache.cache_key'] =
97
+ lambda { |request| request.path_info.reverse }
98
+ @store.cache_key(request).must_equal('tset/')
99
+ end
100
+
101
+ it "allows custom cache keys from class" do
102
+ request = mock_request('/test', {})
103
+ request.env['rack-cache.cache_key'] = Class.new do
104
+ def self.call(request); request.path_info.reverse end
105
+ end
106
+ @store.cache_key(request).must_equal('tset/')
107
+ end
108
+
109
+ it 'does not blow up when given a non-marhsalable object with an ALL_CAPS key' do
110
+ store_simple_entry('/bad', { 'SOME_THING' => Proc.new {} })
111
+ end
112
+
113
+ # Abstract methods ===========================================================
114
+
115
+ it 'stores a cache entry' do
116
+ cache_key = store_simple_entry
117
+ @store.read(cache_key).wont_be_empty
118
+ end
119
+
120
+ it 'sets the X-Content-Digest response header before storing' do
121
+ cache_key = store_simple_entry
122
+ req, res = @store.read(cache_key).first
123
+ res['X-Content-Digest'].must_equal('a94a8fe5ccb19ba61c4c0873d391e987982fbbd3')
124
+ end
125
+
126
+ it 'finds a stored entry with #lookup' do
127
+ store_simple_entry
128
+ response = @store.lookup(@request, @entity_store)
129
+ response.wont_be_nil
130
+ response.must_be_kind_of(Rack::Cache::Response)
131
+ end
132
+
133
+ it 'does not find an entry with #lookup when none exists' do
134
+ req = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
135
+ @store.lookup(req, @entity_store).must_be_nil
136
+ end
137
+
138
+ it "canonizes urls for cache keys" do
139
+ store_simple_entry(path='/test?x=y&p=q')
140
+
141
+ hits_req = mock_request(path, {})
142
+ miss_req = mock_request('/test?p=x', {})
143
+
144
+ @store.lookup(hits_req, @entity_store).wont_be_nil
145
+ @store.lookup(miss_req, @entity_store).must_be_nil
146
+ end
147
+
148
+ it 'does not find an entry with #lookup when the body does not exist' do
149
+ store_simple_entry
150
+ @response.headers['X-Content-Digest'].wont_be_nil
151
+ @entity_store.purge(@response.headers['X-Content-Digest'])
152
+ @store.lookup(@request, @entity_store).must_be_nil
153
+ end
154
+
155
+ it 'restores response headers properly with #lookup' do
156
+ store_simple_entry
157
+ response = @store.lookup(@request, @entity_store)
158
+ response.headers.
159
+ must_equal(@response.headers.merge('Content-Length' => '4'))
160
+ end
161
+
162
+ it 'restores response body from entity store with #lookup' do
163
+ store_simple_entry
164
+ response = @store.lookup(@request, @entity_store)
165
+ body = '' ; response.body.each {|p| body << p}
166
+ body.must_equal('test')
167
+ end
168
+
169
+ it 'invalidates meta and entity store entries with #invalidate' do
170
+ store_simple_entry
171
+ @store.invalidate(@request, @entity_store)
172
+ response = @store.lookup(@request, @entity_store)
173
+ response.must_be_kind_of(Rack::Cache::Response)
174
+ response.wont_be :fresh?
175
+ end
176
+
177
+ it 'succeeds quietly when #invalidate called with no matching entries' do
178
+ req = mock_request('/test', {})
179
+ @store.invalidate(req, @entity_store)
180
+ @store.lookup(@request, @entity_store).must_be_nil
181
+ end
182
+
183
+ # Vary =======================================================================
184
+
185
+ it 'does not return entries that Vary with #lookup' do
186
+ req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
187
+ req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
188
+ res = mock_response(200, {'Vary' => 'Foo Bar'}, ['test'])
189
+ @store.store(req1, res, @entity_store)
190
+
191
+ @store.lookup(req2, @entity_store).must_be_nil
192
+ end
193
+
194
+ it 'stores multiple responses for each Vary combination' do
195
+ req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
196
+ res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
197
+ key = @store.store(req1, res1, @entity_store)
198
+
199
+ req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
200
+ res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
201
+ @store.store(req2, res2, @entity_store)
202
+
203
+ req3 = mock_request('/test', {'HTTP_FOO' => 'Baz', 'HTTP_BAR' => 'Boom'})
204
+ res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
205
+ @store.store(req3, res3, @entity_store)
206
+
207
+ slurp(@store.lookup(req3, @entity_store).body).must_equal('test 3')
208
+ slurp(@store.lookup(req1, @entity_store).body).must_equal('test 1')
209
+ slurp(@store.lookup(req2, @entity_store).body).must_equal('test 2')
210
+
211
+ @store.read(key).length.must_equal(3)
212
+ end
213
+
214
+ it 'overwrites non-varying responses with #store' do
215
+ req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
216
+ res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
217
+ key = @store.store(req1, res1, @entity_store)
218
+ slurp(@store.lookup(req1, @entity_store).body).must_equal('test 1')
219
+
220
+ req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
221
+ res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
222
+ @store.store(req2, res2, @entity_store)
223
+ slurp(@store.lookup(req2, @entity_store).body).must_equal('test 2')
224
+
225
+ req3 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
226
+ res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
227
+ @store.store(req3, res3, @entity_store)
228
+ slurp(@store.lookup(req1, @entity_store).body).must_equal('test 3')
229
+
230
+ @store.read(key).length.must_equal(2)
231
+ end
232
+
233
+ private
234
+ define_method :mock_request do |uri, opts|
235
+ env = Rack::MockRequest.env_for(uri, opts || {})
236
+ Rack::Cache::Request.new(env)
237
+ end
238
+
239
+ define_method :mock_response do |status, headers, body|
240
+ headers ||= {}
241
+ body = Array(body).compact
242
+ Rack::Cache::Response.new(status, headers, body)
243
+ end
244
+
245
+ define_method :slurp do |body|
246
+ buf = ''
247
+ body.each { |part| buf << part }
248
+ buf
249
+ end
250
+
251
+ # Stores an entry for the given request args, returns a url encoded cache key
252
+ # for the request.
253
+ define_method :store_simple_entry do |*request_args|
254
+ path, headers = request_args
255
+ @request = mock_request(path || '/test', headers || {})
256
+ @response = mock_response(200, {'Cache-Control' => 'max-age=420'}, ['test'])
257
+ body = @response.body
258
+ cache_key = @store.store(@request, @response, @entity_store)
259
+ @response.body.must_equal(body)
260
+ cache_key
261
+ end
262
+
263
+ define_method :uri do |uri|
264
+ URI.parse uri
265
+ end
266
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ describe Redis::Rack::Cache::VERSION do
4
+ it "must be equal to 1.1.rc" do
5
+ Redis::Rack::Cache::VERSION.must_equal '1.1.rc'
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ Bundler.setup
2
+ gem 'minitest'
3
+ require 'minitest/spec'
4
+ require 'minitest/autorun'
5
+ require 'mocha'
6
+ require 'redis-rack-cache'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-rack-cache
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
- prerelease:
4
+ hash: 7712070
5
+ prerelease: 4
6
6
  segments:
7
- - 0
8
- - 0
9
- - 0
10
- version: 0.0.0
7
+ - 1
8
+ - 1
9
+ - rc
10
+ version: 1.1.rc
11
11
  platform: ruby
12
12
  authors:
13
13
  - Luca Guidi
@@ -15,9 +15,121 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-08 00:00:00 Z
19
- dependencies: []
20
-
18
+ date: 2011-12-30 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: redis-store
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - "="
27
+ - !ruby/object:Gem::Version
28
+ hash: 7712002
29
+ segments:
30
+ - 1
31
+ - 1
32
+ - 0
33
+ - rc
34
+ version: 1.1.0.rc
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rack-cache
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - "="
44
+ - !ruby/object:Gem::Version
45
+ hash: 13
46
+ segments:
47
+ - 1
48
+ - 1
49
+ version: "1.1"
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: rake
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 11
61
+ segments:
62
+ - 0
63
+ - 9
64
+ - 2
65
+ - 2
66
+ version: 0.9.2.2
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ hash: 7712070
78
+ segments:
79
+ - 1
80
+ - 1
81
+ - rc
82
+ version: 1.1.rc
83
+ type: :development
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: mocha
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ hash: 55
94
+ segments:
95
+ - 0
96
+ - 10
97
+ - 0
98
+ version: 0.10.0
99
+ type: :development
100
+ version_requirements: *id005
101
+ - !ruby/object:Gem::Dependency
102
+ name: minitest
103
+ prerelease: false
104
+ requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ hash: 47
110
+ segments:
111
+ - 2
112
+ - 8
113
+ - 0
114
+ version: 2.8.0
115
+ type: :development
116
+ version_requirements: *id006
117
+ - !ruby/object:Gem::Dependency
118
+ name: purdytest
119
+ prerelease: false
120
+ requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ hash: 23
126
+ segments:
127
+ - 1
128
+ - 0
129
+ - 0
130
+ version: 1.0.0
131
+ type: :development
132
+ version_requirements: *id007
21
133
  description: Redis for Rack::Cache
22
134
  email:
23
135
  - guidi.luca@gmail.com
@@ -30,10 +142,21 @@ extra_rdoc_files: []
30
142
  files:
31
143
  - .gitignore
32
144
  - Gemfile
145
+ - MIT-LICENSE
146
+ - README.md
33
147
  - Rakefile
148
+ - lib/rack/cache/redis_entitystore.rb
149
+ - lib/rack/cache/redis_metastore.rb
34
150
  - lib/redis-rack-cache.rb
35
151
  - lib/redis-rack-cache/version.rb
36
152
  - redis-rack-cache.gemspec
153
+ - test/rack/.DS_Store
154
+ - test/rack/cache/.DS_Store
155
+ - test/rack/cache/entitystore/pony.jpg
156
+ - test/rack/cache/entitystore/redis_test.rb
157
+ - test/rack/cache/metastore/redis_test.rb
158
+ - test/redis-rack-cache/version_test.rb
159
+ - test/test_helper.rb
37
160
  homepage: http://jodosha.github.com/redis-store
38
161
  licenses: []
39
162
 
@@ -54,12 +177,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
177
  required_rubygems_version: !ruby/object:Gem::Requirement
55
178
  none: false
56
179
  requirements:
57
- - - ">="
180
+ - - ">"
58
181
  - !ruby/object:Gem::Version
59
- hash: 3
182
+ hash: 25
60
183
  segments:
61
- - 0
62
- version: "0"
184
+ - 1
185
+ - 3
186
+ - 1
187
+ version: 1.3.1
63
188
  requirements: []
64
189
 
65
190
  rubyforge_project: redis-rack-cache
@@ -67,5 +192,12 @@ rubygems_version: 1.8.6
67
192
  signing_key:
68
193
  specification_version: 3
69
194
  summary: Redis for Rack::Cache
70
- test_files: []
71
-
195
+ test_files:
196
+ - test/rack/.DS_Store
197
+ - test/rack/cache/.DS_Store
198
+ - test/rack/cache/entitystore/pony.jpg
199
+ - test/rack/cache/entitystore/redis_test.rb
200
+ - test/rack/cache/metastore/redis_test.rb
201
+ - test/redis-rack-cache/version_test.rb
202
+ - test/test_helper.rb
203
+ has_rdoc: