cachetastic 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -1
- data/Gemfile.lock +3 -1
- data/README.md +68 -68
- data/lib/cachetastic/adapters/file.rb +4 -1
- data/lib/cachetastic/adapters/memcached.rb +12 -12
- data/lib/cachetastic/cache.rb +156 -149
- data/lib/cachetastic/cacheable.rb +1 -1
- data/lib/cachetastic/version.rb +1 -1
- data/lib/cachetastic.rb +1 -0
- data/spec/cachetastic/adapters/base_spec.rb +10 -7
- data/spec/cachetastic/cache_spec.rb +0 -5
- data/spec/cachetastic/cacheable_spec.rb +2 -2
- data/spec/spec_helper.rb +9 -16
- metadata +1 -1
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cachetastic (3.
|
4
|
+
cachetastic (3.2.0)
|
5
5
|
activesupport
|
6
6
|
configatron
|
7
7
|
|
@@ -26,6 +26,7 @@ GEM
|
|
26
26
|
rspec-expectations (2.12.1)
|
27
27
|
diff-lcs (~> 1.1.3)
|
28
28
|
rspec-mocks (2.12.1)
|
29
|
+
timecop (0.5.7)
|
29
30
|
yamler (0.1.0)
|
30
31
|
|
31
32
|
PLATFORMS
|
@@ -36,3 +37,4 @@ DEPENDENCIES
|
|
36
37
|
memcache-client
|
37
38
|
rake
|
38
39
|
rspec
|
40
|
+
timecop
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# What is Cachetastic?
|
2
2
|
|
3
3
|
Cachetastic is an incredibly easy to use and administer caching framework. Just because it is easy to use, does not mean that it is light with features. Cachetastic allows you to create classes that extend <code>Cachetastic::Cache</code>, configure them each individually, and much more.
|
4
4
|
|
@@ -6,88 +6,88 @@ Unlike other systems each cache in your system can use different backends via th
|
|
6
6
|
|
7
7
|
Adapters are easy to write, so if the built in adapters don't float your boat, you can easily knock one off in short order.
|
8
8
|
|
9
|
-
|
9
|
+
## Configuration:
|
10
10
|
|
11
|
-
Configuration of Cachetastic is done using the Configatron gem.
|
11
|
+
Configuration of Cachetastic is done using the Configatron gem.
|
12
12
|
|
13
13
|
All configuration settings hang off of the <code>cachetastic</code> namespace on <code>configatron</code>. The default settings all hang off the <code>defaults</code> namespace on the <code>cachetastic</code> namespace, as shown below:
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
15
|
+
```ruby
|
16
|
+
# This will write detailed information to the logger.
|
17
|
+
configatron.cachetastic.defaults.debug = false
|
18
|
+
|
19
|
+
# This is the type of file store to be used for this cache.
|
20
|
+
# More adapters can be developed and plugged in as desired.
|
21
|
+
# The default is Cachetastic::Adapters::LocalMemory
|
22
|
+
configatron.cachetastic.defaults.adapter = Cachetastic::Adapters::LocalMemory
|
23
|
+
configatron.cachetastic.defaults.adapter = Cachetastic::Adapters::File
|
24
|
+
configatron.cachetastic.defaults.adapter = Cachetastic::Adapters::Memcached
|
25
|
+
|
26
|
+
# This will marshall objects into and out of the store.
|
27
|
+
# The default is :none, except for Cachetastic::Adapters::File, which defaults to :yaml
|
28
|
+
configatron.cachetastic.defaults.marshall_method = :none
|
29
|
+
configatron.cachetastic.defaults.marshall_method = :yaml
|
30
|
+
configatron.cachetastic.defaults.marshall_method = :ruby
|
31
|
+
|
32
|
+
# This sets how long objects will live in the cache before they are auto expired.
|
33
|
+
configatron.cachetastic.defaults.default_expiry = 86400 # time in seconds (default: 24 hours)
|
34
|
+
|
35
|
+
# When secodeing objects into the cache the expiry_swing is +/- to the expiry time.
|
36
|
+
# Example: if the expiry time is 1 minute, and the swing is 15 seconds,
|
37
|
+
# objects will go into the cache with an expiry time sometime between 45 seconds and 75 seconds.
|
38
|
+
# The default is 0 seconds.
|
39
|
+
configatron.cachetastic.defaults.expiry_swing = 15
|
40
|
+
|
41
|
+
# Configure logging for the system.
|
42
|
+
# n number of logs can be configured for a cache.
|
43
|
+
log_1 = Logger.new(STDOUT)
|
44
|
+
log_1.level = Logger::DEBUG
|
45
|
+
log_2 = Logger.new("log/cachetastic.log")
|
46
|
+
log_2.level = Logger::ERROR
|
47
|
+
configatron.cachetastic.defaults.logger = [log_1, log_2]
|
48
|
+
```
|
49
49
|
|
50
50
|
Overriding settings per cache is very simple. Let's take the following two caches:
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
```ruby
|
53
|
+
class UserCache < Cachetastic::Cache
|
54
|
+
end
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
class Admin::UserCache < Cachetastic::Cache
|
57
|
+
end
|
58
|
+
```
|
59
59
|
|
60
60
|
If we wanted to set the <code>UserCache</code> to use the <code>Cachetastic::Adapters::File</code> adapter and we wanted to set the adapter for
|
61
61
|
the <code>Admin::UserCache</code> to use <code>Cachetastic::Adapters::Memcached</code>, we would configure them like such:
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
```ruby
|
64
|
+
configatron.cachetastic.user_cache.adapter = Cachetastic::Adapters::File
|
65
|
+
configatron.cachetastic.admin.user_cache.adapter = Cachetastic::Adapters::Memcached
|
66
|
+
```
|
67
67
|
|
68
68
|
In this scenario we have changed the adapters for each of the classes. All of the other default settings will remain intact for each of those classes. This makes it incredibly easy to just change the one parameter you need, and not have to reset them all.
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
70
|
+
## Examples:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class MyAwesomeCache < Cachetastic::Cache
|
74
|
+
end
|
75
|
+
|
76
|
+
MyAwesomeCache.set(1, [1,2,3])
|
77
|
+
MyAwesomeCache.get(1) # => [1,2,3]
|
78
|
+
|
79
|
+
class MyAwesomeCache < Cachetastic::Cache
|
80
|
+
class << self
|
81
|
+
def get(key, x, y)
|
82
|
+
super(key) do
|
83
|
+
n = x + y
|
84
|
+
set(key, n)
|
85
|
+
n
|
87
86
|
end
|
88
87
|
end
|
89
88
|
end
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
89
|
+
end
|
90
|
+
|
91
|
+
MyAwesomeCache.get(1, 2, 4) # => 8
|
92
|
+
MyAwesomeCache.get(1, 4, 4) # => 8
|
93
|
+
```
|
@@ -6,11 +6,11 @@ module Cachetastic # :nodoc:
|
|
6
6
|
# in addition to the default settings:
|
7
7
|
#
|
8
8
|
# configatron.cachetastic.defaults.servers = ['127.0.0.1:11211']
|
9
|
-
# configatron.cachetastic.defaults.mc_options = {:
|
10
|
-
# :
|
11
|
-
# :
|
12
|
-
# :
|
13
|
-
# :
|
9
|
+
# configatron.cachetastic.defaults.mc_options = {c_threshold: 10_000,
|
10
|
+
# compression: true,
|
11
|
+
# debug: false,
|
12
|
+
# readonly: false,
|
13
|
+
# urlencode: false}
|
14
14
|
# configatron.cachetastic.delete_delay = 0
|
15
15
|
#
|
16
16
|
# The <tt>servers</tt> setting defines an <tt>Array</tt> of Mecached
|
@@ -34,11 +34,11 @@ module Cachetastic # :nodoc:
|
|
34
34
|
define_accessor(:delete_delay)
|
35
35
|
self.delete_delay = 0
|
36
36
|
self.servers = ['127.0.0.1:11211']
|
37
|
-
self.mc_options = {:
|
38
|
-
:
|
39
|
-
:
|
40
|
-
:
|
41
|
-
:
|
37
|
+
self.mc_options = {c_threshold: 10_000,
|
38
|
+
compression: true,
|
39
|
+
debug: false,
|
40
|
+
readonly: false,
|
41
|
+
urlencode: false}
|
42
42
|
super
|
43
43
|
connection
|
44
44
|
end
|
@@ -76,14 +76,14 @@ module Cachetastic # :nodoc:
|
|
76
76
|
private
|
77
77
|
def connection
|
78
78
|
unless @_mc_connection && valid? && @_ns_version == get_version
|
79
|
-
@_mc_connection = MemCache.new(self.servers, self.mc_options.merge(:
|
79
|
+
@_mc_connection = MemCache.new(self.servers, self.mc_options.merge(namespace: namespace))
|
80
80
|
end
|
81
81
|
@_mc_connection
|
82
82
|
end
|
83
83
|
|
84
84
|
def ns_connection
|
85
85
|
if !@_ns_connection || !@_ns_connection.active?
|
86
|
-
@_ns_connection = MemCache.new(self.servers, self.mc_options.merge(:
|
86
|
+
@_ns_connection = MemCache.new(self.servers, self.mc_options.merge(namespace: :namespace_versions))
|
87
87
|
end
|
88
88
|
@_ns_connection
|
89
89
|
end
|
data/lib/cachetastic/cache.rb
CHANGED
@@ -13,11 +13,9 @@ module Cachetastic # :nodoc:
|
|
13
13
|
# MyAwesomeCache.get(1) # => nil
|
14
14
|
#
|
15
15
|
# class MyAwesomeCache < Cachetastic::Cache
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# set(key, key * 10)
|
20
|
-
# end
|
16
|
+
# def get(key)
|
17
|
+
# super(key) do
|
18
|
+
# set(key, key * 10)
|
21
19
|
# end
|
22
20
|
# end
|
23
21
|
# end
|
@@ -27,170 +25,179 @@ module Cachetastic # :nodoc:
|
|
27
25
|
# MyAwesomeCache.delete(1)
|
28
26
|
# MyAwesomeCache.get(1) # => 10
|
29
27
|
class Cache
|
28
|
+
include Singleton
|
30
29
|
|
31
30
|
# everything is done at the class level. there won't be any 'instances of it'
|
32
31
|
# using class << self means we don't have to prefix each method with 'self.'
|
33
32
|
class << self
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# An optional third parameter sets the expiry time for the object in the cache.
|
53
|
-
# If no expiry_time is passed in then the default expiry_time that has been configured
|
54
|
-
# will be used.
|
55
|
-
#
|
56
|
-
# If there is an the expiry_swing setting is configured it will be +/- to the
|
57
|
-
# expiry time.
|
58
|
-
def set(key, value, expiry_time = nil)
|
59
|
-
do_with_logging(:set, key) do
|
60
|
-
retryable do
|
61
|
-
self.adapter.set(key, value, calculate_expiry_time(expiry_time))
|
62
|
-
end
|
33
|
+
|
34
|
+
def method_missing(sym, *args, &block)
|
35
|
+
self.instance.send(sym, *args, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
end # class << self
|
39
|
+
|
40
|
+
# Returns an object from the cache for a given key.
|
41
|
+
# If the object comes back as nil and a block is given
|
42
|
+
# that block will be run and the results of the block
|
43
|
+
# will be returned. This can be used to JIT caches, just make
|
44
|
+
# sure in the block to call the set method because the
|
45
|
+
# results of the block are not automatically cached.
|
46
|
+
def get(key, &block)
|
47
|
+
do_with_logging(:get, key) do
|
48
|
+
retryable do
|
49
|
+
val = self.adapter.get(key)
|
50
|
+
handle_store_object(key, adapter.unmarshal(val), &block)
|
63
51
|
end
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
52
|
+
end
|
53
|
+
end # get
|
54
|
+
|
55
|
+
# Set a particular object info the cache for the given key.
|
56
|
+
#
|
57
|
+
# An optional third parameter sets the expiry time for the object in the cache.
|
58
|
+
# If no expiry_time is passed in then the default expiry_time that has been configured
|
59
|
+
# will be used.
|
60
|
+
#
|
61
|
+
# If there is an the expiry_swing setting is configured it will be +/- to the
|
62
|
+
# expiry time.
|
63
|
+
def set(key, value, expiry_time = nil)
|
64
|
+
do_with_logging(:set, key) do
|
65
|
+
retryable do
|
66
|
+
self.adapter.set(key, value, calculate_expiry_time(expiry_time))
|
73
67
|
end
|
74
|
-
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
68
|
+
end
|
69
|
+
end # set
|
70
|
+
|
71
|
+
# Deletes an object from the cache.
|
72
|
+
def delete(key)
|
73
|
+
do_with_logging(:delete, key) do
|
74
|
+
retryable do
|
75
|
+
self.adapter.delete(key)
|
76
|
+
nil
|
83
77
|
end
|
84
|
-
end
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
78
|
+
end
|
79
|
+
end # delete
|
80
|
+
|
81
|
+
# Expires all objects for this cache.
|
82
|
+
def expire_all
|
83
|
+
do_with_logging(:expire_all, nil) do
|
84
|
+
retryable do
|
85
|
+
self.adapter.expire_all
|
86
|
+
nil
|
90
87
|
end
|
91
|
-
@_adapter
|
92
|
-
end # adapter
|
93
|
-
|
94
|
-
# Clears the adapter so it can be redefined. This is useful if you have
|
95
|
-
# reconfigured the cache to use a different adapater, or different settings.
|
96
|
-
def clear_adapter!
|
97
|
-
@_adapter = nil
|
98
88
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
89
|
+
end # expire_all
|
90
|
+
|
91
|
+
# Returns the underlying Cachetastic::Adapters::Base for this cache.
|
92
|
+
def adapter
|
93
|
+
unless @_adapter && @_adapter.valid?
|
94
|
+
@_adapter = Cachetastic::Adapters.build(cache_klass)
|
102
95
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
96
|
+
@_adapter
|
97
|
+
end # adapter
|
98
|
+
|
99
|
+
# Clears the adapter so it can be redefined. This is useful if you have
|
100
|
+
# reconfigured the cache to use a different adapater, or different settings.
|
101
|
+
def clear_adapter!
|
102
|
+
@_adapter = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def cache_klass # :nodoc:
|
106
|
+
self.class
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the Cachetastic::Logger for this cache.
|
110
|
+
def logger
|
111
|
+
unless @_logger
|
112
|
+
@_logger = Cachetastic::Logger.new(adapter.logger)
|
110
113
|
end
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
114
|
+
@_logger
|
115
|
+
end
|
116
|
+
|
117
|
+
def to_configatron(*args) # :nodoc:
|
118
|
+
self.class.to_configatron(*args)
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
# If the expiry time is set to 60 minutes and the expiry_swing time is set to
|
123
|
+
# 15 minutes, this method will return a number between 45 minutes and 75 minutes.
|
124
|
+
def calculate_expiry_time(expiry_time) # :doc:
|
125
|
+
expiry_time = self.adapter.default_expiry if expiry_time.nil?
|
126
|
+
exp_swing = self.adapter.expiry_swing
|
127
|
+
if exp_swing && exp_swing != 0
|
128
|
+
swing = rand(exp_swing.to_i)
|
129
|
+
case rand(2)
|
130
|
+
when 0
|
131
|
+
expiry_time = (expiry_time.to_i + swing)
|
132
|
+
when 1
|
133
|
+
expiry_time = (expiry_time.to_i - swing)
|
126
134
|
end
|
127
|
-
expiry_time
|
128
135
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
if val.respond_to?(:empty?)
|
141
|
-
val = nil if val.empty?
|
142
|
-
elsif val.respond_to?(:blank?)
|
143
|
-
val = nil if val.blank?
|
136
|
+
expiry_time
|
137
|
+
end
|
138
|
+
|
139
|
+
def handle_store_object(key, val, &block)
|
140
|
+
if val.is_a?(Cachetastic::Cache::StoreObject)
|
141
|
+
if val.expired?
|
142
|
+
self.delete(key)
|
143
|
+
val = nil
|
144
|
+
else
|
145
|
+
val = val.value
|
144
146
|
end
|
145
|
-
return val unless val.nil?
|
146
|
-
|
147
|
-
val = yield key if block_given?
|
148
|
-
return val
|
149
147
|
end
|
148
|
+
|
149
|
+
if val.respond_to?(:empty?)
|
150
|
+
val = nil if val.empty?
|
151
|
+
elsif val.respond_to?(:blank?)
|
152
|
+
val = nil if val.blank?
|
153
|
+
end
|
154
|
+
return val unless val.nil?
|
150
155
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
return yield(key) if block_given?
|
156
|
+
val = yield key if block_given?
|
157
|
+
return val
|
158
|
+
end
|
159
|
+
|
160
|
+
def do_with_logging(action, key)
|
161
|
+
if adapter.debug?
|
162
|
+
start_time = Time.now
|
163
|
+
logger.debug(:starting, action, cache_klass.name, key)
|
164
|
+
res = yield if block_given?
|
165
|
+
end_time = Time.now
|
166
|
+
str = ''
|
167
|
+
unless res.nil?
|
168
|
+
str = "[#{res.class.name}]"
|
169
|
+
str << "\t[Size = #{res.size}]" if res.respond_to? :size
|
170
|
+
str << "\t" << res.inspect
|
167
171
|
end
|
172
|
+
logger.debug(:finished, action, cache_klass.name, key, (end_time - start_time), str)
|
173
|
+
return res
|
174
|
+
else
|
175
|
+
return yield(key) if block_given?
|
168
176
|
end
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
177
|
+
end
|
178
|
+
|
179
|
+
def retryable(options = {}, &block)
|
180
|
+
opts = { tries: 3, on: Exception }.merge(options)
|
181
|
+
|
182
|
+
retries = opts[:tries]
|
183
|
+
retry_exceptions = [opts[:on]].flatten
|
184
|
+
|
185
|
+
x = %{
|
186
|
+
begin
|
187
|
+
return yield
|
188
|
+
rescue #{retry_exceptions.join(", ")} => e
|
189
|
+
retries -= 1
|
190
|
+
if retries > 0
|
191
|
+
clear_adapter!
|
192
|
+
retry
|
193
|
+
else
|
194
|
+
raise e
|
187
195
|
end
|
188
|
-
|
196
|
+
end
|
197
|
+
}
|
189
198
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
end # class << self
|
199
|
+
eval(x, &block)
|
200
|
+
end
|
194
201
|
|
195
202
|
end # Cache
|
196
203
|
end # Cachetastic
|
data/lib/cachetastic/version.rb
CHANGED
data/lib/cachetastic.rb
CHANGED
@@ -99,6 +99,7 @@ describe Cachetastic::Adapters do
|
|
99
99
|
before(:each) do
|
100
100
|
configatron.cachetastic.defaults.adapter = "Cachetastic::Adapters::#{adapter}".constantize
|
101
101
|
CarCache.clear_adapter!
|
102
|
+
CarCache.expire_all
|
102
103
|
CarCache.set(:vw, 'Rabbit')
|
103
104
|
end
|
104
105
|
|
@@ -153,12 +154,14 @@ describe Cachetastic::Adapters do
|
|
153
154
|
CarCache.get(:bmw).should_not be_nil
|
154
155
|
end
|
155
156
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
157
|
+
unless adapter == "Memcached"
|
158
|
+
it 'should set an object into the cache with an expiry' do
|
159
|
+
CarCache.get(:bmw).should be_nil
|
160
|
+
CarCache.set(:bmw, 'Beamer!', 1)
|
161
|
+
CarCache.get(:bmw).should_not be_nil
|
162
|
+
Timecop.travel(1.hour.from_now)
|
163
|
+
CarCache.get(:bmw).should be_nil
|
164
|
+
end
|
162
165
|
end
|
163
166
|
|
164
167
|
end
|
@@ -188,7 +191,7 @@ describe Cachetastic::Adapters do
|
|
188
191
|
describe 'retry' do
|
189
192
|
|
190
193
|
it 'should retry if there is an exception' do
|
191
|
-
CarCache.should_receive(:clear_adapter!).twice
|
194
|
+
CarCache.instance.should_receive(:clear_adapter!).twice
|
192
195
|
lambda {
|
193
196
|
CarCache.get(:audi) do
|
194
197
|
raise Cachetastic::BlockError.new
|
@@ -65,11 +65,6 @@ describe Cachetastic::Cache do
|
|
65
65
|
configatron.temp do
|
66
66
|
configatron.cachetastic.defaults.expiry_swing = 15
|
67
67
|
configatron.cachetastic.defaults.default_expiry = 60
|
68
|
-
SimpleCache.class_eval do
|
69
|
-
class << self
|
70
|
-
public :calculate_expiry_time
|
71
|
-
end
|
72
|
-
end
|
73
68
|
10.times do
|
74
69
|
SimpleCache.calculate_expiry_time(60).should >= 45
|
75
70
|
SimpleCache.calculate_expiry_time(60).should <= 75
|
@@ -28,14 +28,14 @@ describe Cachetastic::Cacheable do
|
|
28
28
|
|
29
29
|
it 'should create a new cache class if one doesnt already exist' do
|
30
30
|
MyObject.cache_class.should == Cachetastic::Cacheable::MyObjectCache
|
31
|
-
Cachetastic::Cacheable::MyObjectCache.
|
31
|
+
Cachetastic::Cacheable::MyObjectCache.instance.should be_kind_of(Cachetastic::Cache)
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'should handle namespaced classes correctly' do
|
35
35
|
Cachetastic::Cacheable.should_not be_const_defined(:My_Namespaced_ThingCache)
|
36
36
|
My::Namespaced::Thing.cache_class.should == Cachetastic::Cacheable::My_Namespaced_ThingCache
|
37
37
|
Cachetastic::Cacheable.should be_const_defined(:My_Namespaced_ThingCache)
|
38
|
-
Cachetastic::Cacheable::My_Namespaced_ThingCache.
|
38
|
+
Cachetastic::Cacheable::My_Namespaced_ThingCache.instance.should be_kind_of(Cachetastic::Cache)
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'should override cache_klass to return the name of the original class, not the generated class' do
|
data/spec/spec_helper.rb
CHANGED
@@ -3,25 +3,18 @@ ENV["RACK_ENV"] ||= "test"
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
|
5
5
|
require 'cachetastic' # and any other gems you need
|
6
|
+
require 'timecop'
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
config.before
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
config.after(:all) do
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
config.before(:each) do
|
18
|
-
|
8
|
+
RSpec.configure do |config|
|
9
|
+
|
10
|
+
config.before do
|
11
|
+
Timecop.freeze
|
19
12
|
end
|
20
|
-
|
21
|
-
config.after
|
22
|
-
|
13
|
+
|
14
|
+
config.after do
|
15
|
+
Timecop.return
|
23
16
|
end
|
24
|
-
|
17
|
+
|
25
18
|
end
|
26
19
|
|
27
20
|
class Cachetastic::BlockError < StandardError
|