super_cache 0.0.1 → 0.0.2
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/.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
|
+
[](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
|