cachetastic-three 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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