josh-rack-cache 0.5.1
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 +167 -0
- data/COPYING +18 -0
- data/README +110 -0
- data/Rakefile +137 -0
- data/TODO +27 -0
- data/doc/configuration.markdown +112 -0
- data/doc/faq.markdown +141 -0
- data/doc/index.markdown +121 -0
- data/doc/layout.html.erb +34 -0
- data/doc/license.markdown +24 -0
- data/doc/rack-cache.css +362 -0
- data/doc/server.ru +34 -0
- data/doc/storage.markdown +164 -0
- data/example/sinatra/app.rb +25 -0
- data/example/sinatra/views/index.erb +44 -0
- data/lib/rack/cache.rb +45 -0
- data/lib/rack/cache/appengine.rb +52 -0
- data/lib/rack/cache/cachecontrol.rb +193 -0
- data/lib/rack/cache/context.rb +253 -0
- data/lib/rack/cache/entitystore.rb +339 -0
- data/lib/rack/cache/key.rb +52 -0
- data/lib/rack/cache/metastore.rb +407 -0
- data/lib/rack/cache/options.rb +150 -0
- data/lib/rack/cache/request.rb +33 -0
- data/lib/rack/cache/response.rb +267 -0
- data/lib/rack/cache/storage.rb +62 -0
- data/rack-cache.gemspec +70 -0
- data/test/cache_test.rb +38 -0
- data/test/cachecontrol_test.rb +139 -0
- data/test/context_test.rb +774 -0
- data/test/entitystore_test.rb +230 -0
- data/test/key_test.rb +50 -0
- data/test/metastore_test.rb +302 -0
- data/test/options_test.rb +77 -0
- data/test/pony.jpg +0 -0
- data/test/request_test.rb +19 -0
- data/test/response_test.rb +178 -0
- data/test/spec_setup.rb +237 -0
- data/test/storage_test.rb +94 -0
- metadata +118 -0
@@ -0,0 +1,112 @@
|
|
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
|
+
<a id='setopt'></a>
|
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.<option>` variable in __Rack__'s
|
14
|
+
__Environment__.
|
15
|
+
|
16
|
+
When the __Rack::Cache__ object is instantiated:
|
17
|
+
|
18
|
+
use Rack::Cache,
|
19
|
+
:verbose => true,
|
20
|
+
:metastore => 'memcached://localhost:11211/',
|
21
|
+
:entitystore => 'file:/var/cache/rack'
|
22
|
+
|
23
|
+
Using __Rack__'s __Environment__:
|
24
|
+
|
25
|
+
env.merge!(
|
26
|
+
'rack-cache.verbose' => true,
|
27
|
+
'rack-cache.metastore' => 'memcached://localhost:11211/',
|
28
|
+
'rack-cache.entitystore' => 'file:/var/cache/rack'
|
29
|
+
)
|
30
|
+
|
31
|
+
<a id='options'></a>
|
32
|
+
|
33
|
+
Cache Option Reference
|
34
|
+
----------------------
|
35
|
+
|
36
|
+
Use the following options to customize __Rack::Cache__:
|
37
|
+
|
38
|
+
### `verbose`
|
39
|
+
|
40
|
+
Boolean specifying whether verbose trace logging is enabled. This option is
|
41
|
+
currently enabled (`true`) by default but is likely to be disabled (`false`) in
|
42
|
+
a future release. All log output is written to the `rack.errors` stream, which
|
43
|
+
is typically set to `STDERR`.
|
44
|
+
|
45
|
+
The `trace`, `info`, `warn`, and `error` methods can be used within the
|
46
|
+
configuration context to write messages to the errors stream.
|
47
|
+
|
48
|
+
### `default_ttl`
|
49
|
+
|
50
|
+
An integer specifying the number of seconds a cached object should be considered
|
51
|
+
"fresh" when no explicit freshness information is provided in a response.
|
52
|
+
Explicit `Cache-Control` or `Expires` response headers always override this
|
53
|
+
value. The `default_ttl` option defaults to `0`, meaning responses without
|
54
|
+
explicit freshness information are considered immediately "stale" and will not
|
55
|
+
be served from cache without validation.
|
56
|
+
|
57
|
+
### `metastore`
|
58
|
+
|
59
|
+
A URI specifying the __MetaStore__ implementation used to store request/response
|
60
|
+
meta information. See the [Rack::Cache Storage Documentation](storage.html)
|
61
|
+
for detailed information on different storage implementations.
|
62
|
+
|
63
|
+
If no metastore is specified, the `heap:/` store is assumed. This implementation
|
64
|
+
has significant draw-backs so explicit configuration is recommended.
|
65
|
+
|
66
|
+
### `entitystore`
|
67
|
+
|
68
|
+
A URI specifying the __EntityStore__ implementation used to store
|
69
|
+
response bodies. See the [Rack::Cache Storage Documentation](storage.html)
|
70
|
+
for detailed information on different storage implementations.
|
71
|
+
|
72
|
+
If no entitystore is specified, the `heap:/` store is assumed. This
|
73
|
+
implementation has significant draw-backs so explicit configuration is
|
74
|
+
recommended.
|
75
|
+
|
76
|
+
### `private_headers`
|
77
|
+
|
78
|
+
An array of request header names that cause the response to be treated with
|
79
|
+
private cache control semantics. The default value is `['Authorization', 'Cookie']`.
|
80
|
+
If any of these headers are present in the request, the response is considered
|
81
|
+
private and will not be cached _unless_ the response is explicitly marked public
|
82
|
+
(e.g., `Cache-Control: public`).
|
83
|
+
|
84
|
+
### `allow_reload`
|
85
|
+
|
86
|
+
A boolean specifying whether reload requests sent by the client should be
|
87
|
+
honored by the cache. When this option is enabled (`rack-cache.allow_reload`
|
88
|
+
is `true`), requests that include a `Cache-Control: no-cache` header cause
|
89
|
+
the cache to discard anything it has stored for the request and ask that the
|
90
|
+
response be fully generated.
|
91
|
+
|
92
|
+
Most browsers include a `Cache-Control: no-cache` header when the user performs
|
93
|
+
a "hard refresh" (e.g., holding `Shift` while clicking the "Refresh" button).
|
94
|
+
|
95
|
+
*IMPORTANT: Enabling this option globally allows all clients to break your cache.*
|
96
|
+
|
97
|
+
### `allow_revalidate`
|
98
|
+
|
99
|
+
A boolean specifying whether revalidate requests sent by the client should be
|
100
|
+
honored by the cache. When this option is enabled (`rack-cache.allow_revalidate`
|
101
|
+
is `true`), requests that include a `Cache-Control: max-age=0` header cause the
|
102
|
+
cache to assume its copy of the response is stale, resulting in a conditional
|
103
|
+
GET / validation request to be sent to the server.
|
104
|
+
|
105
|
+
Most browsers include a `Cache-Control: max-age=0` header when the user performs
|
106
|
+
a refresh (e.g., clicking the "Refresh" button).
|
107
|
+
|
108
|
+
*IMPORTANT: Enabling this option globally allows all clients to break your cache.*
|
109
|
+
|
110
|
+
### `cache_key`
|
111
|
+
|
112
|
+
TODO: Document custom cache keys
|
data/doc/faq.markdown
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
Frequently Asked Questions
|
2
|
+
==========================
|
3
|
+
|
4
|
+
<p class='intro'>
|
5
|
+
<strong>NOTE:</strong> This is a work in progress. Please send questions, comments, or
|
6
|
+
suggestions to <a href="mailto:r@tomayko.com">r@tomayko.com</a>.
|
7
|
+
</p>
|
8
|
+
|
9
|
+
General
|
10
|
+
-------
|
11
|
+
|
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
|
+
|
21
|
+
<a class='hash' id='why-not-squid' href='#why-not-squid'>#</a>
|
22
|
+
|
23
|
+
### Q: Why Rack::Cache? Why not Squid, Varnish, Perlbol, etc.?
|
24
|
+
|
25
|
+
__Rack::Cache__ is often easier to setup as part of your existing Ruby
|
26
|
+
application than a separate caching system. __Rack::Cache__ runs entirely inside
|
27
|
+
your backend application processes - no separate / external process is required.
|
28
|
+
This lets __Rack::Cache__ scale down to development environments and simple
|
29
|
+
deployments very easily while not sacrificing the benefits of a standards-based
|
30
|
+
approach to caching.
|
31
|
+
|
32
|
+
|
33
|
+
<a class='hash' id='why-not-rails' href='#why-not-rails'>#</a>
|
34
|
+
|
35
|
+
### Q: Why Rack::Cache? Why not use Rails/Merb/FrameworkX's caching system?
|
36
|
+
|
37
|
+
__Rack::Cache__ takes a standards-based approach to caching that provides some
|
38
|
+
benefits over framework-integrated systems. It uses standard HTTP headers
|
39
|
+
(`Expires`, `Cache-Control`, `Etag`, `Last-Modified`, etc.) to determine
|
40
|
+
what/when to cache. Designing applications to support these standard HTTP
|
41
|
+
mechanisms gives the benefit of being able to switch to a different HTTP
|
42
|
+
cache implementation in the future.
|
43
|
+
|
44
|
+
In addition, using a standards-based approach to caching creates a clear
|
45
|
+
separation between application and caching logic. The application need only
|
46
|
+
specify a basic set of information about the response and all decisions
|
47
|
+
regarding how and when to cache is moved into the caching layer.
|
48
|
+
|
49
|
+
|
50
|
+
<a class='hash' id='scale' href='#scale'>#</a>
|
51
|
+
|
52
|
+
### Q: Will Rack::Cache make my app scale?
|
53
|
+
|
54
|
+
No. Your design is the only thing that can make your app scale.
|
55
|
+
|
56
|
+
Also, __Rack::Cache__ is not overly optimized for performance. The main goal of
|
57
|
+
the project is to provide a portable, easy-to-configure, and standards-based
|
58
|
+
caching solution for small to medium sized deployments. More sophisticated /
|
59
|
+
performant caching systems (e.g., [Varnish][v], [Squid][s],
|
60
|
+
[httpd/mod-cache][h]) may be more appropriate for large deployments with
|
61
|
+
crazy-land throughput requirements.
|
62
|
+
|
63
|
+
[v]: http://varnish.projects.linpro.no/
|
64
|
+
[s]: http://www.squid-cache.org/
|
65
|
+
[h]: http://httpd.apache.org/docs/2.0/mod/mod_cache.html
|
66
|
+
|
67
|
+
|
68
|
+
Features
|
69
|
+
--------
|
70
|
+
|
71
|
+
|
72
|
+
<a class='hash' id='validation' href='#validation'>#</a>
|
73
|
+
|
74
|
+
### Q: Does Rack::Cache support validation?
|
75
|
+
|
76
|
+
Yes. Both freshness and validation-based caching is supported. A response
|
77
|
+
will be cached if it has a freshness lifetime (e.g., `Expires` or
|
78
|
+
`Cache-Control: max-age=N` headers) and/or includes a validator (e.g.,
|
79
|
+
`Last-Modified` or `ETag` headers). When the cache hits and the response is
|
80
|
+
fresh, it's delivered immediately without talking to the backend application;
|
81
|
+
when the cache is stale, the cached response is validated using a conditional
|
82
|
+
GET request.
|
83
|
+
|
84
|
+
|
85
|
+
<a class='hash' id='fragments' href='#fragments'>#</a>
|
86
|
+
|
87
|
+
### Q: Does Rack::Cache support fragment caching?
|
88
|
+
|
89
|
+
Not really. __Rack::Cache__ deals with entire responses and doesn't know
|
90
|
+
anything about how your application constructs them.
|
91
|
+
|
92
|
+
However, something like [ESI](http://www.w3.org/TR/esi-lang) may be implemented
|
93
|
+
in the future (likely as a separate Rack middleware component that could be
|
94
|
+
situated upstream from Rack::Cache), which would allow applications to compose
|
95
|
+
responses based on several "fragment resources". Each fragment would have its
|
96
|
+
own cache policy.
|
97
|
+
|
98
|
+
|
99
|
+
<a class='hash' id='manual-purge' href='#manual-purge'>#</a>
|
100
|
+
|
101
|
+
### Q: How do I manually purge or expire a cached entry?
|
102
|
+
|
103
|
+
Although planned, there is currently no mechanism for manually purging
|
104
|
+
an entry stored in the cache.
|
105
|
+
|
106
|
+
Note that using an `Expires` or `Cache-Control: max-age=N` header and relying on
|
107
|
+
manual purge to invalidate cached entry can often be implemented more simply
|
108
|
+
using efficient validation based caching (`Last-Modified`, `Etag`). Many web
|
109
|
+
frameworks are based entirely on manual purge and do not support validation at
|
110
|
+
the cache level.
|
111
|
+
|
112
|
+
|
113
|
+
<a class='hash' id='efficient-validation' href='#efficient-validation'>#</a>
|
114
|
+
|
115
|
+
### Q: What does "Efficient Validation" mean?
|
116
|
+
|
117
|
+
It means that your application performs only the processing necessary to
|
118
|
+
determine if a response is valid before sending a `304 Not Modified` in response
|
119
|
+
to a conditional GET request. Many applications that perform validation do so
|
120
|
+
only after the entire response has been generated, which provides bandwidth
|
121
|
+
savings but results in no CPU/IO savings. Implementing validation efficiently
|
122
|
+
can increase backend application throughput significantly when fronted by a
|
123
|
+
validating caching system (like __Rack::Cache__).
|
124
|
+
|
125
|
+
[Here's an example Rack application](http://gist.github.com/9395) that performs
|
126
|
+
efficient validation.
|
127
|
+
|
128
|
+
|
129
|
+
<a class='hash' id='orly' href='#orly'>#</a>
|
130
|
+
|
131
|
+
### Q: Did you just make that up?
|
132
|
+
|
133
|
+
Yes.
|
134
|
+
|
135
|
+
|
136
|
+
<a class='hash' id='https' href='#https'>#</a>
|
137
|
+
|
138
|
+
### Q: Can I do HTTPS with Rack::Cache?
|
139
|
+
|
140
|
+
Sure. HTTPS is typically managed by a front-end web server so this isn't really
|
141
|
+
relevant to Rack::Cache.
|
data/doc/index.markdown
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
__Rack::Cache__ is suitable as a quick drop-in component to enable HTTP caching
|
2
|
+
for [Rack][]-based applications that produce freshness (`Expires`,
|
3
|
+
`Cache-Control`) and/or validation (`Last-Modified`, `ETag`) information.
|
4
|
+
|
5
|
+
* Standards-based (see [RFC 2616][rfc] / [Section 13][s13]).
|
6
|
+
* Freshness/expiration based caching
|
7
|
+
* Validation
|
8
|
+
* Vary support
|
9
|
+
* Portable: 100% Ruby / works with any [Rack][]-enabled framework.
|
10
|
+
* Disk, memcached, and heap memory [storage backends][storage].
|
11
|
+
|
12
|
+
News
|
13
|
+
----
|
14
|
+
|
15
|
+
* Rack::Cache 0.5 was released on May 25, 2009. See the
|
16
|
+
[`CHANGES`](http://github.com/rtomayko/rack-cache/blob/0.5.0/CHANGES) file
|
17
|
+
for details.
|
18
|
+
* [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.
|
19
|
+
* [RailsLab's Advanced HTTP Caching Screencast](http://railslab.newrelic.com/2009/02/26/episode-11-advanced-http-caching)
|
20
|
+
is a really great review of HTTP caching concepts and shows how to
|
21
|
+
use Rack::Cache with Rails.
|
22
|
+
|
23
|
+
Installation
|
24
|
+
------------
|
25
|
+
|
26
|
+
$ sudo gem install rack-cache
|
27
|
+
|
28
|
+
Or, from a local working copy:
|
29
|
+
|
30
|
+
$ git clone git://github.com/rtomayko/rack-cache.git
|
31
|
+
$ rake package && sudo rake install
|
32
|
+
|
33
|
+
Basic Usage
|
34
|
+
-----------
|
35
|
+
|
36
|
+
__Rack::Cache__ is implemented as a piece of [Rack][] middleware and can be used
|
37
|
+
with any __Rack__-based application. If your application includes a rackup
|
38
|
+
(`.ru`) file or uses __Rack::Builder__ to construct the application pipeline,
|
39
|
+
simply `require` and `use` as follows:
|
40
|
+
|
41
|
+
require 'rack/cache'
|
42
|
+
|
43
|
+
use Rack::Cache,
|
44
|
+
:verbose => true,
|
45
|
+
:metastore => 'file:/var/cache/rack/meta'
|
46
|
+
:entitystore => 'file:/var/cache/rack/body'
|
47
|
+
|
48
|
+
run app
|
49
|
+
|
50
|
+
Assuming you've designed your backend application to take advantage of HTTP's
|
51
|
+
caching features, no further code or configuration is required for basic
|
52
|
+
caching.
|
53
|
+
|
54
|
+
More
|
55
|
+
----
|
56
|
+
|
57
|
+
* [Configuration Options][config] - how to set cache options.
|
58
|
+
|
59
|
+
* [Cache Storage Documentation][storage] - detailed information on the various
|
60
|
+
storage implementations available in __Rack::Cache__ and how to choose the one
|
61
|
+
that's best for your application.
|
62
|
+
|
63
|
+
* [Things Caches Do][things] - an illustrated guide to how HTTP gateway
|
64
|
+
caches work with pointers to other useful resources on HTTP caching.
|
65
|
+
|
66
|
+
* [GitHub Repository](http://github.com/rtomayko/rack-cache/) - get your
|
67
|
+
fork on.
|
68
|
+
|
69
|
+
* [Mailing List](http://groups.google.com/group/rack-cache) - for hackers
|
70
|
+
and users (`rack-cache@groups.google.com`).
|
71
|
+
|
72
|
+
* [FAQ](./faq) - Frequently Asked Questions about __Rack::Cache__.
|
73
|
+
|
74
|
+
* [RDoc API Documentation](./api/) - Mostly worthless if you just want to use
|
75
|
+
__Rack::Cache__ in your application but mildly insightful if you'd like to
|
76
|
+
get a feel for how the system has been put together; I recommend
|
77
|
+
[reading the source](http://github.com/rtomayko/rack-cache/master/lib/rack/cache).
|
78
|
+
|
79
|
+
|
80
|
+
See Also
|
81
|
+
--------
|
82
|
+
|
83
|
+
The overall design of __Rack::Cache__ is based largely on the work of the
|
84
|
+
internet standards community. The following resources provide a good starting
|
85
|
+
point for exploring the basic concepts of HTTP caching:
|
86
|
+
|
87
|
+
* Mark Nottingham's [Caching Tutorial](http://www.mnot.net/cache_docs/),
|
88
|
+
especially the short section on
|
89
|
+
[How Web Caches Work](http://www.mnot.net/cache_docs/#WORK)
|
90
|
+
|
91
|
+
* Joe Gregorio's [Doing HTTP Caching Right](http://www.xml.com/lpt/a/1642)
|
92
|
+
|
93
|
+
* [RFC 2616](http://www.ietf.org/rfc/rfc2616.txt), especially
|
94
|
+
[Section 13, "Caching in HTTP"](http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html)
|
95
|
+
|
96
|
+
__Rack::Cache__ takes (_liberally_) various concepts from
|
97
|
+
[Varnish](http://varnish.projects.linpro.no/) and
|
98
|
+
[Django's cache framework](http://docs.djangoproject.com/en/dev/topics/cache/).
|
99
|
+
|
100
|
+
License
|
101
|
+
-------
|
102
|
+
|
103
|
+
__Rack::Cache__ is Copyright © 2008
|
104
|
+
by [Ryan Tomayko](http://tomayko.com/about)
|
105
|
+
and is provided under [the MIT license](./license)
|
106
|
+
|
107
|
+
[config]: ./configuration "Rack::Cache Configuration Language Documentation"
|
108
|
+
[storage]: ./storage "Rack::Cache Storage Documentation"
|
109
|
+
[things]: http://tomayko.com/writings/things-caches-do
|
110
|
+
|
111
|
+
[rfc]: http://tools.ietf.org/html/rfc2616
|
112
|
+
"RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1 [ietf.org]"
|
113
|
+
|
114
|
+
[s13]: http://tools.ietf.org/html/rfc2616#section-13
|
115
|
+
"RFC 2616 / Section 13 Caching in HTTP"
|
116
|
+
|
117
|
+
[rack]: http://rack.rubyforge.org/
|
118
|
+
"Rack: a Ruby Webserver Interface"
|
119
|
+
|
120
|
+
[vcl]: http://tomayko.com/man/vcl
|
121
|
+
"VCL(7) -- Varnish Configuration Language Manual Page"
|
data/doc/layout.html.erb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang='en'>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>
|
5
|
+
<title>Rack::Cache <%= title %></title>
|
6
|
+
<link rel='stylesheet' href='rack-cache.css' type='text/css' media='all'>
|
7
|
+
<script type='text/javascript' src='http://code.jquery.com/jquery-1.2.3.js'></script>
|
8
|
+
<script type='text/javascript' src='http://tomayko.com/js/tomayko.js'></script>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<div id='container'>
|
12
|
+
<div id='header'>
|
13
|
+
<h1><a href="./">rack-cache</a></h1>
|
14
|
+
<p>
|
15
|
+
<a href="./configuration" title='Configuration Language Documentation'>Config</a> |
|
16
|
+
<a href="./storage" title='Cache Storage Documentation'>Storage</a> |
|
17
|
+
<a href="http://tomayko.com/writings/things-caches-do" title="Things Caches Do">Things</a> |
|
18
|
+
<a href="./faq" title='Frequently Asked Questions'>FAQ</a> |
|
19
|
+
<a href="./api/" title='Fucking Sucks.'>RDoc</a>
|
20
|
+
</p>
|
21
|
+
</div>
|
22
|
+
<div id='content'><%= content %></div>
|
23
|
+
<div id='footer'>
|
24
|
+
<p class='rights'>
|
25
|
+
Copyright
|
26
|
+
<a href="./license" rel="license">©</a>
|
27
|
+
2003-2008
|
28
|
+
by
|
29
|
+
<a href='http://tomayko.com/about' rel='me author'>Ryan Tomayko</a>
|
30
|
+
</p>
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
</body>
|
34
|
+
</html>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
License (MIT)
|
2
|
+
=============
|
3
|
+
|
4
|
+
__Rack::Cache__ is Copyright © 2008
|
5
|
+
by [Ryan Tomayko](http://tomayko.com/about)
|
6
|
+
|
7
|
+
<pre class='license'>
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
of this software and associated documentation files (the "Software"), to
|
10
|
+
deal in the Software without restriction, including without limitation the
|
11
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
12
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
13
|
+
furnished to do so, subject to the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be included in
|
16
|
+
all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
21
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
22
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
23
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
</pre>
|
data/doc/rack-cache.css
ADDED
@@ -0,0 +1,362 @@
|
|
1
|
+
/* rack-cache.css
|
2
|
+
*---------------------------------------------------------------------------
|
3
|
+
* Copyright (C) 2005-08 Ryan Tomayko <r@tomayko.com>
|
4
|
+
*/
|
5
|
+
|
6
|
+
|
7
|
+
/* 18px base font size / 25px baseline */
|
8
|
+
body {
|
9
|
+
font-size:112.5%; /* 18px (probably) */
|
10
|
+
line-height:1.3888; /* 25px */
|
11
|
+
letter-spacing:-0.02em;
|
12
|
+
margin:0 10px;
|
13
|
+
font-family: 'lucida sans unicode', 'lucida grande',
|
14
|
+
helvetica, 'bitstream vera sans', sans-serif;
|
15
|
+
color:#556;
|
16
|
+
background-color:#fff;
|
17
|
+
}
|
18
|
+
|
19
|
+
#container {
|
20
|
+
max-width:45em;
|
21
|
+
margin:0 auto;
|
22
|
+
}
|
23
|
+
|
24
|
+
h1, h2, h3 {
|
25
|
+
font-family:georgia, 'bitstream vera sans serif', 'lucida grande',
|
26
|
+
helvetica, verdana, sans-serif;
|
27
|
+
font-weight:normal;
|
28
|
+
letter-spacing:-0.05em;
|
29
|
+
color:#000;
|
30
|
+
}
|
31
|
+
i, em {
|
32
|
+
font-style:italic;
|
33
|
+
}
|
34
|
+
b, strong {
|
35
|
+
font-weight:normal;
|
36
|
+
color:#000;
|
37
|
+
}
|
38
|
+
blockquote {
|
39
|
+
color:#555;
|
40
|
+
}
|
41
|
+
blockquote em {
|
42
|
+
color:#333;
|
43
|
+
font-style:italic;
|
44
|
+
}
|
45
|
+
blockquote strong {
|
46
|
+
color:#333;
|
47
|
+
font-weight: normal;
|
48
|
+
}
|
49
|
+
dt {
|
50
|
+
font-weight:bold;
|
51
|
+
color:#000;
|
52
|
+
}
|
53
|
+
tt, pre, code, samp, kbd {
|
54
|
+
font-family: consolas, 'lucida console', 'bitstream vera sans mono',
|
55
|
+
'courier new', monospace;
|
56
|
+
color: #000;
|
57
|
+
}
|
58
|
+
pre {
|
59
|
+
color:#333;
|
60
|
+
background-color:#f9f9f9;
|
61
|
+
}
|
62
|
+
code {
|
63
|
+
color:#007A00;
|
64
|
+
}
|
65
|
+
pre code {
|
66
|
+
color:#333;
|
67
|
+
}
|
68
|
+
pre.license {
|
69
|
+
border:0;
|
70
|
+
background:#fff;
|
71
|
+
padding:0;
|
72
|
+
font-size:1.1em;
|
73
|
+
}
|
74
|
+
a, a:link {
|
75
|
+
color:#023;
|
76
|
+
background:#eef;
|
77
|
+
}
|
78
|
+
a:visited {
|
79
|
+
color:#345;
|
80
|
+
background:#fff;
|
81
|
+
}
|
82
|
+
a:hover {
|
83
|
+
background:#ccf;
|
84
|
+
color:#000;
|
85
|
+
text-decoration:none;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
/* TYPOGRAPHY */
|
90
|
+
|
91
|
+
p, ul, ol, dl, pre, blockquote, table, form {
|
92
|
+
margin:1em 0;
|
93
|
+
}
|
94
|
+
dl {
|
95
|
+
margin-left:2em;
|
96
|
+
}
|
97
|
+
hr {
|
98
|
+
color:#eee;
|
99
|
+
background-color:#ccc;
|
100
|
+
border:0;
|
101
|
+
height:1px;
|
102
|
+
margin:1.5em 0;
|
103
|
+
}
|
104
|
+
blockquote {
|
105
|
+
font-size:0.83333em; /* 15px */
|
106
|
+
line-height:1.66666; /* 25px */
|
107
|
+
margin:1.2em 3em;
|
108
|
+
padding:0;
|
109
|
+
}
|
110
|
+
tt, pre, code, samp, kbd {
|
111
|
+
font-size: 16px;
|
112
|
+
line-height:1.1;
|
113
|
+
}
|
114
|
+
pre {
|
115
|
+
margin:1.5em 0;
|
116
|
+
padding:6px 4px 4px 6px;
|
117
|
+
border:1px solid #eee;
|
118
|
+
border-left-width:20px;
|
119
|
+
overflow:auto;
|
120
|
+
}
|
121
|
+
h1 {
|
122
|
+
font-size:2.3333em; /* 42px */
|
123
|
+
line-height:1.1904; /* 50px */
|
124
|
+
margin:0.5952em 0; /* 25px */
|
125
|
+
}
|
126
|
+
h2 {
|
127
|
+
font-size:1.66666667em; /* 30px */
|
128
|
+
line-height:1.2; /* 36px */
|
129
|
+
margin:1em 0;
|
130
|
+
}
|
131
|
+
h3 {
|
132
|
+
font-size:1.33333333em; /* 22px */
|
133
|
+
line-height:1.13636363; /* 25px */
|
134
|
+
margin:1em 0;
|
135
|
+
}
|
136
|
+
h3 code{
|
137
|
+
font-size:0.95em;
|
138
|
+
color:#000;
|
139
|
+
}
|
140
|
+
h4 {
|
141
|
+
font-size:1em;
|
142
|
+
font-weight:bold;
|
143
|
+
line-height:1.5;
|
144
|
+
margin:1em 0;
|
145
|
+
}
|
146
|
+
p small {
|
147
|
+
font-size:0.8333; /* 15px */
|
148
|
+
line-height:1.2;
|
149
|
+
}
|
150
|
+
|
151
|
+
/* Tables
|
152
|
+
--------------------------------------------------------------------------- */
|
153
|
+
|
154
|
+
table {
|
155
|
+
width:100%;
|
156
|
+
border-style:none;
|
157
|
+
border-color:#ddd;
|
158
|
+
padding:0;
|
159
|
+
}
|
160
|
+
|
161
|
+
th, td {
|
162
|
+
padding: 4px 10px 4px 5px;
|
163
|
+
border-style:solid;
|
164
|
+
border-color:#fff;
|
165
|
+
}
|
166
|
+
|
167
|
+
th {
|
168
|
+
font-weight: bold;
|
169
|
+
background: #eef;
|
170
|
+
}
|
171
|
+
|
172
|
+
td {
|
173
|
+
background: #f9f9f9;
|
174
|
+
}
|
175
|
+
|
176
|
+
tfoot {
|
177
|
+
font-style: italic;
|
178
|
+
}
|
179
|
+
|
180
|
+
caption {
|
181
|
+
background: #eee;
|
182
|
+
}
|
183
|
+
|
184
|
+
/* Header / Titling
|
185
|
+
--------------------------------------------------------------------------- */
|
186
|
+
|
187
|
+
#header {
|
188
|
+
text-align:left;
|
189
|
+
margin:1.5em auto 2em;
|
190
|
+
float:left;
|
191
|
+
width:100%;
|
192
|
+
padding-bottom:1.5em;
|
193
|
+
border-bottom:1px solid #777;
|
194
|
+
}
|
195
|
+
#header h1 {
|
196
|
+
font-family: 'lucida sans unicode', 'lucida grande',
|
197
|
+
helvetica, 'bitstream vera sans', sans-serif;
|
198
|
+
font-size:5em;
|
199
|
+
font-weight:bold;
|
200
|
+
line-height:1;
|
201
|
+
margin:0;
|
202
|
+
float:left;
|
203
|
+
color:#000;
|
204
|
+
letter-spacing:-0.08em;
|
205
|
+
}
|
206
|
+
#header h1 a, #header h1 a:link, #header h1 a:visited, #header h1 a:hover {
|
207
|
+
color:#000;
|
208
|
+
text-decoration:none;
|
209
|
+
background:transparent;
|
210
|
+
}
|
211
|
+
#header p {
|
212
|
+
margin: 0;
|
213
|
+
line-height:1.8;
|
214
|
+
color: #777;
|
215
|
+
text-transform:capitalize;
|
216
|
+
font-variant:small-caps;
|
217
|
+
float:right;
|
218
|
+
}
|
219
|
+
#header a, #header a:link, #header a:visited {
|
220
|
+
color:#445;
|
221
|
+
background:#fff;
|
222
|
+
}
|
223
|
+
#header a:hover {
|
224
|
+
background:#ccf;
|
225
|
+
color:#000;
|
226
|
+
text-decoration:none;
|
227
|
+
}
|
228
|
+
#content {
|
229
|
+
clear:both;
|
230
|
+
}
|
231
|
+
|
232
|
+
/* FOOTER */
|
233
|
+
|
234
|
+
#footer {
|
235
|
+
clear:both;
|
236
|
+
color:#555;
|
237
|
+
font-size:0.88888888em;
|
238
|
+
line-height:1.5625;
|
239
|
+
border-top:1px solid #ddd;
|
240
|
+
padding:19px 0 0 0;
|
241
|
+
margin:40px 0 20px 0;
|
242
|
+
text-align:center;
|
243
|
+
}
|
244
|
+
#footer p {
|
245
|
+
margin:0;
|
246
|
+
}
|
247
|
+
#footer form {
|
248
|
+
float:right;
|
249
|
+
}
|
250
|
+
#footer input{
|
251
|
+
font-size:10px;
|
252
|
+
}
|
253
|
+
|
254
|
+
/* MISC HELPER STYLES */
|
255
|
+
|
256
|
+
ul.clean, ol.clean {
|
257
|
+
list-style-type: none;
|
258
|
+
padding-left: 0;
|
259
|
+
}
|
260
|
+
.caps {
|
261
|
+
font-variant:small-caps;
|
262
|
+
}
|
263
|
+
.clear {
|
264
|
+
clear:both;
|
265
|
+
}
|
266
|
+
.left{
|
267
|
+
float:left;
|
268
|
+
}
|
269
|
+
.right{
|
270
|
+
float:right;
|
271
|
+
}
|
272
|
+
.center{
|
273
|
+
text-align:center;
|
274
|
+
}
|
275
|
+
.intro {
|
276
|
+
font-size:0.833333em; /* 15px */
|
277
|
+
line-height:1.666667; /* 25px */
|
278
|
+
border:1px solid #ccc;
|
279
|
+
padding:0.5em;
|
280
|
+
font-style:italic;
|
281
|
+
color:#555;
|
282
|
+
}
|
283
|
+
a.hash,
|
284
|
+
a.hash:link,
|
285
|
+
a.hash:visited {
|
286
|
+
display:block;
|
287
|
+
float:right;
|
288
|
+
background:#fff;
|
289
|
+
font-size:0.8em;
|
290
|
+
text-decoration:none;
|
291
|
+
line-height:2;
|
292
|
+
color:#999;
|
293
|
+
}
|
294
|
+
a.hash:hover {
|
295
|
+
color:MediumOrchid;
|
296
|
+
}
|
297
|
+
|
298
|
+
/* PRINT */
|
299
|
+
|
300
|
+
@media print {
|
301
|
+
html, body, #container {
|
302
|
+
margin:0;
|
303
|
+
}
|
304
|
+
#container {
|
305
|
+
width:100%;
|
306
|
+
max-width:100%;
|
307
|
+
}
|
308
|
+
#header {
|
309
|
+
margin-top:0;
|
310
|
+
}
|
311
|
+
#header p {
|
312
|
+
display:none;
|
313
|
+
}
|
314
|
+
#footer {
|
315
|
+
display:none;
|
316
|
+
}
|
317
|
+
a, a:link, a:visited {
|
318
|
+
color:#000;
|
319
|
+
background:#fff;
|
320
|
+
text-decoration:none;
|
321
|
+
}
|
322
|
+
pre.license {
|
323
|
+
font-size:0.95em;
|
324
|
+
}
|
325
|
+
@page {
|
326
|
+
size:8.5in 11in;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
|
330
|
+
/* PRETTIFICATION OF SOURCE CODE */
|
331
|
+
|
332
|
+
.str { color: #181; font-style:italic; }
|
333
|
+
.kwd { color: #369; }
|
334
|
+
.com { color: #666; }
|
335
|
+
.typ { color: #c40; }
|
336
|
+
.lit { color: #900; }
|
337
|
+
.pun { color: #000; font-weight: bold; }
|
338
|
+
.pln { color: #333; }
|
339
|
+
.tag { color: #369; font-weight: bold; }
|
340
|
+
.atn { color: #939; font-weight: bold }
|
341
|
+
.atv { color: #181; }
|
342
|
+
.dec { color: #606; }
|
343
|
+
|
344
|
+
@media print {
|
345
|
+
.str { color: #060; }
|
346
|
+
.kwd { color: #006; font-weight: bold; }
|
347
|
+
.com { color: #600; font-style: italic; }
|
348
|
+
.typ { color: #404; font-weight: bold; }
|
349
|
+
.lit { color: #044; }
|
350
|
+
.pun { color: #440; }
|
351
|
+
.pln { color: #000; }
|
352
|
+
.tag { color: #006; font-weight: bold; }
|
353
|
+
.atn { color: #404; }
|
354
|
+
.atv { color: #060; }
|
355
|
+
}
|
356
|
+
|
357
|
+
/* FUCKING IE */
|
358
|
+
|
359
|
+
* html body{width:40em}
|
360
|
+
* html div.index{width:34.5em}
|
361
|
+
|
362
|
+
/* vim: set ft=css ts=4 sw=4 noexpandtab: */
|