redis-rack-cache 0.0.0 → 1.1.rc

Sign up to get free protection for your applications and to get access to all the features.
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: