├── .github └── workflows │ ├── development.yml │ └── gh-pages.yml ├── .gitignore ├── CHANGES ├── MIT-LICENSE ├── README.md ├── Rakefile ├── doc ├── configuration.markdown ├── faq.markdown ├── index.markdown ├── layout.html.erb ├── license.markdown ├── rack-cache.css ├── server.ru └── storage.markdown ├── example └── sinatra │ ├── app.rb │ └── views │ └── index.erb ├── gems.rb ├── gems ├── rack_v2-1.rb ├── rack_v2.rb └── rack_v3.rb ├── lib ├── rack-cache.rb └── rack │ ├── cache.rb │ └── cache │ ├── app_engine.rb │ ├── appengine.rb │ ├── cache_control.rb │ ├── cachecontrol.rb │ ├── context.rb │ ├── entity_store.rb │ ├── entitystore.rb │ ├── headers.rb │ ├── key.rb │ ├── meta_store.rb │ ├── metastore.rb │ ├── options.rb │ ├── request.rb │ ├── response.rb │ ├── storage.rb │ └── version.rb ├── rack-cache.gemspec └── test ├── cache_control_test.rb ├── cache_test.rb ├── context_test.rb ├── entity_store_test.rb ├── key_test.rb ├── meta_store_test.rb ├── options_test.rb ├── pony.jpg ├── request_test.rb ├── response_test.rb ├── storage_test.rb └── test_helper.rb /.github/workflows/development.yml: -------------------------------------------------------------------------------- 1 | name: Development 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | name: ${{matrix.ruby}} on ${{matrix.os}} (${{matrix.gemfile}}) 8 | runs-on: ${{matrix.os}}-latest 9 | continue-on-error: ${{matrix.experimental}} 10 | 11 | strategy: 12 | matrix: 13 | os: 14 | - ubuntu 15 | - macos 16 | 17 | ruby: 18 | - "2.7" 19 | - "3.0" 20 | - "3.1" 21 | - "3.2" 22 | - "3.3" 23 | 24 | gemfile: 25 | - gems/rack_v2.rb 26 | - gems/rack_v2-1.rb 27 | - gems/rack_v3.rb 28 | 29 | experimental: [false] 30 | 31 | include: 32 | - os: ubuntu 33 | ruby: truffleruby 34 | experimental: true 35 | - os: ubuntu 36 | ruby: jruby 37 | experimental: true 38 | - os: ubuntu 39 | ruby: head 40 | experimental: true 41 | 42 | env: 43 | BUNDLE_GEMFILE: ${{matrix.gemfile}} 44 | 45 | steps: 46 | - uses: actions/checkout@v3 47 | 48 | - name: Installing packages (ubuntu) 49 | if: matrix.os == 'ubuntu' 50 | run: sudo apt-get install libmemcached-dev 51 | 52 | - name: Installing packages (macos) 53 | if: matrix.os == 'macos' 54 | run: brew install libmemcached 55 | 56 | - uses: ruby/setup-ruby@v1 57 | with: 58 | ruby-version: ${{matrix.ruby}} 59 | bundler-cache: true 60 | 61 | - run: bundle exec rake 62 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Github Pages 2 | on: 3 | push: 4 | branches: 5 | - main 6 | permissions: 7 | contents: write 8 | jobs: 9 | build-and-deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: ruby/setup-ruby@v1 14 | with: 15 | ruby-version: '2.7' 16 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 17 | 18 | - name: Install and Build 🔧 19 | run: bundle exec rake doc:gh-pages 20 | 21 | - name: Deploy 🚀 22 | uses: JamesIves/github-pages-deploy-action@v4.3.3 23 | with: 24 | branch: gh-pages # The branch the action should deploy to. 25 | folder: doc/gh-pages # The folder the action should deploy. 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | \[. 2 | tags 3 | .vimrc 4 | /dist 5 | /coverage 6 | /doc/api 7 | /doc/*.png 8 | /doc/*.pdf 9 | /doc/*.svg 10 | /doc/config 11 | /doc/configuration.html 12 | /doc/index.html 13 | /doc/license.html 14 | /doc/storage.html 15 | /doc/faq.html 16 | /doc/gh-pages 17 | gems.locked 18 | /pkg 19 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | ## 1.13.0 2 | 3 | * Support lowercase Vary and Age headers 4 | 5 | ## 1.12.0 6 | 7 | * Add a fault_tolerant flag to fail-over to stale cache 8 | 9 | ## 1.11.1 10 | 11 | * when ignoring parts of the query, remove query in key when all params are ignored 12 | 13 | ## 1.11.0 14 | 15 | * Add a proc to allow ignoring parts of the query string in the key 16 | 17 | ## 1.10.0 18 | 19 | * Pass Options To Underlying Storage Driver 20 | * bump required ruby version to 2.3 21 | 22 | ## 1.9.0 23 | 24 | * make purge not raise when not implemented 25 | 26 | ## 1.8.0 27 | 28 | * Meta stores will purge keys when no entity store entries are found 29 | 30 | ## 1.7.2 31 | 32 | * Fix key generation for requests with no query strings 33 | 34 | ## 1.7.0 35 | 36 | * Meta stores now receive a third ttl argument to write when use_native_ttl is used. 37 | 38 | ## 1.6.1 39 | 40 | * Revert 'No longer read responses from cache when we already have them' 41 | 42 | ## 1.6.0 43 | 44 | * Noop backend 45 | * No longer read responses from cache when we already have them 46 | * renamed files from entitystore -> entity_store (metastore/cachecontrol/appengine) and added warns for old ones 47 | 48 | ## 1.5.1 49 | 50 | * fix key generation for query strings that include encoded equals 51 | 52 | ## 1.5.0 53 | 54 | * only catch StandardError and not Exception 55 | 56 | ## 1.4.3 57 | 58 | * After overriding the REQUEST_METHOD, store the original request method in "rack.methodoverride.original_method" 59 | 60 | ## 1.4.1 61 | 62 | * Ignore invalid Expires date as per RFC 63 | 64 | ## 1.4.0 65 | 66 | * Not invalidating the cache for preflight CORS request 67 | 68 | ## 1.3.1 / October 2015 69 | 70 | * Support Ruby 1.9 71 | 72 | ## 1.3 / Octorber 2015 73 | 74 | * Ruby 2.0 only 75 | 76 | * Gracefully degrade when cache store goes offline 77 | 78 | * allow_reload/revalidate is not enabled by default 79 | 80 | * Make Rack::Cache multithread friendly 81 | 82 | ## 1.2 / March 2012 83 | 84 | * Fix a cookie leak vulnerability effecting large numbers of Rails 3.x installs: 85 | https://github.com/rtomayko/rack-cache/pull/52 86 | 87 | * Never 304 on PUT or POST requests. 88 | 89 | * Misc bundler and test tooling fixes. 90 | 91 | ## 1.1 / September 2011 92 | 93 | * Allow (INM/IMS) validation requests through to backend on miss. Makes it 94 | possible to use validation for private / uncacheable responses. A number of 95 | people using Rails's stale?() helper reported that their validation logic was 96 | never kicking in. 97 | 98 | * Add rack env rack-cache.force-pass option to bypass rack-cache on 99 | per request basis 100 | 101 | * Fix an issue with memcache namespace not being set when using the 102 | :namespace option instead of :prefix_key. 103 | 104 | * Fix test failures due to MockResponse changes in recent Rack 105 | version (issue #34) 106 | 107 | ## 1.0.3 / August 2011 108 | 109 | * Fix bug passing options to memcached and dalli 110 | 111 | * Document cache_key 112 | 113 | ## 1.0.1 / April 2011 114 | 115 | * Added lib/rack-cache.rb to match package name for auto-requiring machinery. 116 | 117 | * Fixed a number of issues caused by Rack::Cache not closing the body received 118 | from the application. Rack::Lock and other middleware use body.close to 119 | signal the true end of request processing so failure to call this method 120 | can result in strange issues (e.g., 121 | "ThreadError: deadlock; recursive locking") 122 | 123 | * Fixed a bug where Rack::Cache would blow up writing the rack env to the meta 124 | store when the env contained an all uppercase key whose value wasn't 125 | marshalable. Passenger and some other stuff write such keys apparently. 126 | 127 | * The test suite has moved from test-spec to bacon. This is a short term 128 | solution to the problem of not being able to run tests under Ruby 1.9.x. 129 | The test suite will be moved to basic Test::Unit style sometime in the 130 | future. 131 | 132 | ## 1.0 / December 2010 133 | 134 | * Rack::Cache is 1.0 and will now maintain semantic versioning 135 | 136 | * Add Dalli memcache client support and removed support for the unmaintained 137 | memcache-client library. You will need to move your apps to Dalli before 138 | upgrading rack-cache to 1.0. 139 | 140 | ## 0.5.3 / September 2010 141 | 142 | * A matching If-Modified-Since is ignored if an If-None-Match is also provided 143 | and doesn't match. This is in line with RFC 2616. 144 | 145 | * Converts string status codes to integers before returns to workaround bad 146 | behaving rack middleware and apps. 147 | 148 | * Misc doc clean up. 149 | 150 | ## 0.5.2 / September 2009 151 | 152 | * Exceptions raised from the metastore are not fatal. This makes a lot of 153 | sense in most cases because its okay for the cache to be down - it 154 | shouldn't blow up your app. 155 | 156 | ## 0.5.1 / June 2009 157 | 158 | * Added support for memcached clusters and other advanced 159 | configuration provided by the memcache-client and memcached 160 | libraries. The "metastore" and "entitystore" options can now be 161 | set to a MemCache object or Memcached object: 162 | 163 | memcache = MemCache.new(['127.1.1.1', '127.1.1.2'], :namespace => "/foo") 164 | use Rack::Cache, 165 | :metastore => memcache, 166 | :entitystore => memcache 167 | 168 | * Fix "memcached://" metastore URL handling. The "memcached" variation 169 | blew up, the "memcache" version was fine. 170 | 171 | ## 0.5.0 / May 2009 172 | 173 | * Added meta and entity store implementations based on the 174 | memcache-client library. These are the default unless the memcached 175 | library has already been required. 176 | 177 | * The "allow_reload" and "allow_revalidate" options now default to 178 | false instead of true. This means we break with RFC 2616 out of 179 | the box but this is the expected configuration in a huge majority 180 | of gateway cache scenarios. See the docs on configuration 181 | options for more information on these options: 182 | http://tomayko.com/src/rack-cache/configuration 183 | 184 | * Added Google AppEngine memcache entity store and metastore 185 | implementations. To use GAE's memcache with rack-cache, set the 186 | "metastore" and "entitystore" options as follows: 187 | 188 | use Rack::Cache, 189 | :metastore => 'gae://cache-meta', 190 | :entitystore => 'gae://cache-body' 191 | 192 | The 'cache-meta' and 'cache-body' parts are memcache namespace 193 | prefixes and should be set to different values. 194 | 195 | ## 0.4.0 / March 2009 196 | 197 | * Ruby 1.9.1 / Rack 1.0 compatible. 198 | 199 | * Invalidate cache entries that match the request URL on non-GET/HEAD 200 | requests. i.e., POST, PUT, DELETE cause matching cache entries to 201 | be invalidated. The cache entry is validated with the backend using 202 | a conditional GET the next time it's requested. 203 | 204 | * Implement "Cache-Control: max-age=N" request directive by forcing 205 | validation when the max-age provided exceeds the age of the cache 206 | entry. This can be disabled by setting the "allow_revalidate" option to 207 | false. 208 | 209 | * Properly implement "Cache-Control: no-cache" request directive by 210 | performing a full reload. RFC 2616 states that when "no-cache" is 211 | present in the request, the cache MUST NOT serve a stored response even 212 | after successful validation. This is slightly different from the 213 | "no-cache" directive in responses, which indicates that the cache must 214 | first validate its entry with the origin. Previously, we implemented 215 | "no-cache" on requests by passing so no new cache entry would be stored 216 | based on the response. Now we treat it as a forced miss and enter the 217 | response into the cache if it's cacheable. This can be disabled by 218 | setting the "allow_reload" option to false. 219 | 220 | * Assume identical semantics for the "Pragma: no-cache" request header 221 | as the "Cache-Control: no-cache" directive described above. 222 | 223 | * Less crazy logging. When the verbose option is set, a single log entry 224 | is written with a comma separated list of trace events. For example, if 225 | the cache was stale but validated, the following log entry would be 226 | written: "cache: stale, valid, store". When the verbose option is false, 227 | no logging occurs. 228 | 229 | * Added "X-Rack-Cache" response header with the same comma separated trace 230 | value as described above. This gives some visibility into how the cache 231 | processed the request. 232 | 233 | * Add support for canonicalized cache keys, as well as custom cache key 234 | generators, which are specified in the options as :cache_key as either 235 | any object that has a call() or as a block. Cache key generators get 236 | passed a request object and return a cache key string. 237 | 238 | ## 0.3.0 / December 2008 239 | 240 | * Add support for public and private cache control directives. Responses 241 | marked as explicitly public are cached even when the request includes 242 | an Authorization or Cookie header. Responses marked as explicitly private 243 | are considered uncacheable. 244 | 245 | * Added a "private_headers" option that dictates which request headers 246 | trigger default "private" cache control processing. By default, the 247 | Cookie and Authorization headers are included. Headers may be added or 248 | removed as necessary to change the default private logic. 249 | 250 | * Adhere to must-revalidate/proxy-revalidate cache control directives by 251 | not assigning the default_ttl to responses that don't include freshness 252 | information. This should let us begin using default_ttl more liberally 253 | since we can control it using the must-revalidate/proxy-revalidate directives. 254 | 255 | * Use the s-maxage Cache-Control value in preference to max-age when 256 | present. The ttl= method now sets the s-maxage value instead of max-age. 257 | Code that used ttl= to control freshness at the client needs to change 258 | to set the max-age directive explicitly. 259 | 260 | * Enable support for X-Sendfile middleware by responding to #to_path on 261 | bodies served from disk storage. Adding the Rack::Sendfile component 262 | upstream from Rack::Cache will result in cached bodies being served 263 | directly by the web server (instead of being read in Ruby). 264 | 265 | * BUG: MetaStore hits but EntityStore misses. This would 500 previously; now 266 | we detect it and act as if the MetaStore missed as well. 267 | 268 | * Implement low level #purge method on all concrete entity store 269 | classes -- removes the entity body corresponding to the SHA1 key 270 | provided and returns nil. 271 | 272 | * Basically sane handling of HEAD requests. A HEAD request is never passed 273 | through to the backend except when transitioning with pass!. This means 274 | that the cache responds to HEAD requests without invoking the backend at 275 | all when the cached entry is fresh. When no cache entry exists, or the 276 | cached entry is stale and can be validated, the backend is invoked with 277 | a GET request and the HEAD is handled right before the response 278 | is delivered upstream. 279 | 280 | * BUG: The Age response header was not being set properly when a stale 281 | entry was validated. This would result in Age values that exceeded 282 | the freshness lifetime in responses. 283 | 284 | * BUG: A cached entry in a heap meta store could be unintentionally 285 | modified by request processing since the cached objects were being 286 | returned directly. The result was typically missing/incorrect header 287 | values (e.g., missing Content-Type header). [dkubb] 288 | 289 | * BUG: 304 responses should not include entity headers (especially 290 | Content-Length). This is causing Safari/WebKit weirdness on 304 291 | responses. 292 | 293 | * BUG: The If-None-Match header was being ignored, causing the cache 294 | to send 200 responses to matching conditional GET requests. 295 | 296 | ## 0.2.0 / 2008-10-24 / Initial Release 297 | 298 | * Document events and transitions in `rack/cache/config/default.rb` 299 | * Basic logging support (`trace`, `warn`, `info`, `error` from within Context) 300 | * EntityStore: store entity bodies keyed by SHA 301 | * MetaStore: store response headers keyed by URL 302 | * Last-Modified/ETag validation 303 | * Vary support 304 | * Implement error! transition 305 | * New Rack::Cache::Core 306 | * memcached meta and entity store implementations 307 | * URI based storage configuration 308 | * Read options from Rack env if present (rack-cache.XXX keys) 309 | * `object` is now `entry` 310 | * Documentation framework and website 311 | * Document storage areas and implementations 312 | * Document configuration/events 313 | 314 | ## 0.1.0 / 2008-07-21 / Proof of concept (unreleased) 315 | 316 | * Basic core with event support 317 | * `#import` method for bringing in config files 318 | * Freshness based expiration 319 | * RFC 2616 If-Modified-Since based validation 320 | * A horribly shitty storage back-end (Hash in mem) 321 | * Don't cache hop-by-hop headers: Connection, Keep-Alive, Proxy-Authenticate, 322 | Proxy-Authorization, TE, Trailers, Transfer-Encoding, Upgrade 323 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008 Ryan Tomayko 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Rack::Cache 2 | =========== 3 | 4 | Rack::Cache is suitable as a quick drop-in component to enable HTTP caching for 5 | Rack-based applications that produce freshness (`expires`, `cache-control`) 6 | and/or validation (`last-modified`, `etag`) information: 7 | 8 | * Standards-based (RFC 2616) 9 | * Freshness/expiration based caching 10 | * Validation (`if-modified-since` / `if-none-match`) 11 | * `vary` support 12 | * `cache-control` `public`, `private`, `max-age`, `s-maxage`, `must-revalidate`, 13 | and `proxy-revalidate`. 14 | * Portable: 100% Ruby / works with any Rack-enabled framework 15 | * Disk, memcached, and heap memory storage backends 16 | 17 | For more information about Rack::Cache features and usage, see: 18 | 19 | https://rack.github.io/rack-cache/ 20 | 21 | Rack::Cache is not overly optimized for performance. The main goal of the 22 | project is to provide a portable, easy-to-configure, and standards-based 23 | caching solution for small to medium sized deployments. More sophisticated / 24 | high-performance caching systems (e.g., Varnish, Squid, httpd/mod-cache) may be 25 | more appropriate for large deployments with significant throughput requirements. 26 | 27 | Installation 28 | ------------ 29 | 30 | gem install rack-cache 31 | 32 | Basic Usage 33 | ----------- 34 | 35 | `Rack::Cache` is implemented as a piece of Rack middleware and can be used with 36 | any Rack-based application. If your application includes a rackup (`.ru`) file 37 | or uses Rack::Builder to construct the application pipeline, simply require 38 | and use as follows: 39 | 40 | ```Ruby 41 | require 'rack/cache' 42 | 43 | use Rack::Cache, 44 | metastore: 'file:/var/cache/rack/meta', 45 | entitystore: 'file:/var/cache/rack/body', 46 | verbose: true 47 | 48 | run app 49 | ``` 50 | 51 | Assuming you've designed your backend application to take advantage of HTTP's 52 | caching features, no further code or configuration is required for basic 53 | caching. 54 | 55 | Using with Rails 56 | ---------------- 57 | 58 | ```Ruby 59 | # config/application.rb 60 | config.action_dispatch.rack_cache = true 61 | # or 62 | config.action_dispatch.rack_cache = { 63 | verbose: true, 64 | metastore: 'file:/var/cache/rack/meta', 65 | entitystore: 'file:/var/cache/rack/body' 66 | } 67 | ``` 68 | 69 | You should now see `Rack::Cache` listed in the middleware pipeline: 70 | 71 | rake middleware 72 | 73 | [more information](https://snippets.aktagon.com/snippets/302-how-to-setup-and-use-rack-cache-with-rails) 74 | 75 | Using with Dalli 76 | ---------------- 77 | 78 | Dalli is a high performance memcached client for Ruby. 79 | More information at: https://github.com/mperham/dalli 80 | 81 | ```Ruby 82 | require 'dalli' 83 | require 'rack/cache' 84 | 85 | use Rack::Cache, 86 | verbose: true, 87 | metastore: "memcached://localhost:11211/meta", 88 | entitystore: "memcached://localhost:11211/body" 89 | 90 | run app 91 | ``` 92 | 93 | Noop entity store 94 | ----------------- 95 | 96 | Does not persist response bodies (no disk/memory used).
97 | Responses from the cache will have an empty body.
98 | Clients must ignore these empty cached response (check for `x-rack-cache` response header).
99 | Atm cannot handle streamed responses, patch needed. 100 | 101 | ```Ruby 102 | require 'rack/cache' 103 | 104 | use Rack::Cache, 105 | verbose: true, 106 | metastore: 107 | entitystore: "noop:/" 108 | 109 | run app 110 | ``` 111 | 112 | Ignoring tracking parameters in cache keys 113 | ----------------- 114 | 115 | It's fairly common to include tracking parameters which don't affect the content 116 | of the page. Since Rack::Cache uses the full URL as part of the cache key, this 117 | can cause unneeded churn in your cache. If you're using the default key class 118 | `Rack::Cache::Key`, you can configure a proc to ignore certain keys/values like 119 | so: 120 | 121 | ```Ruby 122 | Rack::Cache::Key.query_string_ignore = proc { |k, v| k =~ /^(trk|utm)_/ } 123 | ``` 124 | 125 | License: MIT
126 | [![Development](https://github.com/rack/rack-cache/actions/workflows/development.yml/badge.svg)](https://github.com/rack/rack-cache/actions/workflows/development.yml) 127 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/setup' 2 | require 'bundler/gem_tasks' 3 | require 'rake/clean' 4 | require 'bump/tasks' 5 | 6 | task :default => :test 7 | 8 | CLEAN.include %w[coverage/ doc/api doc/gh-pages tags] 9 | CLOBBER.include %w[dist] 10 | 11 | desc 'Run tests' 12 | task :test do 13 | sh "bundle exec mtest test" 14 | end 15 | 16 | desc 'Generate test coverage report' 17 | task :rcov do 18 | sh "rcov -I.:lib:test test/*_test.rb" 19 | end 20 | 21 | # DOC ======================================================================= 22 | desc 'Build all documentation' 23 | task :doc => %w[doc:api doc:markdown] 24 | 25 | desc 'Build API documentation (doc/api)' 26 | task 'doc:api' => 'doc/api/index.html' 27 | file 'doc/api/index.html' => FileList['lib/**/*.rb'] do |f| 28 | rm_rf 'doc/api' 29 | sh((<<-SH).gsub(/[\s\n]+/, ' ').strip) 30 | rdoc 31 | --op doc/api 32 | --charset utf8 33 | --fmt hanna 34 | --line-numbers 35 | --main cache.rb 36 | --title 'Rack::Cache API Documentation' 37 | #{f.prerequisites.join(' ')} 38 | SH 39 | end 40 | CLEAN.include 'doc/api' 41 | 42 | desc 'Build markdown documentation files' 43 | task 'doc:markdown' 44 | FileList['doc/*.markdown'].each do |source| 45 | dest = "doc/#{File.basename(source, '.markdown')}.html" 46 | file dest => [source, 'doc/layout.html.erb'] do |f| 47 | puts "markdown: #{source} -> #{dest}" if verbose 48 | require 'erb' unless defined? ERB 49 | template = File.read(source) 50 | content = Markdown.new(ERB.new(template, 0, "%<>").result(binding), :smart).to_html 51 | content.match("

(.*)

")[1] rescue '' 52 | layout = ERB.new(File.read("doc/layout.html.erb"), 0, "%<>") 53 | output = layout.result(binding) 54 | File.open(dest, 'w') { |io| io.write(output) } 55 | end 56 | task 'doc:markdown' => dest 57 | CLEAN.include dest 58 | end 59 | 60 | desc 'Move documentation to directory for github pages' 61 | task 'doc:gh-pages' => [:clean, :doc] do 62 | html_files = FileList['doc/*.markdown'].map { |file| file.gsub('.markdown', '.html')} 63 | css_files = FileList['doc/*.css'] 64 | 65 | FileUtils.mkdir('doc/gh-pages') 66 | FileUtils.cp_r('doc/api/', 'doc/gh-pages/api') 67 | FileUtils.cp([*html_files, *css_files], 'doc/gh-pages') 68 | end 69 | 70 | desc 'Start the documentation development server' 71 | task 'doc:server' do 72 | sh 'cd doc && thin --rackup server.ru --port 3035 start' 73 | end 74 | -------------------------------------------------------------------------------- /doc/configuration.markdown: -------------------------------------------------------------------------------- 1 | Configuration 2 | ============= 3 | 4 | __Rack::Cache__ includes a configuration system that can be used to specify 5 | fairly sophisticated cache policy on a global or per-request basis. 6 | 7 | 8 | 9 | Setting Cache Options 10 | --------------------- 11 | 12 | Cache options can be set when the __Rack::Cache__ object is created, 13 | or by setting a `rack-cache.