expiring_memory_store 0.1.0
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/MIT-LICENSE +20 -0
- data/Rakefile +38 -0
- data/Readme.md +28 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/active_support/cache/expiring_memory_store.rb +33 -0
- data/test/expiring_memory_store_test.rb +138 -0
- metadata +68 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 [Matthew Rudy Jacobs]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the expiring_memory_store plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the expiring_memory_store plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'ExpiringMemoryStore'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'jeweler'
|
26
|
+
project_name = 'expiring_memory_store'
|
27
|
+
Jeweler::Tasks.new do |gem|
|
28
|
+
gem.name = project_name
|
29
|
+
gem.summary = "Fallback when original is not present or somethings not right."
|
30
|
+
gem.email = "dunno@dunno.com"
|
31
|
+
gem.homepage = "http://github.com/matthewrudy/#{project_name}"
|
32
|
+
gem.authors = ["Matthew Rudy Jacobs"]
|
33
|
+
end
|
34
|
+
|
35
|
+
Jeweler::GemcutterTasks.new
|
36
|
+
rescue LoadError
|
37
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
38
|
+
end
|
data/Readme.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
ExpiringMemoryStore
|
2
|
+
===================
|
3
|
+
|
4
|
+
Expiring MemoryStore is a modification to the default Rails MemoryStore which adds the :expires_in functionality that is so useful with Memcache.
|
5
|
+
Although this increases the memory overhead slightly,
|
6
|
+
it ensures that caches can be expired easily, without restarting your webserver.
|
7
|
+
|
8
|
+
Just add;
|
9
|
+
config.cache_store = :expiring_memory_store
|
10
|
+
to your environment.rb.
|
11
|
+
|
12
|
+
Example
|
13
|
+
=======
|
14
|
+
|
15
|
+
>> Rails.cache.write('are you there?', :im_still_here, :expires_in => 30)
|
16
|
+
=> :im_still_here
|
17
|
+
|
18
|
+
>> Rails.cache.read('are you there?')
|
19
|
+
=> :im_still_here
|
20
|
+
|
21
|
+
wait 30 seconds
|
22
|
+
|
23
|
+
>> Rails.cache.read('are you there?')
|
24
|
+
=> nil
|
25
|
+
|
26
|
+
WICKED!!!
|
27
|
+
|
28
|
+
Copyright (c) 2008 [Matthew Rudy Jacobs], released under the MIT license
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_support/cache/expiring_memory_store'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'activesupport'
|
2
|
+
module ActiveSupport
|
3
|
+
module Cache
|
4
|
+
# Like MemoryStore, but caches are expired after the period specified in the :expires_in option.
|
5
|
+
class ExpiringMemoryStore < MemoryStore
|
6
|
+
|
7
|
+
def read(name, options = nil)
|
8
|
+
super
|
9
|
+
value, expiry = @data[name]
|
10
|
+
if expiry && expiry < Time.now
|
11
|
+
delete(name)
|
12
|
+
return nil
|
13
|
+
end
|
14
|
+
return value
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(name, value, options = nil)
|
18
|
+
super
|
19
|
+
@data[name] = [value.freeze, expires_at(options)].freeze
|
20
|
+
return value
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def expires_at(options)
|
26
|
+
if expires_in = options && options[:expires_in]
|
27
|
+
return expires_in.from_now if expires_in != 0
|
28
|
+
end
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'mocha'
|
4
|
+
require File.dirname(__FILE__) + '/../init'
|
5
|
+
|
6
|
+
class CacheStoreTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@cache = ActiveSupport::Cache.lookup_store(:expiring_memory_store)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_fetch_without_cache_miss
|
12
|
+
@cache.stubs(:read).with('foo', {}).returns('bar')
|
13
|
+
@cache.expects(:write).never
|
14
|
+
assert_equal 'bar', @cache.fetch('foo') { 'baz' }
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_fetch_with_cache_miss
|
18
|
+
@cache.stubs(:read).with('foo', {}).returns(nil)
|
19
|
+
@cache.expects(:write).with('foo', 'baz', {})
|
20
|
+
assert_equal 'baz', @cache.fetch('foo') { 'baz' }
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_fetch_with_forced_cache_miss
|
24
|
+
@cache.expects(:read).never
|
25
|
+
@cache.expects(:write).with('foo', 'bar', :force => true)
|
26
|
+
@cache.fetch('foo', :force => true) { 'bar' }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Tests the base functionality that should be identical across all cache stores.
|
31
|
+
module CacheStoreBehavior
|
32
|
+
def test_should_read_and_write_strings
|
33
|
+
@cache.write('foo', 'bar')
|
34
|
+
assert_equal 'bar', @cache.read('foo')
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_should_read_and_write_hash
|
38
|
+
@cache.write('foo', {:a => "b"})
|
39
|
+
assert_equal({:a => "b"}, @cache.read('foo'))
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_should_read_and_write_nil
|
43
|
+
@cache.write('foo', nil)
|
44
|
+
assert_equal nil, @cache.read('foo')
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_fetch_without_cache_miss
|
48
|
+
@cache.write('foo', 'bar')
|
49
|
+
assert_equal 'bar', @cache.fetch('foo') { 'baz' }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_fetch_with_cache_miss
|
53
|
+
assert_equal 'baz', @cache.fetch('foo') { 'baz' }
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_fetch_with_forced_cache_miss
|
57
|
+
@cache.fetch('foo', :force => true) { 'bar' }
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_increment
|
61
|
+
@cache.write('foo', 1, :raw => true)
|
62
|
+
assert_equal 1, @cache.read('foo', :raw => true).to_i
|
63
|
+
assert_equal 2, @cache.increment('foo')
|
64
|
+
assert_equal 2, @cache.read('foo', :raw => true).to_i
|
65
|
+
assert_equal 3, @cache.increment('foo')
|
66
|
+
assert_equal 3, @cache.read('foo', :raw => true).to_i
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_decrement
|
70
|
+
@cache.write('foo', 3, :raw => true)
|
71
|
+
assert_equal 3, @cache.read('foo', :raw => true).to_i
|
72
|
+
assert_equal 2, @cache.decrement('foo')
|
73
|
+
assert_equal 2, @cache.read('foo', :raw => true).to_i
|
74
|
+
assert_equal 1, @cache.decrement('foo')
|
75
|
+
assert_equal 1, @cache.read('foo', :raw => true).to_i
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class ExpiringMemoryStoreTest < Test::Unit::TestCase
|
80
|
+
def setup
|
81
|
+
@cache = ActiveSupport::Cache.lookup_store(:expiring_memory_store)
|
82
|
+
end
|
83
|
+
|
84
|
+
include CacheStoreBehavior
|
85
|
+
|
86
|
+
def test_store_objects_should_be_immutable
|
87
|
+
@cache.write('foo', 'bar')
|
88
|
+
assert_raise(ActiveSupport::FrozenObjectError) { @cache.read('foo').gsub!(/.*/, 'baz') }
|
89
|
+
assert_equal 'bar', @cache.read('foo')
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_by_default_values_should_not_expire
|
93
|
+
time_now = Time.now
|
94
|
+
Time.stubs(:now).returns(time_now)
|
95
|
+
|
96
|
+
@cache.write('foo', 'bar')
|
97
|
+
assert_equal 'bar', @cache.read('foo')
|
98
|
+
|
99
|
+
Time.stubs(:now).returns(time_now + 5.years )
|
100
|
+
assert_equal 'bar', @cache.read('foo')
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_values_should_not_expire_if_expires_in_is_set_to_zero
|
104
|
+
time_now = Time.now
|
105
|
+
Time.stubs(:now).returns(time_now)
|
106
|
+
|
107
|
+
@cache.write('foo', 'bar', :expires_in => 0)
|
108
|
+
assert_equal 'bar', @cache.read('foo')
|
109
|
+
|
110
|
+
Time.stubs(:now).returns(time_now + 5.years )
|
111
|
+
assert_equal 'bar', @cache.read('foo')
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_values_should_expire_is_param_is_set
|
115
|
+
time_now = Time.now
|
116
|
+
Time.stubs(:now).returns(time_now)
|
117
|
+
|
118
|
+
@cache.write('foo', 'bar', :expires_in => 1.year)
|
119
|
+
assert_equal 'bar', @cache.read('foo')
|
120
|
+
|
121
|
+
Time.stubs(:now).returns(time_now + 5.years )
|
122
|
+
assert_equal nil, @cache.read('foo')
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_values_should_expire_when_the_param_tells_it_to
|
126
|
+
time_now = Time.now
|
127
|
+
Time.stubs(:now).returns(time_now)
|
128
|
+
|
129
|
+
@cache.write('foo', 'bar', :expires_in => 1.year)
|
130
|
+
assert_equal 'bar', @cache.read('foo')
|
131
|
+
|
132
|
+
Time.stubs(:now).returns(time_now + 1.year - 1 )
|
133
|
+
assert_equal 'bar', @cache.read('foo')
|
134
|
+
|
135
|
+
Time.stubs(:now).returns(time_now + 1.year + 1 )
|
136
|
+
assert_equal nil, @cache.read('foo')
|
137
|
+
end
|
138
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: expiring_memory_store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Matthew Rudy Jacobs
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-06-25 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: dunno@dunno.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- MIT-LICENSE
|
31
|
+
- Rakefile
|
32
|
+
- Readme.md
|
33
|
+
- VERSION
|
34
|
+
- init.rb
|
35
|
+
- lib/active_support/cache/expiring_memory_store.rb
|
36
|
+
- test/expiring_memory_store_test.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/matthewrudy/expiring_memory_store
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --charset=UTF-8
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
segments:
|
51
|
+
- 0
|
52
|
+
version: "0"
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.3.6
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Fallback when original is not present or somethings not right.
|
67
|
+
test_files:
|
68
|
+
- test/expiring_memory_store_test.rb
|