merb-cache 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/LICENSE +2 -2
  2. data/README +207 -143
  3. data/Rakefile +55 -10
  4. data/TODO +0 -2
  5. data/lib/merb-cache/cache.rb +84 -0
  6. data/lib/merb-cache/core_ext/enumerable.rb +9 -0
  7. data/lib/merb-cache/core_ext/hash.rb +20 -0
  8. data/lib/merb-cache/merb_ext/controller.rb +167 -0
  9. data/lib/merb-cache/stores/fundamental/abstract_store.rb +101 -0
  10. data/lib/merb-cache/stores/fundamental/file_store.rb +112 -0
  11. data/lib/merb-cache/stores/fundamental/memcached_store.rb +112 -0
  12. data/lib/merb-cache/stores/strategy/abstract_strategy_store.rb +123 -0
  13. data/lib/merb-cache/stores/strategy/action_store.rb +56 -0
  14. data/lib/merb-cache/stores/strategy/adhoc_store.rb +69 -0
  15. data/lib/merb-cache/stores/strategy/gzip_store.rb +63 -0
  16. data/lib/merb-cache/stores/strategy/page_store.rb +64 -0
  17. data/lib/merb-cache/stores/strategy/sha1_store.rb +62 -0
  18. data/lib/merb-cache.rb +8 -7
  19. data/spec/merb-cache/cache_spec.rb +88 -0
  20. data/spec/merb-cache/core_ext/enumerable_spec.rb +22 -0
  21. data/spec/merb-cache/core_ext/hash_spec.rb +20 -0
  22. data/spec/merb-cache/merb_ext/controller_spec.rb +284 -0
  23. data/spec/merb-cache/stores/fundamental/abstract_store_spec.rb +166 -0
  24. data/spec/merb-cache/stores/fundamental/file_store_spec.rb +186 -0
  25. data/spec/merb-cache/stores/fundamental/memcached_store_spec.rb +243 -0
  26. data/spec/merb-cache/stores/strategy/abstract_strategy_store_spec.rb +78 -0
  27. data/spec/merb-cache/stores/strategy/action_store_spec.rb +189 -0
  28. data/spec/merb-cache/stores/strategy/adhoc_store_spec.rb +225 -0
  29. data/spec/merb-cache/stores/strategy/gzip_store_spec.rb +51 -0
  30. data/spec/merb-cache/stores/strategy/page_store_spec.rb +111 -0
  31. data/spec/merb-cache/stores/strategy/sha1_store_spec.rb +75 -0
  32. data/spec/spec_helper.rb +69 -72
  33. metadata +42 -31
  34. data/lib/merb-cache/cache-action.rb +0 -144
  35. data/lib/merb-cache/cache-fragment.rb +0 -95
  36. data/lib/merb-cache/cache-page.rb +0 -203
  37. data/lib/merb-cache/cache-store/database-activerecord.rb +0 -88
  38. data/lib/merb-cache/cache-store/database-datamapper.rb +0 -79
  39. data/lib/merb-cache/cache-store/database-sequel.rb +0 -78
  40. data/lib/merb-cache/cache-store/database.rb +0 -144
  41. data/lib/merb-cache/cache-store/dummy.rb +0 -106
  42. data/lib/merb-cache/cache-store/file.rb +0 -194
  43. data/lib/merb-cache/cache-store/memcache.rb +0 -199
  44. data/lib/merb-cache/cache-store/memory.rb +0 -168
  45. data/lib/merb-cache/merb-cache.rb +0 -165
  46. data/lib/merb-cache/merbtasks.rb +0 -6
  47. data/spec/config/database.yml +0 -14
  48. data/spec/controller.rb +0 -101
  49. data/spec/log/merb_test.log +0 -433
  50. data/spec/merb-cache-action_spec.rb +0 -162
  51. data/spec/merb-cache-fragment_spec.rb +0 -100
  52. data/spec/merb-cache-page_spec.rb +0 -150
  53. data/spec/merb-cache_spec.rb +0 -15
  54. data/spec/views/cache_controller/action1.html.erb +0 -4
  55. data/spec/views/cache_controller/action2.html.haml +0 -4
@@ -1,194 +0,0 @@
1
- require 'fileutils'
2
- class Merb::Cache::FileStore
3
- # Provides the file cache store for merb-cache
4
-
5
- def initialize
6
- @config = Merb::Controller._cache.config
7
- @config[:cache_directory] ||= Merb.root_path("tmp/cache")
8
- # @config[:cache_action_directory] ||= Merb.dir_for(:public) / "cache"
9
- prepare
10
- end
11
-
12
- class NotAccessible < Exception #
13
- def initialize(message)
14
- super("Cache directories are not readable/writeable (#{message})")
15
- end
16
- end
17
-
18
- # This method is there to ensure minimal requirements are met
19
- # (directories are accessible, table exists, connected to server, ...)
20
- def prepare
21
- FileUtils.mkdir_p @config[:cache_directory]
22
- unless File.readable?(@config[:cache_directory]) &&
23
- File.writable?(@config[:cache_directory])
24
- raise NotAccessible, @config[:cache_directory]
25
- end
26
- true
27
- end
28
-
29
- # Checks whether a cache entry exists
30
- #
31
- # ==== Parameter
32
- # key<String>:: The key identifying the cache entry
33
- #
34
- # ==== Returns
35
- # true if the cache entry exists, false otherwise
36
- def cached?(key)
37
- cache_file = @config[:cache_directory] / "#{key}.cache"
38
- _data = _expire = nil
39
- if File.file?(cache_file)
40
- _data, _expire = Marshal.load(cache_read(cache_file))
41
- return true if _expire.nil? || Time.now < _expire
42
- FileUtils.rm_f(cache_file)
43
- end
44
- false
45
- end
46
-
47
- # Capture or restore the data in cache.
48
- # If the cache entry expired or does not exist, the data are taken
49
- # from the execution of the block, marshalled and stored in cache.
50
- # Otherwise, the data are loaded from the cache and returned unmarshalled
51
- #
52
- # ==== Parameters
53
- # _controller<Merb::Controller>:: The instance of the current controller
54
- # key<String>:: The key identifying the cache entry
55
- # from_now<~minutes>::
56
- # The number of minutes (from now) the cache should persist
57
- # &block:: The template to be used or not
58
- #
59
- # ==== Additional information
60
- # When fetching data (the cache entry exists and has not expired)
61
- # The data are loaded from the cache and returned unmarshalled.
62
- # Otherwise:
63
- # The controller is used to capture the rendered template (from the block).
64
- # It uses the capture_#{engine} and concat_#{engine} methods to do so.
65
- # The captured data are then marshalled and stored.
66
- def cache(_controller, key, from_now = nil, &block)
67
- cache_file = @config[:cache_directory] / "#{key}.cache"
68
- _cache_hit = _data = _expire = nil
69
-
70
- if File.file?(cache_file)
71
- _data, _expire = Marshal.load(cache_read(cache_file))
72
- _cache_hit = true if _expire.nil? || Time.now < _expire
73
- end
74
- unless _cache_hit
75
- cache_directory = File.dirname(cache_file)
76
- FileUtils.mkdir_p(cache_directory)
77
- _expire = from_now ? from_now.minutes.from_now : nil
78
- _data = _controller.send(:capture, &block)
79
- cache_write(cache_file, Marshal.dump([_data, _expire]))
80
- end
81
- _controller.send(:concat, _data, block.binding)
82
- true
83
- end
84
-
85
- # Store data to the file using the specified key
86
- #
87
- # ==== Parameters
88
- # key<Sting>:: The key identifying the cache entry
89
- # data<String>:: The data to be put in cache
90
- # from_now<~minutes>::
91
- # The number of minutes (from now) the cache should persist
92
- def cache_set(key, data, from_now = nil)
93
- cache_file = @config[:cache_directory] / "#{key}.cache"
94
- cache_directory = File.dirname(cache_file)
95
- FileUtils.mkdir_p(cache_directory)
96
- _expire = from_now ? from_now.minutes.from_now : nil
97
- cache_write(cache_file, Marshal.dump([data, _expire]))
98
- Merb.logger.info("cache: set (#{key})")
99
- true
100
- end
101
-
102
- # Fetch data from the file using the specified key
103
- # The entry is deleted if it has expired
104
- #
105
- # ==== Parameter
106
- # key<Sting>:: The key identifying the cache entry
107
- #
108
- # ==== Returns
109
- # data<String, NilClass>::
110
- # nil is returned whether the entry expired or was not found
111
- def cache_get(key)
112
- cache_file = @config[:cache_directory] / "#{key}.cache"
113
- if File.file?(cache_file)
114
- _data, _expire = Marshal.load(cache_read(cache_file))
115
- if _expire.nil? || Time.now < _expire
116
- Merb.logger.info("cache: hit (#{key})")
117
- return _data
118
- end
119
- FileUtils.rm_f(cache_file)
120
- end
121
- Merb.logger.info("cache: miss (#{key})")
122
- nil
123
- end
124
-
125
- # Expire the cache entry identified by the given key
126
- #
127
- # ==== Parameter
128
- # key<Sting>:: The key identifying the cache entry
129
- def expire(key)
130
- FileUtils.rm_f(@config[:cache_directory] / "#{key}.cache")
131
- Merb.logger.info("cache: expired (#{key})")
132
- true
133
- end
134
-
135
- # Expire the cache entries matching the given key
136
- #
137
- # ==== Parameter
138
- # key<Sting>:: The key matching the cache entries
139
- def expire_match(key)
140
- #files = Dir.glob(@config[:cache_directory] / "#{key}*.cache")
141
- files = Dir.glob(@config[:cache_directory] / "#{key}*")
142
- FileUtils.rm_rf(files)
143
- Merb.logger.info("cache: expired matching (#{key})")
144
- true
145
- end
146
-
147
- # Expire all the cache entries
148
- def expire_all
149
- FileUtils.rm_rf(Dir.glob("#{@config[:cache_directory]}/*"))
150
- Merb.logger.info("cache: expired all")
151
- true
152
- end
153
-
154
- # Gives info on the current cache store
155
- #
156
- # ==== Returns
157
- # The type of the current cache store
158
- def cache_store_type
159
- "file"
160
- end
161
-
162
- private
163
-
164
- # Read data from the file using exclusive lock
165
- #
166
- # ==== Parameters
167
- # cache_file<String>:: The full path to the file
168
- #
169
- # ==== Returns
170
- # _data<String>:: The data read from the file
171
- def cache_read(cache_file)
172
- _data = nil
173
- File.open(cache_file, "r") do |cache_data|
174
- cache_data.flock(File::LOCK_EX)
175
- _data = cache_data.read
176
- cache_data.flock(File::LOCK_UN)
177
- end
178
- _data
179
- end
180
-
181
- # Write data to the file using exclusive lock
182
- #
183
- # ==== Parameters
184
- # cache_file<String>:: The full path to the file
185
- # data<String>:: The data to be put in cache
186
- def cache_write(cache_file, data)
187
- File.open(cache_file, "w+") do |cache_data|
188
- cache_data.flock(File::LOCK_EX)
189
- cache_data.write(data)
190
- cache_data.flock(File::LOCK_UN)
191
- end
192
- true
193
- end
194
- end
@@ -1,199 +0,0 @@
1
- class Merb::Cache::MemcacheStore
2
- # Provides the memcache cache store for merb-cache
3
-
4
- def initialize
5
- @config = Merb::Controller._cache.config
6
- prepare
7
- end
8
-
9
- class NotReady < Exception
10
- def initialize
11
- super("Memcache server is not ready")
12
- end
13
- end
14
-
15
- class NotDefined < Exception
16
- def initialize
17
- super("Memcache is not defined (require it in init.rb)")
18
- end
19
- end
20
-
21
- # This method is there to ensure minimal requirements are met
22
- # (directories are accessible, table exists, connected to server, ...)
23
- def prepare
24
- namespace = @config[:namespace] || 'merb-cache'
25
- host = @config[:host] || '127.0.0.1:11211'
26
- @memcache = MemCache.new(host, {:namespace => namespace})
27
- @tracking_key = "_#{namespace}_keys" unless @config[:no_tracking] == true
28
- raise NotReady unless @memcache.active?
29
- true
30
- rescue NameError
31
- raise NotDefined
32
- end
33
-
34
- # Checks whether a cache entry exists
35
- #
36
- # ==== Parameter
37
- # key<String>:: The key identifying the cache entry
38
- #
39
- # ==== Returns
40
- # true if the cache entry exists, false otherwise
41
- def cached?(key)
42
- not cache_get(key).nil?
43
- end
44
-
45
- # Capture or restore the data in cache.
46
- # If the cache entry expired or does not exist, the data are taken
47
- # from the execution of the block, marshalled and stored in cache.
48
- # Otherwise, the data are loaded from the cache and returned unmarshalled
49
- #
50
- # ==== Parameters
51
- # _controller<Merb::Controller>:: The instance of the current controller
52
- # key<String>:: The key identifying the cache entry
53
- # from_now<~minutes>::
54
- # The number of minutes (from now) the cache should persist
55
- # &block:: The template to be used or not
56
- #
57
- # ==== Additional information
58
- # When fetching data (the cache entry exists and has not expired)
59
- # The data are loaded from the cache and returned unmarshalled.
60
- # Otherwise:
61
- # The controller is used to capture the rendered template (from the block).
62
- # It uses the capture_#{engine} and concat_#{engine} methods to do so.
63
- # The captured data are then marshalled and stored.
64
- def cache(_controller, key, from_now = nil, &block)
65
- _data = cache_get(key)
66
- if _data.nil?
67
- _data = _controller.send(:capture, &block)
68
- cache_set(key, _data, from_now)
69
- end
70
- _controller.send(:concat, _data, block.binding)
71
- true
72
- end
73
-
74
- # Store data to memcache using the specified key
75
- #
76
- # ==== Parameters
77
- # key<Sting>:: The key identifying the cache entry
78
- # data<String>:: The data to be put in cache
79
- # from_now<~minutes>::
80
- # The number of minutes (from now) the cache should persist
81
- def cache_set(key, data, from_now = nil)
82
- _expire = from_now ? from_now.minutes.from_now.to_i : 0
83
- @memcache.set(key, data, _expire)
84
- cache_start_tracking(key)
85
- Merb.logger.info!("cache: set (#{key})")
86
- true
87
- end
88
-
89
- # Fetch data from memcache using the specified key
90
- # The entry is deleted if it has expired
91
- #
92
- # ==== Parameter
93
- # key<Sting>:: The key identifying the cache entry
94
- #
95
- # ==== Returns
96
- # data<String, NilClass>::
97
- # nil is returned whether the entry expired or was not found
98
- def cache_get(key)
99
- data = @memcache.get(key)
100
- if data.nil?
101
- Merb.logger.info!("cache: miss (#{key})")
102
- else
103
- Merb.logger.debug!("cache: hit (#{key})")
104
- end
105
- data
106
- end
107
-
108
- # Expire the cache entry identified by the given key
109
- #
110
- # ==== Parameter
111
- # key<Sting>:: The key identifying the cache entry
112
- def expire(key)
113
- @memcache.delete(key)
114
- cache_stop_tracking(key)
115
- Merb.logger.info!("cache: expired (#{key})")
116
- true
117
- end
118
-
119
- # Expire the cache entries matching the given key
120
- #
121
- # ==== Parameter
122
- # key<Sting>:: The key matching the cache entries
123
- #
124
- # ==== Additional info
125
- # In memcache this requires to keep track of all keys (on by default).
126
- # If you don't need this, set :no_tracking => true in the config.
127
- def expire_match(key)
128
- Merb.logger.debug!("cache: attempting to expire #{key}")
129
- if @tracking_key
130
- for _key in get_tracked_keys
131
- expire(_key) if /#{key}/ =~ _key
132
- end
133
- else
134
- Merb.logger.info("cache: expire_match is not supported with memcache (set :no_tracking => false in your config")
135
- end
136
- true
137
- end
138
-
139
- # Expire all the cache entries
140
- def expire_all
141
- @memcache.flush_all
142
- stop_tracking_keys
143
- Merb.logger.info("cache: expired all")
144
- true
145
- end
146
-
147
- # Gives info on the current cache store
148
- #
149
- # ==== Returns
150
- # The type of the current cache store
151
- def cache_store_type
152
- "memcache"
153
- end
154
-
155
- private
156
-
157
- # Store the tracked keys in memcache (used by expire_match)
158
- #
159
- # ==== Parameter
160
- # keys<Array[String]>:: The keys to keep track of
161
- def set_tracked_keys(keys)
162
- @memcache.set(@tracking_key, keys)
163
- end
164
-
165
- # Retrieve tracked keys from memcache
166
- #
167
- # ==== Returns
168
- # keys<Array[String]>:: The tracked keys
169
- def get_tracked_keys
170
- @memcache.get(@tracking_key) || []
171
- end
172
-
173
- # Remove all tracked keys
174
- def stop_tracking_keys
175
- @memcache.delete(@tracking_key) if @tracking_key
176
- end
177
-
178
- # Add a key in the array of tracked keys (used by expire_match)
179
- #
180
- # ==== Parameter
181
- # key<String>:: the key to add
182
- def cache_start_tracking(key)
183
- return unless @tracking_key
184
- keys = get_tracked_keys
185
- keys.push(key)
186
- set_tracked_keys(keys)
187
- end
188
-
189
- # Remove a key from the array of tracked keys (used by expire_match)
190
- #
191
- # ==== Parameter
192
- # key<String>:: the key to remove
193
- def cache_stop_tracking(key)
194
- return unless @tracking_key
195
- keys = get_tracked_keys
196
- keys.delete(key)
197
- set_tracked_keys(keys)
198
- end
199
- end
@@ -1,168 +0,0 @@
1
- class Merb::Cache::MemoryStore
2
- # Provides the memory cache store for merb-cache
3
-
4
- def initialize
5
- @config = Merb::Controller._cache.config
6
- @cache = {}
7
- @mutex = Mutex.new
8
- prepare
9
- end
10
-
11
- # This method is there to ensure minimal requirements are met
12
- # (directories are accessible, table exists, connected to server, ...)
13
- def prepare
14
- true
15
- end
16
-
17
- # Checks whether a cache entry exists
18
- #
19
- # ==== Parameter
20
- # key<String>:: The key identifying the cache entry
21
- #
22
- # ==== Returns
23
- # true if the cache entry exists, false otherwise
24
- def cached?(key)
25
- if @cache.key?(key)
26
- _data, _expire = *cache_read(key)
27
- return true if _expire.nil? || Time.now < _expire
28
- expire(key)
29
- end
30
- false
31
- end
32
-
33
- # Capture or restore the data in cache.
34
- # If the cache entry expired or does not exist, the data are taken
35
- # from the execution of the block, marshalled and stored in cache.
36
- # Otherwise, the data are loaded from the cache and returned unmarshalled
37
- #
38
- # ==== Parameters
39
- # _controller<Merb::Controller>:: The instance of the current controller
40
- # key<String>:: The key identifying the cache entry
41
- # from_now<~minutes>::
42
- # The number of minutes (from now) the cache should persist
43
- # &block:: The template to be used or not
44
- #
45
- # ==== Additional information
46
- # When fetching data (the cache entry exists and has not expired)
47
- # The data are loaded from the cache and returned unmarshalled.
48
- # Otherwise:
49
- # The controller is used to capture the rendered template (from the block).
50
- # It uses the capture_#{engine} and concat_#{engine} methods to do so.
51
- # The captured data are then marshalled and stored.
52
- def cache(_controller, key, from_now = nil, &block)
53
- if @cache.key?(key)
54
- _data, _expire = *cache_read(key)
55
- _cache_hit = _expire.nil? || Time.now < _expire
56
- end
57
- unless _cache_hit
58
- _expire = from_now ? from_now.minutes.from_now : nil
59
- _data = _controller.send(:capture, &block)
60
- cache_write(key, [_data, _expire])
61
- end
62
- _controller.send(:concat, _data, block.binding)
63
- true
64
- end
65
-
66
- # Store data to the file using the specified key
67
- #
68
- # ==== Parameters
69
- # key<Sting>:: The key identifying the cache entry
70
- # data<String>:: The data to be put in cache
71
- # from_now<~minutes>::
72
- # The number of minutes (from now) the cache should persist
73
- def cache_set(key, data, from_now = nil)
74
- _expire = from_now ? from_now.minutes.from_now : nil
75
- cache_write(key, [data, _expire])
76
- Merb.logger.info("cache: set (#{key})")
77
- true
78
- end
79
-
80
- # Fetch data from the file using the specified key
81
- # The entry is deleted if it has expired
82
- #
83
- # ==== Parameter
84
- # key<Sting>:: The key identifying the cache entry
85
- #
86
- # ==== Returns
87
- # data<String, NilClass>::
88
- # nil is returned whether the entry expired or was not found
89
- def cache_get(key)
90
- if @cache.key?(key)
91
- _data, _expire = *cache_read(key)
92
- if _expire.nil? || Time.now < _expire
93
- Merb.logger.info("cache: hit (#{key})")
94
- return _data
95
- end
96
- @mutex.synchronize do @cache.delete(key) end
97
- end
98
- Merb.logger.info("cache: miss (#{key})")
99
- nil
100
- end
101
-
102
- # Expire the cache entry identified by the given key
103
- #
104
- # ==== Parameter
105
- # key<Sting>:: The key identifying the cache entry
106
- def expire(key)
107
- @mutex.synchronize do
108
- @cache.delete(key)
109
- end
110
- Merb.logger.info("cache: expired (#{key})")
111
- true
112
- end
113
-
114
- # Expire the cache entries matching the given key
115
- #
116
- # ==== Parameter
117
- # key<Sting>:: The key matching the cache entries
118
- def expire_match(key)
119
- @mutex.synchronize do
120
- @cache.delete_if do |k,v| k.match(/#{key}/) end
121
- end
122
- Merb.logger.info("cache: expired matching (#{key})")
123
- true
124
- end
125
-
126
- # Expire all the cache entries
127
- def expire_all
128
- @mutex.synchronize do
129
- @cache.clear
130
- end
131
- Merb.logger.info("cache: expired all")
132
- true
133
- end
134
-
135
- # Gives info on the current cache store
136
- #
137
- # ==== Returns
138
- # The type of the current cache store
139
- def cache_store_type
140
- "memory"
141
- end
142
-
143
- private
144
-
145
- # Read data from the memory hash table using mutex
146
- #
147
- # ==== Parameters
148
- # cache_file<String>:: The key identifying the cache entry
149
- #
150
- # ==== Returns
151
- # _data<String>:: The data fetched from the cache
152
- def cache_read(key)
153
- @mutex.synchronize do
154
- @cache[key]
155
- end
156
- end
157
-
158
- # Write data to the memory hash table using mutex
159
- #
160
- # ==== Parameters
161
- # cache_file<String>:: The key identifying the cache entry
162
- # data<String>:: The data to be put in cache
163
- def cache_write(key, data)
164
- @mutex.synchronize do
165
- @cache[key] = data
166
- end
167
- end
168
- end