rack-cache 0.5 → 0.5.2

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.

Potentially problematic release.


This version of rack-cache might be problematic. Click here for more details.

data/CHANGES CHANGED
@@ -1,3 +1,18 @@
1
+ ## 0.6.0 / Unreleased
2
+
3
+ * Added support for memcached clusters and other advanced
4
+ configuration provided by the memcache-client and memcached
5
+ libraries. The "metastore" and "entitystore" options can now be
6
+ set to a MemCache object or Memcached object:
7
+
8
+ memcache = MemCache.new(['127.1.1.1', '127.1.1.2'], :namespace => "/foo")
9
+ use Rack::Cache,
10
+ :metastore => memcache,
11
+ :entitystore => memcache
12
+
13
+ * Fix "memcached://" metastore URL handling. The "memcached" variation
14
+ blew up, the "memcache" version was fine.
15
+
1
16
  ## 0.5.0 / May 2009
2
17
 
3
18
  * Added meta and entity store implementations based on the
data/Rakefile CHANGED
@@ -110,13 +110,21 @@ file package('.tar.gz') => %w[dist/] + $spec.files do |f|
110
110
  end
111
111
 
112
112
  desc 'Upload gem and tar.gz distributables to rubyforge'
113
- task :release => [package('.gem'), package('.tar.gz')] do |t|
113
+ task 'release:rubyforge' => [package('.gem'), package('.tar.gz')] do |t|
114
114
  sh <<-SH
115
115
  rubyforge add_release wink rack-cache #{$spec.version} #{package('.gem')} &&
116
116
  rubyforge add_file wink rack-cache #{$spec.version} #{package('.tar.gz')}
117
117
  SH
118
118
  end
119
119
 
120
+ desc 'Upload gem to gemcutter.org'
121
+ task 'release:gemcutter' => [package('.gem')] do |t|
122
+ sh "gem push #{package('.gem')}"
123
+ end
124
+
125
+ desc 'Upload gem to gemcutter and rubyforge'
126
+ task 'release' => ['release:gemcutter', 'release:rubyforge']
127
+
120
128
  # GEMSPEC ===================================================================
121
129
 
122
130
  file 'rack-cache.gemspec' => FileList['{lib,test}/**','Rakefile'] do |f|
@@ -62,10 +62,9 @@ deployments so explicit configuration is advised.
62
62
  The default metastore and entitystore values can be specified when the
63
63
  __Rack::Cache__ object is added to the Rack middleware pipeline as follows:
64
64
 
65
- use Rack::Cache do
66
- set :metastore, 'file:/var/cache/rack/meta'
67
- set :entitystore, 'file:/var/cache/rack/body'
68
- end
65
+ use Rack::Cache,
66
+ :metastore => 'file:/var/cache/rack/meta',
67
+ :entitystore => 'file:/var/cache/rack/body'
69
68
 
70
69
  Alternatively, the `rack-cache.metastore` and `rack-cache.entitystore`
71
70
  variables may be set in the Rack environment by an upstream component.
@@ -82,8 +81,9 @@ use a specific storage implementation as well as pros and cons of each.
82
81
 
83
82
  Uses local process memory to store cached entries.
84
83
 
85
- set :metastore, 'heap:/'
86
- set :entitystore, 'heap:/'
84
+ use Rack::Cache,
85
+ :metastore => 'heap:/',
86
+ :entitystore => 'heap:/'
87
87
 
88
88
  The heap storage backend is simple, fast, and mostly useless. All cache
89
89
  information is stored in each backend application's local process memory (using
@@ -102,8 +102,9 @@ is small and well understood.
102
102
 
103
103
  Stores cached entries on the filesystem.
104
104
 
105
- set :metastore, 'file:/var/cache/rack/meta'
106
- set :entitystore, 'file:/var/cache/rack/body'
105
+ use Rack::Cache,
106
+ :metastore => 'file:/var/cache/rack/meta',
107
+ :entitystore => 'file:/var/cache/rack/body'
107
108
 
108
109
  The URI may specify an absolute, relative, or home-rooted path:
109
110
 
@@ -132,18 +133,19 @@ collision.
132
133
  Stores cached entries in a remote [memcached](http://www.danga.com/memcached/)
133
134
  instance.
134
135
 
135
- set :metastore, 'memcached://localhost:11211/meta'
136
- set :entitystore, 'memcached://localhost:11211/body'
136
+ use Rack::Cache,
137
+ :metastore => 'memcached://localhost:11211/meta',
138
+ :entitystore => 'memcached://localhost:11211/body'
137
139
 
138
140
  The URI must specify the host and port of a remote memcached daemon. The path
139
141
  portion is an optional (but recommended) namespace that is prepended to each
140
142
  cache key.
141
143
 
142
- The memcached storage backend requires [Evan Weaver's memcached client library][e].
143
- This is a [fast][f] client implementation built on the SWIG/[libmemcached][l] C
144
- library. The library may be installed from Gem as follows:
144
+ The memcached storage backend requires either the `memcache-client` or
145
+ `memcached` libraries. By default, the `memcache-client` library is used;
146
+ require the `memcached` library explicitly to use it instead.
145
147
 
146
- sudo gem install memcached --no-rdoc --no-ri
148
+ gem install memcache-client
147
149
 
148
150
  Memcached storage is reasonably fast and allows multiple backends to share a
149
151
  single cache. It is also the only storage implementation that allows the cache
@@ -133,8 +133,12 @@ module Rack::Cache
133
133
  # Invalidate POST, PUT, DELETE and all methods not understood by this cache
134
134
  # See RFC2616 13.10
135
135
  def invalidate
136
- record :invalidate
137
136
  metastore.invalidate(@request, entitystore)
137
+ rescue Exception => e
138
+ log_error(e)
139
+ pass
140
+ else
141
+ record :invalidate
138
142
  pass
139
143
  end
140
144
 
@@ -147,18 +151,26 @@ module Rack::Cache
147
151
  if @request.no_cache? && allow_reload?
148
152
  record :reload
149
153
  fetch
150
- elsif entry = metastore.lookup(@request, entitystore)
151
- if fresh_enough?(entry)
152
- record :fresh
153
- entry.headers['Age'] = entry.age.to_s
154
- entry
154
+ else
155
+ begin
156
+ entry = metastore.lookup(@request, entitystore)
157
+ rescue Exception => e
158
+ log_error(e)
159
+ return pass
160
+ end
161
+ if entry
162
+ if fresh_enough?(entry)
163
+ record :fresh
164
+ entry.headers['Age'] = entry.age.to_s
165
+ entry
166
+ else
167
+ record :stale
168
+ validate(entry)
169
+ end
155
170
  else
156
- record :stale
157
- validate(entry)
171
+ record :miss
172
+ fetch
158
173
  end
159
- else
160
- record :miss
161
- fetch
162
174
  end
163
175
  end
164
176
 
@@ -225,9 +237,17 @@ module Rack::Cache
225
237
 
226
238
  # Write the response to the cache.
227
239
  def store(response)
228
- record :store
229
240
  metastore.store(@request, response, entitystore)
230
241
  response.headers['Age'] = response.age.to_s
242
+ rescue Exception => e
243
+ log_error(e)
244
+ nil
245
+ else
246
+ record :store
247
+ end
248
+
249
+ def log_error(exception)
250
+ @env['rack.errors'].write("cache error: #{exception.message}\n#{exception.backtrace.join("\n")}\n")
231
251
  end
232
252
  end
233
253
  end
@@ -182,19 +182,25 @@ module Rack::Cache
182
182
  end
183
183
 
184
184
  def self.resolve(uri)
185
- server = "#{uri.host}:#{uri.port || '11211'}"
186
- options = parse_query(uri.query)
187
- options.keys.each do |key|
188
- value =
189
- case value = options.delete(key)
190
- when 'true' ; true
191
- when 'false' ; false
192
- else value.to_sym
193
- end
194
- options[k.to_sym] = value
185
+ if uri.respond_to?(:scheme)
186
+ server = "#{uri.host}:#{uri.port || '11211'}"
187
+ options = parse_query(uri.query)
188
+ options.keys.each do |key|
189
+ value =
190
+ case value = options.delete(key)
191
+ when 'true' ; true
192
+ when 'false' ; false
193
+ else value.to_sym
194
+ end
195
+ options[k.to_sym] = value
196
+ end
197
+ options[:namespace] = uri.path.sub(/^\//, '')
198
+ new server, options
199
+ else
200
+ # if the object provided is not a URI, pass it straight through
201
+ # to the underlying implementation.
202
+ new uri
195
203
  end
196
- options[:namespace] = uri.path.sub(/^\//, '')
197
- new server, options
198
204
  end
199
205
  end
200
206
 
@@ -274,19 +274,27 @@ module Rack::Cache
274
274
  # Query parameter names and values are documented with the memcached
275
275
  # library: http://tinyurl.com/4upqnd
276
276
  def self.resolve(uri)
277
- server = "#{uri.host}:#{uri.port || '11211'}"
278
- options = parse_query(uri.query)
279
- options.keys.each do |key|
280
- value =
281
- case value = options.delete(key)
282
- when 'true' ; true
283
- when 'false' ; false
284
- else value.to_sym
285
- end
286
- options[k.to_sym] = value
277
+ if uri.respond_to?(:scheme)
278
+ server = "#{uri.host}:#{uri.port || '11211'}"
279
+ options = parse_query(uri.query)
280
+ options.keys.each do |key|
281
+ value =
282
+ case value = options.delete(key)
283
+ when 'true' ; true
284
+ when 'false' ; false
285
+ else value.to_sym
286
+ end
287
+ options[k.to_sym] = value
288
+ end
289
+
290
+ options[:namespace] = uri.path.to_s.sub(/^\//, '')
291
+
292
+ new server, options
293
+ else
294
+ # if the object provided is not a URI, pass it straight through
295
+ # to the underlying implementation.
296
+ new uri
287
297
  end
288
- options[:namespace] = uri.path.sub(/^\//, '')
289
- new server, options
290
298
  end
291
299
  end
292
300
 
@@ -359,7 +367,7 @@ module Rack::Cache
359
367
  else
360
368
  MemCache
361
369
  end
362
- MEMCACHED = MemCache
370
+ MEMCACHED = MEMCACHE
363
371
 
364
372
  class GAEStore < MetaStore
365
373
  attr_reader :cache
@@ -30,12 +30,25 @@ module Rack::Cache
30
30
 
31
31
  private
32
32
  def create_store(type, uri)
33
- uri = URI.parse(uri) unless uri.respond_to?(:scheme)
34
- if type.const_defined?(uri.scheme.upcase)
35
- klass = type.const_get(uri.scheme.upcase)
36
- klass.resolve(uri)
33
+ if uri.respond_to?(:scheme) || uri.respond_to?(:to_str)
34
+ uri = URI.parse(uri) unless uri.respond_to?(:scheme)
35
+ if type.const_defined?(uri.scheme.upcase)
36
+ klass = type.const_get(uri.scheme.upcase)
37
+ klass.resolve(uri)
38
+ else
39
+ fail "Unknown storage provider: #{uri.to_s}"
40
+ end
37
41
  else
38
- fail "Unknown storage provider: #{uri.to_s}"
42
+ # hack in support for passing a MemCache or Memcached object
43
+ # as the storage URI.
44
+ case
45
+ when defined?(::MemCache) && uri.kind_of?(::MemCache)
46
+ type.const_get(:MemCache).resolve(uri)
47
+ when defined?(::Memcached) && uri.respond_to?(:stats)
48
+ type.const_get(:MemCached).resolve(uri)
49
+ else
50
+ fail "Unknown storage provider: #{uri.to_s}"
51
+ end
39
52
  end
40
53
  end
41
54
 
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
3
3
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
4
 
5
5
  s.name = 'rack-cache'
6
- s.version = '0.5'
7
- s.date = '2009-05-25'
6
+ s.version = '0.5.2'
7
+ s.date = '2009-09-25'
8
8
 
9
9
  s.description = "HTTP Caching for Rack"
10
10
  s.summary = "HTTP Caching for Rack"
@@ -746,4 +746,29 @@ describe 'Rack::Cache::Context' do
746
746
  response['X-Response-Count'].should.equal '3'
747
747
  end
748
748
  end
749
+
750
+ it 'passes if there was a metastore exception' do
751
+ respond_with 200, 'Cache-Control' => 'max-age=10000' do |req,res|
752
+ res.body = ['Hello World']
753
+ end
754
+
755
+ get '/'
756
+ response.should.be.ok
757
+ response.body.should.equal 'Hello World'
758
+ cache.trace.should.include :store
759
+
760
+ get '/' do |cache|
761
+ cache.meta_def(:metastore) { raise Timeout::Error }
762
+ end
763
+ response.should.be.ok
764
+ response.body.should.equal 'Hello World'
765
+ cache.trace.should.include :pass
766
+
767
+ post '/' do |cache|
768
+ cache.meta_def(:metastore) { raise Timeout::Error }
769
+ end
770
+ response.should.be.ok
771
+ response.body.should.equal 'Hello World'
772
+ cache.trace.should.include :pass
773
+ end
749
774
  end
@@ -272,7 +272,7 @@ describe 'Rack::Cache::MetaStore' do
272
272
  end
273
273
  end
274
274
  end
275
-
275
+
276
276
  need_java 'entity store testing' do
277
277
  module Rack::Cache::AppEngine
278
278
  module MC
@@ -282,12 +282,12 @@ describe 'Rack::Cache::MetaStore' do
282
282
  def get(key); self[key]; end;
283
283
  def put(key, value, ttl = nil)
284
284
  self[key] = value
285
- end
285
+ end
286
286
 
287
287
  end
288
288
  end
289
289
  end
290
-
290
+
291
291
  describe 'GAEStore' do
292
292
  it_should_behave_like 'A Rack::Cache::MetaStore Implementation'
293
293
  before :each do
@@ -296,7 +296,7 @@ describe 'Rack::Cache::MetaStore' do
296
296
  @entity_store = Rack::Cache::EntityStore::Heap.new
297
297
  end
298
298
  end
299
-
299
+
300
300
  end
301
301
 
302
302
  end
@@ -74,5 +74,4 @@ describe 'Rack::Cache::Options' do
74
74
  @options.should.respond_to :verbose?
75
75
  @options.verbose.should.not.be.nil
76
76
  end
77
-
78
77
  end
@@ -13,7 +13,7 @@ end
13
13
 
14
14
  # Set the MEMCACHED environment variable as follows to enable testing
15
15
  # of the MemCached meta and entity stores.
16
- ENV['MEMCACHED'] ||= 'localhost:11215'
16
+ ENV['MEMCACHED'] ||= 'localhost:11211'
17
17
  $memcached = nil
18
18
  $memcache = nil
19
19
 
@@ -70,7 +70,6 @@ def need_memcache(forwhat)
70
70
  end
71
71
 
72
72
  def need_java(forwhat)
73
-
74
73
  if RUBY_PLATFORM =~ /java/
75
74
  yield
76
75
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.5"
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Tomayko
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-25 00:00:00 -07:00
12
+ date: 2009-09-25 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -75,6 +75,8 @@ files:
75
75
  - test/storage_test.rb
76
76
  has_rdoc: true
77
77
  homepage: http://tomayko.com/src/rack-cache/
78
+ licenses: []
79
+
78
80
  post_install_message:
79
81
  rdoc_options:
80
82
  - --line-numbers
@@ -100,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
102
  requirements: []
101
103
 
102
104
  rubyforge_project: wink
103
- rubygems_version: 1.3.1
105
+ rubygems_version: 1.3.4
104
106
  signing_key:
105
107
  specification_version: 2
106
108
  summary: HTTP Caching for Rack