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 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