that_old_cache 0.0.1
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/README.md +16 -0
- data/Rakefile +34 -0
- data/VERSION +1 -0
- data/lib/that_old_cache.rb +1 -0
- data/lib/that_old_cache/ttled_mem_cache_store.rb +60 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/that_old_cache_spec.rb +79 -0
- metadata +95 -0
data/README.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
That Old Cache
|
2
|
+
==============
|
3
|
+
|
4
|
+
Description
|
5
|
+
-----------
|
6
|
+
|
7
|
+
Getting sick of memcached just kicking your stuff out of memory in Rails? Maybe you've thought
|
8
|
+
*"Gee, wouldn't it be nice to just serve the old cache while I refresh it."* Well, look no
|
9
|
+
further! **That Old Cache** is a Rubygem that does just that, giving you the ability to fire
|
10
|
+
off a process to refresh the cache once it expires, without the annoying "initial load" problem
|
11
|
+
that affects your users.
|
12
|
+
|
13
|
+
Authors
|
14
|
+
-------
|
15
|
+
|
16
|
+
Joey Robert ([http://joeyrobert.org/](http://joeyrobert.org/))
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'spec/rake/spectask'
|
5
|
+
|
6
|
+
desc 'Default: run specs.'
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
desc 'Run the specs'
|
10
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
11
|
+
t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
|
12
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
13
|
+
end
|
14
|
+
|
15
|
+
PKG_FILES = FileList['lib/**/*', 'spec/*', 'Rakefile', 'README.md', 'VERSION']
|
16
|
+
|
17
|
+
spec = Gem::Specification.new do |s|
|
18
|
+
s.name = "that_old_cache"
|
19
|
+
s.version = "0.0.1"
|
20
|
+
s.author = "Joey Robert"
|
21
|
+
s.email = "joey@joeyrobert.org"
|
22
|
+
s.homepage = "http://github.com/joeyrobert/that_old_cache"
|
23
|
+
s.platform = Gem::Platform::RUBY
|
24
|
+
s.summary = "Serve old caches from memcached while you update in Rails"
|
25
|
+
s.description = "An ActiveSupport MemCache store that requires serves keys until they are explicitly overwritten"
|
26
|
+
s.files = PKG_FILES.to_a
|
27
|
+
s.require_path = "lib"
|
28
|
+
s.has_rdoc = false
|
29
|
+
s.add_dependency "yajl-ruby", ">= 0.7.x"
|
30
|
+
s.add_dependency "activesupport", ">= 2.3.x"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Turn this plugin into a gem.'
|
34
|
+
Rake::GemPackageTask.new(spec) { |pkg| pkg.gem_spec = spec }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'that_old_cache/ttled_mem_cache_store'
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'yajl'
|
3
|
+
|
4
|
+
module ActiveSupport
|
5
|
+
module Cache
|
6
|
+
class TTLedMemCacheStore < MemCacheStore
|
7
|
+
# Adds the following option:
|
8
|
+
# :valid_for => number of seconds from now that the cache with "expire"
|
9
|
+
# :raw is not supported with :valid_for
|
10
|
+
def write(key, value, options = nil)
|
11
|
+
if options && options[:valid_for]
|
12
|
+
options.delete(:raw)
|
13
|
+
super(key, encode({ :data => value, :ttl => time_for(options.delete(:valid_for)) }), options)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Adds the following option:
|
20
|
+
# :valid_for => true
|
21
|
+
# :raw is not supported with :valid_for
|
22
|
+
def read(key, options = nil)
|
23
|
+
if options && options.delete(:valid_for)
|
24
|
+
options.delete(:raw)
|
25
|
+
parse(super)[:data] rescue nil
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# only works for TTLed keys
|
32
|
+
def expired?(key)
|
33
|
+
begin
|
34
|
+
ttl(key) < Time.now.to_i
|
35
|
+
rescue NoMethodError
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# only works for TTLed keys
|
41
|
+
def ttl(key)
|
42
|
+
parse(read(key))[:ttl] rescue nil
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def time_for(seconds)
|
48
|
+
Time.now.to_i + seconds.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse(val)
|
52
|
+
Yajl::Parser.new(:symbolize_keys => true).parse(val)
|
53
|
+
end
|
54
|
+
|
55
|
+
def encode(val)
|
56
|
+
Yajl::Encoder.encode(val)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe ActiveSupport::Cache::TTLedMemCacheStore do
|
4
|
+
# Since this is about interface to a cache, I think it makes sense to run a
|
5
|
+
# real cache in this case and not mock/stub it out. TODO: Rake to start/detach
|
6
|
+
# a memcached?
|
7
|
+
before(:all) do
|
8
|
+
begin
|
9
|
+
# Run on non-default port so not to accidentally mess with a real cache
|
10
|
+
@cache = ActiveSupport::Cache::TTLedMemCacheStore.new("127.0.0.1:12345")
|
11
|
+
# Call to make sure we have a live connection
|
12
|
+
@cache.exist?("cache_key")
|
13
|
+
rescue => e
|
14
|
+
$stderr.puts e.message
|
15
|
+
$stderr.puts "Make sure memcached is listening on tcpport 12345: /path/to/memcached -p 12345"
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
|
19
|
+
@key = "example_key"
|
20
|
+
@value = "example_value"
|
21
|
+
end
|
22
|
+
|
23
|
+
after(:each) do
|
24
|
+
@cache.clear
|
25
|
+
end
|
26
|
+
|
27
|
+
context "ttl'd keys" do
|
28
|
+
before(:each) do
|
29
|
+
@valid_for = 10
|
30
|
+
@cache.write(@key, @value, :valid_for => @valid_for)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should set the expected value in the cache" do
|
34
|
+
@cache.read(@key, :valid_for => true).should == @value
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have the proper ttl" do
|
38
|
+
@cache.ttl(@key).should be_close(Time.now.to_i + @valid_for, 1)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Vendor something to time_travel if this sleep stuff gets annoying
|
42
|
+
it "should be expired if the ttl is less than now" do
|
43
|
+
@cache.write(@key, @value, :valid_for => 0.1)
|
44
|
+
sleep 1
|
45
|
+
@cache.expired?(@key).should be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not be expired if the ttl is greater than now" do
|
49
|
+
@cache.write(@key, @value, :valid_for => 5)
|
50
|
+
@cache.expired?(@key).should be_false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "non-ttl'd keys" do
|
55
|
+
before(:each) do
|
56
|
+
@cache.write(@key, @value)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should set the non-serialized value in the cache" do
|
60
|
+
@cache.read(@key).should == @value
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should have a nil ttl" do
|
64
|
+
@cache.ttl(@key).should be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should not be expired" do
|
68
|
+
@cache.expired?(@key).should be_false
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should not raise an exception if trying a ttl'd read on a non-ttl'd key" do
|
72
|
+
lambda { @cache.read(@key, :valid_for => true) }.should_not raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return nil if trying a ttl'd read on a non-ttl'd key" do
|
76
|
+
@cache.read(@key, :valid_for => true).should be_nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: that_old_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Joey Robert
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-13 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: yajl-ruby
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 7
|
30
|
+
- x
|
31
|
+
version: 0.7.x
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: activesupport
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 2
|
43
|
+
- 3
|
44
|
+
- x
|
45
|
+
version: 2.3.x
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: An ActiveSupport MemCache store that requires serves keys until they are explicitly overwritten
|
49
|
+
email: joey@joeyrobert.org
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files: []
|
55
|
+
|
56
|
+
files:
|
57
|
+
- lib/that_old_cache.rb
|
58
|
+
- lib/that_old_cache/ttled_mem_cache_store.rb
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
- spec/that_old_cache_spec.rb
|
61
|
+
- Rakefile
|
62
|
+
- README.md
|
63
|
+
- VERSION
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://github.com/joeyrobert/that_old_cache
|
66
|
+
licenses: []
|
67
|
+
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
segments:
|
85
|
+
- 0
|
86
|
+
version: "0"
|
87
|
+
requirements: []
|
88
|
+
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.3.6
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: Serve old caches from memcached while you update in Rails
|
94
|
+
test_files: []
|
95
|
+
|