josevalim-easy_http_cache 2.0 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1,21 +1,11 @@
1
- Copyright (c) 2008 José Valim (jose.valim at gmail dot com)
2
- Site: http://www.pagestacker.com/
3
- Blog: http://josevalim.blogspot.com/
1
+ Easy HTTP Cache
4
2
  License: MIT
5
- Version: 2.0
3
+ Version: 2.1
6
4
 
7
5
  You can also read this README in pretty html at the GitHub project Wiki page
8
6
 
9
7
  http://github.com/josevalim/easy_http_cache/wikis/home
10
8
 
11
- Warning
12
- -------
13
-
14
- Since version 2.0, this plugin/gem has drastically changed to fit Rails 2.2
15
- http cache goodness. :expires_in, :expires_at and :control options were
16
- removed, so if you want to use previous versions, see "Previous versions"
17
- below.
18
-
19
9
  Description
20
10
  -----------
21
11
 
@@ -23,36 +13,42 @@ Allows Rails applications to do conditional cache easily and in a DRY way
23
13
  (without messing up your actions):
24
14
 
25
15
  class ListsController < ApplicationController
26
- http_cache :index, :show
16
+ http_cache :index, :show, :last_modified => :list
17
+
18
+ protected
19
+ def list
20
+ @list ||= List.find(params[:id])
21
+ end
27
22
  end
28
23
 
29
24
  It uses :last_modified and :etag keys, that besides Time, String or resources
30
- accepts Proc, Method and Symbols that are evaluated within the current controller.
31
- Read more about each option below:
25
+ accepts Proc, Method and Symbol that are evaluated within the current controller.
26
+
27
+ Read more about each option (more examples at the end of this page):
32
28
 
33
29
  :last_modified
34
30
  Used to manipulate Last-Modified header. You can pass any object that responds
35
- to :to_time. If you pass a Proc or Method or Symbols, they will be evaluated
36
- within the current controller and :to_time will be called.
31
+ to :updated_at, :updated_on or :to_time. If you pass a Proc or Method or Symbol,
32
+ they will be evaluated within the current controller first.
37
33
 
38
- You can also pass resources and :updated_at or :updated_on will be called on
39
- it. If you want to call a different method on your resource, you can pass it as
40
- a symbol using the :method option.
41
-
42
- All times will be converted to UTC. Finally, if you pass an array, it will get
43
- the most recent time to be used.
34
+ Finally, if you pass an array, it will get the most recent time to be used.
44
35
 
45
36
  :etag
46
- Used to manipulate Etag header. If you pass a Proc or Method or Symbols, they
47
- will be evaluated within the current controller.
48
-
49
- You can also pass an array and each element will be also evaluated with needed.
37
+ Used to manipulate Etag header. The Etag is generated as memcached keys are
38
+ generated, i.e. calling to_param in the object and then MD5 is applied.
39
+
40
+ If you pass a Proc or Method or Symbols, they will be also evaluated within the
41
+ current controller first.
50
42
 
51
43
  :if
52
44
  Only perform http cache if it returns true.
53
45
 
54
46
  :unless
55
47
  Only perform http cache if it returns false.
48
+
49
+ :method
50
+ If in :last_modified you want to pass a object that doesn't respond to updated_at,
51
+ updated_on or to_time, you can specify the method that will be called in this object.
56
52
 
57
53
 
58
54
  Install
@@ -62,9 +58,6 @@ Install Easy HTTP Cache is very easy. It is stored in GitHub, so if you
62
58
  have never installed a gem via GitHub run the following:
63
59
 
64
60
  gem sources -a http://gems.github.com
65
-
66
- Then install the gem:
67
-
68
61
  sudo gem install josevalim-easy_http_cache
69
62
 
70
63
  In RAILS_ROOT/config/environment.rb:
@@ -77,6 +70,7 @@ If you want it as plugin, just do:
77
70
  git clone git://github.com/josevalim/easy_http_cache.git
78
71
  rm -rf vendor/plugins/easy_http_cache/.git
79
72
 
73
+ Current version supports Rails 2.2.x and Rails 2.3.x.
80
74
 
81
75
  Previous versions
82
76
  -----------------
@@ -89,21 +83,21 @@ If you are running on Rails 2.1.x, you should use v1.2.3:
89
83
  git checkout v1.2.3
90
84
  rm -rf ./.git
91
85
 
92
- If you are using a previous version, please updagrade your app. =)
86
+ If you are using earlier than 2.1, please upgrade your app. =)
93
87
 
94
88
 
95
89
  Variables
96
90
  ---------
97
91
 
98
- You can set ENV['RAILS_CACHE_ID'] or ENV['RAILS_APP_VERSION'] to change
99
- the ETag that will be generated, expiring all previous caches. Those variables
100
- are also used by other cache stores (memcached, file, ...).
92
+ As in memcached, you can set ENV['RAILS_CACHE_ID'] or ENV['RAILS_APP_VERSION'] variables
93
+ to change the Etag that will be generated. This means you can control the cache by setting
94
+ a timestamp or a version number in ENV['RAILS_APP_VERSION'] everytime you deploy.
101
95
 
102
96
 
103
97
  Examples
104
98
  --------
105
99
 
106
- Just as above:
100
+ The example below will cache your actions and it will never expire:
107
101
 
108
102
  class ListsController < ApplicationController
109
103
  http_cache :index, :show
@@ -113,10 +107,10 @@ If you do not want to cache when you are showing a flash message (and you
113
107
  usually want that), you can simply do:
114
108
 
115
109
  class ListsController < ApplicationController
116
- http_cache :index, :show, :if => Proc.new { |c| c.__send__(:flash).empty? }
110
+ http_cache :index, :show, :if => Proc.new { |c| c.send(:flash).empty? }
117
111
  end
118
112
 
119
- And if you do not want JSON requests:
113
+ And if you do not want to cache JSON requests:
120
114
 
121
115
  class ListsController < ApplicationController
122
116
  http_cache :index, :show, :unless => Proc.new { |c| c.request.format.json? }
@@ -128,8 +122,8 @@ Or if you want to expire all http cache before 2008, just do:
128
122
  http_cache :index, :show, :last_modified => Time.utc(2008)
129
123
  end
130
124
 
131
- If You want to cache a list and automatically expire the cache when
132
- it changes, just do:
125
+ If you want to cache a list and automatically expire the cache when it changes,
126
+ just do (it will check updated_at and updated_on on the @list object):
133
127
 
134
128
  class ListsController < ApplicationController
135
129
  http_cache :index, :show, :last_modified => :list
@@ -140,7 +134,8 @@ it changes, just do:
140
134
  end
141
135
  end
142
136
 
143
- You can also set :etag header:
137
+ You can also set :etag header (it will generate an etag calling to_param
138
+ in the object and applying MD5):
144
139
 
145
140
  class ListsController < ApplicationController
146
141
  http_cache :index, :show, :etag => :list
@@ -152,23 +147,54 @@ You can also set :etag header:
152
147
  end
153
148
 
154
149
  If you are using a resource that doesn't respond to updated_at or updated_on,
155
- you can pass a method as parameter and it will be called in your resources:
150
+ you can pass a method as parameter that will be called in your resources:
156
151
 
157
152
  class ListsController < ApplicationController
158
153
  http_cache :index, :show, :last_modified => :list, :method => :cached_at
159
154
 
160
155
  protected
161
- def list
162
- @list ||= List.find(params[:id])
163
- end
156
+ def list
157
+ @list ||= List.find(params[:id])
158
+ end
164
159
  end
165
160
 
161
+ The sample below will call @list.cached_at to generate Last-Modified header.
166
162
  Finally, you can also pass an array at :last_modified as below:
167
163
 
168
- class ListsController < ApplicationController
164
+ class ItemsController < ApplicationController
169
165
  http_cache :index, :show,
170
- :last_modified => [ :list, Time.utc(2007,12,27) ]
166
+ :last_modified => [ :list, :item ]
167
+
168
+ protected
169
+ def list
170
+ @list ||= List.find(params[:list_id])
171
+ end
172
+
173
+ def item
174
+ @item ||= list.items.find(params[:id])
175
+ end
171
176
  end
172
177
 
173
178
  This will check which one is the most recent to compare with the
174
- "Last-Modified" field sent by the client.
179
+ "Last-Modified" field sent by the client.
180
+
181
+
182
+ What if?
183
+ --------
184
+
185
+ At this point (or at some point), you will ask what happens if you use :etag
186
+ and :last_modified at the same time.
187
+
188
+ Well, Padawan, the specification says that if both are sent by the client, both have
189
+ to be valid for the cache not be considered stale. This subject was already brought
190
+ to Rails Core group and this is also how Rails' current implementation behaves.
191
+
192
+ Bugs and Feedback
193
+ -----------------
194
+
195
+ If you discover any bugs, please send an e-mail to jose.valim@gmail.com
196
+ If you just want to give some positive feedback or drop a line, that's fine too! =)
197
+
198
+ Copyright (c) 2009 José Valim
199
+ http://www.pagestacker.com/
200
+ http://josevalim.blogspot.com/
data/Rakefile CHANGED
@@ -2,11 +2,18 @@ require 'rake'
2
2
  require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
4
 
5
- desc 'Generate documentation for Footnotes plugin.'
5
+ desc 'Run tests for Easy HTTP Cache.'
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.pattern = 'test/**/*_test.rb'
8
+ t.verbose = true
9
+ end
10
+
11
+ desc 'Generate documentation for Easy HTTP Cache.'
6
12
  Rake::RDocTask.new(:rdoc) do |rdoc|
7
13
  rdoc.rdoc_dir = 'rdoc'
8
14
  rdoc.title = 'Easy HTTP Cache'
9
15
  rdoc.options << '--line-numbers' << '--inline-source'
10
16
  rdoc.rdoc_files.include('README')
17
+ rdoc.rdoc_files.include('MIT-LICENSE')
11
18
  rdoc.rdoc_files.include('lib/**/*.rb')
12
- end
19
+ end
@@ -33,10 +33,6 @@ module ActionController #:nodoc:
33
33
  end
34
34
 
35
35
  def filter(controller)
36
- # We don't go ahead if we are rendering a component
37
- #
38
- return if component_request?(controller)
39
-
40
36
  last_modified = get_last_modified(controller)
41
37
  controller.response.last_modified = last_modified if last_modified
42
38
 
@@ -44,7 +40,7 @@ module ActionController #:nodoc:
44
40
  controller.response.etag = processed_etags if processed_etags
45
41
 
46
42
  if controller.request.fresh?(controller.response)
47
- controller.__send__(:head, :not_modified)
43
+ controller.send(:head, :not_modified)
48
44
  return false
49
45
  end
50
46
  end
@@ -53,11 +49,6 @@ module ActionController #:nodoc:
53
49
  # If :etag is an array, it processes all Methods, Procs and Symbols
54
50
  # and return them as array. If it's an object, we only evaluate it.
55
51
  #
56
- # Finally, if :etag is not sent but RAILS_CACHE_ID or RAILS_APP_VERSION
57
- # are set, we return an empty string allowing etag to be performed
58
- # because those variables, when modified, are a valid way to expire
59
- # all previous caches.
60
- #
61
52
  def get_processed_etags(controller)
62
53
  if @options[:etag].is_a?(Array)
63
54
  @options[:etag].collect do |item|
@@ -65,8 +56,6 @@ module ActionController #:nodoc:
65
56
  end
66
57
  elsif @options[:etag]
67
58
  evaluate_method(@options[:etag], controller)
68
- elsif ENV['RAILS_CACHE_ID'] || ENV['RAILS_APP_VERSION']
69
- ''
70
59
  else
71
60
  nil
72
61
  end
@@ -126,15 +115,10 @@ module ActionController #:nodoc:
126
115
  end
127
116
  end
128
117
 
129
- # We should not do http cache when we are using components
130
- #
131
- def component_request?(controller)
132
- controller.instance_variable_get('@parent_controller')
133
- end
134
118
  end
135
119
 
136
120
  end
137
121
  end
138
122
  end
139
123
 
140
- ActionController::Base.__send__ :include, ActionController::Caching::HttpCache
124
+ ActionController::Base.send :include, ActionController::Caching::HttpCache
@@ -1,9 +1,16 @@
1
1
  # Those lines are plugin test settings
2
- ENV["RAILS_ENV"] = "test"
2
+ require 'test/unit'
3
+ require 'rubygems'
3
4
  require 'ostruct'
4
- require File.dirname(__FILE__) + '/../../../../config/environment'
5
+
6
+ ENV["RAILS_ENV"] = "test"
7
+
8
+ require 'active_support'
9
+ require 'action_controller'
10
+ require 'action_controller/test_case'
11
+ require 'action_controller/test_process'
12
+
5
13
  require File.dirname(__FILE__) + '/../lib/easy_http_cache.rb'
6
- require 'test_help'
7
14
 
8
15
  ActionController::Base.perform_caching = true
9
16
  ActionController::Routing::Routes.draw do |map|
@@ -62,7 +69,7 @@ class HttpCacheTestController < ActionController::Base
62
69
  end
63
70
  end
64
71
 
65
- class HttpCacheTest < Test::Unit::TestCase
72
+ class HttpCacheTest < ActionController::TestCase
66
73
  def setup
67
74
  reset!
68
75
  end
@@ -115,17 +122,7 @@ class HttpCacheTest < Test::Unit::TestCase
115
122
  @request.env['HTTP_ACCEPT'] = 'application/json'
116
123
  @request.env['HTTP_IF_MODIFIED_SINCE'] = 1.hour.ago.httpdate
117
124
  get :show
118
- assert_equal '200 OK', @response.headers['Status']
119
- end
120
-
121
- def test_http_cache_without_input_with_env_variable
122
- ENV['RAILS_APP_VERSION'] = '1.2.3'
123
-
124
- get :index
125
- assert_headers('200 OK', 'private, max-age=0, must-revalidate', 'Last-Modified', Time.utc(0).httpdate)
126
- reset!
127
-
128
- etag_http_cache(:index, '')
125
+ assert_equal '200 OK', @response.status
129
126
  end
130
127
 
131
128
  def test_etag_http_cache
@@ -141,22 +138,6 @@ class HttpCacheTest < Test::Unit::TestCase
141
138
  etag_http_cache(:etag, 'ETAG_CACHE')
142
139
  end
143
140
 
144
- def test_should_not_cache_when_rendering_components
145
- set_parent_controller!
146
- get :show
147
- assert_headers('200 OK', 'no-cache')
148
-
149
- set_parent_controller!
150
- @request.env['HTTP_IF_MODIFIED_SINCE'] = 1.hour.ago.httpdate
151
- get :show
152
- assert_headers('200 OK', 'no-cache')
153
-
154
- set_parent_controller!
155
- @request.env['HTTP_IF_MODIFIED_SINCE'] = 3.hours.ago.httpdate
156
- get :show
157
- assert_headers('200 OK', 'no-cache')
158
- end
159
-
160
141
  private
161
142
  def reset!
162
143
  @request = ActionController::TestRequest.new
@@ -164,20 +145,12 @@ class HttpCacheTest < Test::Unit::TestCase
164
145
  @controller = HttpCacheTestController.new
165
146
  end
166
147
 
167
- def set_parent_controller!
168
- get :index
169
- old_controller = @controller.dup
170
- reset!
171
-
172
- @controller.instance_variable_set('@parent_controller', old_controller)
173
- end
174
-
175
148
  def etag_for(etag)
176
149
  %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
177
150
  end
178
151
 
179
152
  def assert_headers(status, control, cache_header=nil, value=nil)
180
- assert_equal status, @response.headers['Status']
153
+ assert_equal status, @response.status
181
154
  assert_equal control, @response.headers['Cache-Control']
182
155
 
183
156
  if cache_header
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: josevalim-easy_http_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: "2.0"
4
+ version: "2.1"
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Jos\xC3\xA9 Valim"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-29 00:00:00 -08:00
12
+ date: 2009-02-04 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,7 +25,6 @@ files:
25
25
  - MIT-LICENSE
26
26
  - README
27
27
  - Rakefile
28
- - init.rb
29
28
  - lib/easy_http_cache.rb
30
29
  - test/easy_http_cache_test.rb
31
30
  has_rdoc: true
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require 'easy_http_cache'