merb-cache 0.9.7 → 0.9.8

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.
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