sir_cachealot 0.4.1 → 0.4.2
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/lib/sir_cachealot.rb +222 -209
- data/lib/sir_cachealot/version.rb +1 -1
- data/spec/sir_cachealot_spec.rb +82 -57
- metadata +2 -2
data/lib/sir_cachealot.rb
CHANGED
@@ -2,216 +2,229 @@ require "sir_cachealot/version"
|
|
2
2
|
|
3
3
|
module Sir
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
@@ram_cache = { }
|
8
|
-
|
9
|
-
@@configuration = {
|
10
|
-
mode: RAM,
|
11
|
-
debug: false,
|
12
|
-
annoy: false, #super annoying debug messages
|
13
|
-
default_expiry: 3600, #Integer(1.hour),
|
14
|
-
delete_on_nil: true
|
15
|
-
|
16
|
-
}
|
17
|
-
|
18
|
-
#Configuration parameters
|
19
|
-
# configure() yields a block, as per convention
|
20
|
-
# configure(key) returns the value of key, or nil
|
21
|
-
# configure(key, value) sets key to value
|
22
|
-
def self.configure(key = nil, value = nil)
|
23
|
-
|
24
|
-
key = key.downcase.to_sym unless key.nil?
|
25
|
-
|
26
|
-
if !key.nil? && !value.nil?
|
27
|
-
@@configuration[key] = value
|
28
|
-
return value
|
29
|
-
|
30
|
-
elsif !key.nil? && value.nil?
|
31
|
-
return @@configuration[key]
|
32
|
-
|
33
|
-
elsif key.nil? && value.nil?
|
34
|
-
yield(@@configuration)
|
35
|
-
|
36
|
-
#normalize keynames
|
37
|
-
@@configuration.keys.each do |k|
|
38
|
-
|
39
|
-
knew = k.downcase.to_sym
|
40
|
-
|
41
|
-
unless knew == k
|
42
|
-
@@configuration[knew] = @@configuration[k]
|
43
|
-
@@configuration.delete(k)
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
class << self
|
53
|
-
alias :config :configure
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
# Gets value for supplied key
|
58
|
-
# Returns nil if empty or expired
|
59
|
-
def self.get(key)
|
60
|
-
|
61
|
-
case config(:mode)
|
62
|
-
when RAM
|
63
|
-
|
64
|
-
if x = @@ram_cache[key]
|
65
|
-
|
66
|
-
if x[:expiry].nil? || x[:expiry] > Time.now
|
67
|
-
return x[:value]
|
68
|
-
else
|
69
|
-
# cache entry is stale
|
70
|
-
puts (" SirCachealot: Cache entry <#{key}> expired at #{x[:expiry]}. Deleting...") if config(:debug)
|
71
|
-
@@ram_cache.delete(key)
|
72
|
-
if block_given?
|
73
|
-
yield
|
74
|
-
else
|
75
|
-
nil
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
else
|
80
|
-
|
81
|
-
if block_given?
|
82
|
-
yield
|
83
|
-
else
|
84
|
-
return nil
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
else
|
89
|
-
puke
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
# deletes the specified key from the cache.
|
95
|
-
# returns true if successful, false if not found
|
96
|
-
def self.delete(key)
|
97
|
-
|
98
|
-
case config(:mode)
|
99
|
-
when RAM
|
100
|
-
if @@ram_cache.has_key?(key)
|
101
|
-
@@ram_cache.delete(key)
|
102
|
-
return true
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
# Puts value in cache, key is param key
|
109
|
-
# Param expiry is optional, it can be a relative or absolute Fixnum or Time object
|
110
|
-
# Returns the value you put into it, unless config(:delete_on_nil) == true and value == nil.
|
111
|
-
# Returns true (because it deleted the key) if config(:delete_on_nil) == true and value == nil.
|
112
|
-
def self.put(key, value, expiry = config(:default_expiry))
|
113
|
-
|
114
|
-
case expiry.class.name
|
115
|
-
when "Fixnum"
|
116
|
-
true
|
117
|
-
when "Time"
|
118
|
-
expiry = Integer(expiry)
|
119
|
-
when "NilClass"
|
120
|
-
true
|
121
|
-
else
|
122
|
-
raise ArgumentError, "Expiry must be a Fixnum or Time object"
|
123
|
-
end
|
124
|
-
|
125
|
-
|
126
|
-
unless (!expiry.nil? && expiry > Integer(Time.now))
|
127
|
-
expiry = Time.now + expiry
|
128
|
-
end
|
129
|
-
|
130
|
-
puts " SirCachealot: Will expire <#{key}> at #{expiry}" if config(:annoy) == true
|
131
|
-
|
132
|
-
if config(:delete_on_nil) == true && value == nil
|
133
|
-
self.delete(key)
|
134
|
-
else
|
135
|
-
case config(:mode)
|
136
|
-
when RAM
|
137
|
-
|
138
|
-
@@ram_cache[key] ||= { }
|
139
|
-
@@ram_cache[key][:value] = value
|
140
|
-
@@ram_cache[key][:expiry] = expiry
|
141
|
-
return value
|
142
|
-
|
143
|
-
else
|
144
|
-
puke
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end
|
151
|
-
|
152
|
-
# Gets the qty of keys in the cache
|
153
|
-
def self.size?
|
154
|
-
|
155
|
-
case config(:mode)
|
156
|
-
when RAM
|
157
|
-
return @@ram_cache.count
|
158
|
-
else
|
159
|
-
puke
|
160
|
-
end
|
161
|
-
|
162
|
-
end
|
163
|
-
|
164
|
-
# Dumps list of cache keys to console, with their value's class.name and expiry
|
165
|
-
def self.dump
|
166
|
-
|
167
|
-
case config(:mode)
|
168
|
-
when RAM
|
169
|
-
@@ram_cache.each do |k, v|
|
170
|
-
puts("%-20s %-20s %20s" % [k, v[:value].class, v[:expiry]])
|
171
|
-
end
|
172
|
-
else
|
173
|
-
puke
|
174
|
-
end
|
175
|
-
|
176
|
-
|
177
|
-
return nil
|
178
|
-
|
179
|
-
end
|
180
|
-
|
181
|
-
# Clears the cache, erases all cache entries
|
182
|
-
def self.clear
|
183
|
-
|
184
|
-
case config(:mode)
|
185
|
-
when RAM
|
186
|
-
@@ram_cache = { }
|
187
|
-
else
|
188
|
-
puke
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
# Sweeps the cache for expired keys and purges them. NOT THREAD-SAFE!
|
194
|
-
def self.clean
|
195
|
-
|
196
|
-
case config(:mode)
|
197
|
-
|
198
|
-
when RAM
|
199
|
-
@@ram_cache.each_key do |k|
|
200
|
-
if !@@ram_cache[k][:expiry].nil? && @@ram_cache[k][:expiry] < Time.now
|
201
|
-
puts(" SirCachealot: Cleaned #{k}") if config(:debug)
|
202
|
-
@@ram_cache.delete(k)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
else
|
206
|
-
puke
|
207
|
-
end
|
208
|
-
|
209
|
-
end
|
5
|
+
RAM = :ram_cache
|
210
6
|
|
211
|
-
|
7
|
+
@@ram_cache = { }
|
212
8
|
|
213
|
-
|
214
|
-
|
215
|
-
|
9
|
+
@@configuration = {
|
10
|
+
mode: RAM,
|
11
|
+
debug: false,
|
12
|
+
annoy: false, #super annoying debug messages
|
13
|
+
default_expiry: 3600, #Integer(1.hour),
|
14
|
+
delete_on_nil: true
|
15
|
+
|
16
|
+
}
|
17
|
+
|
18
|
+
#Configuration parameters
|
19
|
+
# configure() yields a block, as per convention
|
20
|
+
# configure(key) returns the value of key, or nil
|
21
|
+
# configure(key, value) sets key to value
|
22
|
+
def self.configure(key = nil, value = nil)
|
23
|
+
|
24
|
+
key = key.downcase.to_sym unless key.nil?
|
25
|
+
|
26
|
+
if !key.nil? && !value.nil?
|
27
|
+
@@configuration[key] = value
|
28
|
+
return value
|
29
|
+
|
30
|
+
elsif !key.nil? && value.nil?
|
31
|
+
return @@configuration[key]
|
32
|
+
|
33
|
+
elsif key.nil? && value.nil?
|
34
|
+
yield(@@configuration)
|
35
|
+
|
36
|
+
#normalize keynames
|
37
|
+
@@configuration.keys.each do |k|
|
38
|
+
|
39
|
+
knew = k.downcase.to_sym
|
40
|
+
|
41
|
+
unless knew == k
|
42
|
+
@@configuration[knew] = @@configuration[k]
|
43
|
+
@@configuration.delete(k)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
class << self
|
54
|
+
alias :config :configure
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Gets value for supplied key
|
59
|
+
# Returns nil if empty or expired
|
60
|
+
def self.get(key, copy = false)
|
61
|
+
|
62
|
+
to_ret = nil
|
63
|
+
|
64
|
+
case config(:mode)
|
65
|
+
when RAM
|
66
|
+
|
67
|
+
if x = @@ram_cache[key]
|
68
|
+
|
69
|
+
if x[:expiry].nil? || x[:expiry] > Time.now
|
70
|
+
to_ret = x[:value]
|
71
|
+
else
|
72
|
+
# cache entry is stale
|
73
|
+
puts (" SirCachealot: Cache entry <#{key}> expired at #{x[:expiry]}. Deleting...") if config(:debug)
|
74
|
+
@@ram_cache.delete(key)
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
else
|
81
|
+
puke
|
82
|
+
end
|
83
|
+
|
84
|
+
if copy
|
85
|
+
to_ret = self.crude_clone(to_ret)
|
86
|
+
end
|
87
|
+
|
88
|
+
if to_ret.nil? && block_given?
|
89
|
+
to_ret = yield
|
90
|
+
end
|
91
|
+
|
92
|
+
return to_ret
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# deletes the specified key from the cache.
|
98
|
+
# returns true if successful, false if not found
|
99
|
+
def self.delete(key)
|
100
|
+
|
101
|
+
case config(:mode)
|
102
|
+
when RAM
|
103
|
+
if @@ram_cache.has_key?(key)
|
104
|
+
@@ram_cache.delete(key)
|
105
|
+
return true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# Puts value in cache, key is param key
|
113
|
+
# Param expiry is optional, it can be a relative or absolute Fixnum or Time object
|
114
|
+
# Returns the value you put into it, unless config(:delete_on_nil) == true and value == nil.
|
115
|
+
# Returns true (because it deleted the key) if config(:delete_on_nil) == true and value == nil.
|
116
|
+
def self.put(key, value, expiry = config(:default_expiry))
|
117
|
+
|
118
|
+
case expiry.class.name
|
119
|
+
when "Fixnum"
|
120
|
+
true
|
121
|
+
when "Time"
|
122
|
+
expiry = Integer(expiry)
|
123
|
+
when "NilClass"
|
124
|
+
true
|
125
|
+
else
|
126
|
+
raise ArgumentError, "Expiry must be a Fixnum or Time object"
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
unless (!expiry.nil? && expiry > Integer(Time.now))
|
131
|
+
expiry = Time.now + expiry
|
132
|
+
end
|
133
|
+
|
134
|
+
puts " SirCachealot: Will expire <#{key}> at #{expiry}" if config(:annoy) == true
|
135
|
+
|
136
|
+
if config(:delete_on_nil) == true && value == nil
|
137
|
+
self.delete(key)
|
138
|
+
else
|
139
|
+
case config(:mode)
|
140
|
+
when RAM
|
141
|
+
|
142
|
+
@@ram_cache[key] ||= { }
|
143
|
+
@@ram_cache[key][:value] = value
|
144
|
+
@@ram_cache[key][:expiry] = expiry
|
145
|
+
return value
|
146
|
+
|
147
|
+
else
|
148
|
+
puke
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
# Gets the qty of keys in the cache
|
157
|
+
def self.size?
|
158
|
+
|
159
|
+
case config(:mode)
|
160
|
+
when RAM
|
161
|
+
return @@ram_cache.count
|
162
|
+
else
|
163
|
+
puke
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
# Dumps list of cache keys to console, with their value's class.name and expiry
|
170
|
+
def self.dump
|
171
|
+
|
172
|
+
case config(:mode)
|
173
|
+
when RAM
|
174
|
+
@@ram_cache.each do |k, v|
|
175
|
+
puts("%-20s %-20s %20s" % [k, v[:value].class, v[:expiry]])
|
176
|
+
end
|
177
|
+
else
|
178
|
+
puke
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
return nil
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# Clears the cache, erases all cache entries
|
188
|
+
def self.clear
|
189
|
+
|
190
|
+
case config(:mode)
|
191
|
+
when RAM
|
192
|
+
@@ram_cache = { }
|
193
|
+
else
|
194
|
+
puke
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
# Sweeps the cache for expired keys and purges them. NOT THREAD-SAFE!
|
201
|
+
def self.clean
|
202
|
+
|
203
|
+
case config(:mode)
|
204
|
+
|
205
|
+
when RAM
|
206
|
+
@@ram_cache.each_key do |k|
|
207
|
+
if !@@ram_cache[k][:expiry].nil? && @@ram_cache[k][:expiry] < Time.now
|
208
|
+
puts(" SirCachealot: Cleaned #{k}") if config(:debug)
|
209
|
+
@@ram_cache.delete(k)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
else
|
213
|
+
puke
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
private
|
220
|
+
|
221
|
+
def self.puke
|
222
|
+
raise TypeError, "Invalid config(:mode). Check the inputs sent to Sir.configure()"
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
def self.crude_clone(obj)
|
227
|
+
return Marshal.load(Marshal.dump(obj))
|
228
|
+
end
|
216
229
|
|
217
230
|
end
|
data/spec/sir_cachealot_spec.rb
CHANGED
@@ -1,84 +1,109 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
TEST
|
3
|
+
TEST = "test"
|
4
4
|
DEFAULT_EXPIRY = 600
|
5
5
|
|
6
6
|
describe SirCachealot do
|
7
7
|
|
8
|
-
|
8
|
+
it 'should be configurable' do
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
Sir.configure do |config|
|
11
|
+
config[:default_expiry] = DEFAULT_EXPIRY
|
12
|
+
config["MODE"] = :ram_cache
|
13
|
+
config[:debug] = true
|
14
|
+
end
|
15
15
|
|
16
|
-
|
16
|
+
(Sir.config(:default_expiry) == DEFAULT_EXPIRY && Sir.config("MODE") == :ram_cache).should == true
|
17
17
|
|
18
|
-
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
it 'should return the key that is put into it' do
|
21
|
+
Sir.put(:test, TEST).should == TEST
|
22
|
+
end
|
23
23
|
|
24
|
-
|
24
|
+
it 'should return an arbitrary key' do
|
25
25
|
|
26
|
-
|
26
|
+
(Sir.get(:test) == TEST).should == true
|
27
27
|
|
28
|
-
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
it 'should yield when given a block and a key that does not exist' do
|
31
|
+
(Sir.get(:asdoiajdoaijdaodijaodiajdoaidjaodijaodij) { 5 }).should == 5
|
32
|
+
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
it 'should return nil when not given a block and a key that does not exist' do
|
35
|
+
(Sir.get(:asdoiajdoaijdaodijaodiajdoaidjaodijaodij)).should == nil
|
36
|
+
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
it 'should immediately expire a 0-expiry key' do
|
39
|
+
Sir.put(:expire, TEST, 0)
|
40
|
+
sleep(1)
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
Sir.get(:expire).should == nil
|
43
|
+
end
|
44
44
|
|
45
|
-
|
45
|
+
it 'should report its size correctly' do
|
46
46
|
|
47
|
-
|
47
|
+
Sir.size?.should == 1
|
48
48
|
|
49
|
-
|
49
|
+
end
|
50
50
|
|
51
|
-
|
51
|
+
it 'should clean() correctly' do
|
52
52
|
|
53
|
-
|
53
|
+
Sir.clear
|
54
54
|
|
55
|
-
|
56
|
-
|
55
|
+
Sir.put(:clean, TEST, 0)
|
56
|
+
Sir.clean
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
Sir.size?.should == 0
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should dump() correctly' do
|
63
|
+
Sir.put(:dump, TEST)
|
64
|
+
Sir.dump
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should accept a nil-expiry key' do
|
68
|
+
Sir.put(:test_nil, TEST).should == TEST
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should not expire a nil-expiry key' do
|
72
|
+
Sir.get(:test_nil).should == TEST
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should auto-delete a key when fed a nil' do
|
76
|
+
Sir.put(:test_nil, nil).should == true
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should delete a key if specified' do
|
80
|
+
Sir.put(:delete_me, TEST)
|
81
|
+
Sir.delete(:delete_me).should == true
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should return a shallow copy by default' do
|
85
|
+
hash = { :a => { :aa => 0 } }
|
86
|
+
Sir.put(:shallow_copy, hash)
|
87
|
+
|
88
|
+
newhash = Sir.get(:shallow_copy)
|
89
|
+
|
90
|
+
newhash[:a][:aa] = 1
|
91
|
+
|
92
|
+
(hash[:a][:aa]).should == newhash[:a][:aa]
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should return a deep copy when asked' do
|
97
|
+
hash = { :a => { :aa => "0" } }
|
98
|
+
Sir.put(:deep_copy, hash)
|
99
|
+
|
100
|
+
newhash = Sir.get(:deep_copy, true)
|
101
|
+
|
102
|
+
newhash[:a][:aa] = "1"
|
103
|
+
|
104
|
+
(hash[:a][:aa]).should_not == newhash[:a][:aa]
|
105
|
+
|
106
|
+
end
|
61
107
|
|
62
|
-
it 'should dump() correctly' do
|
63
|
-
Sir.put(:dump, TEST)
|
64
|
-
Sir.dump
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'should accept a nil-expiry key' do
|
68
|
-
Sir.put(:test_nil, TEST).should == TEST
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'should not expire a nil-expiry key' do
|
72
|
-
Sir.get(:test_nil).should == TEST
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'should auto-delete a key when fed a nil' do
|
76
|
-
Sir.put(:test_nil, nil).should == true
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'should delete a key if specified' do
|
80
|
-
Sir.put(:delete_me, TEST)
|
81
|
-
Sir.delete(:delete_me).should == true
|
82
|
-
end
|
83
108
|
|
84
109
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sir_cachealot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|