cache-machine 0.1.9 → 0.1.10
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/.gitignore +6 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +1 -0
- data/VERSION +1 -1
- data/cache-machine.gemspec +7 -2
- data/lib/cache_machine/cache.rb +55 -8
- data/lib/cache_machine/cache/map.rb +106 -49
- data/lib/cache_machine/helpers/cache_helper.rb +12 -0
- data/lib/cache_machine/logger.rb +8 -1
- data/spec/fixtures.rb +86 -0
- data/spec/lib/cache_machine_spec.rb +110 -209
- metadata +26 -9
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.10
|
data/cache-machine.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cache-machine}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.10"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Sergei Zinin", "Kevin Goslar"]
|
12
|
-
s.date = %q{2011-10-
|
12
|
+
s.date = %q{2011-10-22}
|
13
13
|
s.description = %q{A Ruby on Rails framework to support cache management based on explicitely modeled caching dependencies.}
|
14
14
|
s.email = %q{kgoslar@partyearth.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -29,15 +29,20 @@ Gem::Specification.new do |s|
|
|
29
29
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
30
30
|
s.add_runtime_dependency(%q<rails>, [">= 0"])
|
31
31
|
s.add_runtime_dependency(%q<activemodel>, [">= 0"])
|
32
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
32
33
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
33
34
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
|
34
35
|
else
|
35
36
|
s.add_dependency(%q<rails>, [">= 0"])
|
37
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
38
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
36
39
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
37
40
|
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
38
41
|
end
|
39
42
|
else
|
40
43
|
s.add_dependency(%q<rails>, [">= 0"])
|
44
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
45
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
41
46
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
42
47
|
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
43
48
|
end
|
data/lib/cache_machine/cache.rb
CHANGED
@@ -4,13 +4,38 @@ module CacheMachine
|
|
4
4
|
module Cache
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
+
# Enable cache by default.
|
8
|
+
@enabled = true
|
9
|
+
|
7
10
|
# Supported by default cache formats.
|
8
11
|
@formats = [nil, :ehtml, :html, :json, :xml]
|
9
12
|
|
13
|
+
# Returns if cache is enabled.
|
14
|
+
#
|
15
|
+
# @return [ false, true ]
|
16
|
+
def self.enabled?
|
17
|
+
@enabled
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns currently set formats.
|
21
|
+
#
|
22
|
+
# @return [Array<Symbol>]
|
10
23
|
def self.formats
|
11
24
|
@formats
|
12
25
|
end
|
13
26
|
|
27
|
+
# Enables/disables cache.
|
28
|
+
#
|
29
|
+
# @param [ false, true ] is_enabled
|
30
|
+
def self.enabled= is_enabled
|
31
|
+
@enabled = is_enabled
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets default formats.
|
35
|
+
#
|
36
|
+
# @note Empty format entry will always be present.
|
37
|
+
#
|
38
|
+
# @param [ Array<Symbol> ] formats
|
14
39
|
def self.formats= formats
|
15
40
|
@formats = [nil] | [*formats]
|
16
41
|
end
|
@@ -21,46 +46,68 @@ module CacheMachine
|
|
21
46
|
end
|
22
47
|
|
23
48
|
module ClassMethods
|
49
|
+
|
24
50
|
# Initializes tracking associations to write and reset cache.
|
25
|
-
# +associations+ parameter is to represent cache map with hash.
|
26
51
|
#
|
27
|
-
#
|
28
|
-
# # Cache associated collections
|
52
|
+
# @example Cache associated collections.
|
29
53
|
# acts_as_cache_machine_for :cats, :dogs
|
30
|
-
#
|
31
|
-
# # Cache result of method to be expired when collection changes.
|
54
|
+
# @example Cache result of method to be expired when collection changes.
|
32
55
|
# acts_as_cache_machine_for :cats => :cat_ids
|
33
|
-
#
|
34
|
-
# # Cache and expire dependent collections (_mouse_ change invalidates all other collection caches by chain)
|
56
|
+
# @example Cache and expire dependent collections (_mouse_ change invalidates all other collection caches by chain)
|
35
57
|
# acts_as_cache_machine_for :mouses => :cats, :cats => [:dogs, :bears], :dogs, :bears
|
58
|
+
#
|
59
|
+
# @param [ Hash<Symbol, Array> ] associations Cache Map
|
36
60
|
def acts_as_cache_machine_for *associations
|
61
|
+
Time.zone ||= ActiveSupport::TimeZone[0]
|
62
|
+
|
37
63
|
include CacheMachine::Cache::Map
|
38
64
|
cache_associated(associations)
|
39
65
|
end
|
40
66
|
alias :cache_map :acts_as_cache_machine_for
|
41
67
|
|
42
68
|
# Returns timestamp of class collection.
|
69
|
+
#
|
70
|
+
# @example Return timestamp of the class.
|
71
|
+
# MyActiveRecordClass.timestamp
|
72
|
+
#
|
73
|
+
# @param [ Symbol ] format
|
74
|
+
#
|
75
|
+
# @return [ String ]
|
43
76
|
def timestamp format = nil
|
44
77
|
Rails.cache.fetch(timestamp_key format) { Time.now.to_i.to_s }
|
45
78
|
end
|
46
79
|
|
47
80
|
# Returns cache key to fetch timestamp from memcached.
|
81
|
+
#
|
82
|
+
# @param [ Symbol ] format
|
83
|
+
#
|
84
|
+
# @return [ String ]
|
48
85
|
def timestamp_key format = nil
|
49
86
|
[self.name, format, 'timestamp'].join '_'
|
50
87
|
end
|
51
88
|
|
52
|
-
# Returns cache key of
|
89
|
+
# Returns cache key of anything with timestamp attached.
|
90
|
+
#
|
91
|
+
# @example Return timestamped key of the class.
|
92
|
+
# MyActiveRecordClass.timestamped_key
|
93
|
+
#
|
94
|
+
# @param [Symbol] format
|
95
|
+
#
|
96
|
+
# @return [ String ]
|
53
97
|
def timestamped_key format = nil
|
54
98
|
[timestamp_key(format), timestamp(format)].join '_'
|
55
99
|
end
|
56
100
|
|
57
101
|
# Resets timestamp of class collection.
|
102
|
+
#
|
103
|
+
# @param [ Symbol ] format
|
58
104
|
def reset_timestamp format = nil
|
59
105
|
cache_key = timestamp_key format
|
60
106
|
CacheMachine::Logger.info "CACHE_MACHINE (reset_timestamp): deleting '#{cache_key}'."
|
61
107
|
Rails.cache.delete(cache_key)
|
62
108
|
end
|
63
109
|
|
110
|
+
# Resets all timestams for all formats.
|
64
111
|
def reset_timestamps
|
65
112
|
CacheMachine::Cache.formats.each { |format| reset_timestamp format }
|
66
113
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module CacheMachine
|
2
2
|
module Cache
|
3
3
|
|
4
|
-
# Module to write and expire association cache by given map.
|
5
4
|
module Map
|
6
5
|
extend ActiveSupport::Concern
|
7
6
|
|
@@ -14,7 +13,10 @@ module CacheMachine
|
|
14
13
|
end
|
15
14
|
|
16
15
|
module ClassMethods
|
16
|
+
|
17
17
|
# Fills cache map.
|
18
|
+
#
|
19
|
+
# @param [ Hash<Symbol, Array> ] associations
|
18
20
|
def cache_associated associations
|
19
21
|
[*associations].each do |association|
|
20
22
|
self.cache_map.merge! association.is_a?(Hash) ? association : {association => []}
|
@@ -22,20 +24,32 @@ module CacheMachine
|
|
22
24
|
end
|
23
25
|
|
24
26
|
# Defines timestamp for object.
|
27
|
+
#
|
28
|
+
# @example Define timestamp to be updated every hour.
|
29
|
+
# class MyModel < ActiveRecord::Base
|
30
|
+
# include CacheMachine::Cache
|
31
|
+
# define_timestamp(:my_timestamp, :expires_in => 1.hour) { my_optional_value }
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @param [ String, Symbol ] timestamp_name
|
35
|
+
# @param [ Hash ] options
|
25
36
|
def define_timestamp timestamp_name, options = {}, &block
|
26
|
-
|
37
|
+
if block_given?
|
38
|
+
options[:timestamp] = block
|
39
|
+
end
|
27
40
|
|
28
41
|
define_method timestamp_name do
|
29
42
|
fetch_cache_of(timestamp_key_of(timestamp_name), options) do
|
30
43
|
CacheMachine::Logger.info "CACHE_MACHINE (define_timestamp): deleting old timestamp '#{timestamp_name}'."
|
31
44
|
delete_cache_of timestamp_name # Case when cache expired by time.
|
32
|
-
Time.now.to_i.to_s
|
45
|
+
Time.zone.now.to_i.to_s
|
33
46
|
end
|
34
47
|
end
|
35
48
|
end
|
36
49
|
|
37
|
-
# Deletes cache of collection
|
38
|
-
#
|
50
|
+
# Deletes cache of collection associated via many-to-many.
|
51
|
+
#
|
52
|
+
# @param [ ActiveRecord::Base ]
|
39
53
|
def delete_association_cache_on record, reflection
|
40
54
|
pk = record.class.primary_key
|
41
55
|
|
@@ -50,8 +64,10 @@ module CacheMachine
|
|
50
64
|
end
|
51
65
|
end
|
52
66
|
|
53
|
-
#
|
54
|
-
|
67
|
+
# Hooks association changes.
|
68
|
+
#
|
69
|
+
# @private
|
70
|
+
def has_many(association_id, options = {}) #:nodoc:
|
55
71
|
# Ensure what collection should be tracked.
|
56
72
|
if (should_be_on_hook = self.cache_map.keys.include?(association_id)) && options[:through]
|
57
73
|
# If relation is _many_to_many_ track collection changes.
|
@@ -62,11 +78,15 @@ module CacheMachine
|
|
62
78
|
hook_cache_machine_on association_id if should_be_on_hook
|
63
79
|
end
|
64
80
|
|
65
|
-
#
|
66
|
-
|
81
|
+
# Hooks association changes.
|
82
|
+
#
|
83
|
+
# @private
|
84
|
+
def has_and_belongs_to_many(association_id, options = {}) #:nodoc:
|
85
|
+
|
67
86
|
# Ensure what collection should be tracked.
|
68
87
|
if(should_be_on_hook = self.cache_map.keys.include?(association_id))
|
69
|
-
|
88
|
+
|
89
|
+
# If relation is many-to-many track collection changes.
|
70
90
|
options[:after_add] = \
|
71
91
|
options[:before_remove] = :delete_association_cache_on
|
72
92
|
end
|
@@ -76,7 +96,9 @@ module CacheMachine
|
|
76
96
|
|
77
97
|
protected
|
78
98
|
|
79
|
-
# Hooks Cache Machine
|
99
|
+
# Hooks Cache Machine.
|
100
|
+
#
|
101
|
+
# @param [ Symbol ] association_id
|
80
102
|
def hook_cache_machine_on association_id
|
81
103
|
reset_cache_proc = Proc.new do |reflection, target_class, &block|
|
82
104
|
block ||= lambda { target_class.delete_association_cache_on self, reflection }
|
@@ -104,48 +126,65 @@ module CacheMachine
|
|
104
126
|
end
|
105
127
|
|
106
128
|
module InstanceMethods
|
107
|
-
|
108
|
-
#
|
129
|
+
|
130
|
+
# Returns cache key of the member.
|
131
|
+
#
|
132
|
+
# @param [ Symbol ] _member
|
133
|
+
# @param [ Hash ] options
|
134
|
+
#
|
135
|
+
# @return [ String ]
|
109
136
|
def cache_key_of _member, options = {}
|
110
|
-
|
137
|
+
timestamp = instance_eval(&options[:timestamp]) if options.has_key? :timestamp
|
138
|
+
|
139
|
+
[ self.class.name,
|
140
|
+
self.to_param,
|
141
|
+
_member,
|
142
|
+
options[:format],
|
143
|
+
options[:page] || 1,
|
144
|
+
timestamp ].flatten.compact.join '/'
|
111
145
|
end
|
112
146
|
|
113
|
-
# Fetches cache of
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
147
|
+
# Fetches cache of the member.
|
148
|
+
#
|
149
|
+
# @example Fetch cache of associated collection to be refreshed every hour.
|
150
|
+
# @instance.fetch_cache_of :association, :timestamp => lambda { custom_instance_method },
|
151
|
+
# :expires_in => 1.hour
|
152
|
+
#
|
153
|
+
# @param [ Symbol ] _member
|
154
|
+
# @param [ Hash ] options
|
155
|
+
#
|
156
|
+
# @return [ * ]
|
117
157
|
def fetch_cache_of _member, options = {}, &block
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
expires_in = if expires_at = options[:expires_at]
|
126
|
-
expires_at = expires_at.call if expires_at.kind_of? Proc
|
158
|
+
if CacheMachine::Cache::enabled?
|
159
|
+
expires_in = if expires_at = options[:expires_at]
|
160
|
+
if expires_at.kind_of? Proc
|
161
|
+
expires_at = expires_at.call
|
162
|
+
end
|
127
163
|
|
128
|
-
|
129
|
-
|
164
|
+
if expires_at.kind_of? Time
|
165
|
+
expires_at - Time.zone.now
|
166
|
+
else
|
167
|
+
raise ArgumentError, "expires_at is not a Time"
|
168
|
+
end
|
130
169
|
else
|
131
|
-
|
170
|
+
options[:expires_in]
|
132
171
|
end
|
172
|
+
|
173
|
+
CacheMachine::Logger.info "CACHE_MACHINE (fetch_cache_of): reading '#{cache_key}'."
|
174
|
+
Rails.cache.fetch(cache_key_of(_member, options), :expires_in => expires_in, &block)
|
133
175
|
else
|
134
|
-
|
176
|
+
yield
|
135
177
|
end
|
136
|
-
|
137
|
-
CacheMachine::Logger.info "CACHE_MACHINE (fetch_cache_of): reading '#{cache_key}'."
|
138
|
-
Rails.cache.fetch(cache_key, :expires_in => expires_in, &block)
|
139
178
|
end
|
140
179
|
|
141
180
|
# Removes all caches using map.
|
142
181
|
def delete_all_caches
|
143
|
-
self.class.cache_map.
|
144
|
-
delete_cache_of cached_collection
|
145
|
-
end
|
182
|
+
self.class.cache_map.to_a.flatten.uniq.each &method(:delete_cache_of)
|
146
183
|
end
|
147
184
|
|
148
|
-
# Recursively deletes cache by map
|
185
|
+
# Recursively deletes cache by map starting from the member.
|
186
|
+
#
|
187
|
+
# @param [ Symbol ] _member
|
149
188
|
def delete_cache_of _member
|
150
189
|
delete_cache_of_only _member
|
151
190
|
if chain = self.class.cache_map[_member]
|
@@ -153,7 +192,9 @@ module CacheMachine
|
|
153
192
|
end
|
154
193
|
end
|
155
194
|
|
156
|
-
# Deletes cache of only
|
195
|
+
# Deletes cache of the only member ignoring cache map.
|
196
|
+
#
|
197
|
+
# @param [ Symbol ] _member
|
157
198
|
def delete_cache_of_only _member
|
158
199
|
CacheMachine::Cache.formats.each do |cache_format|
|
159
200
|
page_nr = 0; begin
|
@@ -164,24 +205,38 @@ module CacheMachine
|
|
164
205
|
reset_timestamp_of _member
|
165
206
|
end
|
166
207
|
|
167
|
-
# Returns timestamp cache key for
|
208
|
+
# Returns timestamp cache key for anything.
|
209
|
+
#
|
210
|
+
# @param [ String, Symbol ] anything
|
211
|
+
#
|
212
|
+
# @return [ String ]
|
168
213
|
def timestamp_key_of anything
|
169
|
-
[self.class.name, self.to_param, anything, 'timestamp'].join '
|
214
|
+
[self.class.name, self.to_param, anything, 'timestamp'].join '/'
|
170
215
|
end
|
171
216
|
|
172
|
-
# Returns timestamp of
|
217
|
+
# Returns timestamp of anything from memcached.
|
218
|
+
#
|
219
|
+
# @param [ String, Symbol ] anything
|
220
|
+
#
|
221
|
+
# @return [ String ]
|
173
222
|
def timestamp_of anything
|
174
|
-
|
175
|
-
|
176
|
-
|
223
|
+
if CacheMachine::Cache::enabled?
|
224
|
+
key = timestamp_key_of anything
|
225
|
+
CacheMachine::Logger.info "CACHE_MACHINE (timestamp_of): reading timestamp '#{key}'."
|
226
|
+
Rails.cache.fetch(key) { Time.zone.now.to_i.to_s }
|
227
|
+
else
|
228
|
+
Time.zone.now.to_i.to_s
|
229
|
+
end
|
177
230
|
end
|
178
231
|
|
179
232
|
# Returns cache key of +anything+ with timestamp attached.
|
233
|
+
#
|
234
|
+
# @return [ String ]
|
180
235
|
def timestamped_key_of anything, options = {}
|
181
|
-
[cache_key_of(anything, options), timestamp_of(anything)].join '
|
236
|
+
[cache_key_of(anything, options), timestamp_of(anything)].join '/'
|
182
237
|
end
|
183
238
|
|
184
|
-
# Deletes cache of
|
239
|
+
# Deletes cache of anything from memory.
|
185
240
|
def reset_timestamp_of anything
|
186
241
|
cache_key = timestamp_key_of anything
|
187
242
|
CacheMachine::Logger.info "CACHE_MACHINE (reset_timestamp_of): deleting '#{cache_key}'."
|
@@ -190,8 +245,10 @@ module CacheMachine
|
|
190
245
|
|
191
246
|
protected
|
192
247
|
|
193
|
-
# Deletes cache of associated collection what contains
|
194
|
-
# Called only when
|
248
|
+
# Deletes cache of associated collection what contains record.
|
249
|
+
# Called only when many-to-many collection changed.
|
250
|
+
#
|
251
|
+
# @param [ ActiveRecord::Base ] record
|
195
252
|
def delete_association_cache_on record
|
196
253
|
|
197
254
|
# Find all associations with +record+ by its class.
|
@@ -1,6 +1,18 @@
|
|
1
1
|
module CacheMachine
|
2
2
|
module Helpers
|
3
3
|
module CacheHelper
|
4
|
+
|
5
|
+
# Returns cached EHTML content.
|
6
|
+
#
|
7
|
+
# @example Return html from cache.
|
8
|
+
# = cache_for @instance, :association do
|
9
|
+
# %div= @instance.associated_records
|
10
|
+
#
|
11
|
+
# @param [ ActiveRecord::Base ] record
|
12
|
+
# @param [ Symbol ] cacheable
|
13
|
+
# @param [ Hash ] options
|
14
|
+
#
|
15
|
+
# @return [ String ]
|
4
16
|
def cache_for record, cacheable, options = {}, &block
|
5
17
|
record.fetch_cache_of(cacheable, options.merge(:format => :ehtml)) { capture &block }
|
6
18
|
end
|
data/lib/cache_machine/logger.rb
CHANGED
@@ -16,7 +16,11 @@ module CacheMachine
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# Sets the log level for CacheMachine.
|
19
|
-
#
|
19
|
+
#
|
20
|
+
# @example Call like this in your your code, best in development.rb:
|
21
|
+
# ActiveRecord::CacheMachine::Logger.level = :info
|
22
|
+
#
|
23
|
+
# @param [Symbol] value
|
20
24
|
def level= value
|
21
25
|
@@level = LOGGING_LEVELS[value] or raise "CACHE_MACHINE: Unknown log level: '#{value}'."
|
22
26
|
if @@level <= LOGGING_LEVELS[:info]
|
@@ -25,6 +29,9 @@ module CacheMachine
|
|
25
29
|
end
|
26
30
|
|
27
31
|
# Logs the given entry with the given log level.
|
32
|
+
#
|
33
|
+
# @param [ Symbol ] level
|
34
|
+
# @param [ String ] text
|
28
35
|
def write level, text
|
29
36
|
if @@level <= (LOGGING_LEVELS[level] or raise "CACHE_MACHINE: Unknown log level: '#{level}'.")
|
30
37
|
puts text
|
data/spec/fixtures.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
TARGET_TABLE_NAME = "cachers"
|
2
|
+
HABTM_TABLE_NAME = "has_and_belongs_to_many_cacheables"
|
3
|
+
HABTM_JOINS_TABLE_NAME = [TARGET_TABLE_NAME, HABTM_TABLE_NAME].join('_')
|
4
|
+
HABTM_ASSOCIATION_NAME = HABTM_TABLE_NAME.singularize
|
5
|
+
HM_TABLE_NAME = "has_many_cacheables"
|
6
|
+
HMT_JOINS_TABLE_NAME = "joins"
|
7
|
+
HMT_TABLE_NAME = "has_many_through_cacheables"
|
8
|
+
HO_TABLE_NAME = "hs_one_cacheables"
|
9
|
+
POLY_TABLE_NAME = "polymorphics"
|
10
|
+
TARGET_ASSOCIATION_NAME = TARGET_TABLE_NAME.singularize
|
11
|
+
HMT_ASSOCIATION_NAME = HMT_TABLE_NAME.singularize
|
12
|
+
|
13
|
+
class TestMigration < ActiveRecord::Migration
|
14
|
+
def self.up
|
15
|
+
self.down
|
16
|
+
create_table(HABTM_TABLE_NAME)
|
17
|
+
create_table(HM_TABLE_NAME) { |t| t.references TARGET_ASSOCIATION_NAME }
|
18
|
+
create_table(HMT_TABLE_NAME)
|
19
|
+
create_table(HMT_JOINS_TABLE_NAME) { |t| [TARGET_ASSOCIATION_NAME, HMT_ASSOCIATION_NAME].each &t.method(:references) }
|
20
|
+
create_table(POLY_TABLE_NAME) { |t| t.references(:polymorhicable); t.string(:polymorhicable_type) }
|
21
|
+
create_table(TARGET_TABLE_NAME) { |t| t.string :name; t.integer(:parent_id) }
|
22
|
+
create_table(HABTM_JOINS_TABLE_NAME, :id => false) { |t| [TARGET_ASSOCIATION_NAME, HABTM_ASSOCIATION_NAME].each &t.method(:references) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.down
|
26
|
+
drop_table POLY_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(POLY_TABLE_NAME)
|
27
|
+
drop_table TARGET_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(TARGET_TABLE_NAME)
|
28
|
+
drop_table HABTM_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HABTM_TABLE_NAME)
|
29
|
+
drop_table HM_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HM_TABLE_NAME)
|
30
|
+
drop_table HMT_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HMT_TABLE_NAME)
|
31
|
+
drop_table HO_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HO_TABLE_NAME)
|
32
|
+
drop_table HMT_JOINS_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HMT_JOINS_TABLE_NAME)
|
33
|
+
drop_table HABTM_JOINS_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HABTM_JOINS_TABLE_NAME)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
TestMigration.up
|
37
|
+
|
38
|
+
class HasManyCacheable < ActiveRecord::Base
|
39
|
+
set_table_name HM_TABLE_NAME
|
40
|
+
belongs_to :cacher, :class_name => 'Cacher'
|
41
|
+
end
|
42
|
+
|
43
|
+
class HasManyThroughCacheable < ActiveRecord::Base
|
44
|
+
set_table_name HMT_TABLE_NAME
|
45
|
+
|
46
|
+
has_many :joins, :class_name => 'Join'
|
47
|
+
has_many :cachers, :through => :joins, :class_name => 'Cacher'
|
48
|
+
end
|
49
|
+
|
50
|
+
class Join < ActiveRecord::Base
|
51
|
+
set_table_name HMT_JOINS_TABLE_NAME
|
52
|
+
|
53
|
+
belongs_to :cacher, :class_name => 'Cacher'
|
54
|
+
belongs_to :has_many_through_cacheable, :class_name => 'HasManyThroughCacheable'
|
55
|
+
end
|
56
|
+
|
57
|
+
class HasAndBelongsToManyCacheable < ActiveRecord::Base
|
58
|
+
set_table_name HABTM_TABLE_NAME
|
59
|
+
has_and_belongs_to_many :cachers, :class_name => 'Cacher'
|
60
|
+
end
|
61
|
+
|
62
|
+
class Polymorphic < ActiveRecord::Base
|
63
|
+
set_table_name POLY_TABLE_NAME
|
64
|
+
belongs_to :polymorhicable, :polymorphic => true
|
65
|
+
end
|
66
|
+
|
67
|
+
class Cacher < ActiveRecord::Base
|
68
|
+
set_table_name TARGET_TABLE_NAME
|
69
|
+
|
70
|
+
cache_map :polymorphics,
|
71
|
+
:child_cachers,
|
72
|
+
:has_many_cacheables => :dependent_cache,
|
73
|
+
:has_many_through_cacheables => :dependent_cache,
|
74
|
+
:has_and_belongs_to_many_cacheables => :dependent_cache
|
75
|
+
|
76
|
+
define_timestamp(:dynamic_timestamp) { execute_timestamp }
|
77
|
+
|
78
|
+
has_and_belongs_to_many :has_and_belongs_to_many_cacheables, :class_name => 'HasAndBelongsToManyCacheable'
|
79
|
+
has_many :has_many_cacheables, :class_name => 'HasManyCacheable'
|
80
|
+
has_many :joins, :class_name => 'Join'
|
81
|
+
has_many :has_many_through_cacheables, :through => :joins, :class_name => 'HasManyThroughCacheable'
|
82
|
+
has_many :polymorphics, :as => :polymorhicable
|
83
|
+
has_many :child_cachers, :class_name => 'Cacher', :foreign_key => 'parent_id', :primary_key => 'id'
|
84
|
+
|
85
|
+
def to_param; name end
|
86
|
+
end
|
@@ -1,258 +1,159 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'fixtures'
|
2
3
|
|
3
4
|
describe CacheMachine do
|
4
|
-
|
5
|
-
HABTM_TABLE_NAME = "has_and_belongs_to_many_cacheables"
|
6
|
-
HABTM_JOINS_TABLE_NAME = [TARGET_TABLE_NAME, HABTM_TABLE_NAME].join('_')
|
7
|
-
HABTM_ASSOCIATION_NAME = HABTM_TABLE_NAME.singularize
|
8
|
-
HM_TABLE_NAME = "has_many_cacheables"
|
9
|
-
HMT_JOINS_TABLE_NAME = "joins"
|
10
|
-
HMT_TABLE_NAME = "has_many_through_cacheables"
|
11
|
-
HO_TABLE_NAME = "hs_one_cacheables"
|
12
|
-
POLY_TABLE_NAME = "polymorphics"
|
13
|
-
TARGET_ASSOCIATION_NAME = TARGET_TABLE_NAME.singularize
|
14
|
-
HMT_ASSOCIATION_NAME = HMT_TABLE_NAME.singularize
|
15
|
-
|
16
|
-
class TestMigration < ActiveRecord::Migration
|
17
|
-
def self.up
|
18
|
-
self.down
|
19
|
-
create_table(HABTM_TABLE_NAME)
|
20
|
-
create_table(HM_TABLE_NAME) { |t| t.references TARGET_ASSOCIATION_NAME }
|
21
|
-
create_table(HMT_TABLE_NAME)
|
22
|
-
create_table(HMT_JOINS_TABLE_NAME) { |t| [TARGET_ASSOCIATION_NAME, HMT_ASSOCIATION_NAME].each &t.method(:references) }
|
23
|
-
create_table(POLY_TABLE_NAME) { |t| t.references(:polymorhicable); t.string(:polymorhicable_type) }
|
24
|
-
create_table(TARGET_TABLE_NAME) { |t| t.string :name; t.integer(:parent_id) }
|
25
|
-
create_table(HABTM_JOINS_TABLE_NAME, :id => false) { |t| [TARGET_ASSOCIATION_NAME, HABTM_ASSOCIATION_NAME].each &t.method(:references) }
|
26
|
-
end
|
5
|
+
subject { Cacher.create(:name => 'foo') }
|
27
6
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
drop_table HO_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HO_TABLE_NAME)
|
35
|
-
drop_table HMT_JOINS_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HMT_JOINS_TABLE_NAME)
|
36
|
-
drop_table HABTM_JOINS_TABLE_NAME if ActiveRecord::Base.connection.tables.include?(HABTM_JOINS_TABLE_NAME)
|
7
|
+
describe "#cache_key_of" do
|
8
|
+
it "generates association cache keys" do
|
9
|
+
subject.cache_key_of(:anything).should eql("Cacher/foo/anything/1")
|
10
|
+
subject.cache_key_of(:anything, :format => :ehtml).should eql("Cacher/foo/anything/ehtml/1")
|
11
|
+
subject.cache_key_of(:anything, :page => 2).should eql("Cacher/foo/anything/2")
|
12
|
+
subject.cache_key_of(:anything, :format => :ehtml, :page => 2).should eql("Cacher/foo/anything/ehtml/2")
|
37
13
|
end
|
38
14
|
end
|
39
|
-
TestMigration.up
|
40
|
-
|
41
|
-
class HasManyCacheable < ActiveRecord::Base
|
42
|
-
set_table_name HM_TABLE_NAME
|
43
|
-
belongs_to :cacher, :class_name => 'Cacher'
|
44
|
-
end
|
45
|
-
|
46
|
-
class HasManyThroughCacheable < ActiveRecord::Base
|
47
|
-
set_table_name HMT_TABLE_NAME
|
48
|
-
|
49
|
-
has_many :joins, :class_name => 'Join'
|
50
|
-
has_many :cachers, :through => :joins, :class_name => 'Cacher'
|
51
|
-
end
|
52
|
-
|
53
|
-
class Join < ActiveRecord::Base
|
54
|
-
set_table_name HMT_JOINS_TABLE_NAME
|
55
|
-
|
56
|
-
belongs_to :cacher, :class_name => 'Cacher'
|
57
|
-
belongs_to :has_many_through_cacheable, :class_name => 'HasManyThroughCacheable'
|
58
|
-
end
|
59
|
-
|
60
|
-
class HasAndBelongsToManyCacheable < ActiveRecord::Base
|
61
|
-
set_table_name HABTM_TABLE_NAME
|
62
|
-
has_and_belongs_to_many :cachers, :class_name => 'Cacher'
|
63
|
-
end
|
64
|
-
|
65
|
-
class Polymorphic < ActiveRecord::Base
|
66
|
-
set_table_name POLY_TABLE_NAME
|
67
|
-
belongs_to :polymorhicable, :polymorphic => true
|
68
|
-
end
|
69
15
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
:has_many_cacheables => :dependent_cache,
|
76
|
-
:has_many_through_cacheables => :dependent_cache,
|
77
|
-
:has_and_belongs_to_many_cacheables => :dependent_cache
|
78
|
-
|
79
|
-
define_timestamp(:dynamic_timestamp) { execute_timestamp }
|
80
|
-
define_timestamp(:static_timestamp)
|
81
|
-
|
82
|
-
has_and_belongs_to_many :has_and_belongs_to_many_cacheables, :class_name => 'HasAndBelongsToManyCacheable'
|
83
|
-
has_many :has_many_cacheables, :class_name => 'HasManyCacheable'
|
84
|
-
has_many :joins, :class_name => 'Join'
|
85
|
-
has_many :has_many_through_cacheables, :through => :joins, :class_name => 'HasManyThroughCacheable'
|
86
|
-
has_many :polymorphics, :as => :polymorhicable
|
87
|
-
has_many :child_cachers, :class_name => 'Cacher', :foreign_key => 'parent_id', :primary_key => 'id'
|
88
|
-
|
89
|
-
def to_param; name end
|
90
|
-
end
|
91
|
-
|
92
|
-
subject { Cacher.create(:name => 'foo') }
|
93
|
-
|
94
|
-
it "generates association cache keys" do
|
95
|
-
subject.cache_key_of(:has_many_cacheables, :format => :ehtml).should eql("Cacher_foo_has_many_cacheables_ehtml_1")
|
96
|
-
end
|
16
|
+
describe "#fetch_cache_of" do
|
17
|
+
it "stores association cache" do
|
18
|
+
subject.fetch_cache_of(:has_many_cacheables) { 'cache' }
|
19
|
+
subject.fetch_cache_of(:has_many_cacheables).should == 'cache'
|
20
|
+
end
|
97
21
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
22
|
+
context "timestamps" do
|
23
|
+
it "works with timestamps" do
|
24
|
+
subject.should_receive(:cache_key_of).with(:anything, hash_including(:timestamp => :dynamic_timestamp)).and_return "returned stamp"
|
25
|
+
Rails.cache.should_receive(:fetch).with("returned stamp", :expires_in => nil).once
|
26
|
+
subject.fetch_cache_of(:anything, :timestamp => :dynamic_timestamp)
|
27
|
+
end
|
103
28
|
|
104
|
-
|
29
|
+
it "calls for instance methods" do
|
30
|
+
subject.should_receive(:execute_timestamp).once
|
31
|
+
subject.fetch_cache_of(:anything, :timestamp => :dynamic_timestamp)
|
32
|
+
end
|
105
33
|
|
106
|
-
|
107
|
-
|
108
|
-
subject.
|
109
|
-
subject.fetch_cache_of(:something, :timestamp => :dynamic_timestamp) { "cache" }
|
110
|
-
sleep(2)
|
111
|
-
subject.fetch_cache_of(:something, :timestamp => :dynamic_timestamp) { "foo" }.should eql("cache")
|
112
|
-
subject.stub!(:execute_timestamp).and_return(2)
|
113
|
-
sleep(2)
|
114
|
-
subject.fetch_cache_of(:something, :timestamp => :dynamic_timestamp) { "fresh cache" }.should eql("fresh cache")
|
34
|
+
it "passes expires_in param" do
|
35
|
+
Rails.cache.should_receive(:fetch).with(anything(), :expires_in => 10.minutes).once
|
36
|
+
subject.fetch_cache_of(:anything, :expires_in => 10.minutes)
|
115
37
|
end
|
116
|
-
end
|
117
38
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
subject.fetch_cache_of(:
|
122
|
-
sleep(2)
|
123
|
-
subject.fetch_cache_of(:something, :timestamp => :static_timestamp) { "foo" }.should eql("cache")
|
39
|
+
it "passes expires_at param" do
|
40
|
+
Time.stub_chain("zone.now").and_return(Time.parse('01/01/01'))
|
41
|
+
Rails.cache.should_receive(:fetch).with(anything(), :expires_in => 10.minutes).once
|
42
|
+
subject.fetch_cache_of(:anything, :expires_at => 10.minutes.from_now)
|
124
43
|
end
|
125
44
|
end
|
126
45
|
end
|
127
46
|
|
128
|
-
context "
|
129
|
-
|
47
|
+
context "resets cache" do
|
130
48
|
describe "#delete_all_caches" do
|
131
49
|
it "removes all caches using map" do
|
132
|
-
subject.
|
133
|
-
subject.
|
134
|
-
|
50
|
+
subject.should_receive(:delete_cache_of).with(:polymorphics).once
|
51
|
+
subject.should_receive(:delete_cache_of).with(:child_cachers).once
|
52
|
+
subject.should_receive(:delete_cache_of).with(:has_many_cacheables).once
|
53
|
+
subject.should_receive(:delete_cache_of).with(:dependent_cache).once
|
54
|
+
subject.should_receive(:delete_cache_of).with(:has_many_through_cacheables).once
|
55
|
+
subject.should_receive(:delete_cache_of).with(:has_and_belongs_to_many_cacheables).once
|
135
56
|
subject.delete_all_caches
|
136
|
-
|
137
|
-
subject.fetch_cache_of(:polymorphics) { 'new cache' }.should == 'new cache'
|
138
|
-
subject.fetch_cache_of(:dependent_cache) { 'new cache' }.should == 'new cache'
|
139
57
|
end
|
140
58
|
end
|
141
59
|
|
142
|
-
|
143
|
-
it "
|
144
|
-
|
145
|
-
subject.
|
146
|
-
|
147
|
-
|
148
|
-
cached_result.should eql('new cache')
|
60
|
+
describe "#delete_cache_of" do
|
61
|
+
it "resets cache" do
|
62
|
+
subject.fetch_cache_of(:anything) { 'cache' }
|
63
|
+
subject.delete_cache_of :anything
|
64
|
+
subject.fetch_cache_of(:anything).should be_nil
|
149
65
|
end
|
150
|
-
end
|
151
66
|
|
152
|
-
|
153
|
-
|
67
|
+
it "resets cache by map" do
|
68
|
+
subject.fetch_cache_of(:dependent_cache) { 'cache' }
|
154
69
|
subject.delete_cache_of :has_many_cacheables
|
70
|
+
subject.fetch_cache_of(:dependent_cache).should be_nil
|
155
71
|
end
|
156
72
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
73
|
+
context "callbacks" do
|
74
|
+
context "on polymorphic associations" do
|
75
|
+
it "resets cache on add new item to associated collection" do
|
76
|
+
subject.fetch_cache_of(:polymorphics) { 'cache' }
|
77
|
+
subject.polymorphics.create
|
78
|
+
subject.fetch_cache_of(:polymorphics).should be_nil
|
79
|
+
end
|
80
|
+
end
|
165
81
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
82
|
+
context "on self-join associations" do
|
83
|
+
it "resets cache on add new item to associated collection" do
|
84
|
+
subject.fetch_cache_of(:child_cachers) { 'cache' }
|
85
|
+
Cacher.create(:parent_id => subject.id)
|
86
|
+
subject.fetch_cache_of(:child_cachers).should be_nil
|
87
|
+
end
|
88
|
+
end
|
171
89
|
|
172
|
-
|
173
|
-
|
174
|
-
end
|
90
|
+
context "on has_many associations" do
|
91
|
+
let(:new_entry) { HasManyCacheable.create }
|
175
92
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
subject.fetch_cache_of(:has_many_cacheables) { 'cache' }
|
181
|
-
end
|
93
|
+
before :each do
|
94
|
+
@existing_entry = subject.has_many_cacheables.create
|
95
|
+
subject.fetch_cache_of(:has_many_cacheables) { 'cache' }
|
96
|
+
end
|
182
97
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
98
|
+
after :each do
|
99
|
+
subject.fetch_cache_of(:has_many_cacheables).should be_nil
|
100
|
+
subject.delete_cache_of(:has_many_cacheables)
|
101
|
+
end
|
102
|
+
|
103
|
+
it("on update entry in collection") { @existing_entry.save }
|
104
|
+
it("on add new entry in collection") { subject.has_many_cacheables << new_entry }
|
105
|
+
it("on destroy intem in collection") { subject.has_many_cacheables.destroy @existing_entry }
|
106
|
+
it("on destroy intem") { HasManyCacheable.destroy @existing_entry }
|
107
|
+
end
|
187
108
|
end
|
188
109
|
|
189
|
-
|
190
|
-
|
191
|
-
it("on add new entry in collection") { subject.has_many_cacheables << @new_entry }
|
192
|
-
it("on destroy intem in collection") { subject.has_many_cacheables.destroy @existing_entry }
|
193
|
-
it("on destroy intem") { HasManyCacheable.destroy @existing_entry }
|
110
|
+
context "has_many :through associations" do
|
111
|
+
let(:new_entry) { HasManyThroughCacheable.create }
|
194
112
|
|
195
|
-
|
196
|
-
|
197
|
-
subject.fetch_cache_of(:
|
198
|
-
subject.has_many_cacheables.create
|
199
|
-
subject.fetch_cache_of(:dependent_cache) { 'fresh cache' }.should eql('fresh cache')
|
113
|
+
before :each do
|
114
|
+
@existing_entry = subject.has_many_through_cacheables.create
|
115
|
+
subject.fetch_cache_of(:has_many_through_cacheables) { 'cache' }
|
200
116
|
end
|
201
|
-
end
|
202
|
-
end
|
203
117
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
subject.fetch_cache_of(:has_many_through_cacheables) { 'cache' }
|
209
|
-
end
|
118
|
+
after :each do
|
119
|
+
subject.fetch_cache_of(:has_many_through_cacheables).should be_nil
|
120
|
+
subject.delete_cache_of(:has_many_through_cacheables)
|
121
|
+
end
|
210
122
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
123
|
+
it("on update entry in collection") { @existing_entry.save }
|
124
|
+
it("on add new entry in collection") { subject.has_many_through_cacheables << new_entry }
|
125
|
+
it("on destroy intem in collection") { subject.has_many_through_cacheables.destroy @existing_entry }
|
126
|
+
it("on destroy intem") { HasManyThroughCacheable.destroy @existing_entry }
|
215
127
|
end
|
216
128
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
129
|
+
context "has_and_belongs_to_many associations" do
|
130
|
+
let(:new_entry) { HasAndBelongsToManyCacheable.create }
|
131
|
+
before :each do
|
132
|
+
@existing_entry = subject.has_and_belongs_to_many_cacheables.create
|
133
|
+
subject.fetch_cache_of(:has_and_belongs_to_many_cacheables) { 'cache' }
|
134
|
+
end
|
222
135
|
|
223
|
-
|
224
|
-
|
225
|
-
subject.
|
226
|
-
subject.has_many_through_cacheables.create
|
227
|
-
subject.fetch_cache_of(:dependent_cache) { 'fresh cache' }.should eql('fresh cache')
|
136
|
+
after :each do
|
137
|
+
subject.fetch_cache_of(:has_and_belongs_to_many_cacheables).should be_nil
|
138
|
+
subject.delete_cache_of(:has_and_belongs_to_many_cacheables)
|
228
139
|
end
|
229
|
-
end
|
230
|
-
end
|
231
140
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
subject.fetch_cache_of(:has_and_belongs_to_many_cacheables) { 'cache' }
|
141
|
+
it("on update entry in collection") { @existing_entry.save }
|
142
|
+
it("on add new entry in collection") { subject.has_and_belongs_to_many_cacheables << new_entry }
|
143
|
+
it("on destroy intem in collection") { subject.has_and_belongs_to_many_cacheables.destroy @existing_entry }
|
144
|
+
it("on destroy intem") { HasAndBelongsToManyCacheable.destroy @existing_entry }
|
237
145
|
end
|
238
146
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
147
|
+
context "paginated content" do
|
148
|
+
it "works" do
|
149
|
+
subject.delete_cache_of :has_many_cacheables
|
150
|
+
subject.fetch_cache_of(:has_many_cacheables, :page => 1) { 'page 1' }.should eql('page 1')
|
151
|
+
subject.fetch_cache_of(:has_many_cacheables, :page => 2) { 'page 2' }.should eql('page 2')
|
244
152
|
|
245
|
-
|
246
|
-
it("on update entry in collection") { @existing_entry.save }
|
247
|
-
it("on add new entry in collection") { subject.has_and_belongs_to_many_cacheables << @new_entry }
|
248
|
-
it("on destroy intem in collection") { subject.has_and_belongs_to_many_cacheables.destroy @existing_entry }
|
249
|
-
it("on destroy intem") { HasAndBelongsToManyCacheable.destroy @existing_entry }
|
153
|
+
subject.delete_cache_of(:has_many_cacheables)
|
250
154
|
|
251
|
-
|
252
|
-
|
253
|
-
subject.fetch_cache_of(:dependent_cache) { 'cache' }
|
254
|
-
subject.has_and_belongs_to_many_cacheables.create
|
255
|
-
subject.fetch_cache_of(:dependent_cache) { 'fresh cache' }.should eql('fresh cache')
|
155
|
+
subject.fetch_cache_of(:has_many_cacheables, :page => 1).should be_nil
|
156
|
+
subject.fetch_cache_of(:has_many_cacheables, :page => 2).should be_nil
|
256
157
|
end
|
257
158
|
end
|
258
159
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache-machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 10
|
10
|
+
version: 0.1.10
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sergei Zinin
|
@@ -16,7 +16,8 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-10-
|
19
|
+
date: 2011-10-22 00:00:00 +08:00
|
20
|
+
default_executable:
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
22
23
|
name: rails
|
@@ -47,9 +48,23 @@ dependencies:
|
|
47
48
|
type: :runtime
|
48
49
|
version_requirements: *id002
|
49
50
|
- !ruby/object:Gem::Dependency
|
50
|
-
name:
|
51
|
+
name: activesupport
|
51
52
|
prerelease: false
|
52
53
|
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
type: :runtime
|
63
|
+
version_requirements: *id003
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: bundler
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
68
|
none: false
|
54
69
|
requirements:
|
55
70
|
- - ~>
|
@@ -61,11 +76,11 @@ dependencies:
|
|
61
76
|
- 0
|
62
77
|
version: 1.0.0
|
63
78
|
type: :development
|
64
|
-
version_requirements: *
|
79
|
+
version_requirements: *id004
|
65
80
|
- !ruby/object:Gem::Dependency
|
66
81
|
name: jeweler
|
67
82
|
prerelease: false
|
68
|
-
requirement: &
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
69
84
|
none: false
|
70
85
|
requirements:
|
71
86
|
- - ~>
|
@@ -77,7 +92,7 @@ dependencies:
|
|
77
92
|
- 2
|
78
93
|
version: 1.6.2
|
79
94
|
type: :development
|
80
|
-
version_requirements: *
|
95
|
+
version_requirements: *id005
|
81
96
|
description: A Ruby on Rails framework to support cache management based on explicitely modeled caching dependencies.
|
82
97
|
email: kgoslar@partyearth.com
|
83
98
|
executables: []
|
@@ -103,8 +118,10 @@ files:
|
|
103
118
|
- lib/cache_machine/helpers/cache_helper.rb
|
104
119
|
- lib/cache_machine/logger.rb
|
105
120
|
- lib/cache_machine/railtie.rb
|
121
|
+
- spec/fixtures.rb
|
106
122
|
- spec/lib/cache_machine_spec.rb
|
107
123
|
- spec/spec_helper.rb
|
124
|
+
has_rdoc: true
|
108
125
|
homepage: http://github.com/partyearth/cache-machine
|
109
126
|
licenses:
|
110
127
|
- MIT
|
@@ -134,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
151
|
requirements: []
|
135
152
|
|
136
153
|
rubyforge_project:
|
137
|
-
rubygems_version: 1.
|
154
|
+
rubygems_version: 1.5.0
|
138
155
|
signing_key:
|
139
156
|
specification_version: 3
|
140
157
|
summary: A Ruby on Rails framework to support cache management based on explicitely modeled caching dependencies.
|