expiring_memory_store 0.1.2 → 1.0.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +1 -1
- data/lib/expiring_memory_store.rb +56 -0
- data/lib/expiring_memory_store/version.rb +4 -0
- metadata +28 -51
- data/Rakefile +0 -38
- data/Readme.md +0 -28
- data/VERSION +0 -1
- data/expiring_memory_store.gemspec +0 -43
- data/init.rb +0 -1
- data/lib/active_support/cache/expiring_memory_store.rb +0 -33
- data/test/expiring_memory_store_test.rb +0 -140
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 57f921197804eacb997b64aef1c87565d8adc47cfba73c98538f2f7d2ec68336
|
4
|
+
data.tar.gz: 0d9dbb97ff8d42f575573709adc440c1eb27df8abb7150b0268da785cf8bfa26
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b2d3debd19a816a55be0457d8eeb12449ab70ea329cc499925603c28c2ca7e4053e5935abd2bcd19a4fdb234a094590f97f2b1532d1bd32778e9edb51bedf681
|
7
|
+
data.tar.gz: '048b7c734a7febb2cdd6d5fb05f0f4b1686be9885888dfa771fe4c716c29971af725b774b08bd309ff8073900fdaac7c0c5663ec1f8fd0cac441b26b2fa93b5f'
|
data/MIT-LICENSE
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class ExpiringMemoryStore
|
3
|
+
MAX_EXPIRES_IN = 2**32
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@data = {}
|
7
|
+
@mutex = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(key)
|
11
|
+
_get(key)[1]
|
12
|
+
end
|
13
|
+
|
14
|
+
def set(key, value, expires_in: MAX_EXPIRES_IN)
|
15
|
+
@data[key] = { value: value, expires_at: now + expires_in }
|
16
|
+
value
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(key, value, **args)
|
20
|
+
@mutex.synchronize do
|
21
|
+
return false if _get(key)[0]
|
22
|
+
set(key, value, **args)
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch(key, **args)
|
28
|
+
@mutex.synchronize do
|
29
|
+
success, value = _get(key)
|
30
|
+
return value if success
|
31
|
+
value = yield
|
32
|
+
set key, value, **args
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# remove everything that is expired to prevent leaking memory over time
|
37
|
+
def cleanup
|
38
|
+
@mutex.synchronize do
|
39
|
+
now = now()
|
40
|
+
@data.delete_if { |_key, info| info[:expires_at] < now }
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def _get(key)
|
48
|
+
return [false, nil] unless (info = @data[key])
|
49
|
+
return [false, nil] unless info[:expires_at] > now
|
50
|
+
[true, info[:value]]
|
51
|
+
end
|
52
|
+
|
53
|
+
def now
|
54
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
55
|
+
end
|
56
|
+
end
|
metadata
CHANGED
@@ -1,69 +1,46 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: expiring_memory_store
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 1
|
8
|
-
- 2
|
9
|
-
version: 0.1.2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
12
|
-
-
|
6
|
+
authors:
|
7
|
+
- Michael Grosser
|
13
8
|
autorequire:
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
|
-
|
17
|
-
date: 2010-06-28 00:00:00 +02:00
|
18
|
-
default_executable:
|
11
|
+
date: 2019-05-03 00:00:00.000000000 Z
|
19
12
|
dependencies: []
|
20
|
-
|
21
13
|
description:
|
22
|
-
email:
|
14
|
+
email: michael@grosser.it
|
23
15
|
executables: []
|
24
|
-
|
25
16
|
extensions: []
|
26
|
-
|
27
17
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
files:
|
18
|
+
files:
|
30
19
|
- MIT-LICENSE
|
31
|
-
-
|
32
|
-
-
|
33
|
-
|
34
|
-
|
35
|
-
-
|
36
|
-
|
37
|
-
- test/expiring_memory_store_test.rb
|
38
|
-
has_rdoc: true
|
39
|
-
homepage: http://github.com/matthewrudy/expiring_memory_store
|
40
|
-
licenses: []
|
41
|
-
|
20
|
+
- lib/expiring_memory_store.rb
|
21
|
+
- lib/expiring_memory_store/version.rb
|
22
|
+
homepage: https://github.com/grosser/expiring_memory_store
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
42
26
|
post_install_message:
|
43
|
-
rdoc_options:
|
44
|
-
|
45
|
-
require_paths:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
46
29
|
- lib
|
47
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
-
requirements:
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
49
32
|
- - ">="
|
50
|
-
- !ruby/object:Gem::Version
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
-
requirements:
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 2.3.0
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
56
37
|
- - ">="
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
|
59
|
-
- 0
|
60
|
-
version: "0"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
61
40
|
requirements: []
|
62
|
-
|
63
41
|
rubyforge_project:
|
64
|
-
rubygems_version:
|
42
|
+
rubygems_version: 2.7.6
|
65
43
|
signing_key:
|
66
|
-
specification_version:
|
67
|
-
summary:
|
68
|
-
test_files:
|
69
|
-
- test/expiring_memory_store_test.rb
|
44
|
+
specification_version: 4
|
45
|
+
summary: Fast & Simple Ruby In-Memory Store with expiration
|
46
|
+
test_files: []
|
data/Rakefile
DELETED
@@ -1,38 +0,0 @@
|
|
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
DELETED
@@ -1,28 +0,0 @@
|
|
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
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.1.2
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
|
-
|
6
|
-
Gem::Specification.new do |s|
|
7
|
-
s.name = %q{expiring_memory_store}
|
8
|
-
s.version = "0.1.2"
|
9
|
-
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Matthew Rudy Jacobs"]
|
12
|
-
s.date = %q{2010-06-28}
|
13
|
-
s.email = %q{dunno@dunno.com}
|
14
|
-
s.files = [
|
15
|
-
"MIT-LICENSE",
|
16
|
-
"Rakefile",
|
17
|
-
"Readme.md",
|
18
|
-
"VERSION",
|
19
|
-
"expiring_memory_store.gemspec",
|
20
|
-
"init.rb",
|
21
|
-
"lib/active_support/cache/expiring_memory_store.rb",
|
22
|
-
"test/expiring_memory_store_test.rb"
|
23
|
-
]
|
24
|
-
s.homepage = %q{http://github.com/matthewrudy/expiring_memory_store}
|
25
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
26
|
-
s.require_paths = ["lib"]
|
27
|
-
s.rubygems_version = %q{1.3.6}
|
28
|
-
s.summary = %q{Fallback when original is not present or somethings not right.}
|
29
|
-
s.test_files = [
|
30
|
-
"test/expiring_memory_store_test.rb"
|
31
|
-
]
|
32
|
-
|
33
|
-
if s.respond_to? :specification_version then
|
34
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
35
|
-
s.specification_version = 3
|
36
|
-
|
37
|
-
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
38
|
-
else
|
39
|
-
end
|
40
|
-
else
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
data/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'active_support/cache/expiring_memory_store'
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'active_support'
|
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
|
@@ -1,140 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'test/unit'
|
3
|
-
require 'mocha'
|
4
|
-
|
5
|
-
gem 'activesupport', '>=2.3'
|
6
|
-
require File.dirname(__FILE__) + '/../init'
|
7
|
-
|
8
|
-
class CacheStoreTest < Test::Unit::TestCase
|
9
|
-
def setup
|
10
|
-
@cache = ActiveSupport::Cache.lookup_store(:expiring_memory_store)
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_fetch_without_cache_miss
|
14
|
-
@cache.stubs(:read).with('foo', {}).returns('bar')
|
15
|
-
@cache.expects(:write).never
|
16
|
-
assert_equal 'bar', @cache.fetch('foo') { 'baz' }
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_fetch_with_cache_miss
|
20
|
-
@cache.stubs(:read).with('foo', {}).returns(nil)
|
21
|
-
@cache.expects(:write).with('foo', 'baz', {})
|
22
|
-
assert_equal 'baz', @cache.fetch('foo') { 'baz' }
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_fetch_with_forced_cache_miss
|
26
|
-
@cache.expects(:read).never
|
27
|
-
@cache.expects(:write).with('foo', 'bar', :force => true)
|
28
|
-
@cache.fetch('foo', :force => true) { 'bar' }
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# Tests the base functionality that should be identical across all cache stores.
|
33
|
-
module CacheStoreBehavior
|
34
|
-
def test_should_read_and_write_strings
|
35
|
-
@cache.write('foo', 'bar')
|
36
|
-
assert_equal 'bar', @cache.read('foo')
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_should_read_and_write_hash
|
40
|
-
@cache.write('foo', {:a => "b"})
|
41
|
-
assert_equal({:a => "b"}, @cache.read('foo'))
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_should_read_and_write_nil
|
45
|
-
@cache.write('foo', nil)
|
46
|
-
assert_equal nil, @cache.read('foo')
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_fetch_without_cache_miss
|
50
|
-
@cache.write('foo', 'bar')
|
51
|
-
assert_equal 'bar', @cache.fetch('foo') { 'baz' }
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_fetch_with_cache_miss
|
55
|
-
assert_equal 'baz', @cache.fetch('foo') { 'baz' }
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_fetch_with_forced_cache_miss
|
59
|
-
@cache.fetch('foo', :force => true) { 'bar' }
|
60
|
-
end
|
61
|
-
|
62
|
-
def test_increment
|
63
|
-
@cache.write('foo', 1, :raw => true)
|
64
|
-
assert_equal 1, @cache.read('foo', :raw => true).to_i
|
65
|
-
assert_equal 2, @cache.increment('foo')
|
66
|
-
assert_equal 2, @cache.read('foo', :raw => true).to_i
|
67
|
-
assert_equal 3, @cache.increment('foo')
|
68
|
-
assert_equal 3, @cache.read('foo', :raw => true).to_i
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_decrement
|
72
|
-
@cache.write('foo', 3, :raw => true)
|
73
|
-
assert_equal 3, @cache.read('foo', :raw => true).to_i
|
74
|
-
assert_equal 2, @cache.decrement('foo')
|
75
|
-
assert_equal 2, @cache.read('foo', :raw => true).to_i
|
76
|
-
assert_equal 1, @cache.decrement('foo')
|
77
|
-
assert_equal 1, @cache.read('foo', :raw => true).to_i
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class ExpiringMemoryStoreTest < Test::Unit::TestCase
|
82
|
-
def setup
|
83
|
-
@cache = ActiveSupport::Cache.lookup_store(:expiring_memory_store)
|
84
|
-
end
|
85
|
-
|
86
|
-
include CacheStoreBehavior
|
87
|
-
|
88
|
-
def test_store_objects_should_be_immutable
|
89
|
-
@cache.write('foo', 'bar')
|
90
|
-
assert_raise(ActiveSupport::FrozenObjectError) { @cache.read('foo').gsub!(/.*/, 'baz') }
|
91
|
-
assert_equal 'bar', @cache.read('foo')
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_by_default_values_should_not_expire
|
95
|
-
time_now = Time.now
|
96
|
-
Time.stubs(:now).returns(time_now)
|
97
|
-
|
98
|
-
@cache.write('foo', 'bar')
|
99
|
-
assert_equal 'bar', @cache.read('foo')
|
100
|
-
|
101
|
-
Time.stubs(:now).returns(time_now + 5.years )
|
102
|
-
assert_equal 'bar', @cache.read('foo')
|
103
|
-
end
|
104
|
-
|
105
|
-
def test_values_should_not_expire_if_expires_in_is_set_to_zero
|
106
|
-
time_now = Time.now
|
107
|
-
Time.stubs(:now).returns(time_now)
|
108
|
-
|
109
|
-
@cache.write('foo', 'bar', :expires_in => 0)
|
110
|
-
assert_equal 'bar', @cache.read('foo')
|
111
|
-
|
112
|
-
Time.stubs(:now).returns(time_now + 5.years )
|
113
|
-
assert_equal 'bar', @cache.read('foo')
|
114
|
-
end
|
115
|
-
|
116
|
-
def test_values_should_expire_is_param_is_set
|
117
|
-
time_now = Time.now
|
118
|
-
Time.stubs(:now).returns(time_now)
|
119
|
-
|
120
|
-
@cache.write('foo', 'bar', :expires_in => 1.year)
|
121
|
-
assert_equal 'bar', @cache.read('foo')
|
122
|
-
|
123
|
-
Time.stubs(:now).returns(time_now + 5.years )
|
124
|
-
assert_equal nil, @cache.read('foo')
|
125
|
-
end
|
126
|
-
|
127
|
-
def test_values_should_expire_when_the_param_tells_it_to
|
128
|
-
time_now = Time.now
|
129
|
-
Time.stubs(:now).returns(time_now)
|
130
|
-
|
131
|
-
@cache.write('foo', 'bar', :expires_in => 1.year)
|
132
|
-
assert_equal 'bar', @cache.read('foo')
|
133
|
-
|
134
|
-
Time.stubs(:now).returns(time_now + 1.year - 1 )
|
135
|
-
assert_equal 'bar', @cache.read('foo')
|
136
|
-
|
137
|
-
Time.stubs(:now).returns(time_now + 1.year + 1 )
|
138
|
-
assert_equal nil, @cache.read('foo')
|
139
|
-
end
|
140
|
-
end
|