bchiu-merb_cache_more 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Ben Chiu
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,204 @@
1
+ = merb_cache_more
2
+
3
+ Extends merb-cache to use params, work with pagination, auto-cache all actions and use many key formats
4
+
5
+ This plugin is a fork of merb-cache written by Alex Boussinet. Much of the
6
+ cache-store stuff is unchanged (I only added it so people can run the tests
7
+ and use this plugin without any dependencies on merb-cache).
8
+
9
+ Currently supported methods:
10
+
11
+ - page caching:
12
+ - action caching
13
+ - fragment caching
14
+ - object caching
15
+
16
+ Implemented cache stores:
17
+
18
+ - memory
19
+ - memcache
20
+ - file
21
+ - database (sequel, datamapper, activerecord)
22
+
23
+ == Installation
24
+
25
+ git clone git://github.com/bchiu/merb_cache_more.git
26
+ cd merb_cache_more
27
+ rake install
28
+ remove: dependency 'merb-cache' from init.rb
29
+ add: dependency 'merb_cache_more' to init.rb
30
+
31
+ == Quick intro
32
+ With fragment caching, you can mix dynamic and static content.
33
+
34
+ With action caching, the whole template is cached
35
+ but the before filters are still processed.
36
+
37
+ With page caching, the whole template is put in html files in a special
38
+ directory in order to be handled directly without triggering Merb.
39
+
40
+ == Quick API
41
+
42
+ === Merb::Controller class methods
43
+ cache_action(action, expiration)
44
+ cache_action(action, expiration, options)
45
+ cache_actions(action, [action, expiration], ...)
46
+ cache_actions(action, [action, expiration], [action, expiration, options], ...)
47
+ cache_page(action, expiration)
48
+ cache_page(action, expiration, options)
49
+ cache_pages(action, [action, expiration], ...)
50
+ cache_pages(action, [action, expiration], [action, expiration, options], ...)
51
+
52
+ === Merb::Controller instance methods
53
+ expire_page(key)
54
+ cached_page?(key)
55
+ expire_all_pages()
56
+
57
+ expire_action(key)
58
+ cached_action?(key)
59
+
60
+ cached?(key)
61
+ cache_get(key)
62
+ cache_set(key, data, expiration)
63
+ expire(key)
64
+ expire_all()
65
+
66
+ === Inside your template
67
+ cache(key, expiration) do ... end
68
+
69
+ # expiration is given in minutes
70
+
71
+ # key can be a string or a hash
72
+ # possible keys when it's a hash:
73
+ # :key (full key)
74
+ # :params (array of params to be added to the key)
75
+ # :action, :controller
76
+ # :match (true or partial key)
77
+
78
+ # Don't forget to look at the specs !!
79
+
80
+ == Specs
81
+ $ rake specs:<cache_store>
82
+ example:
83
+ $ rake specs:memory
84
+ $ rake specs:file
85
+ or just:
86
+ $ cd spec
87
+ $ STORE=<cache_store> spec merb-cache_spec.rb
88
+ # cache_store can be:
89
+ # memory, memcache, file, sequel, datamapper, activerecord
90
+
91
+ == Sample configuration
92
+
93
+ Merb::Plugins.config[:merb_cache] = {
94
+ :cache_html_directory => Merb.dir_for(:public) / "cache",
95
+
96
+ #:store => "database",
97
+ #:table_name => "merb_cache",
98
+
99
+ #:disable => "development", # disable caching for development
100
+ #:disable => true, # disable caching for all environments
101
+
102
+ :store => "file",
103
+ :cache_directory => Merb.root_path("tmp/cache"),
104
+
105
+ #:store => "memcache",
106
+ #:host => "127.0.0.1:11211",
107
+ #:namespace => "merb_cache",
108
+ #:no_tracking => "false",
109
+
110
+ #:store => "memory",
111
+ # store could be: file, memcache, memory, database, dummy, ...
112
+
113
+ # can be nil|:snake|:tree|:hash|:query or a custom string
114
+ # such as ":paramname1/:paramname2_and_:paramname3"
115
+ #:cache_key_format => nil,
116
+
117
+ # expiration time in minutes
118
+ #:cache_action_ttl => 10,
119
+ #:cache_page_ttl => 10
120
+ }
121
+
122
+
123
+ == Quick Example
124
+
125
+ ==== controller part
126
+ class Users < Merb::Controller
127
+ cache_page :action_name
128
+ # this will cache the action in public/cache/something.html
129
+ # this cache entry will never expire (no expiration provided)
130
+ # for permanent caching you could set your lighty/nginx so as to handle
131
+ # the .html file directly
132
+ # for multiple page caching:
133
+ # cache_pages :action_name, [:another_action, 5], :some_action
134
+
135
+ cache_action :another_action, 10
136
+ # this will cache the action using the cache store
137
+ # this cache entry will expire in 10 minutes
138
+ # for multiple action caching:
139
+ # cache_actions :action_name, [:another_action, 5], :some_action
140
+
141
+ cache_action :action_with_config
142
+ # this will cache the action using the config settings:
143
+ # :cache_action_ttl => 10
144
+ # :cache_key_format => nil|:snake|:tree|:query|:hash or custom
145
+
146
+ cache_action :action_with_params, 10, :format => :snake, :params => [:id, :name]
147
+ # config settings may be overriden per action
148
+ # this will cache the action using a snake case key
149
+ # key will only include only the params :id and :name
150
+ # this cache entry will expire in 10 minutes
151
+
152
+ def list
153
+ unless @users = cache_get("active_users")
154
+ @users = User.all(:active => true)
155
+ cache_set("active_users", @users)
156
+ # object caching can be used to avoid pulling huge amounts of data
157
+ # from the database.
158
+ # you could have calle cache_set with an expiration time as well:
159
+ # cache_set("active_users", @users, 10)
160
+ end
161
+ render
162
+ end
163
+
164
+ def some_action_that_invalidates_cache
165
+ expire_page(:action_name)
166
+ expire_action(:another_action)
167
+ render
168
+ end
169
+
170
+ def delete
171
+ expire("active_users")
172
+ render
173
+ end
174
+
175
+ def archives
176
+ @archives = User.archives unless cached?("users_archives")
177
+ render
178
+ end
179
+
180
+ def index
181
+ render
182
+ end
183
+
184
+ cache_actions :all, 10, :exclude => [:list]
185
+ # this will cache all actions in the current controller
186
+ # except for the :list action
187
+ # cache entries will expire in 10 minutes
188
+ # note: this line must appear at the end of the class declaration
189
+ end
190
+
191
+
192
+ ====views/users/index.html.erb
193
+ # this entry will expire in 10 minutes
194
+ <%- cache "users_index", 10 do %>
195
+ <div>some big template</div>
196
+ <% end -%>
197
+
198
+ ====views/users/archive.html.erb
199
+ <%- cache "users_archives" do %>
200
+ <div>some big template</div>
201
+ <% end -%>
202
+
203
+ == Credits
204
+ This plugin is a fork of merb-cache written by Alex Boussinet.
@@ -0,0 +1,81 @@
1
+ require 'rubygems'
2
+ require 'rubygems/specification'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+ require 'spec/rake/spectask'
6
+ require 'date'
7
+ require 'merb_rake_helper'
8
+
9
+ PLUGIN = "merb_cache_more"
10
+ NAME = "merb_cache_more"
11
+ GEM_VERSION = "0.9.4"
12
+ AUTHOR = "Ben Chiu"
13
+ EMAIL = "bchiu@yahoo.com"
14
+ HOMEPAGE = "http://github.com/bchiu/merb_cache_more"
15
+ SUMMARY = "Extends merb-cache to use params, work with pagination, auto-cache all actions and use many key formats"
16
+
17
+ spec = Gem::Specification.new do |s|
18
+ s.name = NAME
19
+ s.version = GEM_VERSION
20
+ s.platform = Gem::Platform::RUBY
21
+ s.has_rdoc = true
22
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
23
+ s.summary = SUMMARY
24
+ s.description = s.summary
25
+ s.author = AUTHOR
26
+ s.email = EMAIL
27
+ s.homepage = HOMEPAGE
28
+ s.add_dependency('merb-core', '>= 0.9.4')
29
+ s.require_path = 'lib'
30
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
31
+ end
32
+
33
+ Rake::GemPackageTask.new(spec) do |pkg|
34
+ pkg.gem_spec = spec
35
+ end
36
+
37
+ task :install => [:package] do
38
+ sh %{#{sudo} #{gemx} install pkg/#{NAME}-#{GEM_VERSION} --local --no-update-sources}
39
+ end
40
+
41
+ task :install_frozen => [:package] do
42
+ sh %{#{sudo} #{gemx} install pkg/#{NAME}-#{GEM_VERSION} -i ../../ --local --no-update-sources}
43
+ end
44
+
45
+ desc "create a gemspec file"
46
+ task :make_spec do
47
+ File.open("#{NAME}.gemspec", "w") do |file|
48
+ file.puts spec.to_ruby
49
+ end
50
+ end
51
+
52
+ namespace :jruby do
53
+ desc "Run :package and install the resulting .gem with jruby"
54
+ task :install => :package do
55
+ sh %{#{sudo} jruby -S gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION}.gem --local --no-rdoc --no-ri}
56
+ end
57
+ end
58
+
59
+ namespace :specs do
60
+ ["file", "memory", "memcache", "sequel", "datamapper", "activerecord"].each do |store|
61
+ desc "Run spec with the \"#{store}\" cache store"
62
+ task "#{store}" do
63
+ cwd = Dir.getwd
64
+ Dir.chdir(File.dirname(__FILE__) + "/spec")
65
+ ENV["STORE"] = store
66
+ system("spec --format specdoc --colour merb_cache_more_spec.rb")
67
+ Dir.chdir(cwd)
68
+ end
69
+ end
70
+ end
71
+
72
+ namespace :doc do
73
+ Rake::RDocTask.new do |rdoc|
74
+ files = ["README", "LICENSE", "lib/**/*.rb"]
75
+ rdoc.rdoc_files.add(files)
76
+ rdoc.main = "README"
77
+ rdoc.title = "merb_cache_more docs"
78
+ rdoc.rdoc_dir = "doc/rdoc"
79
+ rdoc.options << "--line-numbers" << "--inline-source"
80
+ end
81
+ end
data/TODO ADDED
@@ -0,0 +1 @@
1
+ TODO:
@@ -0,0 +1,33 @@
1
+ if defined?(Merb::Plugins)
2
+ require 'merb_cache_more/merb-cache.rb'
3
+ require 'merb_cache_more/cache-action.rb'
4
+ require 'merb_cache_more/cache-page.rb'
5
+ require "merb_cache_more/cache-fragment"
6
+ require 'merb_cache_more/request.rb'
7
+ require 'merb_cache_more/request_helper.rb'
8
+ require 'digest/md5'
9
+
10
+ unless 1.respond_to? :minutes
11
+ class Numeric
12
+ def minutes; self * 60; end
13
+ def from_now(now = Time.now); now + self; end
14
+ end
15
+ end
16
+
17
+ module Merb
18
+ class Controller
19
+ cattr_reader :_cache
20
+ @@_cache = Merb::Cache.new
21
+ include Merb::Cache::ControllerInstanceMethods
22
+ class << self
23
+ include Merb::Cache::ControllerClassMethods
24
+ end
25
+ end
26
+ end
27
+
28
+ Merb::BootLoader.after_app_loads do
29
+ Merb::Controller._cache.start
30
+ end
31
+
32
+ Merb::Plugins.add_rakefiles "merb_cache_more/merbtasks"
33
+ end
@@ -0,0 +1,176 @@
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
+ # options<Hash>::
16
+ # Key formats :format => :snake|:tree|:hash|:query or nil for default
17
+ # Custom format :format => ":param1/:param2-and_:param3"
18
+ # Params :params => [params to include] or false to disable
19
+ #
20
+ # ==== Examples
21
+ # cache_action :mostly_static
22
+ # cache_action :barely_dynamic, 10
23
+ # cache_action :barely_dynamic, 10, {:format => :hash, :params => [:id, :name]}
24
+ # cache_action :barely_dynamic, :format => ":param1/:param2-and_:param3[key]"
25
+ def cache_action(action, from_now = nil, opts = {})
26
+ from_now, opts = nil, from_now if Hash === from_now
27
+
28
+ cache_opts = {:format => opts[:format], :params => opts[:params]}
29
+ opts.delete(:format); opts.delete(:params); opts.delete(:exclude)
30
+
31
+ before("cache_#{action}_before", opts.merge(:only => action, :with => [cache_opts]))
32
+ after("cache_#{action}_after", opts.merge(:only => action, :with => [cache_opts]))
33
+ alias_method "cache_#{action}_before", :cache_action_before
34
+ alias_method "cache_#{action}_after", :cache_action_after
35
+
36
+ _actions = Merb::Cache.cached_actions[controller_name] ||= {}
37
+ _actions[action] = from_now
38
+ end
39
+
40
+ # Register actions for action caching (before and after filters)
41
+ #
42
+ # ==== Parameter
43
+ # actions<Symbol,Array[Symbol,~minutes,Hash]>:: See #cache_action
44
+ #
45
+ # ==== Example
46
+ # cache_actions :mostly_static, :barely_dynamic
47
+ # cache_actions :mostly_static, [:barely_dynamic, 10]
48
+ # cache_actions :barely_dynamic, [:barely_dynamic, 10, :format => :hash]
49
+ # cache_actions :barely_dynamic, [:barely_dynamic, 10, :params => [:id, :name]]
50
+ # cache_actions :all, 10, :exclude => [:show], :format => :snake, :params => [:id, :name]
51
+ def cache_actions(*actions)
52
+ config = Merb::Plugins.config[:merb_cache]
53
+
54
+ if actions[0] == :all
55
+ from_now = Hash === actions[1] ? config[:cache_action_ttl] : actions[1]
56
+ opts = Hash === actions[1] ? actions[1] : actions[2] || {}
57
+ excludes = opts[:exclude] || []
58
+ actions = self.instance_methods(false).map {|action|
59
+ [action.to_sym, from_now, opts] unless excludes.include?(action.to_sym)
60
+ }.compact
61
+ end
62
+
63
+ actions.each do |act_opts|
64
+ if Array === act_opts
65
+ action = act_opts[0]
66
+ from_now = Hash === act_opts[1] ? config[:cache_action_ttl] : act_opts[1]
67
+ opts = Hash === act_opts[1] ? act_opts[1] : act_opts[2]
68
+ else
69
+ action = act_opts
70
+ from_now = config[:cache_action_ttl]
71
+ opts = {}
72
+ end
73
+ cache_action(action, from_now, opts||{})
74
+ end
75
+ true
76
+ end
77
+ end
78
+
79
+ module Merb::Cache::ControllerInstanceMethods
80
+ # Mixed in Merb::Controller. Provides methods related to action caching
81
+
82
+ # Checks whether a cache entry exists
83
+ #
84
+ # ==== Parameter
85
+ # options<String,Hash>:: The options that will be passed to #key_for
86
+ #
87
+ # ==== Returns
88
+ # true if the cache entry exists, false otherwise
89
+ #
90
+ # ==== Example
91
+ # cached_action?(:action => 'show', :params => [params[:page]])
92
+ def cached_action?(options)
93
+ key = Merb::Controller._cache.key_for(options, controller_name, true)
94
+ Merb::Controller._cache.store.cached?(key)
95
+ end
96
+
97
+ # Expires the action identified by the key computed after the parameters
98
+ #
99
+ # ==== Parameter
100
+ # options<String,Hash>:: The options that will be passed to #expire_key_for
101
+ #
102
+ # ==== Examples
103
+ # expire_action(:action => 'show', :controller => 'news')
104
+ # expire_action(:action => 'show', :match => true)
105
+ def expire_action(options)
106
+ Merb::Controller._cache.expire_key_for(options, controller_name, true) do |key, match|
107
+ if match
108
+ Merb::Controller._cache.store.expire_match(key)
109
+ else
110
+ Merb::Controller._cache.store.expire(key)
111
+ end
112
+ end
113
+ true
114
+ end
115
+
116
+ # You can call this method if you need to prevent caching the action
117
+ # after it has been rendered.
118
+ def abort_cache_action
119
+ @capture_action = false
120
+ end
121
+
122
+ private
123
+
124
+ # Called by the before and after filters. Stores or recalls a cache entry.
125
+ # The key is based on the result of request.path
126
+ # If the key with "/" then it is removed
127
+ # If the key is "/" then it will be replaced by "index"
128
+ #
129
+ # ==== Parameters
130
+ # data<String>:: the data to put in cache using the cache store
131
+ #
132
+ # ==== Examples
133
+ # If request.path is "/", the key will be "index"
134
+ # If request.path is "/news/show/1", the key will be "/news/show/1"
135
+ # If request.path is "/news/show/", the key will be "/news/show"
136
+ def _cache_action(data = nil, opts = {})
137
+ controller = controller_name
138
+ action = action_name.to_sym
139
+ actions = Merb::Controller._cache.cached_actions[controller]
140
+ return unless actions && actions.key?(action)
141
+
142
+ path = request.path.chomp("/")
143
+ path = "index" if path.empty?
144
+
145
+ _format = opts[:format] || Merb::Controller._cache.config[:cache_key_format]
146
+ _params = opts[:params]==false ? nil : Merb::Request.query_parse(request.query_string, '&', true)
147
+ _params.delete_if {|k,v| !opts[:params].include?(k.to_sym) } if _params && opts[:params]
148
+
149
+ key = Merb::Controller._cache.key_for({:key => path, :params => _params, :format => _format})
150
+
151
+ if data
152
+ from_now = Merb::Controller._cache.cached_actions[controller][action]
153
+ Merb::Controller._cache.store.cache_set(key, data, from_now)
154
+ else
155
+ @capture_action = false
156
+ _data = Merb::Controller._cache.store.cache_get(key)
157
+ throw(:halt, _data) unless _data.nil?
158
+ @capture_action = true
159
+ end
160
+ true
161
+ end
162
+
163
+ # before filter
164
+ def cache_action_before(opts)
165
+ # recalls a cached entry or set @capture_action to true in order
166
+ # to grab the response in the after filter
167
+ _cache_action(nil, opts)
168
+ end
169
+
170
+ # after filter
171
+ def cache_action_after(opts)
172
+ # takes the body of the response and put it in cache
173
+ # if the cache entry expired, if it doesn't exist or status is 200
174
+ _cache_action(body, opts) if @capture_action && status == 200
175
+ end
176
+ end