super_cache 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +6 -0
- data/Gemfile +5 -1
- data/README.md +9 -1
- data/Rakefile +23 -0
- data/lib/super_cache/dog_pile_filter.rb +100 -0
- data/lib/super_cache/lock.rb +44 -0
- data/lib/super_cache/simple_filter.rb +48 -0
- data/lib/super_cache/version.rb +1 -1
- data/lib/super_cache.rb +13 -53
- data/super_cache.gemspec +1 -1
- data/test/dog_pile_filter_test.rb +37 -0
- data/test/locales/en.yml +2 -0
- data/test/my_controller.rb +10 -0
- data/test/super_cache_test.rb +38 -0
- data/test/test_helper.rb +47 -0
- metadata +54 -21
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/ShiningRay/super_cache.png?branch=master)](https://travis-ci.org/ShiningRay/super_cache)
|
2
|
+
|
1
3
|
# SuperCache
|
2
4
|
|
3
5
|
SuperCache for rails is a caching middleware inspired by the "SuperCache" plugin
|
@@ -25,7 +27,8 @@ Just call `super_caches_page` inside your controller with the action names to be
|
|
25
27
|
class MyController < ApplicationController
|
26
28
|
super_caches_page :index
|
27
29
|
def index
|
28
|
-
# action to be
|
30
|
+
# action to be cached
|
31
|
+
@expires_in = 1.hour
|
29
32
|
edn
|
30
33
|
end
|
31
34
|
```
|
@@ -33,6 +36,11 @@ end
|
|
33
36
|
Super_cache will store the response body into `Rails.cache`. The next time requesting
|
34
37
|
that action will get the same result.
|
35
38
|
|
39
|
+
There are several instance variables can be used for controlling the cache:
|
40
|
+
|
41
|
+
* `@cache_path` control the cache key, defaults to the request uri.
|
42
|
+
* `@expires_in` control the expiration time, now defaults to 600 sec.
|
43
|
+
|
36
44
|
## Contributing
|
37
45
|
|
38
46
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -1 +1,24 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require "bundler/gem_tasks"
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rdoc/task'
|
6
|
+
|
7
|
+
Rake::TestTask.new do |t|
|
8
|
+
t.libs << 'test'
|
9
|
+
t.pattern = 'test/**/*_test.rb'
|
10
|
+
t.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Run tests"
|
14
|
+
task :default => :test
|
15
|
+
|
16
|
+
desc 'Generate documentation for InheritedResources.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'InheritedResources'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README.rdoc')
|
22
|
+
rdoc.rdoc_files.include('MIT-LICENSE')
|
23
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
24
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module SuperCache
|
2
|
+
class DogPileFilter
|
3
|
+
attr_accessor :options
|
4
|
+
def initialize(options={})
|
5
|
+
self.options = options
|
6
|
+
end
|
7
|
+
# 1. check the expiration info of target key
|
8
|
+
# 2. if target key is expired, add a lock against target key
|
9
|
+
# 2.1 if not expired, return the cache
|
10
|
+
# 3.1 if lock successfully, then continue to action
|
11
|
+
# 3.2 if lock failed, then obtain target key
|
12
|
+
# 3.2.1 if target key is missing, then
|
13
|
+
# 3.2.1.1 wait for N sec to check if the cache is generated
|
14
|
+
# 3.2.1.1.1 if timeout, go to action
|
15
|
+
# 3.2.2 target key is not missing, return the cache
|
16
|
+
# 3.3 go to the action and obtain response body
|
17
|
+
# 3.4 store the response body to the target key and set the expiration with 2x longer
|
18
|
+
# 3.5 store the expireation info of target key
|
19
|
+
def filter(controller, action=nil, &block)
|
20
|
+
action ||= block
|
21
|
+
return action.call unless controller.perform_caching
|
22
|
+
options = self.options.dup
|
23
|
+
|
24
|
+
options[:controller] = controller
|
25
|
+
options[:action] = action || block
|
26
|
+
options[:cache_path] ||= weird_cache_path(options)
|
27
|
+
options[:flag_key] = "expires_at:#{options[:cache_path]}"
|
28
|
+
options[:expires_in] ||= 600
|
29
|
+
options[:content] = nil
|
30
|
+
|
31
|
+
if Rails.cache.read(options[:flag_key], :raw => true)
|
32
|
+
check_cache(options)
|
33
|
+
else
|
34
|
+
cache_expired(options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
def write_cache(options)
|
40
|
+
response = options[:controller].response
|
41
|
+
return if response.status.to_i != 200
|
42
|
+
expires_in = options[:expires_in].to_i
|
43
|
+
Rails.cache.write(options[:flag_key], expires_in, :raw => true, :expires_in => expires_in)
|
44
|
+
Rails.cache.write(options[:cache_path], response.body, :raw => true, :expires_in => expires_in * 2)
|
45
|
+
end
|
46
|
+
|
47
|
+
def check_cache(options)
|
48
|
+
if options[:content] = Rails.cache.read(options[:cache_path], :raw => true) and options[:content].size > 0
|
49
|
+
cache_hit(options)
|
50
|
+
else
|
51
|
+
cache_miss(options)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def cache_hit(options)
|
56
|
+
controller = options[:controller]
|
57
|
+
request = controller.request
|
58
|
+
headers = controller.headers
|
59
|
+
content = options[:content]
|
60
|
+
Rails.logger.info "Hit #{options[:cache_path]}"
|
61
|
+
headers['Content-Length'] ||= content.size.to_s
|
62
|
+
headers['Content-Type'] ||= request.format.to_s.strip unless request.format == :all
|
63
|
+
controller.send :render, :text => content, :content_type => 'text/html'
|
64
|
+
end
|
65
|
+
|
66
|
+
#when the target cache is not established yet
|
67
|
+
def cache_miss(options)
|
68
|
+
Lock.synchronize(options[:cache_path]) do
|
69
|
+
options[:action].call
|
70
|
+
write_cache(options)
|
71
|
+
end
|
72
|
+
rescue Lock::MaxRetriesError
|
73
|
+
options[:action].call
|
74
|
+
write_cache(options)
|
75
|
+
end
|
76
|
+
|
77
|
+
# the cache is expired
|
78
|
+
def cache_expired(options)
|
79
|
+
if Lock.acquire_lock(options[:cache_path])
|
80
|
+
options[:action].call
|
81
|
+
write_cache(options)
|
82
|
+
else
|
83
|
+
# haven't acquired lock, return stale cache
|
84
|
+
check_cache(options)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def weird_cache_path(options)
|
89
|
+
controller = options[:controller]
|
90
|
+
request = controller.request
|
91
|
+
path = File.join request.host, request.path
|
92
|
+
q = request.query_string
|
93
|
+
request.format ||= :html
|
94
|
+
format = request.format.to_sym
|
95
|
+
path = "#{path}.#{format}" if format != :html and format != :all and controller.params[:format].blank?
|
96
|
+
path = "#{path}?#{q}" if !q.empty? && q =~ /=/
|
97
|
+
path
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module SuperCache
|
2
|
+
class Lock
|
3
|
+
class MaxRetriesError < RuntimeError; end
|
4
|
+
|
5
|
+
DEFAULT_RETRY = 5
|
6
|
+
DEFAULT_EXPIRY = 30
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def synchronize(key, lock_expiry = DEFAULT_EXPIRY, retries = DEFAULT_RETRY)
|
10
|
+
if recursive_lock?(key)
|
11
|
+
yield
|
12
|
+
else
|
13
|
+
begin
|
14
|
+
retries.times do |count|
|
15
|
+
return yield if acquire_lock(key, lock_expiry)
|
16
|
+
raise MaxRetriesError if count == retries - 1
|
17
|
+
exponential_sleep(count) unless count == retries - 1
|
18
|
+
end
|
19
|
+
raise MaxRetriesError, "Couldn't acquire memcache lock for: #{key}"
|
20
|
+
ensure
|
21
|
+
release_lock(key)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def acquire_lock(key, lock_expiry = DEFAULT_EXPIRY)
|
27
|
+
Rails.cache.write("lock/#{key}", Process.pid, :unless_exist => true, :expires_in => lock_expiry)
|
28
|
+
end
|
29
|
+
|
30
|
+
def release_lock(key)
|
31
|
+
Rails.cache.delete("lock/#{key}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def exponential_sleep(count)
|
35
|
+
Benchmark::measure { sleep((2**count) / 5.0) }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def recursive_lock?(key)
|
40
|
+
Rails.cache.read("lock/#{key}") == Process.pid
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SuperCache
|
2
|
+
class SimpleFilter
|
3
|
+
def initialize(options={})
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
def filter(controller)
|
8
|
+
return yield unless controller.perform_caching
|
9
|
+
@cache_path = controller.instance_variable_get('@caches_path') || weird_cache_path(controller)
|
10
|
+
request = controller.request
|
11
|
+
response = controller.response
|
12
|
+
headers = response.headers
|
13
|
+
|
14
|
+
if content = Rails.cache.read(@cache_path, :raw => true)
|
15
|
+
return yield if content.size <= 0
|
16
|
+
Rails.logger.debug "Hit #{@cache_path}"
|
17
|
+
headers['Content-Length'] ||= content.size.to_s
|
18
|
+
headers['Content-Type'] ||= request.format.to_s.strip unless request.format == :all
|
19
|
+
controller.send :render, :text => content, :content_type => 'text/html'
|
20
|
+
return false
|
21
|
+
else
|
22
|
+
yield
|
23
|
+
body = response.body.to_s
|
24
|
+
return if controller.instance_variable_get('@no_cache') || body.size == 0 || response.status.to_i != 200
|
25
|
+
@expires_in = controller.instance_variable_get('@expires_in') || 600
|
26
|
+
Rails.logger.debug("Write #{@cache_path}")
|
27
|
+
Rails.cache.write(@cache_path, body, :raw => true, :expires_in => @expires_in.to_i)
|
28
|
+
end
|
29
|
+
rescue ArgumentError => e
|
30
|
+
@no_cache = true
|
31
|
+
Rails.logger.info e.to_s
|
32
|
+
Rails.logger.debug {e.backtrace}
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def weird_cache_path(controller)
|
37
|
+
controller.instance_eval do
|
38
|
+
path = File.join request.host, request.path
|
39
|
+
q = request.query_string
|
40
|
+
request.format ||= :html
|
41
|
+
format = request.format.to_sym
|
42
|
+
path = "#{path}.#{format}" if format != :html and format != :all and params[:format].blank?
|
43
|
+
path = "#{path}?#{q}" if !q.empty? && q =~ /=/
|
44
|
+
path
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/super_cache/version.rb
CHANGED
data/lib/super_cache.rb
CHANGED
@@ -4,7 +4,12 @@ require 'fileutils'
|
|
4
4
|
# for static-caching the generated html pages
|
5
5
|
|
6
6
|
module SuperCache
|
7
|
+
autoload :Lock, 'super_cache/lock'
|
8
|
+
autoload :DogPileFilter, 'super_cache/dog_pile_filter'
|
9
|
+
autoload :SimpleFilter, 'super_cache/simple_filter'
|
10
|
+
|
7
11
|
def self.included(base)
|
12
|
+
base.class_attribute :cache_filter
|
8
13
|
base.extend(ClassMethods)
|
9
14
|
end
|
10
15
|
|
@@ -13,66 +18,21 @@ module SuperCache
|
|
13
18
|
return unless perform_caching
|
14
19
|
options = pages.extract_options!
|
15
20
|
options[:only] = (Array(options[:only]) + pages).flatten
|
16
|
-
|
17
|
-
|
21
|
+
self.cache_filter = if options.delete(:lock)
|
22
|
+
DogPileFilter.new
|
23
|
+
else
|
24
|
+
SimpleFilter.new
|
25
|
+
end
|
26
|
+
around_filter self.cache_filter, options
|
18
27
|
end
|
19
28
|
|
20
29
|
def skip_super_caches_page(*pages)
|
30
|
+
return unless self.cache_filter
|
21
31
|
options = pages.extract_options!
|
22
32
|
options[:only] = (Array(options[:only]) + pages).flatten
|
23
|
-
|
24
|
-
skip_after_filter :weird_cache, options
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def check_weird_cache
|
29
|
-
return unless perform_caching
|
30
|
-
@cache_path ||= weird_cache_path
|
31
|
-
|
32
|
-
if content = Rails.cache.read(@cache_path, :raw => true)
|
33
|
-
return if content.size <= 1
|
34
|
-
logger.info "Hit #{@cache_path}"
|
35
|
-
|
36
|
-
headers['Content-Length'] ||= content.size.to_s
|
37
|
-
headers['Content-Type'] ||= request.format.to_s.strip unless request.format == :all
|
38
|
-
render :text => content, :content_type => 'text/html'
|
39
|
-
return false
|
33
|
+
skip_around_filter self.cache_filter, options
|
40
34
|
end
|
41
|
-
rescue ArgumentError => e
|
42
|
-
@no_cache = true
|
43
|
-
logger.info e.to_s
|
44
|
-
logger.debug {e.backtrace}
|
45
35
|
end
|
46
|
-
|
47
|
-
def weird_cache
|
48
|
-
return if @no_cache
|
49
|
-
return unless perform_caching
|
50
|
-
return if request.format.to_sym == :mobile
|
51
|
-
@cache_path ||= weird_cache_path
|
52
|
-
@expires_in ||= 600
|
53
|
-
return if response.body.size <= 1
|
54
|
-
return if response.respond_to?(:status) and response.status.to_i != 200
|
55
|
-
#benchmark "Super Cached page: #{@cache_path}" do
|
56
|
-
# @cache_subject = Array(@cache_subject)
|
57
|
-
# @cache_subject.compact.flatten.select{|s|s.respond_to?(:append_cached_key)}.each do |subject|
|
58
|
-
# subject.append_cached_key @cache_path
|
59
|
-
# end
|
60
|
-
Rails.cache.write(@cache_path, response.body, :raw => true, :expires_in => @expires_in.to_i)
|
61
|
-
#end
|
62
|
-
end
|
63
|
-
|
64
|
-
protected :check_weird_cache
|
65
|
-
protected :weird_cache
|
66
|
-
private
|
67
|
-
def weird_cache_path
|
68
|
-
path = File.join request.host, request.path
|
69
|
-
q = request.query_string
|
70
|
-
request.format ||= :html
|
71
|
-
format = request.format.to_sym
|
72
|
-
path = "#{path}.#{format}" if format != :html and format != :all and params[:format].blank?
|
73
|
-
path = "#{path}?#{q}" #if !q.empty? && q =~ /=/
|
74
|
-
path
|
75
|
-
end
|
76
36
|
end
|
77
37
|
|
78
38
|
ActionController::Base.__send__ :include, SuperCache
|
data/super_cache.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.authors = ["ShiningRay"]
|
10
10
|
gem.email = ["tsowly@hotmail.com"]
|
11
11
|
gem.description = %q{A simple caching middleware for rails}
|
12
|
-
gem.summary = %q{A simple caching middleware for rails}
|
12
|
+
gem.summary = %q{A simple caching middleware for rails, with solution for dog-pile effect}
|
13
13
|
gem.homepage = "https://github.com/shiningray/super_cache"
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path('test_helper', File.dirname(__FILE__))
|
2
|
+
require File.expand_path('my_controller', File.dirname(__FILE__))
|
3
|
+
|
4
|
+
class MyController < ApplicationController
|
5
|
+
around_filter do |controller, action |
|
6
|
+
DogPileFilter.new.filter(controller, action)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class DogPileFilterTest < ActionController::TestCase
|
11
|
+
tests MyController
|
12
|
+
setup do
|
13
|
+
MyController.counter = 0
|
14
|
+
end
|
15
|
+
test "should get index successfully and store cache and then get the cached version" do
|
16
|
+
get :index
|
17
|
+
assert_response :success
|
18
|
+
assert_equal '0', @response.body.strip
|
19
|
+
assert_equal '0', Rails.cache.read('test.host/my', :raw => true)
|
20
|
+
get :index
|
21
|
+
assert_response :success
|
22
|
+
assert_equal '0', @response.body.strip
|
23
|
+
end
|
24
|
+
test "should not cache when performing cache is disabled" do
|
25
|
+
ActionController::Base.perform_caching=false
|
26
|
+
get :index
|
27
|
+
assert_response :success
|
28
|
+
assert_equal '0', @response.body.strip
|
29
|
+
assert_nil Rails.cache.read('test.host/my', :raw => true)
|
30
|
+
ActionController::Base.perform_caching=true
|
31
|
+
end
|
32
|
+
test "should not cache when response is redirected" do
|
33
|
+
get :redirect
|
34
|
+
assert_response :redirect
|
35
|
+
assert_nil Rails.cache.read('test.host/redirect', :raw => true)
|
36
|
+
end
|
37
|
+
end
|
data/test/locales/en.yml
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path('test_helper', File.dirname(__FILE__))
|
2
|
+
require File.expand_path('my_controller', File.dirname(__FILE__))
|
3
|
+
class MyController
|
4
|
+
super_caches_page :index
|
5
|
+
end
|
6
|
+
class SuperCacheTest < ActionController::TestCase
|
7
|
+
tests MyController
|
8
|
+
setup do
|
9
|
+
MyController.counter = 0
|
10
|
+
end
|
11
|
+
test "should get index successfully and store cache and then get the cached version" do
|
12
|
+
get :index
|
13
|
+
assert_response :success
|
14
|
+
assert_equal '0', @response.body.strip
|
15
|
+
assert_equal '0', Rails.cache.read('test.host/my', :raw => true)
|
16
|
+
get :index
|
17
|
+
assert_response :success
|
18
|
+
assert_equal '0', @response.body.strip
|
19
|
+
Rails.cache.delete('test.host/my')
|
20
|
+
get :index
|
21
|
+
assert_response :success
|
22
|
+
assert_equal '1', @response.body.strip
|
23
|
+
assert_equal '1', Rails.cache.read('test.host/my', :raw => true)
|
24
|
+
end
|
25
|
+
test "should not cache when performing cache is disabled" do
|
26
|
+
ActionController::Base.perform_caching=false
|
27
|
+
get :index
|
28
|
+
assert_response :success
|
29
|
+
assert_equal '0', @response.body.strip
|
30
|
+
assert_nil Rails.cache.read('test.host/my', :raw => true)
|
31
|
+
ActionController::Base.perform_caching=true
|
32
|
+
end
|
33
|
+
test "should not cache when response is redirected" do
|
34
|
+
get :redirect
|
35
|
+
assert_response :redirect
|
36
|
+
assert_nil Rails.cache.read('test.host/redirect', :raw => true)
|
37
|
+
end
|
38
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
#require 'mocha/setup'
|
8
|
+
|
9
|
+
ENV["RAILS_ENV"] = "test"
|
10
|
+
RAILS_ROOT = "anywhere"
|
11
|
+
|
12
|
+
require "active_support"
|
13
|
+
require "active_model"
|
14
|
+
require "action_controller"
|
15
|
+
|
16
|
+
I18n.load_path << File.join(File.dirname(__FILE__), 'locales', 'en.yml')
|
17
|
+
I18n.reload!
|
18
|
+
|
19
|
+
class ApplicationController < ActionController::Base; end
|
20
|
+
class Rails
|
21
|
+
cattr_accessor :cache, :logger
|
22
|
+
@@cache = ActiveSupport::Cache::MemoryStore.new
|
23
|
+
@@logger = Logger.new($stderr)
|
24
|
+
end
|
25
|
+
# Add IR to load path and load the main file
|
26
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
27
|
+
require 'super_cache'
|
28
|
+
|
29
|
+
ActionController::Base.view_paths = File.join(File.dirname(__FILE__), 'views')
|
30
|
+
ActionController::Base.perform_caching=true
|
31
|
+
SuperCache::Routes = ActionDispatch::Routing::RouteSet.new
|
32
|
+
SuperCache::Routes.draw do
|
33
|
+
match ':controller(/:action(/:id))'
|
34
|
+
match ':controller(/:action)'
|
35
|
+
resources 'posts'
|
36
|
+
root :to => 'posts#index'
|
37
|
+
end
|
38
|
+
|
39
|
+
ActionController::Base.send :include, SuperCache::Routes.url_helpers
|
40
|
+
|
41
|
+
class ActionController::TestCase
|
42
|
+
setup do
|
43
|
+
@routes = SuperCache::Routes
|
44
|
+
@request.host = 'test.host'
|
45
|
+
Rails.cache.clear
|
46
|
+
end
|
47
|
+
end
|
metadata
CHANGED
@@ -1,53 +1,86 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: super_cache
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- ShiningRay
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
17
|
+
|
18
|
+
date: 2013-03-08 00:00:00 Z
|
13
19
|
dependencies: []
|
20
|
+
|
14
21
|
description: A simple caching middleware for rails
|
15
|
-
email:
|
22
|
+
email:
|
16
23
|
- tsowly@hotmail.com
|
17
24
|
executables: []
|
25
|
+
|
18
26
|
extensions: []
|
27
|
+
|
19
28
|
extra_rdoc_files: []
|
20
|
-
|
29
|
+
|
30
|
+
files:
|
21
31
|
- .gitignore
|
32
|
+
- .travis.yml
|
22
33
|
- Gemfile
|
23
34
|
- LICENSE.txt
|
24
35
|
- README.md
|
25
36
|
- Rakefile
|
26
37
|
- lib/super_cache.rb
|
38
|
+
- lib/super_cache/dog_pile_filter.rb
|
39
|
+
- lib/super_cache/lock.rb
|
40
|
+
- lib/super_cache/simple_filter.rb
|
27
41
|
- lib/super_cache/version.rb
|
28
42
|
- super_cache.gemspec
|
43
|
+
- test/dog_pile_filter_test.rb
|
44
|
+
- test/locales/en.yml
|
45
|
+
- test/my_controller.rb
|
46
|
+
- test/super_cache_test.rb
|
47
|
+
- test/test_helper.rb
|
29
48
|
homepage: https://github.com/shiningray/super_cache
|
30
49
|
licenses: []
|
50
|
+
|
31
51
|
post_install_message:
|
32
52
|
rdoc_options: []
|
33
|
-
|
53
|
+
|
54
|
+
require_paths:
|
34
55
|
- lib
|
35
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
57
|
none: false
|
37
|
-
requirements:
|
38
|
-
- -
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
|
41
|
-
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
66
|
none: false
|
43
|
-
requirements:
|
44
|
-
- -
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
47
74
|
requirements: []
|
75
|
+
|
48
76
|
rubyforge_project:
|
49
|
-
rubygems_version: 1.8.
|
77
|
+
rubygems_version: 1.8.16
|
50
78
|
signing_key:
|
51
79
|
specification_version: 3
|
52
|
-
summary: A simple caching middleware for rails
|
53
|
-
test_files:
|
80
|
+
summary: A simple caching middleware for rails, with solution for dog-pile effect
|
81
|
+
test_files:
|
82
|
+
- test/dog_pile_filter_test.rb
|
83
|
+
- test/locales/en.yml
|
84
|
+
- test/my_controller.rb
|
85
|
+
- test/super_cache_test.rb
|
86
|
+
- test/test_helper.rb
|