cachetastic-three 3.0.0

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 (41) hide show
  1. data/LICENSE +21 -0
  2. data/README +89 -0
  3. data/doc/classes/Cachetastic/Adapters.html +180 -0
  4. data/doc/classes/Cachetastic/Adapters/Base.html +419 -0
  5. data/doc/classes/Cachetastic/Adapters/File.html +135 -0
  6. data/doc/classes/Cachetastic/Adapters/LocalMemory.html +125 -0
  7. data/doc/classes/Cachetastic/Adapters/Memcached.html +193 -0
  8. data/doc/classes/Cachetastic/Cache.html +425 -0
  9. data/doc/classes/Cachetastic/Cacheable.html +255 -0
  10. data/doc/classes/Cachetastic/Cacheable/ClassAndInstanceMethods.html +290 -0
  11. data/doc/classes/Cachetastic/Cacheable/ClassOnlyMethods.html +197 -0
  12. data/doc/classes/Cachetastic/Logger.html +186 -0
  13. data/doc/created.rid +1 -0
  14. data/doc/files/LICENSE.html +132 -0
  15. data/doc/files/README.html +222 -0
  16. data/doc/files/lib/cachetastic/adapters/base_rb.html +101 -0
  17. data/doc/files/lib/cachetastic/adapters/file_rb.html +101 -0
  18. data/doc/files/lib/cachetastic/adapters/local_memory_rb.html +101 -0
  19. data/doc/files/lib/cachetastic/adapters/memcached_rb.html +101 -0
  20. data/doc/files/lib/cachetastic/cache_rb.html +101 -0
  21. data/doc/files/lib/cachetastic/cacheable_rb.html +101 -0
  22. data/doc/files/lib/cachetastic/extensions/string_rb.html +108 -0
  23. data/doc/files/lib/cachetastic/logger_rb.html +101 -0
  24. data/doc/files/lib/cachetastic/store_object_rb.html +101 -0
  25. data/doc/files/lib/cachetastic_rb.html +112 -0
  26. data/doc/fr_class_index.html +36 -0
  27. data/doc/fr_file_index.html +38 -0
  28. data/doc/fr_method_index.html +52 -0
  29. data/doc/index.html +24 -0
  30. data/doc/rdoc-style.css +208 -0
  31. data/lib/cachetastic.rb +20 -0
  32. data/lib/cachetastic/adapters/base.rb +178 -0
  33. data/lib/cachetastic/adapters/file.rb +66 -0
  34. data/lib/cachetastic/adapters/local_memory.rb +37 -0
  35. data/lib/cachetastic/adapters/memcached.rb +114 -0
  36. data/lib/cachetastic/cache.rb +165 -0
  37. data/lib/cachetastic/cacheable.rb +202 -0
  38. data/lib/cachetastic/extensions/string.rb +8 -0
  39. data/lib/cachetastic/logger.rb +49 -0
  40. data/lib/cachetastic/store_object.rb +22 -0
  41. metadata +122 -0
@@ -0,0 +1,66 @@
1
+ module Cachetastic # :nodoc:
2
+ module Adapters
3
+ # An adapter to cache objects to the file system.
4
+ #
5
+ # This adapter supports the following configuration settings,
6
+ # in addition to the default settings:
7
+ #
8
+ # configatron.cachetastic.defaults.storage_path = ::File.join(FileUtils.pwd, 'cachetastic')
9
+ # configatron.cachetastic.defaults.marshal_method = :yaml
10
+ #
11
+ # The <tt>storage_path</tt> setting defines the path to where cached
12
+ # objects are written to on disk.
13
+ #
14
+ # See <tt>Cachetastic::Adapters::Base</tt> for a list of public API
15
+ # methods.
16
+ class File < Cachetastic::Adapters::Base
17
+
18
+ def initialize(klass) # :nodoc:
19
+ define_accessor(:storage_path)
20
+ self.storage_path = ::File.join(FileUtils.pwd, 'cachetastic')
21
+ super
22
+ self.marshal_method = :yaml if self.marshal_method == :none
23
+ @_file_paths = {}
24
+ end
25
+
26
+ def get(key) # :nodoc:
27
+ path = file_path(key)
28
+ val = nil
29
+ val = ::File.read(path) if ::File.exists?(path)
30
+ return val
31
+ end # get
32
+
33
+ def set(key, value, expiry_time = configatron.cachetastic.defaults.default_expiry) # :nodoc:
34
+ so = Cachetastic::Cache::StoreObject.new(key, value, expiry_time.from_now)
35
+ path = file_path(key)
36
+ ::File.open(path, 'w') {|f| f.write marshal(so)}
37
+ value
38
+ end # set
39
+
40
+ def delete(key) # :nodoc:
41
+ FileUtils.rm(file_path(key))
42
+ end # delete
43
+
44
+ def expire_all # :nodoc:
45
+ @_file_paths = {}
46
+ ::FileUtils.rm_rf(::File.join(self.storage_path, klass.name.underscore))
47
+ return nil
48
+ end # expire_all
49
+
50
+ def transform_key(key) # :nodoc:
51
+ key.to_s.hexdigest
52
+ end
53
+
54
+ def file_path(key) # :nodoc:
55
+ path = @_file_paths[key]
56
+ if path.nil?
57
+ path = ::File.join(self.storage_path, klass.name.underscore, transform_key(key).scan(/(.{1,4})/).flatten, 'cache.data')
58
+ @_file_paths[key] = path
59
+ FileUtils.mkdir_p(::File.dirname(path))
60
+ end
61
+ return path
62
+ end
63
+
64
+ end # File
65
+ end # Adapters
66
+ end # Cachetastic
@@ -0,0 +1,37 @@
1
+ module Cachetastic # :nodoc:
2
+ module Adapters
3
+ # An adapter to cache objects to memory. It is important to note
4
+ # that this cache is <b>volatile</b>. If the VM it is running in
5
+ # shuts down, everything in the cache gets vaporized.
6
+ #
7
+ # See <tt>Cachetastic::Adapters::Base</tt> for a list of public API
8
+ # methods.
9
+ class LocalMemory < Cachetastic::Adapters::Base
10
+
11
+ def initialize(klass) # :nodoc:
12
+ super
13
+ @_store = {}
14
+ end
15
+
16
+ def get(key) # :nodoc:
17
+ @_store[key]
18
+ end # get
19
+
20
+ def set(key, value, expiry_time = configatron.cachetastic.defaults.default_expiry) # :nodoc:
21
+ so = Cachetastic::Cache::StoreObject.new(key, value, expiry_time.from_now)
22
+ @_store[key] = marshal(so)
23
+ value
24
+ end # set
25
+
26
+ def delete(key) # :nodoc:
27
+ @_store.delete(key)
28
+ end # delete
29
+
30
+ def expire_all # :nodoc:
31
+ @_store = {}
32
+ return nil
33
+ end # expire_all
34
+
35
+ end # LocalMemory
36
+ end # Adapters
37
+ end # Cachetastic
@@ -0,0 +1,114 @@
1
+ module Cachetastic # :nodoc:
2
+ module Adapters
3
+ # An adapter to cache objects to the file system.
4
+ #
5
+ # This adapter supports the following configuration settings,
6
+ # in addition to the default settings:
7
+ #
8
+ # configatron.cachetastic.defaults.servers = ['127.0.0.1:11211']
9
+ # configatron.cachetastic.defaults.mc_options = {:c_threshold => 10_000,
10
+ # :compression => true,
11
+ # :debug => false,
12
+ # :readonly => false,
13
+ # :urlencode => false}
14
+ # configatron.cachetastic.delete_delay = 0
15
+ #
16
+ # The <tt>servers</tt> setting defines an <tt>Array</tt> of Mecached
17
+ # servers, represented as "<host>:<port>".
18
+ #
19
+ # The <tt>mc_options</tt> setting is a <tt>Hash</tt> of settings required
20
+ # by Memcached. See the Memcached documentation for more information on
21
+ # what the settings mean.
22
+ #
23
+ # The <tt>delete_delay</tt> setting tells Memcached how long to wait
24
+ # before it deletes the object. This is not the same as <tt>expiry_time</tt>.
25
+ # It is only used when the <tt>delete</tt> method is called.
26
+ #
27
+ # See <tt>Cachetastic::Adapters::Base</tt> for a list of public API
28
+ # methods.
29
+ class Memcached < Cachetastic::Adapters::Base
30
+
31
+ def initialize(klass) # :nodoc:
32
+ define_accessor(:servers)
33
+ define_accessor(:mc_options)
34
+ define_accessor(:delete_delay)
35
+ self.delete_delay = 0
36
+ self.servers = ['127.0.0.1:11211']
37
+ self.mc_options = {:c_threshold => 10_000,
38
+ :compression => true,
39
+ :debug => false,
40
+ :readonly => false,
41
+ :urlencode => false}
42
+ super
43
+ connection
44
+ end
45
+
46
+ def get(key) # :nodoc:
47
+ connection.get(transform_key(key), false)
48
+ end # get
49
+
50
+ def set(key, value, expiry_time = configatron.cachetastic.defaults.default_expiry) # :nodoc:
51
+ connection.set(transform_key(key), marshal(value), expiry_time, false)
52
+ end # set
53
+
54
+ def delete(key) # :nodoc:
55
+ connection.delete(transform_key(key), self.delete_delay)
56
+ end # delete
57
+
58
+ def expire_all # :nodoc:
59
+ increment_version
60
+ @_mc_connection = nil
61
+ return nil
62
+ end # expire_all
63
+
64
+ def transform_key(key) # :nodoc:
65
+ key.to_s.hexdigest
66
+ end
67
+
68
+ # Return <tt>false</tt> if the connection to Memcached is
69
+ # either <tt>nil</tt> or not active.
70
+ def valid?
71
+ return false if @_mc_connection.nil?
72
+ return false unless @_mc_connection.active?
73
+ return true
74
+ end
75
+
76
+ private
77
+ def connection
78
+ unless @_mc_connection && valid? && @_ns_version == get_version
79
+ @_mc_connection = MemCache.new(self.servers, self.mc_options.merge(:namespace => namespace))
80
+ end
81
+ @_mc_connection
82
+ end
83
+
84
+ def ns_connection
85
+ unless @_ns_connection
86
+ @_ns_connection = MemCache.new(self.servers, self.mc_options.merge(:namespace => :namespace_versions))
87
+ end
88
+ @_ns_connection
89
+ end
90
+
91
+ def increment_version
92
+ name = self.klass.name
93
+ v = get_version
94
+ ns_connection.set(name, v + 1)
95
+ end
96
+
97
+ def get_version
98
+ name = self.klass.name
99
+ v = ns_connection.get(name)
100
+ if v.nil?
101
+ ns_connection.set(name, 1)
102
+ v = 1
103
+ end
104
+ v
105
+ end
106
+
107
+ def namespace
108
+ @_ns_version = get_version
109
+ "#{self.klass.name}.#{@_ns_version}"
110
+ end
111
+
112
+ end # Memcached
113
+ end # Adapters
114
+ end # Cachetastic
@@ -0,0 +1,165 @@
1
+ module Cachetastic # :nodoc:
2
+ # When creating a new 'Cache' this class should be extended.
3
+ # Once extended you'll only need to override just the methods
4
+ # that are different for your cache.
5
+ # class MyAwesomeCache < Cachetastic::Cache
6
+ # end
7
+ #
8
+ # MyAwesomeCache.set(1, "One")
9
+ # MyAwesomeCache.get(1) # => "One"
10
+ # MyAwesomeCache.update(1, "One!!")
11
+ # MyAwesomeCache.get(1) # => "One!!"
12
+ # MyAwesomeCache.delete(1)
13
+ # MyAwesomeCache.get(1) # => nil
14
+ #
15
+ # class MyAwesomeCache < Cachetastic::Cache
16
+ # class << self
17
+ # def get(key)
18
+ # super(key) do
19
+ # set(key, key * 10)
20
+ # end
21
+ # end
22
+ # end
23
+ # end
24
+ #
25
+ # MyAwesomeCache.set(1, "One")
26
+ # MyAwesomeCache.get(1) # => "One"
27
+ # MyAwesomeCache.delete(1)
28
+ # MyAwesomeCache.get(1) # => 10
29
+ class Cache
30
+
31
+ # everything is done at the class level. there won't be any 'instances of it'
32
+ # using class << self means we don't have to prefix each method with 'self.'
33
+ class << self
34
+
35
+ # Returns an object from the cache for a given key.
36
+ # If the object comes back as nil and a block is given
37
+ # that block will be run and the results of the block
38
+ # will be returned. This can be used to JIT caches, just make
39
+ # sure in the block to call the set method because the
40
+ # results of the block are not automatically cached.
41
+ def get(key, &block)
42
+ do_with_logging(:get, key) do
43
+ val = self.adapter.get(key)
44
+ handle_store_object(key, adapter.unmarshal(val), &block)
45
+ end
46
+ end # get
47
+
48
+ # Set a particular object info the cache for the given key.
49
+ #
50
+ # An optional third parameter sets the expiry time for the object in the cache.
51
+ # If no expiry_time is passed in then the default expiry_time that has been configured
52
+ # will be used.
53
+ #
54
+ # If there is an the expiry_swing setting is configured it will be +/- to the
55
+ # expiry time.
56
+ def set(key, value, expiry_time = nil)
57
+ do_with_logging(:set, key) do
58
+ self.adapter.set(key, value, calculate_expiry_time(expiry_time))
59
+ end
60
+ end # set
61
+
62
+ # Deletes an object from the cache.
63
+ def delete(key)
64
+ do_with_logging(:delete, key) do
65
+ self.adapter.delete(key)
66
+ nil
67
+ end
68
+ end # delete
69
+
70
+ # Expires all objects for this cache.
71
+ def expire_all
72
+ do_with_logging(:expire_all, nil) do
73
+ self.adapter.expire_all
74
+ nil
75
+ end
76
+ end # expire_all
77
+
78
+ # Returns the underlying Cachetastic::Adapters::Base for this cache.
79
+ def adapter
80
+ unless @_adapter && @_adapter.valid?
81
+ @_adapter = Cachetastic::Adapters.build(cache_klass)
82
+ end
83
+ @_adapter
84
+ end # adapter
85
+
86
+ # Clears the adapter so it can be redefined. This is useful if you have
87
+ # reconfigured the cache to use a different adapater, or different settings.
88
+ def clear_adapter!
89
+ @_adapter = nil
90
+ end
91
+
92
+ def cache_klass # :nodoc:
93
+ self
94
+ end
95
+
96
+ # Returns the Cachetastic::Logger for this cache.
97
+ def logger
98
+ unless @_logger
99
+ @_logger = Cachetastic::Logger.new(adapter.logger)
100
+ end
101
+ @_logger
102
+ end
103
+
104
+ private
105
+ # If the expiry time is set to 60 minutes and the expiry_swing time is set to
106
+ # 15 minutes, this method will return a number between 45 minutes and 75 minutes.
107
+ def calculate_expiry_time(expiry_time) # :doc:
108
+ expiry_time = self.adapter.default_expiry if expiry_time.nil?
109
+ exp_swing = self.adapter.expiry_swing
110
+ if exp_swing && exp_swing != 0
111
+ swing = rand(exp_swing.to_i)
112
+ case rand(2)
113
+ when 0
114
+ expiry_time = (expiry_time.to_i + swing)
115
+ when 1
116
+ expiry_time = (expiry_time.to_i - swing)
117
+ end
118
+ end
119
+ expiry_time
120
+ end
121
+
122
+ def handle_store_object(key, val, &block)
123
+ if val.is_a?(Cachetastic::Cache::StoreObject)
124
+ if val.expired?
125
+ self.delete(key)
126
+ val = nil
127
+ else
128
+ val = val.value
129
+ end
130
+ end
131
+
132
+ if val.respond_to?(:empty?)
133
+ val = nil if val.empty?
134
+ elsif val.respond_to?(:blank?)
135
+ val = nil if val.blank?
136
+ end
137
+ return val unless val.nil?
138
+
139
+ val = yield if block_given?
140
+ return val
141
+ end
142
+
143
+ def do_with_logging(action, key)
144
+ if adapter.debug?
145
+ start_time = Time.now
146
+ logger.debug(:starting, action, cache_klass.name, key)
147
+ res = yield if block_given?
148
+ end_time = Time.now
149
+ str = ''
150
+ unless res.nil?
151
+ str = "[#{res.class.name}]"
152
+ str << "\t[Size = #{res.size}]" if res.respond_to? :size
153
+ str << "\t" << res.inspect
154
+ end
155
+ logger.debug(:finished, action, cache_klass.name, key, (end_time - start_time), str)
156
+ return res
157
+ else
158
+ return yield if block_given?
159
+ end
160
+ end
161
+
162
+ end # class << self
163
+
164
+ end # Cache
165
+ end # Cachetastic
@@ -0,0 +1,202 @@
1
+ module Cachetastic # :nodoc:
2
+ # Include this module into an Object to achieve simplistic Object level caching.
3
+ #
4
+ # Example:
5
+ # class Person
6
+ # include Cachetastic::Cacheable
7
+ #
8
+ # attr_accessor :name
9
+ #
10
+ # def cachetastic_key
11
+ # self.name
12
+ # end
13
+ #
14
+ # def always_the_same(x, y)
15
+ # cacher("always_the_same") do
16
+ # x + y
17
+ # end
18
+ # end
19
+ #
20
+ # end
21
+ module Cacheable
22
+
23
+ module ClassAndInstanceMethods
24
+ # Returns the Cachetastic::Cache object associated with the object.
25
+ # If a cache hasn't been defined the one will be created on the fly.
26
+ # The cache for the object is expected to be defined as:
27
+ # Cachetastic::Cacheable::{CLASS_NAME_HERE}Cache
28
+ #
29
+ # Examples:
30
+ # class Person
31
+ # include Cachetastic::Cacheable
32
+ # end
33
+ #
34
+ # Person.cache_class # => Cachetastic::Cacheable::PersonCache
35
+ #
36
+ # class Admin::Person
37
+ # include Cachetastic::Cacheable
38
+ # end
39
+ #
40
+ # Admin::Person.cache_class # => Cachetastic::Cacheable::Admin_PersonCache
41
+ def cache_class
42
+ n = self.class.name
43
+ n = self.name if n == "Class"
44
+ c_name = "Cachetastic::Cacheable::#{n.gsub('::', '_')}Cache"
45
+ begin
46
+ return c_name.constantize
47
+ rescue NameError => e
48
+ eval %{
49
+ class #{c_name} < Cachetastic::Cache
50
+
51
+ def self.cache_klass
52
+ #{n}
53
+ end
54
+
55
+ end
56
+ }
57
+ return c_name.constantize
58
+ end
59
+
60
+ end
61
+
62
+ # How much did I want to call this method cache?? It originally was that, but
63
+ # in Rails 2.0 they decided to use that name, so I had to rename this method.
64
+ # This method will attempt to get an object from the cache for a given key.
65
+ # If the object is nil and a block is given the block will be run, and the results
66
+ # of the block will be automatically cached.
67
+ #
68
+ # Example:
69
+ # class Person
70
+ # include Cachetastic::Cacheable
71
+ #
72
+ # def always_the_same(x,y)
73
+ # cacher("always_the_same") do
74
+ # x + y
75
+ # end
76
+ # end
77
+ # end
78
+ #
79
+ # Person.new.always_the_same(1,2) # => 3
80
+ # Person.new.always_the_same(2,2) # => 3
81
+ # Person.new.always_the_same(3,3) # => 3
82
+ # Person.cacher("always_the_same") # => 3
83
+ # Person.get_from_cache("always_the_same") # => 3
84
+ # Cachetastic::Cacheable::PersonCache.get("always_the_same") # => 3
85
+ #
86
+ # Person.cacher("say_hi") {"Hi There"} # => "Hi There"
87
+ # Person.get_from_cache("say_hi") # => "Hi There"
88
+ # Cachetastic::Cacheable::PersonCache.get("say_hi") # => "Hi There"
89
+ def cacher(key, expiry = nil)
90
+ cache_class.get(key) do
91
+ if block_given?
92
+ res = yield
93
+ cache_class.set(key, res, expiry)
94
+ end
95
+ end
96
+ end
97
+
98
+ # Expires the entire cache associated with this objects's cache.
99
+ #
100
+ # Example:
101
+ # class Person
102
+ # include Cachetastic::Cacheable
103
+ # attr_accessor :name
104
+ # def cachetastic_key
105
+ # self.name
106
+ # end
107
+ # end
108
+ #
109
+ # Person.set_into_cache(1, "one")
110
+ # Person.get_from_cache(1) # => "one"
111
+ # Person.expire_all
112
+ # Person.get_from_cache(1) # => nil
113
+ # Person.set_into_cache(1, "one")
114
+ # Person.get_from_cache(1) # => "one"
115
+ # Cachetastic::Cacheable::PersonCache.expire_all
116
+ # Person.get_from_cache(1) # => nil
117
+ def expire_all
118
+ cache_class.expire_all
119
+ end
120
+
121
+ end
122
+
123
+ # --------------------------
124
+ # Instance only methods:
125
+
126
+ # Unless the object's cachetastic_key method returns nil this method will store
127
+ # the object in the cache using the object's cachetastic_key as the key.
128
+ # You *MUST* create an instance level method called cachetastic_key and
129
+ # have it return a valid key! If you return nil from the cachetastic_key method or you will not be
130
+ # able to use the cache_self and uncache_self methods.
131
+ #
132
+ # Example:
133
+ # class Person
134
+ # include Cachetastic::Cacheable
135
+ # attr_accessor :name
136
+ # def cachetastic_key
137
+ # self.name
138
+ # end
139
+ # end
140
+ #
141
+ # Person.get_from_cache("Mark Bates") # => nil
142
+ # p = Person.new
143
+ # p.name = "Mark Bates"
144
+ # p.cache_self
145
+ # Person.get_from_cache("Mark Bates") # => "Mark Bates"
146
+ def cache_self
147
+ cache_class.set(self.cachetastic_key, self) unless self.cachetastic_key.nil?
148
+ end
149
+
150
+ # Unless the object's cachetastic_key method returns nil this method will delete
151
+ # the object in the cache using the object's cachetastic_key as the key.
152
+ # You *MUST* create an instance level method called cachetastic_key and
153
+ # have it return a valid key! If you return nil from the cachetastic_key method or you will not be
154
+ # able to use the cache_self and uncache_self methods.
155
+ #
156
+ # Example:
157
+ # class Person
158
+ # include Cachetastic::Cacheable
159
+ # attr_accessor :name
160
+ # def cachetastic_key
161
+ # self.name
162
+ # end
163
+ # end
164
+ #
165
+ # Person.get_from_cache("Mark Bates") # => nil
166
+ # p = Person.new
167
+ # p.name = "Mark Bates"
168
+ # p.cache_self
169
+ # Person.get_from_cache("Mark Bates") # => "Mark Bates"
170
+ # p.uncache_self
171
+ # Person.get_from_cache("Mark Bates") # => nil
172
+ def uncache_self
173
+ cache_class.delete(self.cachetastic_key) unless self.cachetastic_key.nil?
174
+ end
175
+
176
+ # --------------------------
177
+
178
+ def self.included(klass) # :nodoc:
179
+ klass.send(:include, ClassAndInstanceMethods)
180
+ klass.extend(ClassOnlyMethods)
181
+ klass.extend(ClassAndInstanceMethods)
182
+ end
183
+
184
+ module ClassOnlyMethods
185
+ # Returns an object from the cache for a given key.
186
+ def get_from_cache(key, &block)
187
+ cache_class.get(key, &block)
188
+ end
189
+
190
+ # Deletes an object from the cache for a given key.
191
+ def delete_from_cache(key)
192
+ cache_class.delete(key)
193
+ end
194
+
195
+ # Sets an object into the cache for a given key.
196
+ def set_into_cache(key, value, expiry = 0)
197
+ cache_class.set(key, value, expiry)
198
+ end
199
+ end # ClassMethods
200
+
201
+ end # Cacheable
202
+ end # Cachetastic