expiring_memory_store 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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