timeout_cache 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://www.rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ (MIT License)
2
+
3
+ Copyright (c) 2012 Adam Prescott
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,71 @@
1
+ # TimeoutCache
2
+
3
+ A `TimeoutCache` is a simple cache where objects are stored with a fixed expiration time. It is useful when you want to keep an object around for a sufficiently long period of time, but want them to disappear after, say, 5 seconds, or on the first day of next month.
4
+
5
+ # How do I use this thing?
6
+
7
+ A `TimeoutCache` is easy to use.
8
+
9
+ ```ruby
10
+ cache = TimeoutCache.new
11
+ cache[:foo] = :bar
12
+ cache[:foo] #=> bar
13
+
14
+ # wait some time (by default, 60 seconds)
15
+
16
+ cache[:foo] #=> nil
17
+ ```
18
+
19
+ By default, retrievals return `nil` 60 seconds after they're put into the cache. You can control the length of time by using `#set` with the `:time` option:
20
+
21
+ ```ruby
22
+ cache.set(:a, :b, :time => 5)
23
+ cache[:a] #=> :b
24
+ sleep 5
25
+ cache[:a] #=> nil
26
+ ```
27
+
28
+ You can also use an instance of `Time`:
29
+
30
+ ```ruby
31
+ cache.set(:x, :y, :time => Time.now + 50)
32
+ ```
33
+
34
+ If you want to change the default expiration time, do so when you make a new instance of `TimeoutCache` by passing the length of time in seconds.
35
+
36
+ ```ruby
37
+ cache = TimeoutCache.new(10 * 60 * 60) # 10 hours
38
+ ```
39
+
40
+ Unless an object is added to the cache using the `:time` option, the default is used. This default length of time is 60 seconds.
41
+
42
+ # Entry deletion and pruning
43
+
44
+ Expired entries are deleted lazily. If an entry is added with an expire time of 15 seconds and nothing touches the cache, the entry will still be in the cache after 20 seconds. Expired entries are deleted only when a call to `#[]` (or, equivalently, `#get`) finds an expired entry. At that point, `#prune` is called.
45
+
46
+ If you want to manually prune the cache, you may do so by calling `#prune`.
47
+
48
+ # Documentation
49
+
50
+ There's not much to the code, but it's all commented and you can generate documentation with `rake docs`.
51
+
52
+ # Tests
53
+
54
+ You can run the tests with `rake test`.
55
+
56
+ # License / Copyright
57
+
58
+ Copyright (c) 2012 Adam Prescott, released under the MIT license. See the LICENSE file for details.
59
+
60
+ # Contributing
61
+
62
+ The official repository is on GitHub at [aprescott/timeout_cache](https://github.com/aprescott/timeout_cache). Issues should be opened there, as well as pull requests. Submissions should be on a separate feature branch:
63
+
64
+ * Fork and clone
65
+ * Create a feature branch
66
+ * Add code and tests
67
+ * Run all the tests
68
+ * Push you branch to your GitHub repository
69
+ * Send a pull request
70
+
71
+ Your contribution will be assumed to also be licensed under the MIT license.
@@ -0,0 +1,151 @@
1
+ # Copyright (c) 2012 Adam Prescott, licensed under the MIT license. See LICENSE.
2
+
3
+ #
4
+ # TimeoutCache is a simple key-value store where entries expire after a certain
5
+ # time. It implements parts of the Hash interface.
6
+ #
7
+ # cache = TimeoutCache.new
8
+ # cache[:foo] = :bar
9
+ # cache[:foo] #=> bar
10
+ #
11
+ # # wait some time (by default, 60 seconds)
12
+ #
13
+ # cache[:foo] #=> nil
14
+ #
15
+ class TimeoutCache
16
+ VERSION = "0.0.1"
17
+
18
+ # Wraps an object by attaching a time to it.
19
+ class TimedObject # :nodoc:
20
+ attr_reader :value, :expires_at
21
+
22
+ def initialize(value, time)
23
+ @value = value
24
+ @expires_at = time
25
+ end
26
+
27
+ # Returns true if the object has expired.
28
+ # Returns false if the object has not yet expired.
29
+ def expired?
30
+ @expires_at <= Time.now
31
+ end
32
+ end
33
+
34
+ # The default number of seconds an object stays alive.
35
+ DEFAULT_TIMEOUT = 60
36
+
37
+ attr_reader :timeout
38
+
39
+ # Creates a new TimeoutCache.
40
+ #
41
+ # If <tt>timeout</tt> is specified, the default survival time for
42
+ # a cache entry is <tt>timeout</tt> in seconds.
43
+ #
44
+ # If no default value is used, then DEFAULT_TIMEOUT is the default
45
+ # time-to-expire in seconds.
46
+ def initialize(timeout = DEFAULT_TIMEOUT)
47
+ raise ArgumentError.new("Timeout must be > 0") unless timeout > 0
48
+
49
+ @timeout = timeout
50
+
51
+ # we can use this for look-ups in O(1), instead of only find-min in O(1)
52
+ @store = {}
53
+ end
54
+
55
+ # Returns the number of items in the cache.
56
+ def size
57
+ @store.size
58
+ end
59
+ alias_method :length, :size
60
+
61
+ # Returns the value for the given key. If there is no such key in the cache,
62
+ # then this returns nil. If the value has an expire time earlier than or equal
63
+ # to the current time, this returns nil.
64
+ #
65
+ # As an implementation detail, this method calls #prune whenever it finds
66
+ # an element that has expired.
67
+ def [](key)
68
+ val = @store[key]
69
+
70
+ if val
71
+ if val.expired?
72
+ prune
73
+ nil
74
+ else
75
+ val.value
76
+ end
77
+ else
78
+ nil
79
+ end
80
+ end
81
+ alias_method :get, :[]
82
+
83
+ # Returns the expire time of the value for the given key.
84
+ def expire_time(key)
85
+ @store[key].expires_at
86
+ end
87
+
88
+ # Stores an object in the cache with an expire time DEFAULT_TIMEOUT
89
+ # seconds from now.
90
+ def []=(key, value)
91
+ v = TimedObject.new(value, Time.now + timeout)
92
+ @store[key] = v
93
+ end
94
+
95
+ # Stores an object in the cache. options is a hash with symbol keys:
96
+ #
97
+ # :time:: can be either an Integer representing the number of seconds the object should be alive
98
+ # or a Time object representing a fixed time.
99
+ #
100
+ # If time is not specified in the hash, the default timeout length is used.
101
+ #
102
+ # If the object would expire immediately, returns nil, otherwise returns the object stored.
103
+ def set(key, value, options = {})
104
+ time = options[:time] || timeout
105
+
106
+ time = case time
107
+ when Integer
108
+ Time.now + time
109
+ when Time
110
+ time
111
+ end
112
+
113
+ return nil if time <= Time.now
114
+
115
+ v = TimedObject.new(value, time)
116
+ @store[key] = v
117
+
118
+ value
119
+ end
120
+
121
+ # Returns true if the cache is empty, otherwise false.
122
+ def empty?
123
+ @store.empty?
124
+ end
125
+
126
+ # Deletes the key-value pair for the given key.
127
+ #
128
+ # Returns nil if there is no such key, otherwise returns the deleted value.
129
+ def delete(key)
130
+ v = @store.delete(key)
131
+ v ? v.value : v
132
+ end
133
+
134
+ # Removes any expired entries from the cache.
135
+ #
136
+ # If nothing was removed, returns nil, otherwise returns
137
+ # the number of elements removed.
138
+ def prune
139
+ return nil if empty?
140
+
141
+ count = 0
142
+
143
+ @store.delete_if { |k, v| v.expired? && count += 1 }
144
+
145
+ count == 0 ? nil : count
146
+ end
147
+
148
+ def inspect
149
+ %Q{#<#{self.class} #{@store.inspect}>}
150
+ end
151
+ end
@@ -0,0 +1,151 @@
1
+ # Copyright (c) 2012 Adam Prescott, licensed under the MIT license. See LICENSE.
2
+
3
+ #
4
+ # TimeoutCache is a simple key-value store where entries expire after a certain
5
+ # time. It implements parts of the Hash interface.
6
+ #
7
+ # cache = TimeoutCache.new
8
+ # cache[:foo] = :bar
9
+ # cache[:foo] #=> bar
10
+ #
11
+ # # wait some time (by default, 60 seconds)
12
+ #
13
+ # cache[:foo] #=> nil
14
+ #
15
+ class TimeoutCache
16
+ VERSION = "0.0.1"
17
+
18
+ # Wraps an object by attaching a time to it.
19
+ class TimedObject #:nodoc:
20
+ attr_reader :value, :expires_at
21
+
22
+ def initialize(value, time)
23
+ @value = value
24
+ @expires_at = time
25
+ end
26
+
27
+ # Returns true if the object has expired.
28
+ # Returns false if the object has not yet expired.
29
+ def expired?
30
+ @expires_at <= Time.now
31
+ end
32
+ end
33
+
34
+ # The default number of seconds an object stays alive.
35
+ DEFAULT_TIMEOUT = 60
36
+
37
+ attr_reader :timeout
38
+
39
+ # Creates a new TimeoutCache.
40
+ #
41
+ # If <tt>timeout</tt> is specified, the default survival time for
42
+ # a cache entry is <tt>timeout</tt> in seconds.
43
+ #
44
+ # If no default value is used, then DEFAULT_TIMEOUT is the default
45
+ # time-to-expire in seconds.
46
+ def initialize(timeout = DEFAULT_TIMEOUT)
47
+ raise ArgumentError.new("Timeout must be > 0") unless timeout > 0
48
+
49
+ @timeout = timeout
50
+
51
+ # we can use this for look-ups in O(1), instead of only find-min in O(1)
52
+ @store = {}
53
+ end
54
+
55
+ # Returns the number of items in the cache.
56
+ def size
57
+ @store.size
58
+ end
59
+ alias_method :length, :size
60
+
61
+ # Returns the value for the given key. If there is no such key in the cache,
62
+ # then this returns nil. If the value has an expire time earlier than or equal
63
+ # to the current time, this returns nil.
64
+ #
65
+ # As an implementation detail, this method calls #prune whenever it finds
66
+ # an element that has expired.
67
+ def [](key)
68
+ val = @store[key]
69
+
70
+ if val
71
+ if val.expired?
72
+ prune
73
+ nil
74
+ else
75
+ val.value
76
+ end
77
+ else
78
+ nil
79
+ end
80
+ end
81
+ alias_method :get, :[]
82
+
83
+ # Returns the expire time of the value for the given key.
84
+ def expire_time(key)
85
+ @store[key].expires_at
86
+ end
87
+
88
+ # Stores an object in the cache with an expire time DEFAULT_TIMEOUT
89
+ # seconds from now.
90
+ def []=(key, value)
91
+ v = TimedObject.new(value, Time.now + timeout)
92
+ @store[key] = v
93
+ end
94
+
95
+ # Stores an object in the cache. options is a hash with symbol keys:
96
+ #
97
+ # :time:: can be either an Integer representing the number of seconds the object should be alive
98
+ # or a Time object representing a fixed time.
99
+ #
100
+ # If time is not specified in the hash, the default timeout length is used.
101
+ #
102
+ # If the object would expire immediately, returns nil, otherwise returns the object stored.
103
+ def set(key, value, options = {})
104
+ time = options[:time] || timeout
105
+
106
+ time = case time
107
+ when Integer
108
+ Time.now + time
109
+ when Time
110
+ time
111
+ end
112
+
113
+ return nil if time <= Time.now
114
+
115
+ v = TimedObject.new(value, time)
116
+ @store[key] = v
117
+
118
+ value
119
+ end
120
+
121
+ # Returns true if the cache is empty, otherwise false.
122
+ def empty?
123
+ @store.empty?
124
+ end
125
+
126
+ # Deletes the key-value pair for the given key.
127
+ #
128
+ # Returns nil if there is no such key, otherwise returns the deleted value.
129
+ def delete(key)
130
+ v = @store.delete(key)
131
+ v ? v.value : v
132
+ end
133
+
134
+ # Removes any expired entries from the cache.
135
+ #
136
+ # If nothing was removed, returns nil, otherwise returns
137
+ # the number of elements removed.
138
+ def prune
139
+ return nil if empty?
140
+
141
+ count = 0
142
+
143
+ @store.delete_if { |k, v| v.expired? && count += 1 }
144
+
145
+ count == 0 ? nil : count
146
+ end
147
+
148
+ def inspect
149
+ %Q{#<#{self.class} #{@store.inspect}>}
150
+ end
151
+ end
@@ -0,0 +1,26 @@
1
+ require "rake"
2
+ require "rdoc/task"
3
+ require "rspec/core/rake_task"
4
+
5
+ $:.unshift(File.expand_path("lib", __FILE__))
6
+ require "timeout_cache"
7
+
8
+ RSpec::Core::RakeTask.new(:test) do |t|
9
+ t.rspec_opts = "-I test --color --format nested"
10
+ t.pattern = "test/**/*_spec.rb"
11
+ t.verbose = false
12
+ t.fail_on_error = true
13
+ end
14
+
15
+ task :doc => [:docs]
16
+
17
+ Rake::RDocTask.new(:docs) do |rd|
18
+ #rd.main = "docs/README.md"
19
+ rd.main = "" # I'm broken, fix me
20
+ rd.rdoc_dir = "docs"
21
+ rd.title = "TimeoutCache #{TimeoutCache::VERSION}"
22
+ rd.options << '--line-numbers' << '--inline-source'
23
+ rd.rdoc_files.include("README.md", "lib")
24
+ end
25
+
26
+ task :default => :test
@@ -0,0 +1,167 @@
1
+ require "timeout_cache"
2
+ require "rspec"
3
+
4
+ describe TimeoutCache do
5
+ it "uses the global default timeout with no time specified" do
6
+ subject.timeout.should == TimeoutCache::DEFAULT_TIMEOUT
7
+ end
8
+
9
+ it "uses a specified timeout if one is given" do
10
+ TimeoutCache.new(50).timeout.should == 50
11
+ end
12
+
13
+ it "cannot be instantiated with a global timeout <= 0" do
14
+ [0, -1, -5].each do |i|
15
+ expect { TimeoutCache.new(i) }.to raise_error(ArgumentError)
16
+ end
17
+
18
+ expect { TimeoutCache.new(1) }.to_not raise_error
19
+ end
20
+
21
+ describe "#set" do
22
+ it "sets the given key-value pair" do
23
+ subject.set(:a, 1)
24
+ subject.get(:a).should == 1
25
+ end
26
+
27
+ it "sets the given key-value pair with a timeout" do
28
+ t = Time.now + 10
29
+ subject.set(:a, 1, :time => t)
30
+ subject.expire_time(:a).should == t
31
+ end
32
+
33
+ # here be dragons. if it takes too long to execute these
34
+ # commands, the times won't match, so this test isn't deterministic
35
+ it "sets a default timeout time with no time value specified" do
36
+ t = Time.now + subject.timeout
37
+ subject.set(:a, 1)
38
+ subject.expire_time(:a).should_not be_nil
39
+ subject.expire_time(:a).to_i.should == t.to_i
40
+ end
41
+
42
+ it "doesn't set a value if the timeout time is <= now" do
43
+ subject.set(:a, 1, :time => Time.now)
44
+ subject.get(:a).should be_nil
45
+ end
46
+
47
+ it "can have a negative time value" do
48
+ expect { subject.set(:a, 1, :time => -1) }.to_not raise_error
49
+ subject.get(:a).should be_nil
50
+ end
51
+ end
52
+
53
+ describe "#get" do
54
+ it "returns nil if there is no matching key" do
55
+ subject.get(:no_such_key).should be_nil
56
+ end
57
+
58
+ it "returns nil if the object has expired" do
59
+ subject.set(:a, 1, :time => 1)
60
+ subject.get(:a).should == 1
61
+ sleep 2
62
+ subject.get(:a).should be_nil
63
+ end
64
+ end
65
+
66
+ describe "#prune" do
67
+ it "erases expired entries" do
68
+ subject.set(:a, 1, :time => 1)
69
+ subject.get(:a).should == 1
70
+ sleep 2
71
+ subject.prune
72
+ subject.get(:a).should be_nil
73
+ end
74
+
75
+ it "returns nil if nothing was pruned" do
76
+ subject.prune.should be_nil
77
+ end
78
+ end
79
+
80
+ describe "#delete" do
81
+ it "deletes entries from the cache" do
82
+ subject[0] = 1
83
+ subject.delete(0)
84
+ subject[0].should be_nil
85
+ end
86
+
87
+ it "returns nil if nothing was deleted" do
88
+ subject[:no_such_key].should be_nil
89
+
90
+ subject[0] = 1
91
+ subject.delete(0)
92
+ subject.delete(0).should be_nil
93
+ end
94
+
95
+ it "returns the value deleted if the key is deleted" do
96
+ subject[0] = 1
97
+ subject.delete(0).should == 1
98
+ end
99
+ end
100
+
101
+ describe "#size" do
102
+ it "returns the number of entries in the cache" do
103
+ subject.size.should == 0
104
+ subject[:a] = :b
105
+ subject.size.should == 1
106
+ (1..10).each { |n| subject[n] = n }
107
+ subject.size.should == 11
108
+ end
109
+
110
+ it "is 0 if the cache is empty" do
111
+ subject.empty?.should be_true
112
+ subject.size.should == 0
113
+ end
114
+
115
+ it "is non-zero if the cache is empty" do
116
+ subject[:a] = 1
117
+ subject.size.should_not == 0
118
+ end
119
+ end
120
+
121
+ describe "pruning" do
122
+ it "happens when calling #get(key) when get(key) is expired" do
123
+ subject.set(:a, 1, :time => 2)
124
+ subject.set(:b, 1, :time => 2)
125
+ sleep 3
126
+ subject.size.should == 2
127
+ subject.get(:a)
128
+ subject.size.should == 0
129
+ end
130
+
131
+ it "does not happen when calling #get(key) when get(key) is not expired" do
132
+ subject.set(:a, 1, :time => 200)
133
+ subject.set(:b, 1, :time => 2)
134
+ sleep 3
135
+ subject.size.should == 2
136
+ subject.get(:a)
137
+ subject.size.should == 2
138
+ end
139
+ end
140
+
141
+ describe "#empty?" do
142
+ it "is true if the cache is empty" do
143
+ subject.empty?.should be_true
144
+ end
145
+
146
+ it "is false if the cache is not empty" do
147
+ subject.set(:a, 1)
148
+ subject.empty?.should be_false
149
+ end
150
+ end
151
+ end
152
+
153
+ describe TimeoutCache::TimedObject do
154
+ describe "#expired?" do
155
+ it "returns true for expire time > now" do
156
+ TimeoutCache::TimedObject.new(:value, Time.now + 50)
157
+ end
158
+
159
+ it "returns false for expire time < now" do
160
+ TimeoutCache::TimedObject.new(:value, Time.now - 50)
161
+ end
162
+
163
+ it "returns false for expire time = now" do
164
+ TimeoutCache::TimedObject.new(:value, Time.now)
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,163 @@
1
+ require "timeout_cache"
2
+ require "rspec"
3
+
4
+ describe TimeoutCache do
5
+ it "uses the global default timeout with no time specified" do
6
+ subject.timeout.should == TimeoutCache::DEFAULT_TIMEOUT
7
+ end
8
+
9
+ it "uses a specified timeout if one is given" do
10
+ TimeoutCache.new(50).timeout.should == 50
11
+ end
12
+
13
+ it "cannot be instantiated with a global timeout <= 0" do
14
+ [0, -1, -5].each do |i|
15
+ expect { TimeoutCache.new(i) }.to raise_error(ArgumentError)
16
+ end
17
+
18
+ expect { TimeoutCache.new(1) }.to_not raise_error
19
+ end
20
+
21
+ describe "#set" do
22
+ it "sets the given key-value pair" do
23
+ subject.set(:a, 1)
24
+ subject.get(:a).should == 1
25
+ end
26
+
27
+ it "sets the given key-value pair with a timeout" do
28
+ t = Time.now + 10
29
+ subject.set(:a, 1, :time => t)
30
+ subject.expire_time(:a).should == t
31
+ end
32
+
33
+ # here be dragons. if it takes too long to execute these
34
+ # commands, the times won't match, so this test isn't deterministic
35
+ it "sets a default timeout time with no time value specified" do
36
+ t = Time.now + subject.timeout
37
+ subject.set(:a, 1)
38
+ subject.expire_time(:a).should_not be_nil
39
+ subject.expire_time(:a).to_i.should == t.to_i
40
+ end
41
+
42
+ it "doesn't set a value if the timeout time is <= now" do
43
+ subject.set(:a, 1, :time => Time.now)
44
+ subject.get(:a).should be_nil
45
+ end
46
+
47
+ it "can have a negative time value" do
48
+ expect { subject.set(:a, 1, :time => -1) }.to_not raise_error
49
+ subject.get(:a).should be_nil
50
+ end
51
+ end
52
+
53
+ describe "#get" do
54
+ it "returns nil if there is no matching key" do
55
+ subject.get(:no_such_key).should be_nil
56
+ end
57
+
58
+ it "returns nil if the object has expired" do
59
+ subject.set(:a, 1, :time => 1)
60
+ subject.get(:a).should == 1
61
+ sleep 2
62
+ subject.get(:a).should be_nil
63
+ end
64
+ end
65
+
66
+ describe "#prune" do
67
+ it "erases expired entries" do
68
+ subject.set(:a, 1, :time => 1)
69
+ subject.get(:a).should == 1
70
+ sleep 2
71
+ subject.prune
72
+ subject.get(:a).should be_nil
73
+ end
74
+
75
+ it "returns nil if nothing was pruned" do
76
+ subject.prune.should be_nil
77
+ end
78
+ end
79
+
80
+ describe "#delete" do
81
+ it "deletes entries from the cache" do
82
+ subject[0] = 1
83
+ subject.delete(0)
84
+ subject[0].should be_nil
85
+ end
86
+
87
+ it "returns nil if nothing was deleted" do
88
+ subject[:no_such_key].should be_nil
89
+ end
90
+
91
+ it "returns the value deleted if the key is deleted" do
92
+ subject[0] = 1
93
+ subject.delete(0).should == 1
94
+ end
95
+ end
96
+
97
+ describe "#size" do
98
+ it "returns the number of entries in the cache" do
99
+ subject.size.should == 0
100
+ subject[:a] = :b
101
+ subject.size.should == 1
102
+ (1..10).each { |n| subject[n] = n }
103
+ subject.size.should == 11
104
+ end
105
+
106
+ it "is 0 if the cache is empty" do
107
+ subject.empty?.should be_true
108
+ subject.size.should == 0
109
+ end
110
+
111
+ it "is non-zero if the cache is empty" do
112
+ subject[:a] = 1
113
+ subject.size.should_not == 0
114
+ end
115
+ end
116
+
117
+ describe "pruning" do
118
+ it "happens when calling #get(key) when get(key) is expired" do
119
+ subject.set(:a, 1, :time => 2)
120
+ subject.set(:b, 1, :time => 2)
121
+ sleep 3
122
+ subject.size.should == 2
123
+ subject.get(:a)
124
+ subject.size.should == 0
125
+ end
126
+
127
+ it "does not happen when calling #get(key) when get(key) is not expired" do
128
+ subject.set(:a, 1, :time => 200)
129
+ subject.set(:b, 1, :time => 2)
130
+ sleep 3
131
+ subject.size.should == 2
132
+ subject.get(:a)
133
+ subject.size.should == 2
134
+ end
135
+ end
136
+
137
+ describe "#empty?" do
138
+ it "is true if the cache is empty" do
139
+ subject.empty?.should be_true
140
+ end
141
+
142
+ it "is false if the cache is not empty" do
143
+ subject.set(:a, 1)
144
+ subject.empty?.should be_false
145
+ end
146
+ end
147
+ end
148
+
149
+ describe TimeoutCache::TimedObject do
150
+ describe "#expired?" do
151
+ it "returns true for expire time > now" do
152
+ TimeoutCache::TimedObject.new(:value, Time.now + 50)
153
+ end
154
+
155
+ it "returns false for expire time < now" do
156
+ TimeoutCache::TimedObject.new(:value, Time.now - 50)
157
+ end
158
+
159
+ it "returns false for expire time = now" do
160
+ TimeoutCache::TimedObject.new(:value, Time.now)
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,19 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require "timeout_cache"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "timeout_cache"
8
+ s.version = TimeoutCache::VERSION
9
+ s.authors = ["Adam Prescott"]
10
+ s.email = ["adam@aprescott.com"]
11
+ s.homepage = "https://github.com/aprescott/timeout_cache"
12
+ s.summary = "Simple time-based cache."
13
+ s.description = "Simple time-based cache."
14
+ s.files = Dir["{lib/**/*,test/**/*}"] + %w[timeout_cache.gemspec .gemtest LICENSE Gemfile rakefile README.md]
15
+ s.require_path = "lib"
16
+ s.test_files = Dir["test/*"]
17
+ s.add_development_dependency "rake"
18
+ s.add_development_dependency "rspec"
19
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timeout_cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Adam Prescott
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Simple time-based cache.
47
+ email:
48
+ - adam@aprescott.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - lib/timeout_cache.rb~
54
+ - lib/timeout_cache.rb
55
+ - test/timeout_cache_spec.rb
56
+ - test/timeout_cache_spec.rb~
57
+ - timeout_cache.gemspec
58
+ - .gemtest
59
+ - LICENSE
60
+ - Gemfile
61
+ - rakefile
62
+ - README.md
63
+ homepage: https://github.com/aprescott/timeout_cache
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.24
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Simple time-based cache.
87
+ test_files:
88
+ - test/timeout_cache_spec.rb
89
+ - test/timeout_cache_spec.rb~