merb-cache 0.9.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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Alex Boussinet
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,160 @@
1
+ = merb-cache
2
+
3
+ A plugin for the Merb framework that provides caching
4
+
5
+ Currently supported methods:
6
+
7
+ - page caching:
8
+ - action caching
9
+ - fragment caching
10
+ - object caching
11
+
12
+ Implemented cache stores:
13
+
14
+ - memory
15
+ - memcache
16
+ - file
17
+ - database (sequel, datamapper, activerecord)
18
+
19
+ == Quick intro
20
+ With fragment caching, you can mix dynamic and static content.
21
+
22
+ With action caching, the whole template is cached
23
+ but the before filters are still processed.
24
+
25
+ With page caching, the whole template is put in html files in a special
26
+ directory in order to be handled directly without triggering Merb.
27
+
28
+ == Quick API
29
+
30
+ === Merb::Controller class methods
31
+ cache_action(action, expiration)
32
+ cache_actions(action, [action, expiration], ...)
33
+ cache_page(action, expiration)
34
+ cache_pages(action, [action, expiration], ...)
35
+
36
+ === Merb::Controller instance methods
37
+ expire_page(key)
38
+ cached_page?(key)
39
+ expire_all_pages()
40
+
41
+ expire_action(key)
42
+ cached_action?(key)
43
+
44
+ cached?(key)
45
+ cache_get(key)
46
+ cache_set(key, data, expiration)
47
+ expire(key)
48
+ expire_all()
49
+
50
+ === Inside your template
51
+ cache(key, expiration) do ... end
52
+
53
+ # expiration is given in minutes
54
+
55
+ # key can be a string or a hash
56
+ # possible keys when it's a hash:
57
+ # :key (full key)
58
+ # :params (array of params to be added to the key)
59
+ # :action, :controller
60
+ # :match (true or partial key)
61
+
62
+ # Don't forget to look at the specs !!
63
+
64
+ == Specs
65
+ $ rake specs:<cache_store>
66
+ example:
67
+ $ rake specs:memory
68
+ $ rake specs:file
69
+ or just:
70
+ $ cd spec
71
+ $ STORE=<cache_store> spec merb-cache_spec.rb
72
+ # cache_store can be:
73
+ # memory, memcache, file, sequel, datamapper, activerecord
74
+
75
+ == Sample configuration
76
+
77
+ Merb::Plugins.config[:merb_cache] = {
78
+ :cache_html_directory => Merb.dir_for(:public) / "cache",
79
+
80
+ #:store => "database",
81
+ #:table_name => "merb_cache",
82
+
83
+ #:disable => "development", # disable merb-cache in development
84
+ #:disable => true, # disable merb-cache in all environments
85
+
86
+ :store => "file",
87
+ :cache_directory => Merb.root_path("tmp/cache"),
88
+
89
+ #:store => "memcache",
90
+ #:host => "127.0.0.1:11211",
91
+ #:namespace => "merb_cache",
92
+ #:no_tracking => "false",
93
+
94
+ #:store => "memory",
95
+ # store could be: file, memcache, memory, database, dummy, ...
96
+ }
97
+
98
+
99
+ == Quick Example
100
+
101
+ ==== controller part
102
+ class Users < Merb::Controller
103
+ cache_page :action_name
104
+ # this will cache the action in public/cache/something.html
105
+ # this cache entry will never expire (no expiration provided)
106
+ # for permanent caching you could set your lighty/nginx so as to handle
107
+ # the .html file directly
108
+ # for multiple page caching:
109
+ # cache_pages :action_name, [:another_action, 5], :some_action
110
+
111
+ cache_action :another_action, 10
112
+ # this will cache the action using the cache store
113
+ # this cache entry will expire in 10 minutes
114
+ # for multiple action caching:
115
+ # cache_actions :action_name, [:another_action, 5], :some_action
116
+
117
+ def list
118
+ unless @users = cache_get("active_users")
119
+ @users = User.all(:active => true)
120
+ cache_set("active_users", @users)
121
+ # object caching can be used to avoid pulling huge amounts of data
122
+ # from the database.
123
+ # you could have calle cache_set with an expiration time as well:
124
+ # cache_set("active_users", @users, 10)
125
+ end
126
+ render
127
+ end
128
+
129
+ def some_action_that_invalidates_cache
130
+ expire_page(:action_name)
131
+ expire_action(:another_action)
132
+ render
133
+ end
134
+
135
+ def delete
136
+ expire("active_users")
137
+ render
138
+ end
139
+
140
+ def archives
141
+ @archives = User.archives unless cached?("users_archives")
142
+ render
143
+ end
144
+
145
+ def index
146
+ render
147
+ end
148
+ end
149
+
150
+
151
+ ====views/users/index.html.erb
152
+ # this entry will expire in 10 minutes
153
+ <%- cache "users_index", 10 do %>
154
+ <div>some big template</div>
155
+ <% end -%>
156
+
157
+ ====views/users/archive.html.erb
158
+ <%- cache "users_archives" do %>
159
+ <div>some big template</div>
160
+ <% end -%>
data/Rakefile ADDED
@@ -0,0 +1,77 @@
1
+ require 'rubygems'
2
+ require "rake/rdoctask"
3
+ require 'rake/gempackagetask'
4
+ require "spec/rake/spectask"
5
+
6
+ PLUGIN = "merb-cache"
7
+ NAME = "merb-cache"
8
+ MERB_CACHE_VERSION = Merb::MORE_VERSION rescue "0.9.2"
9
+ AUTHOR = "Alex Boussinet"
10
+ EMAIL = "alex.boussinet@gmail.com"
11
+ HOMEPAGE = "http://www.merbivore.com"
12
+ SUMMARY = "Merb plugin that provides caching (page, action, fragment, object)"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = NAME
16
+ s.version = MERB_CACHE_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.has_rdoc = true
19
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
20
+ s.summary = SUMMARY
21
+ s.description = s.summary
22
+ s.author = AUTHOR
23
+ s.email = EMAIL
24
+ s.homepage = HOMEPAGE
25
+ s.add_dependency('merb-core', '>= 0.9.2')
26
+ s.require_path = 'lib'
27
+ s.autorequire = PLUGIN
28
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
29
+
30
+ # rdoc
31
+ s.has_rdoc = true
32
+ s.extra_rdoc_files = %w( README LICENSE TODO )
33
+ end
34
+
35
+ namespace :specs do
36
+ ["file", "memory", "memcache", "sequel", "datamapper", "activerecord"].each do |store|
37
+ desc "Run spec with the \"#{store}\" cache store"
38
+ task "#{store}" do
39
+ cwd = Dir.getwd
40
+ Dir.chdir(File.dirname(__FILE__) + "/spec")
41
+ ENV["STORE"] = store
42
+ system("spec --format specdoc --colour merb-cache_spec.rb")
43
+ Dir.chdir(cwd)
44
+ end
45
+ end
46
+ end
47
+
48
+ namespace :doc do
49
+ Rake::RDocTask.new do |rdoc|
50
+ files = ["README", "LICENSE", "lib/**/*.rb"]
51
+ rdoc.rdoc_files.add(files)
52
+ rdoc.main = "README"
53
+ rdoc.title = "merb-cache docs"
54
+ if File.file?("../../merb-core/tools/allison-2.0.2/lib/allison.rb")
55
+ rdoc.template = "../../merb-core/tools/allison-2.0.2/lib/allison.rb"
56
+ end
57
+ rdoc.rdoc_dir = "doc/rdoc"
58
+ rdoc.options << "--line-numbers" << "--inline-source"
59
+ end
60
+ end
61
+
62
+ Rake::GemPackageTask.new(spec) do |pkg|
63
+ pkg.gem_spec = spec
64
+ end
65
+
66
+ task :install => [:package] do
67
+ sh %{sudo gem install pkg/#{NAME}-#{MERB_CACHE_VERSION} --no-update-sources}
68
+ end
69
+
70
+ namespace :jruby do
71
+
72
+ desc "Run :package and install the resulting .gem with jruby"
73
+ task :install => :package do
74
+ sh %{#{SUDO} jruby -S gem install pkg/#{NAME}-#{Merb::VERSION}.gem --no-rdoc --no-ri}
75
+ end
76
+
77
+ end
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ capture_#{engine} and concat_#{engine} are required for cache()
2
+ implement other cache store ?
@@ -0,0 +1,132 @@
1
+ class Merb::Cache
2
+ cattr_accessor :cached_actions
3
+ self.cached_actions = {}
4
+ end
5
+
6
+ module Merb::Cache::ControllerClassMethods
7
+ # Mixed in Merb::Controller. Provides methods related to action caching
8
+
9
+ # Register the action for action caching
10
+ #
11
+ # ==== Parameters
12
+ # action<Symbol>:: The name of the action to register
13
+ # from_now<~minutes>::
14
+ # The number of minutes (from now) the cache should persist
15
+ #
16
+ # ==== Examples
17
+ # cache_action :mostly_static
18
+ # cache_action :barely_dynamic, 10
19
+ def cache_action(action, from_now = nil)
20
+ cache_actions([action, from_now])
21
+ end
22
+
23
+ # Register actions for action caching (before and after filters)
24
+ #
25
+ # ==== Parameter
26
+ # actions<Symbol,Array[Symbol,~minutes]>:: See #cache_action
27
+ #
28
+ # ==== Example
29
+ # cache_actions :mostly_static, [:barely_dynamic, 10]
30
+ def cache_actions(*actions)
31
+ if actions.any? && Merb::Cache.cached_actions.empty?
32
+ before(:cache_action_before)
33
+ after(:cache_action_after)
34
+ end
35
+ actions.each do |action, from_now|
36
+ _actions = Merb::Cache.cached_actions[controller_name] ||= {}
37
+ _actions[action] = from_now
38
+ end
39
+ true
40
+ end
41
+ end
42
+
43
+ module Merb::Cache::ControllerInstanceMethods
44
+ # Mixed in Merb::Controller. Provides methods related to action caching
45
+
46
+ # Checks whether a cache entry exists
47
+ #
48
+ # ==== Parameter
49
+ # options<String,Hash>:: The options that will be passed to #key_for
50
+ #
51
+ # ==== Returns
52
+ # true if the cache entry exists, false otherwise
53
+ #
54
+ # ==== Example
55
+ # cached_action?(:action => 'show', :params => [params[:page]])
56
+ def cached_action?(options)
57
+ key = Merb::Controller._cache.key_for(options, controller_name, true)
58
+ Merb::Controller._cache.store.cached?(key)
59
+ end
60
+
61
+ # Expires the action identified by the key computed after the parameters
62
+ #
63
+ # ==== Parameter
64
+ # options<String,Hash>:: The options that will be passed to #expire_key_for
65
+ #
66
+ # ==== Examples
67
+ # expire_action(:action => 'show', :controller => 'news')
68
+ # expire_action(:action => 'show', :match => true)
69
+ def expire_action(options)
70
+ Merb::Controller._cache.expire_key_for(options, controller_name, true) do |key, match|
71
+ if match
72
+ Merb::Controller._cache.store.expire_match(key)
73
+ else
74
+ Merb::Controller._cache.store.expire(key)
75
+ end
76
+ end
77
+ true
78
+ end
79
+
80
+ # You can call this method if you need to prevent caching the action
81
+ # after it has been rendered.
82
+ def abort_cache_action
83
+ @capture_action = false
84
+ end
85
+
86
+ private
87
+
88
+ # Called by the before and after filters. Stores or recalls a cache entry.
89
+ # The key is based on the result of request.path
90
+ # If the key with "/" then it is removed
91
+ # If the key is "/" then it will be replaced by "index"
92
+ #
93
+ # ==== Parameters
94
+ # data<String>:: the data to put in cache using the cache store
95
+ #
96
+ # ==== Examples
97
+ # If request.path is "/", the key will be "index"
98
+ # If request.path is "/news/show/1", the key will be "/news/show/1"
99
+ # If request.path is "/news/show/", the key will be "/news/show"
100
+ def _cache_action(data = nil)
101
+ controller = controller_name
102
+ action = action_name.to_sym
103
+ actions = Merb::Controller._cache.cached_actions[controller]
104
+ return unless actions && actions.key?(action)
105
+ path = request.path.chomp("/")
106
+ path = "index" if path.empty?
107
+ if data
108
+ from_now = Merb::Controller._cache.cached_actions[controller][action]
109
+ Merb::Controller._cache.store.cache_set(path, data, from_now)
110
+ else
111
+ @capture_action = false
112
+ _data = Merb::Controller._cache.store.cache_get(path)
113
+ throw(:halt, _data) unless _data.nil?
114
+ @capture_action = true
115
+ end
116
+ true
117
+ end
118
+
119
+ # before filter
120
+ def cache_action_before
121
+ # recalls a cached entry or set @capture_action to true in order
122
+ # to grab the response in the after filter
123
+ _cache_action
124
+ end
125
+
126
+ # after filter
127
+ def cache_action_after
128
+ # takes the body of the response and put it in cache
129
+ # if the cache entry expired, if it doesn't exist or status is 200
130
+ _cache_action(body) if @capture_action && status == 200
131
+ end
132
+ end
@@ -0,0 +1,95 @@
1
+ module Merb::Cache::ControllerInstanceMethods
2
+ # Mixed in Merb::Controller. Provides methods related to fragment caching
3
+
4
+ # Checks whether a cache entry exists
5
+ #
6
+ # ==== Parameter
7
+ # options<String,Hash>:: The options that will be passed to #key_for
8
+ #
9
+ # ==== Returns
10
+ # true if the cache entry exists, false otherwise
11
+ #
12
+ # ==== Example
13
+ # cached_action?("my_key")
14
+ def cached?(options)
15
+ key = Merb::Controller._cache.key_for(options, controller_name)
16
+ Merb::Controller._cache.store.cached?(key)
17
+ end
18
+
19
+ # ==== Example
20
+ # In your view:
21
+ # <%- cache("my_key") do -%>
22
+ # <%= partial :test, :collection => @test %>
23
+ # <%- end -%>
24
+ def cache(options, from_now = nil, &block)
25
+ key = Merb::Controller._cache.key_for(options, controller_name)
26
+ Merb::Controller._cache.store.cache(self, key, from_now, &block)
27
+ end
28
+
29
+ # Fetch data from cache
30
+ #
31
+ # ==== Parameter
32
+ # options<String,Hash>:: The options that will be passed to #key_for
33
+ #
34
+ # ==== Returns
35
+ # data<Object,NilClass>::
36
+ # nil is returned if the cache entry is not found
37
+ #
38
+ # ==== Example
39
+ # if cache_data = cache_get("my_key")
40
+ # @var1, @var2 = *cache_data
41
+ # else
42
+ # @var1 = MyModel.big_query1
43
+ # @var2 = MyModel.big_query2
44
+ # cache_set("my_key", nil, [@var1, @var2])
45
+ # end
46
+ def cache_get(options)
47
+ key = Merb::Controller._cache.key_for(options, controller_name)
48
+ Merb::Controller._cache.store.cache_get(key)
49
+ end
50
+
51
+ # Store data to cache
52
+ #
53
+ # ==== Parameter
54
+ # options<String,Hash>:: The options that will be passed to #key_for
55
+ # object<Object>:: The object(s) to put in cache
56
+ # from_now<~minutes>::
57
+ # The number of minutes (from now) the cache should persist
58
+ #
59
+ # ==== Returns
60
+ # data<Object,NilClass>::
61
+ # nil is returned if the cache entry is not found
62
+ #
63
+ # ==== Example
64
+ # if cache_data = cache_get("my_key")
65
+ # @var1, @var2 = *cache_data
66
+ # else
67
+ # @var1 = MyModel.big_query1
68
+ # @var2 = MyModel.big_query2
69
+ # cache_set("my_key", nil, [@var1, @var2])
70
+ # end
71
+ def cache_set(options, object, from_now = nil)
72
+ key = Merb::Controller._cache.key_for(options, controller_name)
73
+ Merb::Controller._cache.store.cache_set(key, object, from_now)
74
+ end
75
+
76
+ # Expires the entry identified by the key computed after the parameters
77
+ #
78
+ # ==== Parameter
79
+ # options<String,Hash>:: The options that will be passed to #key_for
80
+ #
81
+ # ==== Examples
82
+ # expire("my_key")
83
+ # expire(:key => "my_", :match => true)
84
+ # expire(:key => "my_key", :params => [session[:me], params[:ref]])
85
+ def expire(options)
86
+ Merb::Controller._cache.expire_key_for(options, controller_name) do |key, match|
87
+ if match
88
+ Merb::Controller._cache.store.expire_match(key)
89
+ else
90
+ Merb::Controller._cache.store.expire(key)
91
+ end
92
+ end
93
+ true
94
+ end
95
+ end
@@ -0,0 +1,184 @@
1
+ class Merb::Cache
2
+ cattr_accessor :cached_pages
3
+ self.cached_pages = {}
4
+ end
5
+
6
+ module Merb::Cache::ControllerClassMethods
7
+ # Mixed in Merb::Controller. Provides class methods related to page caching
8
+ # Page caching is mostly action caching with file backend using its own output directory of .html files
9
+
10
+ # Register the action for page caching
11
+ #
12
+ # ==== Parameters
13
+ # action<Symbol>:: The name of the action to register
14
+ # from_now<~minutes>::
15
+ # The number of minutes (from now) the cache should persist
16
+ #
17
+ # ==== Examples
18
+ # cache_page :mostly_static
19
+ # cache_page :barely_dynamic, 10
20
+ def cache_page(action, from_now = nil)
21
+ cache_pages([action, from_now])
22
+ end
23
+
24
+ # Register actions for page caching (before and after filters)
25
+ #
26
+ # ==== Parameter
27
+ # pages<Symbol,Array[Symbol,~minutes]>:: See #cache_page
28
+ #
29
+ # ==== Example
30
+ # cache_pages :mostly_static, [:barely_dynamic, 10]
31
+ def cache_pages(*pages)
32
+ if pages.any? && Merb::Cache.cached_pages.empty?
33
+ before(:cache_page_before)
34
+ after(:cache_page_after)
35
+ end
36
+ pages.each do |action, from_now|
37
+ _pages = Merb::Cache.cached_pages[controller_name] ||= {}
38
+ _pages[action] = [from_now, 0]
39
+ end
40
+ true
41
+ end
42
+ end
43
+
44
+ module Merb::Cache::ControllerInstanceMethods
45
+ # Mixed in Merb::Controller. Provides methods related to page caching
46
+
47
+ # Checks whether a cache entry exists
48
+ #
49
+ # ==== Parameter
50
+ # options<String,Hash>:: The options that will be passed to #key_for
51
+ #
52
+ # ==== Returns
53
+ # true if the cache entry exists, false otherwise
54
+ #
55
+ # ==== Example
56
+ # cached_page?(:action => 'show', :params => [params[:page]])
57
+ def cached_page?(options)
58
+ key = Merb::Controller._cache.key_for(options, controller_name, true)
59
+ File.file?(Merb::Controller._cache.config[:cache_html_directory] / "#{key}.html")
60
+ end
61
+
62
+ # Expires the page identified by the key computed after the parameters
63
+ #
64
+ # ==== Parameter
65
+ # options<String,Hash>:: The options that will be passed to #expire_key_for
66
+ #
67
+ # ==== Examples
68
+ # expire_page(:action => 'show', :controller => 'news')
69
+ # expire_page(:action => 'show', :match => true)
70
+ def expire_page(options)
71
+ config_dir = Merb::Controller._cache.config[:cache_html_directory]
72
+ Merb::Controller._cache.expire_key_for(options, controller_name, true) do |key, match|
73
+ if match
74
+ files = Dir.glob(config_dir / "#{key}*")
75
+ else
76
+ files = config_dir / "#{key}.html"
77
+ end
78
+ FileUtils.rm_rf(files)
79
+ end
80
+ true
81
+ end
82
+
83
+ # Expires all the pages stored in config[:cache_html_directory]
84
+ def expire_all_pages
85
+ FileUtils.rm_rf(Dir.glob(Merb::Controller._cache.config[:cache_html_directory] / "*"))
86
+ end
87
+
88
+ # You can call this method if you need to prevent caching the page
89
+ # after it has been rendered.
90
+ def abort_cache_page
91
+ @capture_page = false
92
+ end
93
+
94
+ private
95
+
96
+ # Called by the before and after filters. Stores or recalls a cache entry.
97
+ # The name used for the cache file is based on request.path
98
+ # If the name ends with "/" then it is removed
99
+ # If the name is "/" then it will be replaced by "index"
100
+ #
101
+ # ==== Parameters
102
+ # data<String>:: the data to put in cache
103
+ #
104
+ # ==== Examples
105
+ # All the file are written to config[:cache_html_directory]
106
+ # If request.path is "/", the name will be "/index.html"
107
+ # If request.path is "/news/show/1", the name will be "/news/show/1.html"
108
+ # If request.path is "/news/show/", the name will be "/news/show.html"
109
+ def _cache_page(data = nil)
110
+ controller = controller_name
111
+ action = action_name.to_sym
112
+ pages = Merb::Controller._cache.cached_pages[controller]
113
+ return unless pages && pages.key?(action)
114
+ path = request.path.chomp("/")
115
+ path = "index" if path.empty?
116
+ cache_file = Merb::Controller._cache.config[:cache_html_directory] / "#{path}.html"
117
+ if data
118
+ cache_directory = File.dirname(cache_file)
119
+ FileUtils.mkdir_p(cache_directory)
120
+ _expire_in = pages[action][0]
121
+ pages[action][1] = _expire_in.minutes.from_now unless _expire_in.nil?
122
+ cache_write_page(cache_file, data)
123
+ Merb.logger.info("cache: set (#{path})")
124
+ else
125
+ @capture_page = false
126
+ if File.file?(cache_file)
127
+ _data = cache_read_page(cache_file)
128
+ _expire_in, _expire_at = pages[action]
129
+ if _expire_in.nil? || Time.now < _expire_at
130
+ Merb.logger.info("cache: hit (#{path})")
131
+ throw(:halt, _data)
132
+ end
133
+ FileUtils.rm_f(cache_file)
134
+ end
135
+ @capture_page = true
136
+ end
137
+ true
138
+ end
139
+
140
+ # Read data from a file using exclusive lock
141
+ #
142
+ # ==== Parameters
143
+ # cache_file<String>:: the full path to the file
144
+ #
145
+ # ==== Returns
146
+ # data<String>:: the data that has been read from the file
147
+ def cache_read_page(cache_file)
148
+ _data = nil
149
+ File.open(cache_file, "r") do |cache_data|
150
+ cache_data.flock(File::LOCK_EX)
151
+ _data = cache_data.read
152
+ cache_data.flock(File::LOCK_UN)
153
+ end
154
+ _data
155
+ end
156
+
157
+ # Write data to a file using exclusive lock
158
+ #
159
+ # ==== Parameters
160
+ # cache_file<String>:: the full path to the file
161
+ # data<String>:: the data that will be written to the file
162
+ def cache_write_page(cache_file, data)
163
+ File.open(cache_file, "w+") do |cache_data|
164
+ cache_data.flock(File::LOCK_EX)
165
+ cache_data.write(data)
166
+ cache_data.flock(File::LOCK_UN)
167
+ end
168
+ true
169
+ end
170
+
171
+ # before filter
172
+ def cache_page_before
173
+ # recalls a cached entry or set @capture_page to true in order
174
+ # to grab the response in the after filter
175
+ _cache_page
176
+ end
177
+
178
+ # after filter
179
+ def cache_page_after
180
+ # takes the body of the response
181
+ # if the cache entry expired, if it doesn't exist or status is 200
182
+ _cache_page(body) if @capture_page && status == 200
183
+ end
184
+ end