timedcache 0.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +28 -13
- data/lib/timedcache.rb +68 -54
- data/lib/timedcache/version.rb +3 -0
- data/misc/thread_test.rb +3 -3
- data/test/test_timed_cache.rb +115 -0
- data/timedcache.gemspec +15 -0
- metadata +40 -32
- data/spec/timed_cache_spec.rb +0 -102
data/Rakefile
CHANGED
@@ -1,16 +1,31 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
# ============================================================================
|
8
|
+
|
9
|
+
# If you're using this file as a template to set up a new gem, this constant
|
10
|
+
# is the only thing you should need to change in the Rakefile:
|
11
|
+
GEM_NAME = 'timedcache'
|
12
|
+
|
13
|
+
# ============================================================================
|
14
|
+
|
15
|
+
Rake::TestTask.new do |t|
|
16
|
+
t.libs << 'test'
|
17
|
+
end
|
18
|
+
|
19
|
+
# ============================================================================
|
20
|
+
# = Gem package and release stuff.
|
21
|
+
# ============================================================================
|
22
|
+
|
23
|
+
spec = eval(File.read(File.join(File.dirname(__FILE__), "#{GEM_NAME}.gemspec")))
|
24
|
+
|
25
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
26
|
+
pkg.need_tar = true
|
16
27
|
end
|
28
|
+
|
29
|
+
# ============================================================================
|
30
|
+
|
31
|
+
task :default => [:test]
|
data/lib/timedcache.rb
CHANGED
@@ -2,59 +2,58 @@ require "pstore"
|
|
2
2
|
require "monitor"
|
3
3
|
|
4
4
|
# == TimedCache
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# TimedCache implements a cache in which you can place objects
|
7
7
|
# and specify a timeout value.
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# If you attempt to retrieve the object within the specified timeout
|
10
10
|
# period, the object will be returned. If the timeout period has elapsed,
|
11
11
|
# the TimedCache will return nil.
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# e.g.:
|
14
14
|
# cache = TimedCache.new
|
15
15
|
# cache.put :my_object_key, "Expensive data", 10 # => "Expensive data"
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# cache.get :my_object_key # => "Expensive data"
|
18
18
|
# cache[:my_object_key] # => "Expensive data"
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# ... 10 seconds later:
|
21
21
|
# cache.get :my_object_key # => nil
|
22
|
-
#
|
22
|
+
#
|
23
23
|
# === Default timeout
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# When creating a new TimedCache, a default timeout value can be set. This value
|
26
26
|
# will be used for each object added to the cache, unless a different timeout value
|
27
27
|
# is specifically set for that object.
|
28
|
-
#
|
28
|
+
#
|
29
29
|
# e.g.:
|
30
|
-
#
|
30
|
+
#
|
31
31
|
# cache = TimedCache.new(:default_timeout => 120)
|
32
32
|
# cache.default_timeout # => 120
|
33
|
-
#
|
33
|
+
#
|
34
34
|
# === File-based cache
|
35
|
-
#
|
36
|
-
# By default, TimedCache will use an in-memory store. A file-based store (using the
|
35
|
+
#
|
36
|
+
# By default, TimedCache will use an in-memory store. A file-based store (using the
|
37
37
|
# PStore library) can also be used.
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# e.g.:
|
40
|
-
#
|
40
|
+
#
|
41
41
|
# TimedCache.new(:type => :file, :filename => "my_cache.db")
|
42
|
-
#
|
43
|
-
# The file-based cache makes it possible to easily share a cache between several ruby
|
44
|
-
# processes.
|
45
|
-
#
|
46
|
-
#
|
42
|
+
#
|
43
|
+
# The file-based cache makes it possible to easily share a cache between several ruby
|
44
|
+
# processes.
|
45
|
+
#
|
47
46
|
# Note that objects that cannot be marshalled (e.g. a Proc) can't be stored using the file-based cache.
|
48
47
|
class TimedCache
|
49
48
|
VERSION = "0.3"
|
50
|
-
|
49
|
+
|
51
50
|
attr_reader :default_timeout
|
52
|
-
|
51
|
+
|
53
52
|
# Create a new TimedCache. Available options are:
|
54
53
|
# <tt>type</tt>:: <tt>:memory</tt> or <tt>:file</tt> (defaults to <tt>:memory</tt>).
|
55
54
|
# <tt>default_timeout</tt>:: Timeout to use if none is specified when adding an object to the cache.
|
56
55
|
# <tt>filename</tt>:: Must be specified when using the <tt>:file</tt> type store.
|
57
|
-
#
|
56
|
+
#
|
58
57
|
# e.g.:
|
59
58
|
# TimedCache.new(:type => :file, :filename => "cache.db")
|
60
59
|
def initialize(opts = {})
|
@@ -63,66 +62,73 @@ class TimedCache
|
|
63
62
|
@store = new_store(opts)
|
64
63
|
@store.extend(MonitorMixin)
|
65
64
|
end
|
66
|
-
|
65
|
+
|
67
66
|
# Add an object to the cache. e.g.:
|
68
67
|
# cache.put(:session_id, 12345)
|
69
|
-
#
|
70
|
-
# The third parameter is an optional timeout value. If not specified, the
|
68
|
+
#
|
69
|
+
# The third parameter is an optional timeout value. If not specified, the
|
71
70
|
# <tt>:default_timeout</tt> for this TimedCache will be used instead.
|
72
71
|
def put(key, value, timeout = @default_timeout)
|
73
72
|
@store.synchronize do
|
74
73
|
@store.put(key, value, timeout) unless value.nil?
|
75
74
|
end
|
76
75
|
end
|
77
|
-
|
76
|
+
alias :set :put
|
77
|
+
|
78
|
+
# Remove an object from the cache. e.g.:
|
79
|
+
# cache.del(:session_id)
|
80
|
+
def delete(key)
|
81
|
+
@store.delete(key)
|
82
|
+
end
|
83
|
+
alias :del :delete
|
84
|
+
|
78
85
|
# Retrieve the object which the given +key+. If the object has expired or
|
79
86
|
# is not present, +nil+ is returned.
|
80
|
-
#
|
87
|
+
#
|
81
88
|
# Optionally, a block can be given. The result of evaluating the block will
|
82
89
|
# be substituted as the cache value, if the cache has expired.
|
83
|
-
#
|
90
|
+
#
|
84
91
|
# e.g.:
|
85
|
-
#
|
92
|
+
#
|
86
93
|
# cache.get("slow_database_query") do
|
87
94
|
# MyDatabase.query("SELECT * FROM bigtable...")
|
88
95
|
# end
|
89
|
-
#
|
90
|
-
# The block syntax can also be used with the in-memory cache.
|
96
|
+
#
|
91
97
|
def get(key, &block)
|
92
98
|
@store.synchronize do
|
93
99
|
@store.get(key, &block)
|
94
100
|
end
|
95
101
|
end
|
96
|
-
|
102
|
+
|
97
103
|
# Add to the cache using a hash-like syntax. e.g.:
|
98
104
|
# cache[:name] = "Nick"
|
99
|
-
#
|
105
|
+
#
|
100
106
|
# Note that adding to the cache this way does not allow you to specify timeout values
|
101
107
|
# on a per-object basis.
|
102
108
|
def []=(key, value)
|
103
109
|
put(key, value)
|
104
110
|
end
|
105
|
-
|
111
|
+
|
106
112
|
# Fetch objects using the hash syntax. e.g.:
|
107
113
|
# cache[:name] # => "Nick"
|
108
114
|
def [](key)
|
109
115
|
get(key)
|
110
116
|
end
|
111
|
-
|
117
|
+
|
112
118
|
protected
|
113
|
-
|
119
|
+
|
114
120
|
def new_store(options) #:nodoc:
|
115
121
|
self.class.const_get(options[:type].to_s.capitalize + "Store").new(self, options)
|
116
122
|
end
|
117
|
-
|
123
|
+
|
118
124
|
class Store #:nodoc:
|
119
125
|
def initialize(timed_cache, options)
|
120
126
|
@timed_cache = timed_cache
|
121
127
|
@options = options
|
122
128
|
end
|
123
|
-
|
129
|
+
|
124
130
|
protected
|
125
|
-
|
131
|
+
|
126
132
|
def generic_get(key, timeout, callback, fetch_key = lambda {|k| @cache[key]})
|
127
133
|
if object_store = fetch_key.call(key)
|
128
134
|
if object_store.expired?
|
@@ -139,40 +145,44 @@ class TimedCache
|
|
139
145
|
run_callback_and_add_to_cache(key, object_store, callback, timeout)
|
140
146
|
end
|
141
147
|
end
|
142
|
-
|
148
|
+
|
143
149
|
def run_callback_and_add_to_cache(key, object_store, callback, timeout)
|
144
150
|
object_store.no_expiry! if object_store
|
145
|
-
|
151
|
+
|
146
152
|
begin
|
147
153
|
result = callback.call
|
148
154
|
rescue
|
149
155
|
object_store.reset_expiry! if object_store
|
150
156
|
raise
|
151
157
|
end
|
152
|
-
|
158
|
+
|
153
159
|
@timed_cache.put(key, result, timeout)
|
154
160
|
result
|
155
161
|
end
|
156
162
|
end
|
157
|
-
|
163
|
+
|
158
164
|
class MemoryStore < Store #:nodoc:
|
159
165
|
def initialize(*args)
|
160
166
|
super(*args)
|
161
167
|
@cache = Hash.new
|
162
168
|
end
|
163
|
-
|
169
|
+
|
164
170
|
def put(key, value, timeout)
|
165
171
|
@cache[key] = ObjectContainer.new(value, timeout)
|
166
172
|
# Return just the given value, so that references to the
|
167
173
|
# ObjectStore instance can't be held outside this TimedCache:
|
168
174
|
value
|
169
175
|
end
|
170
|
-
|
176
|
+
|
171
177
|
def get(key, timeout = @timed_cache.default_timeout, &block)
|
172
178
|
generic_get(key, timeout, block)
|
173
179
|
end
|
180
|
+
|
181
|
+
def delete(key)
|
182
|
+
@cache.delete(key)
|
183
|
+
end
|
174
184
|
end
|
175
|
-
|
185
|
+
|
176
186
|
class FileStore < Store #:nodoc:
|
177
187
|
def initialize(*args)
|
178
188
|
super(*args)
|
@@ -182,15 +192,15 @@ class TimedCache
|
|
182
192
|
end
|
183
193
|
@cache = PStore.new(filename)
|
184
194
|
end
|
185
|
-
|
195
|
+
|
186
196
|
def put(key, value, timeout)
|
187
197
|
@cache.transaction { @cache[key] = ObjectContainer.new(value, timeout) }
|
188
|
-
|
198
|
+
|
189
199
|
# Return just the given value, so that references to the
|
190
200
|
# ObjectStore instance can't be held outside this TimedCache:
|
191
201
|
value
|
192
202
|
end
|
193
|
-
|
203
|
+
|
194
204
|
def get(key, timeout = @timed_cache.default_timeout, &block)
|
195
205
|
if block
|
196
206
|
generic_get(key, timeout, block, lambda {|k| @cache.transaction { @cache[key] } })
|
@@ -198,18 +208,22 @@ class TimedCache
|
|
198
208
|
@cache.transaction { generic_get(key, timeout, block) }
|
199
209
|
end
|
200
210
|
end
|
211
|
+
|
212
|
+
def delete(key)
|
213
|
+
@cache.transaction { @cache.delete(key) }
|
214
|
+
end
|
201
215
|
end
|
202
|
-
|
216
|
+
|
203
217
|
class ObjectContainer #:nodoc:
|
204
218
|
attr_accessor :object
|
205
|
-
|
219
|
+
|
206
220
|
def initialize(object, timeout)
|
207
221
|
@created_at = Time.now.utc
|
208
222
|
@timeout = timeout
|
209
223
|
@object = object
|
210
224
|
@frozen = false
|
211
225
|
end
|
212
|
-
|
226
|
+
|
213
227
|
def expired?
|
214
228
|
if @frozen
|
215
229
|
false
|
@@ -217,11 +231,11 @@ class TimedCache
|
|
217
231
|
(Time.now.utc - @timeout) > @created_at
|
218
232
|
end
|
219
233
|
end
|
220
|
-
|
234
|
+
|
221
235
|
def no_expiry!
|
222
236
|
@frozen = true
|
223
237
|
end
|
224
|
-
|
238
|
+
|
225
239
|
def reset_expiry!
|
226
240
|
@frozen = false
|
227
241
|
end
|
data/misc/thread_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require File.
|
1
|
+
require File.expand_path('../lib/timedcache', File.dirname(__FILE__))
|
2
2
|
|
3
|
-
# This script will almost certainly raise an exception if
|
4
|
-
# thread
|
3
|
+
# This script will almost certainly raise an exception if the cache is not
|
4
|
+
# thread safe.
|
5
5
|
|
6
6
|
db = File.join(File.dirname(__FILE__), "thread_test.db")
|
7
7
|
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'timedcache'
|
3
|
+
|
4
|
+
class TimedCacheTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@filename = File.join(File.dirname(__FILE__), "specs.db")
|
7
|
+
@memory_cache = TimedCache.new
|
8
|
+
@file_cache = TimedCache.new(:type => :file, :filename => @filename)
|
9
|
+
@caches = [@memory_cache, @file_cache]
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
File.delete(@filename) if File.exist?(@filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_can_add_an_object_to_the_cache_specifying_a_timeout_value
|
17
|
+
@caches.each do |cache|
|
18
|
+
assert_equal("This needs caching", cache.put(:myobject, "This needs caching", 10))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_can_add_an_object_to_the_cache_specifying_a_timeout_value_using_the_set_method
|
23
|
+
@caches.each do |cache|
|
24
|
+
assert_equal("This needs caching", cache.set(:myobject, "This needs caching", 10))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_can_remove_objects_from_the_cache
|
29
|
+
@caches.each do |cache|
|
30
|
+
cache.put(:myobject, "This needs caching", 10)
|
31
|
+
assert_equal("This needs caching", cache.get(:myobject))
|
32
|
+
cache.del(:myobject)
|
33
|
+
assert_nil(cache.get(:myobject))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_cache_should_hold_seperate_values_for_each_key
|
38
|
+
@caches.each do |cache|
|
39
|
+
assert_equal("This needs caching", cache.put(:myobject, "This needs caching", 10))
|
40
|
+
assert_equal("...and this too", cache.put(:my_other_object, "...and this too", 10))
|
41
|
+
assert_equal("This needs caching", cache.get(:myobject))
|
42
|
+
assert_equal("...and this too", cache.get(:my_other_object))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_string_and_symbol_keys_are_not_treated_as_equivalent
|
47
|
+
@caches.each do |cache|
|
48
|
+
cache[:symbolkey] = "Referenced by symbol"
|
49
|
+
cache["stringkey"] = "Referenced by string"
|
50
|
+
|
51
|
+
assert_equal("Referenced by symbol", cache[:symbolkey])
|
52
|
+
assert_nil(cache["symbolkey"])
|
53
|
+
|
54
|
+
assert_equal("Referenced by string", cache["stringkey"])
|
55
|
+
assert_nil(cache[:stringkey])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_after_the_specified_timeout_value_has_elapsed_nil_should_be_returned
|
60
|
+
@caches.each do |cache|
|
61
|
+
assert_equal("This needs caching", cache.put(:myobject, "This needs caching", 0))
|
62
|
+
assert_nil(cache.get(:myobject))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_if_no_object_matching_the_given_key_is_found_nil_should_be_returned
|
67
|
+
@caches.each do |cache|
|
68
|
+
assert_nil(cache.get(:my_nonexistant_object))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_should_be_able_to_use_an_array_as_a_cache_key
|
73
|
+
@caches.each do |cache|
|
74
|
+
assert_equal("Array", cache.put([123,234], "Array"))
|
75
|
+
assert_equal("Array", cache.get([123,234]))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_passing_a_block_to_the_get_method_should_substitute_result_of_block_as_value_for_given_key
|
80
|
+
@caches.each do |cache|
|
81
|
+
cache.put("block_test", 1984, 0)
|
82
|
+
assert_equal(2001, cache.get("block_test") { 2001 })
|
83
|
+
assert_equal(2001, cache.get("block_test"))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_passing_block_to_get_should_add_result_of_callback_when_there_is_no_existing_value
|
88
|
+
@caches.each do |cache|
|
89
|
+
assert_equal(nil, cache.get("new_key_with_block"))
|
90
|
+
assert_equal("Nicholas", cache.get("new_key_with_block") { "Nicholas" })
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_is_able_to_specify_default_timeout_when_creating_an_instance
|
95
|
+
cache = TimedCache.new(:default_timeout => 20)
|
96
|
+
assert_equal(20, cache.default_timeout)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_if_no_default_timeout_is_set_60_seconds_should_be_used
|
100
|
+
cache = TimedCache.new
|
101
|
+
assert_equal(60, cache.default_timeout)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_timeout_specified_when_putting_a_new_object_into_the_cache_should_override_default_timeout
|
105
|
+
cache = TimedCache.new(:default_timeout => 20)
|
106
|
+
assert_equal(20, cache.default_timeout)
|
107
|
+
cache.put("alternative_timeout", "2 minutes", 120)
|
108
|
+
|
109
|
+
timeout = cache.instance_variable_get(:@store).
|
110
|
+
instance_variable_get(:@cache)["alternative_timeout"].
|
111
|
+
instance_variable_get(:@timeout)
|
112
|
+
|
113
|
+
assert_equal(120, timeout)
|
114
|
+
end
|
115
|
+
end
|
data/timedcache.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'timedcache/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "timedcache"
|
5
|
+
s.version = TimedCache::VERSION
|
6
|
+
s.summary = %q{TimedCache implements a cache in which you can place objects and specify a timeout value.}
|
7
|
+
s.description = %q{TimedCache implements a cache in which you can place objects and specify a timeout value. If you attempt to retrieve the object within the specified timeout, the object will be returned. If the timeout period has elapsed, the TimedCache will return nil.}
|
8
|
+
s.files = Dir['**/*']
|
9
|
+
s.authors = ["Nicholas Dainty"]
|
10
|
+
s.email = "nick@npad.co.uk"
|
11
|
+
s.homepage = "http://timedcache.rubyforge.org/"
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.rdoc_options = ["--charset=UTF-8", "--line-numbers", "--inline-source"]
|
14
|
+
s.required_ruby_version = '>= 1.8.6'
|
15
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timedcache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Nicholas Dainty
|
@@ -9,64 +15,66 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2011-03-24 00:00:00 +00:00
|
13
19
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
type: :development
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 1.8.2
|
24
|
-
version:
|
25
|
-
description: TimedCache implements a cache in which you can place objects and specify a timeout value. If you attempt to retrieve the object within the specified timeout period, the object will be returned. If the timeout period has elapsed, the TimedCache will return nil.
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: TimedCache implements a cache in which you can place objects and specify a timeout value. If you attempt to retrieve the object within the specified timeout, the object will be returned. If the timeout period has elapsed, the TimedCache will return nil.
|
26
23
|
email: nick@npad.co.uk
|
27
24
|
executables: []
|
28
25
|
|
29
26
|
extensions: []
|
30
27
|
|
31
|
-
extra_rdoc_files:
|
32
|
-
|
33
|
-
- Manifest.txt
|
34
|
-
- README.txt
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
35
30
|
files:
|
36
31
|
- History.txt
|
37
|
-
- Manifest.txt
|
38
|
-
- README.txt
|
39
|
-
- Rakefile
|
40
32
|
- lib/timed_cache.rb
|
33
|
+
- lib/timedcache/version.rb
|
41
34
|
- lib/timedcache.rb
|
35
|
+
- Manifest.txt
|
42
36
|
- misc/thread_test.rb
|
43
|
-
-
|
37
|
+
- Rakefile
|
38
|
+
- README.txt
|
39
|
+
- test/test_timed_cache.rb
|
40
|
+
- timedcache.gemspec
|
44
41
|
has_rdoc: true
|
45
|
-
homepage:
|
42
|
+
homepage: http://timedcache.rubyforge.org/
|
43
|
+
licenses: []
|
44
|
+
|
46
45
|
post_install_message:
|
47
46
|
rdoc_options:
|
48
|
-
- --
|
49
|
-
-
|
47
|
+
- --charset=UTF-8
|
48
|
+
- --line-numbers
|
49
|
+
- --inline-source
|
50
50
|
require_paths:
|
51
51
|
- lib
|
52
52
|
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
53
54
|
requirements:
|
54
55
|
- - ">="
|
55
56
|
- !ruby/object:Gem::Version
|
56
|
-
|
57
|
-
|
57
|
+
hash: 59
|
58
|
+
segments:
|
59
|
+
- 1
|
60
|
+
- 8
|
61
|
+
- 6
|
62
|
+
version: 1.8.6
|
58
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
59
65
|
requirements:
|
60
66
|
- - ">="
|
61
67
|
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
62
71
|
version: "0"
|
63
|
-
version:
|
64
72
|
requirements: []
|
65
73
|
|
66
|
-
rubyforge_project:
|
67
|
-
rubygems_version: 1.3
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.5.3
|
68
76
|
signing_key:
|
69
|
-
specification_version:
|
70
|
-
summary:
|
77
|
+
specification_version: 3
|
78
|
+
summary: TimedCache implements a cache in which you can place objects and specify a timeout value.
|
71
79
|
test_files: []
|
72
80
|
|
data/spec/timed_cache_spec.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "../lib/timedcache")
|
2
|
-
|
3
|
-
$filename = File.join(File.dirname(__FILE__), "specs.db")
|
4
|
-
|
5
|
-
describe "Adding and retrieving objects from the cache" do
|
6
|
-
before(:each) do
|
7
|
-
@memory_cache = TimedCache.new
|
8
|
-
@file_cache = TimedCache.new(:type => :file, :filename => $filename)
|
9
|
-
@caches = [@memory_cache, @file_cache]
|
10
|
-
end
|
11
|
-
|
12
|
-
after do
|
13
|
-
File.delete($filename)
|
14
|
-
end
|
15
|
-
|
16
|
-
it "Can add an object to the cache, specifying a timeout value" do
|
17
|
-
@caches.each do |cache|
|
18
|
-
cache.put(:myobject, "This needs caching", 10).should == "This needs caching"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
it "Cache should hold seperate values for each key" do
|
23
|
-
@caches.each do |cache|
|
24
|
-
cache.put(:myobject, "This needs caching", 10).should == "This needs caching"
|
25
|
-
cache.put(:my_other_object, "...and this too", 10).should == "...and this too"
|
26
|
-
cache.get(:myobject).should == "This needs caching"
|
27
|
-
cache.get(:my_other_object).should == "...and this too"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
it "String and symbol keys are not treated as equivalent" do
|
32
|
-
@caches.each do |cache|
|
33
|
-
cache[:symbolkey] = "Referenced by symbol"
|
34
|
-
cache["stringkey"] = "Referenced by string"
|
35
|
-
|
36
|
-
cache[:symbolkey].should == "Referenced by symbol"
|
37
|
-
cache["symbolkey"].should == nil
|
38
|
-
|
39
|
-
cache["stringkey"].should == "Referenced by string"
|
40
|
-
cache[:stringkey].should == nil
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
it "After the specified timeout value has elapsed, nil should be returned" do
|
45
|
-
@caches.each do |cache|
|
46
|
-
cache.put(:myobject, "This needs caching", 0).should == "This needs caching"
|
47
|
-
cache.get(:myobject).should == nil
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
it "If no object matching the given key is found, nil should be returned" do
|
52
|
-
@caches.each do |cache|
|
53
|
-
cache.get(:my_nonexistant_object).should == nil
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
it "Should be able to use an array as a cache key" do
|
58
|
-
@caches.each do |cache|
|
59
|
-
cache.put([123,234], "Array").should == "Array"
|
60
|
-
cache.get([123,234]).should == "Array"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
it "Passing a block to the TimedCache#get method should substitute the " +
|
65
|
-
"result of the block as the value for the given key" do
|
66
|
-
@caches.each do |cache|
|
67
|
-
cache.put("block_test", 1984, 0)
|
68
|
-
cache.get("block_test") { 2001 }.should == 2001
|
69
|
-
cache.get("block_test").should == 2001
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
it "Passing a block to TimedCache#get should add the result of the callback " +
|
74
|
-
"when there is no existing value for the key given" do
|
75
|
-
@caches.each do |cache|
|
76
|
-
cache.get("new_key_with_block").should == nil
|
77
|
-
cache.get("new_key_with_block") { "Nicholas" }.should == "Nicholas"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
describe "Specifying a default timeout" do
|
83
|
-
it "Should be able to it a default timeout when creating a TimedCache" do
|
84
|
-
cache = TimedCache.new(:default_timeout => 20)
|
85
|
-
cache.should be_kind_of(TimedCache)
|
86
|
-
cache.default_timeout.should == 20
|
87
|
-
end
|
88
|
-
|
89
|
-
it "If no default timeout is set, 60 seconds should be used" do
|
90
|
-
cache = TimedCache.new
|
91
|
-
cache.should be_kind_of(TimedCache)
|
92
|
-
cache.default_timeout.should == 60
|
93
|
-
end
|
94
|
-
|
95
|
-
it "Timeout specified when putting a new object into the cache should override default timeout" do
|
96
|
-
cache = TimedCache.new(:default_timeout => 20)
|
97
|
-
cache.default_timeout.should == 20
|
98
|
-
cache.put("alternative_timeout", "2 minutes", 120)
|
99
|
-
cache.instance_variable_get(:@store).instance_variable_get(:@cache)["alternative_timeout"].
|
100
|
-
instance_variable_get(:@timeout).should == 120
|
101
|
-
end
|
102
|
-
end
|