rtomayko-rack-cache 0.3.9 → 0.4

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/CHANGES CHANGED
@@ -1,4 +1,4 @@
1
- ## 0.4.0 / Unreleased
1
+ ## 0.4.0 / March 2009
2
2
 
3
3
  * Ruby 1.9.1 / Rack 1.0 compatible.
4
4
 
@@ -9,7 +9,8 @@
9
9
 
10
10
  * Implement "Cache-Control: max-age=N" request directive by forcing
11
11
  validation when the max-age provided exceeds the age of the cache
12
- entry.
12
+ entry. This can be disabled by setting the "allow_revalidate" option to
13
+ false.
13
14
 
14
15
  * Properly implement "Cache-Control: no-cache" request directive by
15
16
  performing a full reload. RFC 2616 states that when "no-cache" is
@@ -19,7 +20,8 @@
19
20
  first validate its entry with the origin. Previously, we implemented
20
21
  "no-cache" on requests by passing so no new cache entry would be stored
21
22
  based on the response. Now we treat it as a forced miss and enter the
22
- response into the cache if it's cacheable.
23
+ response into the cache if it's cacheable. This can be disabled by
24
+ setting the "allow_reload" option to false.
23
25
 
24
26
  * Assume identical semantics for the "Pragma: no-cache" request header
25
27
  as the "Cache-Control: no-cache" directive described above.
data/README CHANGED
@@ -24,14 +24,6 @@ caching solution for small to medium sized deployments. More sophisticated /
24
24
  high-performance caching systems (e.g., Varnish, Squid, httpd/mod-cache) may be
25
25
  more appropriate for large deployments with significant throughput requirements.
26
26
 
27
- Status
28
- ------
29
-
30
- Rack::Cache is a young and experimental project that is likely to change
31
- substantially and may not be wholly functional, consistent, fast, or correct.
32
- The current focus is on reaching basic compliance with RFC 2616 and providing
33
- good documentation.
34
-
35
27
  Installation
36
28
  ------------
37
29
 
@@ -65,6 +57,24 @@ Assuming you've designed your backend application to take advantage of HTTP's
65
57
  caching features, no further code or configuration is required for basic
66
58
  caching.
67
59
 
60
+ Using with Rails
61
+ ----------------
62
+
63
+ Add this to your `config/environment.rb`:
64
+
65
+ config.middleware.use Rack::Cache,
66
+ :verbose => true,
67
+ :metastore => 'file:/var/cache/rack/meta',
68
+ :entitystore => 'file:/var/cache/rack/body'
69
+
70
+ You should now see `Rack::Cache` listed in the middleware pipeline:
71
+
72
+ rake middleware
73
+
74
+ See the following for more information:
75
+
76
+ http://snippets.aktagon.com/snippets/302
77
+
68
78
  Links
69
79
  -----
70
80
 
data/Rakefile CHANGED
@@ -31,7 +31,7 @@ end
31
31
 
32
32
  # DOC =======================================================================
33
33
  desc 'Build all documentation'
34
- task :doc => %w[doc:api doc:graphs doc:markdown]
34
+ task :doc => %w[doc:api doc:markdown]
35
35
 
36
36
  # requires the hanna gem:
37
37
  # gem install mislav-hanna --source=http://gems.github.com
@@ -55,19 +55,6 @@ file 'doc/api/index.html' => FileList['lib/**/*.rb'] do |f|
55
55
  end
56
56
  CLEAN.include 'doc/api'
57
57
 
58
- desc 'Build graphviz graphs'
59
- task 'doc:graphs'
60
- %w[pdf png svg].each do |filetype|
61
- FileList["doc/*.dot"].each do |source|
62
- dest = source.sub(/dot$/, filetype)
63
- file dest => source do |f|
64
- sh "dot -T#{filetype} #{source} -o #{f.name}"
65
- end
66
- task 'doc:graphs' => dest
67
- CLEAN.include dest
68
- end
69
- end
70
-
71
58
  desc 'Build markdown documentation files'
72
59
  task 'doc:markdown'
73
60
  FileList['doc/*.markdown'].each do |source|
data/TODO CHANGED
@@ -1,13 +1,8 @@
1
- ## 0.4
1
+ ## Backlog
2
2
 
3
3
  - Move breakers.rb configuration file into rack-contrib as a middleware
4
4
  component.
5
- - Add docs on using Rack::Cache with Rails 2.3 or link to one of the
6
- existing tutorials on this.
7
5
  - Sample apps: Rack, Rails, Sinatra, Merb, etc.
8
-
9
- ## Backlog
10
-
11
6
  - Use Bacon instead of test/spec
12
7
  - Work with both memcache and memcached gems (memcached hasn't built on MacOS
13
8
  for some time now).
data/doc/faq.markdown CHANGED
@@ -10,6 +10,14 @@ General
10
10
  -------
11
11
 
12
12
 
13
+ <a class='hash' id='rails' href='#rails'>#</a>
14
+
15
+ ### Q: Can I use Rack::Cache with Rails?
16
+
17
+ Rack::Cache can be used with Rails 2.3 or above. Documentation and a
18
+ sample application is forthcoming; in the mean time, see
19
+ [this example of using Rack::Cache with Rails 2.3](http://snippets.aktagon.com/snippets/302-How-to-setup-and-use-Rack-Cache-with-Rails-2-3-0-RC-1).
20
+
13
21
  <a class='hash' id='why-not-squid' href='#why-not-squid'>#</a>
14
22
 
15
23
  ### Q: Why Rack::Cache? Why not Squid, Varnish, Perlbol, etc.?
data/doc/index.markdown CHANGED
@@ -9,13 +9,13 @@ for [Rack][]-based applications that produce freshness (`Expires`,
9
9
  * Portable: 100% Ruby / works with any [Rack][]-enabled framework.
10
10
  * Disk, memcached, and heap memory [storage backends][storage].
11
11
 
12
- Status
13
- ------
12
+ News
13
+ ----
14
14
 
15
- __Rack::Cache__ is a young and experimental project that is likely to
16
- change substantially and may not be wholly functional, consistent,
17
- fast, or correct. The current focus is on reaching basic compliance
18
- with RFC 2616 and providing good documentation.
15
+ * [How to use Rack::Cache with Rails 2.3](http://snippets.aktagon.com/snippets/302-How-to-setup-and-use-Rack-Cache-with-Rails-2-3-0-RC-1) - it's really easy.
16
+ * [RailsLab's Advanced HTTP Caching Screencast](http://railslab.newrelic.com/2009/02/26/episode-11-advanced-http-caching)
17
+ is a really great review of HTTP caching concepts and shows how to
18
+ use Rack::Cache with Rails.
19
19
 
20
20
  Installation
21
21
  ------------
@@ -51,7 +51,7 @@ caching.
51
51
  More
52
52
  ----
53
53
 
54
- * [Configuration and Options][config] - how to set cache options.
54
+ * [Configuration Options][config] - how to set cache options.
55
55
 
56
56
  * [Cache Storage Documentation][storage] - detailed information on the various
57
57
  storage implementations available in __Rack::Cache__ and how to choose the one
@@ -15,11 +15,12 @@ module Rack::Cache
15
15
  # The Rack application object immediately downstream.
16
16
  attr_reader :backend
17
17
 
18
- def initialize(backend, options={}, &block)
18
+ def initialize(backend, options={})
19
19
  @backend = backend
20
20
  @trace = []
21
+
21
22
  initialize_options options
22
- instance_eval(&block) if block_given?
23
+ yield self if block_given?
23
24
 
24
25
  @private_header_keys =
25
26
  private_headers.map { |name| "HTTP_#{name.upcase.tr('-', '_')}" }
@@ -109,7 +110,7 @@ module Rack::Cache
109
110
  # Whether the cache entry is "fresh enough" to satisfy the request.
110
111
  def fresh_enough?(entry)
111
112
  if entry.fresh?
112
- if max_age = @request.cache_control.max_age
113
+ if allow_revalidate? && max_age = @request.cache_control.max_age
113
114
  max_age > 0 && max_age >= entry.age
114
115
  else
115
116
  true
@@ -143,7 +144,7 @@ module Rack::Cache
143
144
  # stale, attempt to #validate the entry with the backend using conditional
144
145
  # GET. When no matching cache entry is found, trigger #miss processing.
145
146
  def lookup
146
- if @request.no_cache?
147
+ if @request.no_cache? && allow_reload?
147
148
  record :reload
148
149
  fetch
149
150
  elsif entry = metastore.lookup(@request, entitystore)
@@ -7,20 +7,22 @@ module Rack::Cache
7
7
  # uses the Rack Environment to store option values. All options documented
8
8
  # below are stored in the Rack Environment as "rack-cache.<option>", where
9
9
  # <option> is the option name.
10
- #
11
- # The #set method can be used to configure a option values. When #set is
12
- # called outside of request scope, the value applies to all requests; when
13
- # called from within a request context, applies only to the request being
14
- # processed.
15
10
  module Options
16
- class << self
17
- private
18
- def option_accessor(key)
19
- define_method(key) { || read_option(key) }
20
- define_method("#{key}=") { |value| write_option(key, value) }
21
- define_method("#{key}?") { || !! read_option(key) }
11
+ def self.option_accessor(key)
12
+ name = option_name(key)
13
+ define_method(key) { || options[name] }
14
+ define_method("#{key}=") { |value| options[name] = value }
15
+ define_method("#{key}?") { || !! options[name] }
16
+ end
17
+
18
+ def option_name(key)
19
+ case key
20
+ when Symbol ; "rack-cache.#{key}"
21
+ when String ; key
22
+ else raise ArgumentError
22
23
  end
23
24
  end
25
+ module_function :option_name
24
26
 
25
27
  # Enable verbose trace logging. This option is currently enabled by
26
28
  # default but is likely to be disabled in a future release.
@@ -57,9 +59,9 @@ module Rack::Cache
57
59
  # end
58
60
  option_accessor :cache_key
59
61
 
60
- # A URI specifying the entity-store implement that should be used to store
61
- # response bodies. See the metastore option for information on supported URI
62
- # schemes.
62
+ # A URI specifying the entity-store implementation that should be used to
63
+ # store response bodies. See the metastore option for information on
64
+ # supported URI schemes.
63
65
  #
64
66
  # If no entity store is specified the 'heap:/' store is assumed. This
65
67
  # implementation has significant draw-backs so explicit configuration is
@@ -83,6 +85,16 @@ module Rack::Cache
83
85
  # Default: ['Authorization', 'Cookie']
84
86
  option_accessor :private_headers
85
87
 
88
+ # Specifies whether the client can force a cache reload by including a
89
+ # Cache-Control "no-cache" directive in the request. This is enabled by
90
+ # default for compliance with RFC 2616.
91
+ option_accessor :allow_reload
92
+
93
+ # Specifies whether the client can force a cache revalidate by including
94
+ # a Cache-Control "max-age=0" directive in the request. This is enabled by
95
+ # default for compliance with RFC 2616.
96
+ option_accessor :allow_revalidate
97
+
86
98
  # The underlying options Hash. During initialization (or outside of a
87
99
  # request), this is a default values Hash. During a request, this is the
88
100
  # Rack environment Hash. The default values Hash is merged in underneath
@@ -112,6 +124,21 @@ module Rack::Cache
112
124
  end
113
125
 
114
126
  private
127
+ def initialize_options(options={})
128
+ @default_options = {
129
+ 'rack-cache.cache_key' => Key,
130
+ 'rack-cache.verbose' => true,
131
+ 'rack-cache.storage' => Rack::Cache::Storage.instance,
132
+ 'rack-cache.metastore' => 'heap:/',
133
+ 'rack-cache.entitystore' => 'heap:/',
134
+ 'rack-cache.default_ttl' => 0,
135
+ 'rack-cache.private_headers' => ['Authorization', 'Cookie'],
136
+ 'rack-cache.allow_reload' => true,
137
+ 'rack-cache.allow_revalidate' => true
138
+ }
139
+ self.options = options
140
+ end
141
+
115
142
  def read_option(key)
116
143
  options[option_name(key)]
117
144
  end
@@ -119,27 +146,5 @@ module Rack::Cache
119
146
  def write_option(key, value)
120
147
  options[option_name(key)] = value
121
148
  end
122
-
123
- def option_name(key)
124
- case key
125
- when Symbol ; "rack-cache.#{key}"
126
- when String ; key
127
- else raise ArgumentError
128
- end
129
- end
130
-
131
- private
132
- def initialize_options(options={})
133
- @default_options = {
134
- 'rack-cache.cache_key' => Key,
135
- 'rack-cache.verbose' => true,
136
- 'rack-cache.storage' => Rack::Cache::Storage.instance,
137
- 'rack-cache.metastore' => 'heap:/',
138
- 'rack-cache.entitystore' => 'heap:/',
139
- 'rack-cache.default_ttl' => 0,
140
- 'rack-cache.private_headers' => ['Authorization', 'Cookie']
141
- }
142
- self.options = options
143
- end
144
149
  end
145
150
  end
data/rack-cache.gemspec CHANGED
@@ -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.3.9'
7
- s.date = '2009-03-07'
6
+ s.version = '0.4'
7
+ s.date = '2009-03-16'
8
8
 
9
9
  s.description = "HTTP Caching for Rack"
10
10
  s.summary = "HTTP Caching for Rack"
@@ -20,7 +20,6 @@ Gem::Specification.new do |s|
20
20
  Rakefile
21
21
  TODO
22
22
  doc/configuration.markdown
23
- doc/events.dot
24
23
  doc/faq.markdown
25
24
  doc/index.markdown
26
25
  doc/layout.html.erb
data/test/cache_test.rb CHANGED
@@ -25,14 +25,14 @@ describe 'Rack::Cache::new' do
25
25
  end
26
26
 
27
27
  it 'takes a block; executes it during initialization' do
28
- state, block_scope = 'not invoked', nil
29
- object =
30
- Rack::Cache.new @app do
31
- block_scope = self
28
+ state, object = 'not invoked', nil
29
+ instance =
30
+ Rack::Cache.new @app do |cache|
31
+ object = cache
32
32
  state = 'invoked'
33
- should.respond_to :set
33
+ cache.should.respond_to :set
34
34
  end
35
35
  state.should.equal 'invoked'
36
- object.should.be block_scope
36
+ object.should.be instance
37
37
  end
38
38
  end
data/test/context_test.rb CHANGED
@@ -148,6 +148,31 @@ describe 'Rack::Cache::Context' do
148
148
  cache.trace.should.include :store
149
149
  end
150
150
 
151
+ it 'does not reload responses when allow_reload is set false' do
152
+ count = 0
153
+ respond_with 200, 'Cache-Control' => 'max-age=10000' do |req,res|
154
+ count+= 1
155
+ res.body = (count == 1) ? ['Hello World'] : ['Goodbye World']
156
+ end
157
+
158
+ get '/'
159
+ response.should.be.ok
160
+ response.body.should.equal 'Hello World'
161
+ cache.trace.should.include :store
162
+
163
+ get '/'
164
+ response.should.be.ok
165
+ response.body.should.equal 'Hello World'
166
+ cache.trace.should.include :fresh
167
+
168
+ get '/',
169
+ 'rack-cache.allow_reload' => false,
170
+ 'HTTP_CACHE_CONTROL' => 'no-cache'
171
+ response.should.be.ok
172
+ response.body.should.equal 'Hello World'
173
+ cache.trace.should.not.include :reload
174
+ end
175
+
151
176
  it 'revalidates fresh cache entry when max-age request directive is exceeded' do
152
177
  count = 0
153
178
  respond_with do |req,res|
@@ -175,6 +200,34 @@ describe 'Rack::Cache::Context' do
175
200
  cache.trace.should.include :store
176
201
  end
177
202
 
203
+ it 'does not revalidate fresh cache entry when enable_revalidate option is set false' do
204
+ count = 0
205
+ respond_with do |req,res|
206
+ count+= 1
207
+ res['Cache-Control'] = 'max-age=10000'
208
+ res['ETag'] = count.to_s
209
+ res.body = (count == 1) ? ['Hello World'] : ['Goodbye World']
210
+ end
211
+
212
+ get '/'
213
+ response.should.be.ok
214
+ response.body.should.equal 'Hello World'
215
+ cache.trace.should.include :store
216
+
217
+ get '/'
218
+ response.should.be.ok
219
+ response.body.should.equal 'Hello World'
220
+ cache.trace.should.include :fresh
221
+
222
+ get '/',
223
+ 'rack-cache.allow_revalidate' => false,
224
+ 'HTTP_CACHE_CONTROL' => 'max-age=0'
225
+ response.should.be.ok
226
+ response.body.should.equal 'Hello World'
227
+ cache.trace.should.not.include :stale
228
+ cache.trace.should.not.include :invalid
229
+ cache.trace.should.include :fresh
230
+ end
178
231
  it 'fetches response from backend when cache misses' do
179
232
  respond_with 200, 'Expires' => (Time.now + 5).httpdate
180
233
  get '/'
data/test/spec_setup.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'pp'
2
2
  require 'tmpdir'
3
+ require 'stringio'
3
4
 
4
5
  [ STDOUT, STDERR ].each { |io| io.sync = true }
5
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rtomayko-rack-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: "0.4"
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-03-07 00:00:00 -08:00
12
+ date: 2009-03-16 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,7 +40,6 @@ files:
40
40
  - Rakefile
41
41
  - TODO
42
42
  - doc/configuration.markdown
43
- - doc/events.dot
44
43
  - doc/faq.markdown
45
44
  - doc/index.markdown
46
45
  - doc/layout.html.erb
data/doc/events.dot DELETED
@@ -1,27 +0,0 @@
1
- digraph cache_logic {
2
- nodesep=1.25;
3
- center=true;
4
-
5
- node[fontname="Lucida Sans Unicode",labelloc=c,margin=0.10,0.03]
6
- edge[fontname="Lucida Sans Unicode",fontcolor="#444444",labeldistance=20];
7
-
8
- receive -> pass[label="uncacheable request",color=grey];
9
- receive -> lookup[label="cacheable request"];
10
-
11
- pass -> deliver[label="",color=grey];
12
-
13
- lookup -> hit[label="fresh"];
14
- lookup -> fetch[label="stale (needs validation)"];
15
- lookup -> miss[label="uncached"];
16
-
17
- hit -> deliver[label="sizzling"];
18
- hit -> pass[label="bailing...",color=grey];
19
-
20
- miss -> fetch[label=""];
21
- miss -> pass[color=grey];
22
-
23
- fetch -> store[label="cacheable"];
24
- fetch -> deliver[label="not cacheable",color=grey];
25
-
26
- store -> deliver[label="KTHX"];
27
- }