bchiu-merb_cache_more 0.9.4

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 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