actionpack-page_caching-1.1.0/ 0000755 0000041 0000041 00000000000 13314504367 016251 5 ustar www-data www-data actionpack-page_caching-1.1.0/.travis.yml 0000644 0000041 0000041 00000002562 13314504367 020367 0 ustar www-data www-data language: ruby
sudo: false
cache:
bundler: true
before_install:
- gem install bundler
rvm:
- 1.9.3
- 2.0.0
- 2.1.9
- 2.2.6
- 2.3.3
- 2.4.0
gemfile:
- Gemfile
- gemfiles/Gemfile-4-0-stable
- gemfiles/Gemfile-4-1-stable
- gemfiles/Gemfile-4-2-stable
- gemfiles/Gemfile-5-0-stable
- gemfiles/Gemfile-edge
matrix:
allow_failures:
- gemfile: gemfiles/Gemfile-edge
exclude:
- rvm: 1.9.3
gemfile: Gemfile
- rvm: 2.0.0
gemfile: Gemfile
- rvm: 2.1.9
gemfile: Gemfile
- rvm: 1.9.3
gemfile: gemfiles/Gemfile-5-0-stable
- rvm: 2.0.0
gemfile: gemfiles/Gemfile-5-0-stable
- rvm: 2.1.9
gemfile: gemfiles/Gemfile-5-0-stable
- rvm: 1.9.3
gemfile: gemfiles/Gemfile-edge
- rvm: 2.0.0
gemfile: gemfiles/Gemfile-edge
- rvm: 2.1.9
gemfile: gemfiles/Gemfile-edge
- rvm: 2.4.0
gemfile: gemfiles/Gemfile-4-0-stable
- rvm: 2.4.0
gemfile: gemfiles/Gemfile-4-1-stable
notifications:
email: false
irc:
on_success: change
on_failure: always
channels:
- "irc.freenode.org#rails-contrib"
campfire:
on_success: change
on_failure: always
rooms:
- secure: "eRCx+FMvH50pmLu0GZTF7NN+2X+CesgodYUlHvCr5EXQ0ZO/YUmeW8vAh/N8\njSrLWYpk/4P/JA63JGWsvFor/zpkTnfwzX3LWgw04GV0V3T9jsn9CD2Coiu6\nFll5u4fUCUwpfbB4RlCkjvFdQmW+F9mmbRGMCDO5CmuPHOyyPH0="
actionpack-page_caching-1.1.0/test/ 0000755 0000041 0000041 00000000000 13314504367 017230 5 ustar www-data www-data actionpack-page_caching-1.1.0/test/abstract_unit.rb 0000644 0000041 0000041 00000000526 13314504367 022422 0 ustar www-data www-data require "bundler/setup"
require "minitest/autorun"
require "action_controller"
require "action_controller/page_caching"
if ActiveSupport.respond_to?(:test_order)
ActiveSupport.test_order = :random
end
if ActionController::Base.respond_to?(:enable_fragment_cache_logging=)
ActionController::Base.enable_fragment_cache_logging = true
end
actionpack-page_caching-1.1.0/test/caching_test.rb 0000644 0000041 0000041 00000032227 13314504367 022216 0 ustar www-data www-data require "abstract_unit"
require "mocha/setup"
CACHE_DIR = "test_cache"
# Don't change "../tmp" cavalierly or you might hose something you don't want hosed
TEST_TMP_DIR = File.expand_path("../tmp", __FILE__)
FILE_STORE_PATH = File.join(TEST_TMP_DIR, CACHE_DIR)
module PageCachingTestHelpers
def setup
super
@routes = ActionDispatch::Routing::RouteSet.new
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
FileUtils.mkdir_p(FILE_STORE_PATH)
end
def teardown
super
FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
@controller.perform_caching = false
end
private
def assert_page_cached(action, options = {})
expected = options[:content] || action.to_s
path = cache_file(action, options)
assert File.exist?(path), "The cache file #{path} doesn't exist"
if File.extname(path) == ".gz"
actual = Zlib::GzipReader.open(path) { |f| f.read }
else
actual = File.read(path)
end
assert_equal expected, actual, "The cached content doesn't match the expected value"
end
def assert_page_not_cached(action, options = {})
path = cache_file(action, options)
assert !File.exist?(path), "The cache file #{path} still exists"
end
def cache_file(action, options = {})
path = options[:path] || FILE_STORE_PATH
controller = options[:controller] || self.class.name.underscore
format = options[:format] || "html"
"#{path}/#{controller}/#{action}.#{format}"
end
def draw(&block)
@routes = ActionDispatch::Routing::RouteSet.new
@routes.draw(&block)
@controller.extend(@routes.url_helpers)
end
end
class CachingMetalController < ActionController::Metal
abstract!
include AbstractController::Callbacks
include ActionController::Caching
self.page_cache_directory = FILE_STORE_PATH
self.cache_store = :file_store, FILE_STORE_PATH
end
class PageCachingMetalTestController < CachingMetalController
caches_page :ok
def ok
self.response_body = "ok"
end
end
class PageCachingMetalTest < ActionController::TestCase
include PageCachingTestHelpers
tests PageCachingMetalTestController
def test_should_cache_get_with_ok_status
draw do
get "/page_caching_metal_test/ok", to: "page_caching_metal_test#ok"
end
get :ok
assert_response :ok
assert_page_cached :ok
end
end
ActionController::Base.page_cache_directory = FILE_STORE_PATH
class CachingController < ActionController::Base
abstract!
self.cache_store = :file_store, FILE_STORE_PATH
protected
if ActionPack::VERSION::STRING < "4.1"
def render(options)
if options.key?(:html)
super({ text: options.delete(:html) }.merge(options))
else
super
end
end
end
end
class PageCachingTestController < CachingController
self.page_cache_compression = :best_compression
caches_page :ok, :no_content, if: Proc.new { |c| !c.request.format.json? }
caches_page :found, :not_found
caches_page :about_me
caches_page :default_gzip
caches_page :no_gzip, gzip: false
caches_page :gzip_level, gzip: :best_speed
def ok
render html: "ok"
end
def no_content
head :no_content
end
def found
redirect_to action: "ok"
end
def not_found
head :not_found
end
def custom_path
render html: "custom_path"
cache_page(nil, "/index.html")
end
def default_gzip
render html: "default_gzip"
end
def no_gzip
render html: "no_gzip"
end
def gzip_level
render html: "gzip_level"
end
def expire_custom_path
expire_page("/index.html")
head :ok
end
def trailing_slash
render html: "trailing_slash"
end
def about_me
respond_to do |format|
format.html { render html: "I am html" }
format.xml { render xml: "I am xml" }
end
end
end
class PageCachingTest < ActionController::TestCase
include PageCachingTestHelpers
tests PageCachingTestController
def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
draw do
get "posts.:format", to: "posts#index", as: :formatted_posts
get "/", to: "posts#index", as: :main
end
defaults = { controller: "posts", action: "index", only_path: true }
assert_equal "/posts.rss", @routes.url_for(defaults.merge(format: "rss"))
assert_equal "/", @routes.url_for(defaults.merge(format: nil))
end
def test_should_cache_head_with_ok_status
draw do
get "/page_caching_test/ok", to: "page_caching_test#ok"
end
head :ok
assert_response :ok
assert_page_cached :ok
end
def test_should_cache_get_with_ok_status
draw do
get "/page_caching_test/ok", to: "page_caching_test#ok"
end
get :ok
assert_response :ok
assert_page_cached :ok
end
def test_should_cache_with_custom_path
draw do
get "/page_caching_test/custom_path", to: "page_caching_test#custom_path"
end
get :custom_path
assert_page_cached :index, controller: ".", content: "custom_path"
end
def test_should_expire_cache_with_custom_path
draw do
get "/page_caching_test/custom_path", to: "page_caching_test#custom_path"
get "/page_caching_test/expire_custom_path", to: "page_caching_test#expire_custom_path"
end
get :custom_path
assert_page_cached :index, controller: ".", content: "custom_path"
get :expire_custom_path
assert_page_not_cached :index, controller: ".", content: "custom_path"
end
def test_should_gzip_cache
draw do
get "/page_caching_test/custom_path", to: "page_caching_test#custom_path"
get "/page_caching_test/expire_custom_path", to: "page_caching_test#expire_custom_path"
end
get :custom_path
assert_page_cached :index, controller: ".", format: "html.gz", content: "custom_path"
get :expire_custom_path
assert_page_not_cached :index, controller: ".", format: "html.gz"
end
def test_should_allow_to_disable_gzip
draw do
get "/page_caching_test/no_gzip", to: "page_caching_test#no_gzip"
end
get :no_gzip
assert_page_cached :no_gzip, format: "html"
assert_page_not_cached :no_gzip, format: "html.gz"
end
def test_should_use_config_gzip_by_default
draw do
get "/page_caching_test/default_gzip", to: "page_caching_test#default_gzip"
end
@controller.expects(:cache_page).with(nil, nil, Zlib::BEST_COMPRESSION)
get :default_gzip
end
def test_should_set_gzip_level
draw do
get "/page_caching_test/gzip_level", to: "page_caching_test#gzip_level"
end
@controller.expects(:cache_page).with(nil, nil, Zlib::BEST_SPEED)
get :gzip_level
end
def test_should_cache_without_trailing_slash_on_url
@controller.class.cache_page "cached content", "/page_caching_test/trailing_slash"
assert_page_cached :trailing_slash, content: "cached content"
end
def test_should_obey_http_accept_attribute
draw do
get "/page_caching_test/about_me", to: "page_caching_test#about_me"
end
@request.env["HTTP_ACCEPT"] = "text/xml"
get :about_me
assert_equal "I am xml", @response.body
assert_page_cached :about_me, format: "xml", content: "I am xml"
end
def test_cached_page_should_not_have_trailing_slash_even_if_url_has_trailing_slash
@controller.class.cache_page "cached content", "/page_caching_test/trailing_slash/"
assert_page_cached :trailing_slash, content: "cached content"
end
def test_should_cache_ok_at_custom_path
draw do
get "/page_caching_test/ok", to: "page_caching_test#ok"
end
@request.env["PATH_INFO"] = "/index.html"
get :ok
assert_response :ok
assert_page_cached :index, controller: ".", content: "ok"
end
[:ok, :no_content, :found, :not_found].each do |status|
[:get, :post, :patch, :put, :delete].each do |method|
unless method == :get && status == :ok
define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
draw do
get "/page_caching_test/ok", to: "page_caching_test#ok"
match "/page_caching_test/#{status}", to: "page_caching_test##{status}", via: method
end
send(method, status)
assert_response status
assert_page_not_cached status
end
end
end
end
def test_page_caching_conditional_options
draw do
get "/page_caching_test/ok", to: "page_caching_test#ok"
end
get :ok, format: "json"
assert_page_not_cached :ok
end
def test_page_caching_directory_set_as_pathname
begin
ActionController::Base.page_cache_directory = Pathname.new(FILE_STORE_PATH)
draw do
get "/page_caching_test/ok", to: "page_caching_test#ok"
end
get :ok
assert_response :ok
assert_page_cached :ok
ensure
ActionController::Base.page_cache_directory = FILE_STORE_PATH
end
end
def test_page_caching_directory_set_on_controller_instance
draw do
get "/page_caching_test/ok", to: "page_caching_test#ok"
end
file_store_path = File.join(TEST_TMP_DIR, "instance_cache")
@controller.page_cache_directory = file_store_path
get :ok
assert_response :ok
assert_page_cached :ok, path: file_store_path
end
end
class ProcPageCachingTestController < CachingController
self.page_cache_directory = -> { File.join(TEST_TMP_DIR, request.domain) }
caches_page :ok
def ok
render html: "ok"
end
def expire_ok
expire_page action: :ok
head :ok
end
end
class ProcPageCachingTest < ActionController::TestCase
include PageCachingTestHelpers
tests ProcPageCachingTestController
def test_page_is_cached_by_domain
draw do
get "/proc_page_caching_test/ok", to: "proc_page_caching_test#ok"
get "/proc_page_caching_test/ok/expire", to: "proc_page_caching_test#expire_ok"
end
@request.env["HTTP_HOST"] = "www.foo.com"
get :ok
assert_response :ok
assert_page_cached :ok, path: TEST_TMP_DIR + "/foo.com"
get :expire_ok
assert_response :ok
assert_page_not_cached :ok, path: TEST_TMP_DIR + "/foo.com"
@request.env["HTTP_HOST"] = "www.bar.com"
get :ok
assert_response :ok
assert_page_cached :ok, path: TEST_TMP_DIR + "/bar.com"
get :expire_ok
assert_response :ok
assert_page_not_cached :ok, path: TEST_TMP_DIR + "/bar.com"
end
def test_class_level_cache_page_raise_error
assert_raises(RuntimeError, /class-level cache_page method/) do
@controller.class.cache_page "cached content", "/proc_page_caching_test/ok"
end
end
end
class SymbolPageCachingTestController < CachingController
self.page_cache_directory = :domain_cache_directory
caches_page :ok
def ok
render html: "ok"
end
def expire_ok
expire_page action: :ok
head :ok
end
protected
def domain_cache_directory
File.join(TEST_TMP_DIR, request.domain)
end
end
class SymbolPageCachingTest < ActionController::TestCase
include PageCachingTestHelpers
tests SymbolPageCachingTestController
def test_page_is_cached_by_domain
draw do
get "/symbol_page_caching_test/ok", to: "symbol_page_caching_test#ok"
get "/symbol_page_caching_test/ok/expire", to: "symbol_page_caching_test#expire_ok"
end
@request.env["HTTP_HOST"] = "www.foo.com"
get :ok
assert_response :ok
assert_page_cached :ok, path: TEST_TMP_DIR + "/foo.com"
get :expire_ok
assert_response :ok
assert_page_not_cached :ok, path: TEST_TMP_DIR + "/foo.com"
@request.env["HTTP_HOST"] = "www.bar.com"
get :ok
assert_response :ok
assert_page_cached :ok, path: TEST_TMP_DIR + "/bar.com"
get :expire_ok
assert_response :ok
assert_page_not_cached :ok, path: TEST_TMP_DIR + "/bar.com"
end
def test_class_level_cache_page_raise_error
assert_raises(RuntimeError, /class-level cache_page method/) do
@controller.class.cache_page "cached content", "/symbol_page_caching_test/ok"
end
end
end
class CallablePageCachingTestController < CachingController
class DomainCacheDirectory
def self.call(request)
File.join(TEST_TMP_DIR, request.domain)
end
end
self.page_cache_directory = DomainCacheDirectory
caches_page :ok
def ok
render html: "ok"
end
def expire_ok
expire_page action: :ok
head :ok
end
end
class CallablePageCachingTest < ActionController::TestCase
include PageCachingTestHelpers
tests CallablePageCachingTestController
def test_page_is_cached_by_domain
draw do
get "/callable_page_caching_test/ok", to: "callable_page_caching_test#ok"
get "/callable_page_caching_test/ok/expire", to: "callable_page_caching_test#expire_ok"
end
@request.env["HTTP_HOST"] = "www.foo.com"
get :ok
assert_response :ok
assert_page_cached :ok, path: TEST_TMP_DIR + "/foo.com"
get :expire_ok
assert_response :ok
assert_page_not_cached :ok, path: TEST_TMP_DIR + "/foo.com"
@request.env["HTTP_HOST"] = "www.bar.com"
get :ok
assert_response :ok
assert_page_cached :ok, path: TEST_TMP_DIR + "/bar.com"
get :expire_ok
assert_response :ok
assert_page_not_cached :ok, path: TEST_TMP_DIR + "/bar.com"
end
def test_class_level_cache_page_raise_error
assert_raises(RuntimeError, /class-level cache_page method/) do
@controller.class.cache_page "cached content", "/callable_page_caching_test/ok"
end
end
end
actionpack-page_caching-1.1.0/test/log_subscriber_test.rb 0000644 0000041 0000041 00000002547 13314504367 023630 0 ustar www-data www-data require "abstract_unit"
require "active_support/log_subscriber/test_helper"
require "action_controller/log_subscriber"
module Another
class LogSubscribersController < ActionController::Base
abstract!
self.perform_caching = true
def with_page_cache
cache_page("Super soaker", "/index.html")
head :ok
end
end
end
class ACLogSubscriberTest < ActionController::TestCase
tests Another::LogSubscribersController
include ActiveSupport::LogSubscriber::TestHelper
def setup
super
@routes = ActionDispatch::Routing::RouteSet.new
@cache_path = File.expand_path("../tmp/test_cache", __FILE__)
ActionController::Base.page_cache_directory = @cache_path
@controller.cache_store = :file_store, @cache_path
ActionController::LogSubscriber.attach_to :action_controller
end
def teardown
ActiveSupport::LogSubscriber.log_subscribers.clear
FileUtils.rm_rf(@cache_path)
end
def set_logger(logger)
ActionController::Base.logger = logger
end
def test_with_page_cache
with_routing do |set|
set.draw do
get "/with_page_cache", to: "another/log_subscribers#with_page_cache"
end
get :with_page_cache
wait
logs = @logger.logged(:info)
assert_equal 3, logs.size
assert_match(/Write page/, logs[1])
assert_match(/\/index\.html/, logs[1])
end
end
end
actionpack-page_caching-1.1.0/README.md 0000644 0000041 0000041 00000007541 13314504367 017537 0 ustar www-data www-data actionpack-page_caching
=======================
Static page caching for Action Pack (removed from core in Rails 4.0).
Installation
------------
Add this line to your application's Gemfile:
``` ruby
gem "actionpack-page_caching"
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install actionpack-page_caching
Usage
-----
Page caching is an approach to caching where the entire action output is
stored as a HTML file that the web server can serve without going through
Action Pack. This is the fastest way to cache your content as opposed to going
dynamically through the process of generating the content. Unfortunately, this
incredible speed-up is only available to stateless pages where all visitors are
treated the same. Content management systems -- including weblogs and wikis --
have many pages that are a great fit for this approach, but account-based systems
where people log in and manipulate their own data are often less likely candidates.
First you need to set `page_cache_directory` in your configuration file:
``` ruby
config.action_controller.page_cache_directory = "#{Rails.root}/public/cached_pages"
```
The `page_cache_directory` setting can be used with a Proc:
``` ruby
class WeblogController < ApplicationController
self.page_cache_directory = -> { Rails.root.join("public", request.domain) }
end
```
a Symbol:
``` ruby
class WeblogController < ApplicationController
self.page_cache_directory = :domain_cache_directory
private
def domain_cache_directory
Rails.root.join("public", request.domain)
end
end
```
or a callable object:
``` ruby
class DomainCacheDirectory
def self.call(request)
Rails.root.join("public", request.domain)
end
end
class WeblogController < ApplicationController
self.page_cache_directory = DomainCacheDirectory
end
```
Specifying which actions to cache is done through the `caches_page` class method:
``` ruby
class WeblogController < ActionController::Base
caches_page :show, :new
end
```
This will generate cache files such as `weblog/show/5.html` and
`weblog/new.html`, which match the URLs used that would normally trigger
dynamic page generation. Page caching works by configuring a web server to first
check for the existence of files on disk, and to serve them directly when found,
without passing the request through to Action Pack. This is much faster than
handling the full dynamic request in the usual way.
Expiration of the cache is handled by deleting the cached file, which results
in a lazy regeneration approach where the cache is not restored before another
hit is made against it. The API for doing so mimics the options from `url_for`
and friends:
``` ruby
class WeblogController < ActionController::Base
def update
List.update(params[:list][:id], params[:list])
expire_page action: "show", id: params[:list][:id]
redirect_to action: "show", id: params[:list][:id]
end
end
```
Additionally, you can expire caches using [Sweepers](https://github.com/rails/rails-observers#action-controller-sweeper)
that act on changes in the model to determine when a cache is supposed to be expired.
Finally, configure your web server to serve these static pages when they are present
rather than the original files. See the [project wiki][1] for example configurations.
[1]: https://github.com/rails/actionpack-page_caching/wiki
Contributing
------------
1. Fork it.
2. Create your feature branch (`git checkout -b my-new-feature`).
3. Commit your changes (`git commit -am 'Add some feature'`).
4. Push to the branch (`git push origin my-new-feature`).
5. Create a new Pull Request.
Code Status
-----------
* [](https://travis-ci.org/rails/actionpack-page_caching)
* [](https://gemnasium.com/rails/actionpack-page_caching)
actionpack-page_caching-1.1.0/gemfiles/ 0000755 0000041 0000041 00000000000 13314504367 020044 5 ustar www-data www-data actionpack-page_caching-1.1.0/gemfiles/Gemfile-4-1-stable 0000644 0000041 0000041 00000000204 13314504367 023102 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "4-1-stable"
gem "mime-types", "< 3"
actionpack-page_caching-1.1.0/gemfiles/Gemfile-5-0-stable 0000644 0000041 0000041 00000000154 13314504367 023106 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "5-0-stable"
actionpack-page_caching-1.1.0/gemfiles/Gemfile-4-2-stable 0000644 0000041 0000041 00000000273 13314504367 023111 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "4-2-stable"
gem "mime-types", "< 3"
if RUBY_VERSION < "2.1"
gem "nokogiri", "< 1.7"
end
actionpack-page_caching-1.1.0/gemfiles/Gemfile-edge 0000644 0000041 0000041 00000000233 13314504367 022237 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "master"
gem "arel", github: "rails/arel", branch: "master"
actionpack-page_caching-1.1.0/gemfiles/Gemfile-4-0-stable 0000644 0000041 0000041 00000000204 13314504367 023101 0 ustar www-data www-data source "https://rubygems.org"
gemspec path: ".."
gem "rails", github: "rails/rails", branch: "4-0-stable"
gem "mime-types", "< 3"
actionpack-page_caching-1.1.0/CHANGELOG.md 0000644 0000041 0000041 00000001252 13314504367 020062 0 ustar www-data www-data ## 1.1.0 (January 23, 2017)
* Support dynamic `page_cache_directory` using a Proc, Symbol or callable
*Andrew White*
* Support instance level setting of `page_cache_directory`
*Andrew White*
* Add support for Rails 5.0 and master
*Andrew White*
## 1.0.2 (November 15, 2013)
* Fix load order problem with other gems.
*Rafael Mendonça França*
## 1.0.1 (October 24, 2013)
* Add Railtie to set `page_cache_directory` by default to `public` folder.
Fixes #5.
*Žiga Vidic*
## 1.0.0 (February 27, 2013)
* Extract Action Pack - Action Caching from Rails core.
*Francesco Rodriguez*, *Rafael Mendonça França*, *Michiel Sikkes*
actionpack-page_caching-1.1.0/.rubocop.yml 0000644 0000041 0000041 00000005070 13314504367 020525 0 ustar www-data www-data AllCops:
TargetRubyVersion: 2.2
# RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
# to ignore them, so only the ones explicitly set in this file are enabled.
DisabledByDefault: true
# Prefer &&/|| over and/or.
Style/AndOr:
Enabled: true
# Do not use braces for hash literals when they are the last argument of a
# method call.
Style/BracesAroundHashParameters:
Enabled: true
# Align `when` with `case`.
Style/CaseIndentation:
Enabled: true
# Align comments with method definitions.
Style/CommentIndentation:
Enabled: true
# No extra empty lines.
Style/EmptyLines:
Enabled: true
# In a regular class definition, no empty lines around the body.
Style/EmptyLinesAroundClassBody:
Enabled: true
# In a regular module definition, no empty lines around the body.
Style/EmptyLinesAroundModuleBody:
Enabled: true
# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
Enabled: true
# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Style/IndentationConsistency:
Enabled: true
EnforcedStyle: rails
# Two spaces, no tabs (for indentation).
Style/IndentationWidth:
Enabled: true
Style/SpaceAfterColon:
Enabled: true
Style/SpaceAfterComma:
Enabled: true
Style/SpaceAroundEqualsInParameterDefault:
Enabled: true
Style/SpaceAroundKeyword:
Enabled: true
Style/SpaceAroundOperators:
Enabled: true
Style/SpaceBeforeFirstArg:
Enabled: true
# Defining a method with parameters needs parentheses.
Style/MethodDefParentheses:
Enabled: true
# Use `foo {}` not `foo{}`.
Style/SpaceBeforeBlockBraces:
Enabled: true
# Use `foo { bar }` not `foo {bar}`.
Style/SpaceInsideBlockBraces:
Enabled: true
# Use `{ a: 1 }` not `{a:1}`.
Style/SpaceInsideHashLiteralBraces:
Enabled: true
Style/SpaceInsideParens:
Enabled: true
# Check quotes usage according to lint rule below.
Style/StringLiterals:
Enabled: true
EnforcedStyle: double_quotes
# Detect hard tabs, no hard tabs.
Style/Tab:
Enabled: true
# Blank lines should not have any spaces.
Style/TrailingBlankLines:
Enabled: true
# No trailing whitespace.
Style/TrailingWhitespace:
Enabled: true
# Use quotes for string literals when they are enough.
Style/UnneededPercentQ:
Enabled: true
# Align `end` with the matching keyword or starting expression except for
# assignments, where it should be aligned with the LHS.
Lint/EndAlignment:
Enabled: true
AlignWith: variable
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
Enabled: true
actionpack-page_caching-1.1.0/.gitignore 0000644 0000041 0000041 00000000072 13314504367 020240 0 ustar www-data www-data .ruby-version
Gemfile.lock
gemfiles/*.lock
pkg/*
test/tmp
actionpack-page_caching-1.1.0/.codeclimate.yml 0000644 0000041 0000041 00000000105 13314504367 021317 0 ustar www-data www-data engines:
rubocop:
enabled: true
ratings:
paths:
- "**.rb"
actionpack-page_caching-1.1.0/Rakefile 0000644 0000041 0000041 00000000311 13314504367 017711 0 ustar www-data www-data #!/usr/bin/env rake
require "bundler/gem_tasks"
require "rake/testtask"
Rake::TestTask.new do |t|
t.libs = ["test"]
t.pattern = "test/**/*_test.rb"
t.ruby_opts = ["-w"]
end
task default: :test
actionpack-page_caching-1.1.0/lib/ 0000755 0000041 0000041 00000000000 13314504367 017017 5 ustar www-data www-data actionpack-page_caching-1.1.0/lib/actionpack/ 0000755 0000041 0000041 00000000000 13314504367 021133 5 ustar www-data www-data actionpack-page_caching-1.1.0/lib/actionpack/page_caching/ 0000755 0000041 0000041 00000000000 13314504367 023523 5 ustar www-data www-data actionpack-page_caching-1.1.0/lib/actionpack/page_caching/railtie.rb 0000644 0000041 0000041 00000000767 13314504367 025513 0 ustar www-data www-data require "rails/railtie"
module ActionPack
module PageCaching
class Railtie < Rails::Railtie
initializer "action_pack.page_caching" do
ActiveSupport.on_load(:action_controller) do
require "action_controller/page_caching"
end
end
initializer "action_pack.page_caching.set_config", before: "action_controller.set_configs" do |app|
app.config.action_controller.page_cache_directory ||= app.config.paths["public"].first
end
end
end
end
actionpack-page_caching-1.1.0/lib/actionpack/page_caching.rb 0000644 0000041 0000041 00000000052 13314504367 024045 0 ustar www-data www-data require "actionpack/page_caching/railtie"
actionpack-page_caching-1.1.0/lib/action_controller/ 0000755 0000041 0000041 00000000000 13314504367 022537 5 ustar www-data www-data actionpack-page_caching-1.1.0/lib/action_controller/caching/ 0000755 0000041 0000041 00000000000 13314504367 024133 5 ustar www-data www-data actionpack-page_caching-1.1.0/lib/action_controller/caching/pages.rb 0000644 0000041 0000041 00000024774 13314504367 025575 0 ustar www-data www-data require "fileutils"
require "uri"
require "active_support/core_ext/class/attribute_accessors"
require "active_support/core_ext/string/strip"
module ActionController
module Caching
# Page caching is an approach to caching where the entire action output of is
# stored as a HTML file that the web server can serve without going through
# Action Pack. This is the fastest way to cache your content as opposed to going
# dynamically through the process of generating the content. Unfortunately, this
# incredible speed-up is only available to stateless pages where all visitors are
# treated the same. Content management systems -- including weblogs and wikis --
# have many pages that are a great fit for this approach, but account-based systems
# where people log in and manipulate their own data are often less likely candidates.
#
# Specifying which actions to cache is done through the +caches_page+ class method:
#
# class WeblogController < ActionController::Base
# caches_page :show, :new
# end
#
# This will generate cache files such as weblog/show/5.html and
# weblog/new.html, which match the URLs used that would normally trigger
# dynamic page generation. Page caching works by configuring a web server to first
# check for the existence of files on disk, and to serve them directly when found,
# without passing the request through to Action Pack. This is much faster than
# handling the full dynamic request in the usual way.
#
# Expiration of the cache is handled by deleting the cached file, which results
# in a lazy regeneration approach where the cache is not restored before another
# hit is made against it. The API for doing so mimics the options from +url_for+ and friends:
#
# class WeblogController < ActionController::Base
# def update
# List.update(params[:list][:id], params[:list])
# expire_page action: "show", id: params[:list][:id]
# redirect_to action: "show", id: params[:list][:id]
# end
# end
#
# Additionally, you can expire caches using Sweepers that act on changes in
# the model to determine when a cache is supposed to be expired.
module Pages
extend ActiveSupport::Concern
included do
# The cache directory should be the document root for the web server and is
# set using Base.page_cache_directory = "/document/root". For Rails,
# this directory has already been set to Rails.public_path (which is usually
# set to Rails.root + "/public"). Changing this setting can be useful
# to avoid naming conflicts with files in public/, but doing so will
# likely require configuring your web server to look in the new location for
# cached files.
class_attribute :page_cache_directory
self.page_cache_directory ||= ""
# The compression used for gzip. If +false+ (default), the page is not compressed.
# If can be a symbol showing the ZLib compression method, for example, :best_compression
# or :best_speed or an integer configuring the compression level.
class_attribute :page_cache_compression
self.page_cache_compression ||= false
end
class PageCache #:nodoc:
def initialize(cache_directory, default_extension, controller = nil)
@cache_directory = cache_directory
@default_extension = default_extension
@controller = controller
end
def expire(path)
instrument :expire_page, path do
delete(cache_path(path))
end
end
def cache(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
instrument :write_page, path do
write(content, cache_path(path, extension), gzip)
end
end
private
def cache_directory
case @cache_directory
when Proc
handle_proc_cache_directory
when Symbol
handle_symbol_cache_directory
else
handle_default_cache_directory
end
end
def handle_proc_cache_directory
if @controller
@controller.instance_exec(&@cache_directory)
else
raise_runtime_error
end
end
def handle_symbol_cache_directory
if @controller
@controller.send(@cache_directory)
else
raise_runtime_error
end
end
def handle_callable_cache_directory
if @controller
@cache_directory.call(@controller.request)
else
raise_runtime_error
end
end
def handle_default_cache_directory
if @cache_directory.respond_to?(:call)
handle_callable_cache_directory
else
@cache_directory.to_s
end
end
def raise_runtime_error
raise RuntimeError, <<-MSG.strip_heredoc
Dynamic page_cache_directory used with class-level cache_page method
You have specified either a Proc, Symbol or callable object for page_cache_directory
which needs to be executed within the context of a request. If you need to call the
cache_page method from a class-level context then set the page_cache_directory to a
static value and override the setting at the instance-level using before_action.
MSG
end
def default_extension
@default_extension
end
def cache_file(path, extension)
if path.empty? || path == "/"
name = "/index"
else
name = URI.parser.unescape(path.chomp("/"))
end
if File.extname(name).empty?
name + (extension || default_extension)
else
name
end
end
def cache_path(path, extension = nil)
File.join(cache_directory, cache_file(path, extension))
end
def delete(path)
File.delete(path) if File.exist?(path)
File.delete(path + ".gz") if File.exist?(path + ".gz")
end
def write(content, path, gzip)
FileUtils.makedirs(File.dirname(path))
File.open(path, "wb+") { |f| f.write(content) }
if gzip
Zlib::GzipWriter.open(path + ".gz", gzip) { |f| f.write(content) }
end
end
def instrument(name, path)
ActiveSupport::Notifications.instrument("#{name}.action_controller", path: path) { yield }
end
end
module ClassMethods
# Expires the page that was cached with the +path+ as a key.
#
# expire_page "/lists/show"
def expire_page(path)
if perform_caching
page_cache.expire(path)
end
end
# Manually cache the +content+ in the key determined by +path+.
#
# cache_page "I'm the cached content", "/lists/show"
def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
if perform_caching
page_cache.cache(content, path, extension, gzip)
end
end
# Caches the +actions+ using the page-caching approach that'll store
# the cache in a path within the +page_cache_directory+ that
# matches the triggering url.
#
# You can also pass a :gzip option to override the class configuration one.
#
# # cache the index action
# caches_page :index
#
# # cache the index action except for JSON requests
# caches_page :index, if: Proc.new { !request.format.json? }
#
# # don't gzip images
# caches_page :image, gzip: false
def caches_page(*actions)
if perform_caching
options = actions.extract_options!
gzip_level = options.fetch(:gzip, page_cache_compression)
gzip_level = \
case gzip_level
when Symbol
Zlib.const_get(gzip_level.upcase)
when Integer
gzip_level
when false
nil
else
Zlib::BEST_COMPRESSION
end
after_action({ only: actions }.merge(options)) do |c|
c.cache_page(nil, nil, gzip_level)
end
end
end
private
def page_cache
PageCache.new(page_cache_directory, default_static_extension)
end
end
# Expires the page that was cached with the +options+ as a key.
#
# expire_page controller: "lists", action: "show"
def expire_page(options = {})
if perform_caching?
case options
when Hash
case options[:action]
when Array
options[:action].each { |action| expire_page(options.merge(action: action)) }
else
page_cache.expire(url_for(options.merge(only_path: true)))
end
else
page_cache.expire(options)
end
end
end
# Manually cache the +content+ in the key determined by +options+. If no content is provided,
# the contents of response.body is used. If no options are provided, the url of the current
# request being handled is used.
#
# cache_page "I'm the cached content", controller: "lists", action: "show"
def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION)
if perform_caching? && caching_allowed?
path = \
case options
when Hash
url_for(options.merge(only_path: true, format: params[:format]))
when String
options
else
request.path
end
if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present?
extension = ".#{type_symbol}"
end
page_cache.cache(content || response.body, path, extension, gzip)
end
end
def caching_allowed?
(request.get? || request.head?) && response.status == 200
end
def perform_caching?
self.class.perform_caching
end
private
def page_cache
PageCache.new(page_cache_directory, default_static_extension, self)
end
end
end
end
actionpack-page_caching-1.1.0/lib/action_controller/page_caching.rb 0000644 0000041 0000041 00000000356 13314504367 025460 0 ustar www-data www-data require "action_controller/caching/pages"
module ActionController
module Caching
eager_autoload do
autoload :Pages
end
include Pages
end
end
ActionController::Base.send(:include, ActionController::Caching::Pages)
actionpack-page_caching-1.1.0/Gemfile 0000644 0000041 0000041 00000000064 13314504367 017544 0 ustar www-data www-data source "https://rubygems.org"
gemspec
gem "rails"
actionpack-page_caching-1.1.0/actionpack-page_caching.gemspec 0000644 0000041 0000041 00000001562 13314504367 024324 0 ustar www-data www-data Gem::Specification.new do |gem|
gem.name = "actionpack-page_caching"
gem.version = "1.1.0"
gem.author = "David Heinemeier Hansson"
gem.email = "david@loudthinking.com"
gem.description = "Static page caching for Action Pack (removed from core in Rails 4.0)"
gem.summary = "Static page caching for Action Pack (removed from core in Rails 4.0)"
gem.homepage = "https://github.com/rails/actionpack-page_caching"
gem.license = "MIT"
gem.required_ruby_version = '>= 1.9.3'
gem.files = `git ls-files`.split($/)
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = ["lib"]
gem.license = 'MIT'
gem.add_dependency "actionpack", ">= 4.0.0", "< 6"
gem.add_development_dependency "mocha"
end
actionpack-page_caching-1.1.0/LICENSE.txt 0000644 0000041 0000041 00000002071 13314504367 020074 0 ustar www-data www-data Copyright (c) 2012 David Heinemeier Hansson
MIT License
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.