Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 2bf11fb81e09671a0b9a78c5e2e7928e2daf56b5 @yeah yeah committed Sep 12, 2009
Showing with 230 additions and 0 deletions.
  1. +20 −0 MIT-LICENSE
  2. +13 −0 README
  3. +28 −0 README.rdoc
  4. +23 −0 Rakefile
  5. +19 −0 init.rb
  6. +1 −0 install.rb
  7. +108 −0 lib/page_cache_fu.rb
  8. +6 −0 tasks/page_cache_fu_tasks.rake
  9. +8 −0 test/page_cache_fu_test.rb
  10. +3 −0 test/test_helper.rb
  11. +1 −0 uninstall.rb
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Jan Schulz-Hofen, ROCKET RENTALS GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,13 @@
+PageCacheFu
+===================
+
+Introduction goes here.
+
+
+Example
+=======
+
+Example goes here.
+
+
+Copyright (c) 2009 Jan Schulz-Hofen, ROCKET RENTALS GmbH, released under the MIT license
@@ -0,0 +1,28 @@
+= PageCacheFu
+
+PageCacheFu adds the following missing features:
+
+* Expiry time for cached pages (using <code>:expires_in</code> option)
+* Different caches for different hostnames (e.g. subdomains)
+* Different caches for query strings
+
+== Installation
+
+# Just install the plugin, add something like <code>:expires_in => 30.minutes</code> to your <code>caches_page</code> calls.
+# Set up a cronjob to periodically run the <code>page_cache_fu:sweep_expired_page_caches</code> Rake task.
+# Tell your Apache to use the new cache location using something like this in your <code>Virtualhost</code> config:
+
+ RewriteMap uri_escape int:escape
+
+ <Directory /path/to/my/rails_app/public/>
+ RewriteEngine On
+ RewriteCond %{REQUEST_METHOD} GET [NC]
+ RewriteCond %{DOCUMENT_ROOT}/cache/%{HTTP_HOST}%{REQUEST_URI}%{QUERY_STRING}.html -f
+ RewriteRule ^([^.]+)$ cache/%{HTTP_HOST}/$1${uri_escape:%{QUERY_STRING}}.html [L]
+
+ RewriteCond %{REQUEST_METHOD} GET [NC]
+ RewriteCond %{DOCUMENT_ROOT}/cache/%{HTTP_HOST}/index.html -f
+ RewriteRule ^$ cache/%{HTTP_HOST}/index.html
+ </Directory>
+
+Copyright (c) 2009 Jan Schulz-Hofen, ROCKET RENTALS GmbH, released under the MIT license
@@ -0,0 +1,23 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the page_cache_fu plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the page_cache_fu plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'PageCacheFu'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
@@ -0,0 +1,19 @@
+require 'dispatcher'
+# require 'lib/page_cache_fu.rb'
+Dispatcher.to_prepare do
+
+ ApplicationController.send(:class_inheritable_accessor, :expiry_page_cache_options)
+
+ if File.expand_path(ActionController::Base.page_cache_directory) == File.expand_path('public',RAILS_ROOT)
+ ActionController::Base.page_cache_directory = File.expand_path('public/cache',RAILS_ROOT)
+ end
+
+ unless ActionController::Caching::Pages::ClassMethods.include?(PageCacheFu::Patches::ClassMethods)
+ ActionController::Caching::Pages::ClassMethods.send(:include, PageCacheFu::Patches::ClassMethods)
+ end
+
+ unless ActionController::Caching::Pages.include?(PageCacheFu::Patches::InstanceMethods)
+ ActionController::Caching::Pages.send(:include, PageCacheFu::Patches::InstanceMethods)
+ end
+
+end
@@ -0,0 +1 @@
+# Install hook code here
@@ -0,0 +1,108 @@
+module PageCacheFu
+ module Patches
+ module ClassMethods
+
+ def caches_page_with_expiry(*actions)
+ if actions.last.is_a?(::Hash) and (expires_in = actions.last.delete(:expires_in))
+ self.expiry_page_cache_options ||= {}
+ actions[0..-2].each do |action|
+ self.expiry_page_cache_options[action.to_sym] = (Time.now + expires_in)
+ end
+ end
+ caches_page_without_expiry(*actions)
+ end
+
+ def self.included(base)
+ base.send(:alias_method_chain, :caches_page, :expiry)
+ end
+
+ end
+
+ module InstanceMethods
+
+ def expire_page_with_domain_and_query(options)
+ expire_page_without_domain_and_query(PageCacheFu::page_cache_path_with_domain_and_query(options, request))
+ end
+
+ def cache_page_with_domain_and_query(content = nil, options = nil)
+ path = PageCacheFu::page_cache_path_with_domain_and_query(options, request)
+ cache_page_without_domain_and_query(content, path)
+ end
+
+ def cache_page_with_expiry(content = nil, options = nil)
+ cache_page_without_expiry(content, options)
+ if self.class.expiry_page_cache_options and (expires_in = self.class.expiry_page_cache_options[params[:action].to_sym])
+ file = self.class.send(:page_cache_path, PageCacheFu::page_cache_path_with_domain_and_query((options||request.path), request))
+ File.utime(expires_in.to_time, expires_in.to_time, file) if File.exists?(file)
+ end
+ end
+
+ def self.included(base)
+ base.send(:alias_method_chain, :expire_page, :domain_and_query)
+ base.send(:alias_method_chain, :cache_page, :domain_and_query)
+ base.send(:alias_method_chain, :cache_page, :expiry)
+ end
+
+ end
+ end
+ module CacheSweeper
+ def self.sweep_if_expired(file, options={})
+ if File.exists?(file)
+ if options[:match_mode].nil? or mode_match((mode=sprintf('%o',File.stat(file).mode)[-3,3]), options[:match_mode])
+ if File.directory?(file)
+ if options[:not_if_directory]
+ puts "Skipping directory #{file}. (Call with :recursive => true to sweep recursively.)"
+ else
+ Dir.foreach(file) do |subfile|
+ sweep_if_expired(file+ '/'+ subfile, options.merge({:not_if_directory => !options[:recursive]})) unless ['.','..'].include?(subfile)
+ end
+ end
+ else
+ if File.mtime(file) < Time.now
+ puts "Sweeping #{file}. #{File.mtime(file)} < #{Time.now}"
+ File.delete(file)
+ end
+ end
+ else
+ puts "Skipping file/directory #{file}. Mode does not match. (requested mode: #{options[:match_mode]}. actual mode: #{mode})"
+ end
+ end
+ end
+
+ private
+
+ def self.mode_match(mode1, mode2)
+ mode1, mode2 = mode1.to_s, mode2.to_s
+ length = [mode1.size,mode2.size].max
+ mode1, mode2 = ("%0#{length}d" % mode1), ("%0#{length}d" % mode2)
+ match = true
+ 0.upto(length-1) do |i|
+ unless mode1[i].to_i & mode2[i].to_i == mode2[i].to_i
+ match = false
+ break
+ end
+ end
+ return match
+ end
+ end
+
+ def self.page_cache_path_with_domain_and_query(orig_path, request)
+ path = "/#{request.host}/"
+ path << case orig_path
+ when Hash
+ url_for(orig_path.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format]))
+ when String
+ orig_path
+ else
+ if request.path.empty? || request.path == '/'
+ '/index'
+ else
+ request.path
+ end
+ end
+ path << CGI::escape(request.query_string) unless request.query_string.blank?
+ return path
+ end
+
+
+end
@@ -0,0 +1,6 @@
+namespace :page_cache_fu do
+ desc "Sweeps the cached pages which are expired."
+ task :sweep_expired_page_caches => :environment do
+ PageCacheFu::CacheSweeper.sweep_if_expired(ActionController::Base.page_cache_directory, :recursive => true)
+ end
+end
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class PageCacheFuTest < ActiveSupport::TestCase
+ # Replace this with your real tests.
+ test "the truth" do
+ assert true
+ end
+end
@@ -0,0 +1,3 @@
+require 'rubygems'
+require 'active_support'
+require 'active_support/test_case'
@@ -0,0 +1 @@
+# Uninstall hook code here

0 comments on commit 2bf11fb

Please sign in to comment.