markbates-cachetastic-three 2.9.9.20090525090948
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/README +75 -0
- data/lib/cachetastic.rb +20 -0
- data/lib/cachetastic/adapters/base.rb +106 -0
- data/lib/cachetastic/adapters/file.rb +53 -0
- data/lib/cachetastic/adapters/local_memory.rb +31 -0
- data/lib/cachetastic/adapters/memcached.rb +93 -0
- data/lib/cachetastic/cache.rb +99 -0
- data/lib/cachetastic/cacheable.rb +202 -0
- data/lib/cachetastic/extensions/string.rb +8 -0
- data/lib/cachetastic/logger.rb +37 -0
- data/lib/cachetastic/store_object.rb +22 -0
- metadata +92 -0
data/README
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
=Configuration:
|
2
|
+
|
3
|
+
# this will dump into the log, configuration info for each cache, as well as the .inspect
|
4
|
+
# for each object returned from the cache
|
5
|
+
configatron.cachetastic_default_options.debug = false
|
6
|
+
|
7
|
+
# this is the type of file store to be used for this cache.
|
8
|
+
# more adapters can be developed and plugged in as desired
|
9
|
+
configatron.cachetastic_default_options.adapter = :local_memory # local_memory | memcache | file | drb | html_file (default: local_memory)
|
10
|
+
|
11
|
+
# this will marshall objects into and out of the store.
|
12
|
+
configatron.cachetastic_default_options.marshall_method = :none # none | yaml | ruby (default: none)
|
13
|
+
|
14
|
+
# this sets how long objects will live in the cache before they are auto expired.
|
15
|
+
configatron.cachetastic_default_options.default_expiry = 86400 # time in seconds (default: 24 hours)
|
16
|
+
|
17
|
+
# when setting objects into the cache the expiry_swing is +/- to the expiry time.
|
18
|
+
# example: if the expiry time is 1 hour, and the swing is 15 minutes,
|
19
|
+
# objects will go into the cache with an expiry time sometime between 45 mins and 75 mins.
|
20
|
+
configatron.cachetastic_default_options.expiry_swing = 60 * 15 # time in seconds (default: 0)
|
21
|
+
|
22
|
+
# these options get passed on directly to the store.
|
23
|
+
# listed below are options for memcache:
|
24
|
+
configatron.cachetastic_default_options.store_options.c_threshold = "10_000"
|
25
|
+
configatron.cachetastic_default_options.store_options.compression = true
|
26
|
+
configatron.cachetastic_default_options.store_options.debug = false
|
27
|
+
configatron.cachetastic_default_options.store_options.readonly = false
|
28
|
+
configatron.cachetastic_default_options.store_options.urlencode = false
|
29
|
+
|
30
|
+
# set the servers to be used for memcache
|
31
|
+
configatron.cachetastic_default_options.servers = ["127.0.0.1:11211"] # ip:port used for memcache
|
32
|
+
|
33
|
+
# listed below are the options for file:
|
34
|
+
configatron.cachetastic_default_options.store_options.dir = "/cachetastic/caches"
|
35
|
+
|
36
|
+
# listed below are the options for drb:
|
37
|
+
configatron.cachetastic_default_options.servers = ["druby://127.0.0.1:61676"]
|
38
|
+
|
39
|
+
# configure logging for this cache
|
40
|
+
# n number of logs can be configured for a cache
|
41
|
+
log_1 = Logger.new(STDOUT)
|
42
|
+
log_1.level = Logger::DEBUG
|
43
|
+
log_2 = Logger.new("log/cachetastic.log")
|
44
|
+
log_2.level = Logger::ERROR
|
45
|
+
configatron.cachetastic_default_options.logger = [log_1, log_2]
|
46
|
+
|
47
|
+
=Cachetastic::Drb::Server
|
48
|
+
If you want to use Drb and the Cachetastic::Adapters::Drb adapter, you'll have to use the Cachetastic::Drb::Server that comes with Cachetastic. Using this server is simple. It gets installed as a binary when you install the Cachetastic gem.
|
49
|
+
|
50
|
+
$ cachetastic_drb_server # that will start the drb server on the host 127.0.0.1 on the port 61676
|
51
|
+
|
52
|
+
The server takes to command line parameters: -h <host> -p <port> -v <verbose> -rv <really verbose>
|
53
|
+
|
54
|
+
=Examples:
|
55
|
+
|
56
|
+
class MyAwesomeCache < Cachetastic::Caches::Base
|
57
|
+
end
|
58
|
+
|
59
|
+
MyAwesomeCache.set(1, [1,2,3])
|
60
|
+
MyAwesomeCache.get(1) # => [1,2,3]
|
61
|
+
|
62
|
+
class MyAwesomeCache < Cachetastic::Caches::Base
|
63
|
+
class << self
|
64
|
+
def get(key, x, y)
|
65
|
+
super(key) do
|
66
|
+
n = x + y
|
67
|
+
set(key, n)
|
68
|
+
n
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
MyAwesomeCache.get(1, 2, 4) # => 8
|
75
|
+
MyAwesomeCache.get(1, 4, 4) # => 8
|
data/lib/cachetastic.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'configatron'
|
2
|
+
require 'logger'
|
3
|
+
require 'activesupport'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'memcache'
|
6
|
+
|
7
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'cachetastic', '**/*.rb')).each do |f|
|
8
|
+
require File.expand_path(f)
|
9
|
+
end
|
10
|
+
|
11
|
+
configatron.cachetastic.defaults.set_default(:marshal_method, :none)
|
12
|
+
configatron.cachetastic.defaults.set_default(:expiry_swing, 0)
|
13
|
+
configatron.cachetastic.defaults.set_default(:default_expiry, 86400)
|
14
|
+
configatron.cachetastic.defaults.set_default(:debug, true)
|
15
|
+
configatron.cachetastic.defaults.set_default(:adapter, Cachetastic::Adapters::LocalMemory)
|
16
|
+
log_path = File.join(FileUtils.pwd, 'log', 'cachetastic.log')
|
17
|
+
FileUtils.mkdir_p(File.dirname(log_path))
|
18
|
+
logger = ::Logger.new(log_path)
|
19
|
+
logger.level = ::Logger::DEBUG
|
20
|
+
configatron.cachetastic.defaults.set_default(:logger, logger)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Cachetastic
|
2
|
+
module Adapters
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def build(klass)
|
7
|
+
adp = klass.to_configatron(:cachetastic).adapter
|
8
|
+
if adp.nil?
|
9
|
+
adp = configatron.cachetastic.defaults.adapter
|
10
|
+
end
|
11
|
+
adp.new(klass)
|
12
|
+
end
|
13
|
+
|
14
|
+
end # class << self
|
15
|
+
|
16
|
+
class Base
|
17
|
+
|
18
|
+
attr_accessor :klass
|
19
|
+
|
20
|
+
def initialize(klass)
|
21
|
+
self.klass = klass
|
22
|
+
configatron.cachetastic.defaults.configatron_keys.each do |key|
|
23
|
+
define_accessor(key)
|
24
|
+
self.send("#{key}=", configatron.cachetastic.defaults.send(key))
|
25
|
+
end
|
26
|
+
klass.to_configatron(:cachetastic).configatron_keys.each do |key|
|
27
|
+
define_accessor(key)
|
28
|
+
self.send("#{key}=", klass.to_configatron(:cachetastic).send(key))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Allows an adapter to transform the key
|
33
|
+
# to a safe representation for it's backend.
|
34
|
+
# For example, the key: '$*...123()%~q' is not a
|
35
|
+
# key for the file system, so the
|
36
|
+
# Cachetastic::Adapters::File class should override
|
37
|
+
# this to make it safe for the file system.
|
38
|
+
def transform_key(key)
|
39
|
+
key
|
40
|
+
end
|
41
|
+
|
42
|
+
def valid?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def debug?
|
47
|
+
return self.debug if self.respond_to?(:debug)
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
|
51
|
+
def marshal(value)
|
52
|
+
return nil if value.nil?
|
53
|
+
case self.marshal_method.to_sym
|
54
|
+
when :yaml
|
55
|
+
return YAML.dump(value)
|
56
|
+
when :ruby
|
57
|
+
return Marshal.dump(value)
|
58
|
+
else
|
59
|
+
return value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def unmarshal(value)
|
64
|
+
return nil if value.nil?
|
65
|
+
case self.marshal_method.to_sym
|
66
|
+
when :yaml
|
67
|
+
return YAML.load(value)
|
68
|
+
when :ruby
|
69
|
+
return Marshal.load(value)
|
70
|
+
else
|
71
|
+
return value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
# If the expiry time is set to 60 minutes and the expiry_swing time is set to
|
77
|
+
# 15 minutes, this method will return a number between 45 minutes and 75 minutes.
|
78
|
+
def calculate_expiry_time(expiry_time) # :doc:
|
79
|
+
expiry_time = self.default_expiry if expiry_time.nil?
|
80
|
+
exp_swing = self.expiry_swing
|
81
|
+
if exp_swing && exp_swing != 0
|
82
|
+
swing = rand(exp_swing.to_i)
|
83
|
+
case rand(2)
|
84
|
+
when 0
|
85
|
+
expiry_time = (expiry_time.to_i + swing)
|
86
|
+
when 1
|
87
|
+
expiry_time = (expiry_time.to_i - swing)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
expiry_time
|
91
|
+
end
|
92
|
+
|
93
|
+
def define_accessor(key)
|
94
|
+
instance_eval(%{
|
95
|
+
def #{key}
|
96
|
+
@#{key}
|
97
|
+
end
|
98
|
+
def #{key}=(x)
|
99
|
+
@#{key} = x
|
100
|
+
end
|
101
|
+
})
|
102
|
+
end
|
103
|
+
|
104
|
+
end # Base
|
105
|
+
end # Adapters
|
106
|
+
end # Cachetastic
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Cachetastic
|
2
|
+
module Adapters
|
3
|
+
class File < Cachetastic::Adapters::Base
|
4
|
+
|
5
|
+
def initialize(klass)
|
6
|
+
define_accessor(:storage_path)
|
7
|
+
self.storage_path = ::File.join(FileUtils.pwd, 'cachetastic')
|
8
|
+
super
|
9
|
+
self.marshal_method = :yaml if self.marshal_method == :none
|
10
|
+
@_file_paths = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(key, &block)
|
14
|
+
path = file_path(key)
|
15
|
+
val = nil
|
16
|
+
val = ::File.read(path) if ::File.exists?(path)
|
17
|
+
return val
|
18
|
+
end # get
|
19
|
+
|
20
|
+
def set(key, value, expiry_time = nil)
|
21
|
+
so = Cachetastic::Cache::StoreObject.new(key, value, calculate_expiry_time(expiry_time).from_now)
|
22
|
+
path = file_path(key)
|
23
|
+
::File.open(path, 'w') {|f| f.write marshal(so)}
|
24
|
+
value
|
25
|
+
end # set
|
26
|
+
|
27
|
+
def delete(key)
|
28
|
+
FileUtils.rm(file_path(key))
|
29
|
+
end # delete
|
30
|
+
|
31
|
+
def expire_all
|
32
|
+
@_file_paths = {}
|
33
|
+
::FileUtils.rm_rf(::File.join(self.storage_path, klass.name.underscore))
|
34
|
+
return nil
|
35
|
+
end # expire_all
|
36
|
+
|
37
|
+
def transform_key(key)
|
38
|
+
key.to_s.hexdigest
|
39
|
+
end
|
40
|
+
|
41
|
+
def file_path(key)
|
42
|
+
path = @_file_paths[key]
|
43
|
+
if path.nil?
|
44
|
+
path = ::File.join(self.storage_path, klass.name.underscore, transform_key(key).scan(/(.{1,4})/).flatten, 'cache.data')
|
45
|
+
@_file_paths[key] = path
|
46
|
+
FileUtils.mkdir_p(::File.dirname(path))
|
47
|
+
end
|
48
|
+
return path
|
49
|
+
end
|
50
|
+
|
51
|
+
end # File
|
52
|
+
end # Adapters
|
53
|
+
end # Cachetastic
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Cachetastic
|
2
|
+
module Adapters
|
3
|
+
class LocalMemory < Cachetastic::Adapters::Base
|
4
|
+
|
5
|
+
def initialize(klass)
|
6
|
+
super
|
7
|
+
@_store = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(key, &block)
|
11
|
+
@_store[key]
|
12
|
+
end # get
|
13
|
+
|
14
|
+
def set(key, value, expiry_time = nil)
|
15
|
+
so = Cachetastic::Cache::StoreObject.new(key, value, calculate_expiry_time(expiry_time).from_now)
|
16
|
+
@_store[key] = marshal(so)
|
17
|
+
value
|
18
|
+
end # set
|
19
|
+
|
20
|
+
def delete(key)
|
21
|
+
@_store.delete(key)
|
22
|
+
end # delete
|
23
|
+
|
24
|
+
def expire_all
|
25
|
+
@_store = {}
|
26
|
+
return nil
|
27
|
+
end # expire_all
|
28
|
+
|
29
|
+
end # LocalMemory
|
30
|
+
end # Adapters
|
31
|
+
end # Cachetastic
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Cachetastic
|
2
|
+
module Adapters
|
3
|
+
class Memcached < Cachetastic::Adapters::Base
|
4
|
+
|
5
|
+
def initialize(klass)
|
6
|
+
# puts "initialize: #{klass}"
|
7
|
+
define_accessor(:servers)
|
8
|
+
define_accessor(:mc_options)
|
9
|
+
define_accessor(:delete_delay)
|
10
|
+
self.delete_delay = 0
|
11
|
+
self.servers = ['127.0.0.1:11211']
|
12
|
+
self.mc_options = {:c_threshold => 10_000,
|
13
|
+
:compression => true,
|
14
|
+
:debug => false,
|
15
|
+
:readonly => false,
|
16
|
+
:urlencode => false}
|
17
|
+
super
|
18
|
+
connection
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(key, &block)
|
22
|
+
connection.get(transform_key(key), false)
|
23
|
+
end # get
|
24
|
+
|
25
|
+
def set(key, value, expiry_time = 0)
|
26
|
+
connection.set(transform_key(key), marshal(value), calculate_expiry_time(expiry_time), false)
|
27
|
+
end # set
|
28
|
+
|
29
|
+
def delete(key)
|
30
|
+
connection.delete(transform_key(key), self.delete_delay)
|
31
|
+
end # delete
|
32
|
+
|
33
|
+
def expire_all
|
34
|
+
increment_version
|
35
|
+
@_mc_connection = nil
|
36
|
+
return nil
|
37
|
+
end # expire_all
|
38
|
+
|
39
|
+
def transform_key(key)
|
40
|
+
key.to_s.hexdigest
|
41
|
+
end
|
42
|
+
|
43
|
+
def valid?
|
44
|
+
return false if @_mc_connection.nil?
|
45
|
+
return false unless @_mc_connection.active?
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def connection
|
51
|
+
unless @_mc_connection && valid? && @_ns_version == get_version
|
52
|
+
@_mc_connection = MemCache.new(self.servers, self.mc_options.merge(:namespace => namespace))
|
53
|
+
end
|
54
|
+
@_mc_connection
|
55
|
+
end
|
56
|
+
|
57
|
+
def ns_connection
|
58
|
+
unless @_ns_connection
|
59
|
+
@_ns_connection = MemCache.new(self.servers, self.mc_options.merge(:namespace => :namespace_versions))
|
60
|
+
end
|
61
|
+
@_ns_connection
|
62
|
+
end
|
63
|
+
|
64
|
+
def increment_version
|
65
|
+
name = self.klass.name
|
66
|
+
v = get_version
|
67
|
+
ns_connection.set(name, v + 1)
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_version
|
71
|
+
name = self.klass.name
|
72
|
+
v = ns_connection.get(name)
|
73
|
+
if v.nil?
|
74
|
+
ns_connection.set(name, 1)
|
75
|
+
v = 1
|
76
|
+
end
|
77
|
+
v
|
78
|
+
end
|
79
|
+
|
80
|
+
def namespace
|
81
|
+
@_ns_version = get_version
|
82
|
+
"#{self.klass.name}.#{@_ns_version}"
|
83
|
+
end
|
84
|
+
|
85
|
+
end # Memcached
|
86
|
+
end # Adapters
|
87
|
+
end # Cachetastic
|
88
|
+
|
89
|
+
# c_threshold: 10_000
|
90
|
+
# compression: true
|
91
|
+
# debug: false
|
92
|
+
# readonly: false
|
93
|
+
# urlencode: false
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Cachetastic
|
2
|
+
class Cache
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def get(key, &block)
|
7
|
+
do_with_logging(:get, key) do
|
8
|
+
val = self.adapter.get(key, &block)
|
9
|
+
handle_store_object(key, adapter.unmarshal(val), &block)
|
10
|
+
end
|
11
|
+
end # get
|
12
|
+
|
13
|
+
def set(key, value, expiry_time = nil)
|
14
|
+
do_with_logging(:set, key) do
|
15
|
+
self.adapter.set(key, value, expiry_time)
|
16
|
+
end
|
17
|
+
end # set
|
18
|
+
|
19
|
+
def delete(key)
|
20
|
+
do_with_logging(:delete, key) do
|
21
|
+
self.adapter.delete(key)
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end # delete
|
25
|
+
|
26
|
+
def expire_all
|
27
|
+
do_with_logging(:expire_all, nil) do
|
28
|
+
self.adapter.expire_all
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end # expire_all
|
32
|
+
|
33
|
+
def adapter
|
34
|
+
unless @_adapter && @_adapter.valid?
|
35
|
+
@_adapter = Cachetastic::Adapters.build(cache_klass)
|
36
|
+
end
|
37
|
+
@_adapter
|
38
|
+
end # adapter
|
39
|
+
|
40
|
+
def clear_adapter!
|
41
|
+
@_adapter = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def cache_klass
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def logger
|
49
|
+
unless @_logger
|
50
|
+
@_logger = Cachetastic::Logger.new(adapter.logger)
|
51
|
+
end
|
52
|
+
@_logger
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def handle_store_object(key, val, &block)
|
57
|
+
if val.is_a?(Cachetastic::Cache::StoreObject)
|
58
|
+
if val.expired?
|
59
|
+
self.delete(key)
|
60
|
+
val = nil
|
61
|
+
else
|
62
|
+
val = val.value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if val.respond_to?(:empty?)
|
67
|
+
val = nil if val.empty?
|
68
|
+
elsif val.respond_to?(:blank?)
|
69
|
+
val = nil if val.blank?
|
70
|
+
end
|
71
|
+
return val unless val.nil?
|
72
|
+
|
73
|
+
val = yield if block_given?
|
74
|
+
return val
|
75
|
+
end
|
76
|
+
|
77
|
+
def do_with_logging(action, key)
|
78
|
+
if adapter.debug?
|
79
|
+
start_time = Time.now
|
80
|
+
logger.debug(:starting, action, cache_klass.name, key)
|
81
|
+
res = yield if block_given?
|
82
|
+
end_time = Time.now
|
83
|
+
str = ''
|
84
|
+
unless res.nil?
|
85
|
+
str = "[#{res.class.name}]"
|
86
|
+
str << "\t[Size = #{res.size}]" if res.respond_to? :size
|
87
|
+
str << "\t" << res.inspect
|
88
|
+
end
|
89
|
+
logger.debug(:finished, action, cache_klass.name, key, (end_time - start_time), str)
|
90
|
+
return res
|
91
|
+
else
|
92
|
+
return yield if block_given?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end # class << self
|
97
|
+
|
98
|
+
end # Cache
|
99
|
+
end # Cachetastic
|
@@ -0,0 +1,202 @@
|
|
1
|
+
module Cachetastic
|
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::Caches::Base 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
|
+
# Example:
|
30
|
+
# class Person
|
31
|
+
# include Cachetastic::Cacheable
|
32
|
+
# attr_accessor :name
|
33
|
+
# def cachetastic_key
|
34
|
+
# self.name
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Person.cache_class # => Cachetastic::Cacheable::PersonCache
|
39
|
+
def cache_class
|
40
|
+
n = self.class.name
|
41
|
+
n = self.name if n == "Class"
|
42
|
+
c_name = "Cachetastic::Cacheable::#{n.gsub('::', '_')}Cache"
|
43
|
+
begin
|
44
|
+
return c_name.constantize
|
45
|
+
rescue NameError => e
|
46
|
+
eval %{
|
47
|
+
class #{c_name} < Cachetastic::Cache
|
48
|
+
|
49
|
+
def self.cache_klass
|
50
|
+
#{n}
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
}
|
55
|
+
return c_name.constantize
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# How much did I want to call this method cache?? It originally was that, but
|
61
|
+
# in Rails 2.0 they decided to use that name, so I had to rename this method.
|
62
|
+
# This method will attempt to get an object from the cache for a given key.
|
63
|
+
# If the object is nil and a block is given the block will be run, and the results
|
64
|
+
# of the block will be automatically cached.
|
65
|
+
#
|
66
|
+
# Example:
|
67
|
+
# class Person
|
68
|
+
# include Cachetastic::Cacheable
|
69
|
+
# attr_accessor :name
|
70
|
+
# def cachetastic_key
|
71
|
+
# self.name
|
72
|
+
# end
|
73
|
+
# def always_the_same(x,y)
|
74
|
+
# cacher("always_the_same") do
|
75
|
+
# x + y
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# Person.new.always_the_same(1,2) # => 3
|
81
|
+
# Person.new.always_the_same(2,2) # => 3
|
82
|
+
# Person.new.always_the_same(3,3) # => 3
|
83
|
+
# Person.cacher("always_the_same") # => 3
|
84
|
+
# Person.get_from_cache("always_the_same") # => 3
|
85
|
+
# Cachetastic::Cacheable::PersonCache.get("always_the_same") # => 3
|
86
|
+
#
|
87
|
+
# Person.cacher("say_hi") {"Hi There"} # => "Hi There"
|
88
|
+
# Person.get_from_cache("say_hi") # => "Hi There"
|
89
|
+
# Cachetastic::Cacheable::PersonCache.get("say_hi") # => "Hi There"
|
90
|
+
def cacher(key, expiry = 0)
|
91
|
+
cache_class.get(key) do
|
92
|
+
if block_given?
|
93
|
+
res = yield
|
94
|
+
cache_class.set(key, res, expiry)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Expires the entire cache associated with this objects's cache.
|
100
|
+
#
|
101
|
+
# Example:
|
102
|
+
# class Person
|
103
|
+
# include Cachetastic::Cacheable
|
104
|
+
# attr_accessor :name
|
105
|
+
# def cachetastic_key
|
106
|
+
# self.name
|
107
|
+
# end
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# Person.set_into_cache(1, "one")
|
111
|
+
# Person.get_from_cache(1) # => "one"
|
112
|
+
# Person.expire_all
|
113
|
+
# Person.get_from_cache(1) # => nil
|
114
|
+
# Person.set_into_cache(1, "one")
|
115
|
+
# Person.get_from_cache(1) # => "one"
|
116
|
+
# Cachetastic::Cacheable::PersonCache.expire_all
|
117
|
+
# Person.get_from_cache(1) # => nil
|
118
|
+
def expire_all
|
119
|
+
cache_class.expire_all
|
120
|
+
end
|
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
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# This class handles logging for the caches and their adapters.
|
2
|
+
module Cachetastic
|
3
|
+
class Logger
|
4
|
+
|
5
|
+
# attr_accessor :options
|
6
|
+
# attr_accessor :cache_name
|
7
|
+
attr_accessor :loggers
|
8
|
+
|
9
|
+
def initialize(*loggers)
|
10
|
+
@loggers = [loggers].flatten
|
11
|
+
end
|
12
|
+
|
13
|
+
LOG_LEVELS = [:fatal, :error, :warn, :info, :debug]
|
14
|
+
|
15
|
+
LOG_LEVELS.each do |level|
|
16
|
+
define_method(level) do |*args|
|
17
|
+
lm = "[CACHE] [#{level.to_s.upcase}]\t#{Time.now.strftime("%m/%d/%y %H:%M:%S")}"
|
18
|
+
exs = []
|
19
|
+
args.each do |arg|
|
20
|
+
if arg.is_a?(Exception)
|
21
|
+
exs << arg
|
22
|
+
continue
|
23
|
+
end
|
24
|
+
lm << "\t" << arg.to_s
|
25
|
+
end
|
26
|
+
exs.each do |ex|
|
27
|
+
lm << "\n#{ex.message}\n" << ex.backtrace.join("\n")
|
28
|
+
end
|
29
|
+
# puts "lm: #{lm}"
|
30
|
+
self.loggers.each do |log|
|
31
|
+
log.send(level, lm)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end # Logger
|
37
|
+
end # Cachetastic
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Cachetastic
|
2
|
+
class Cache
|
3
|
+
|
4
|
+
class StoreObject # :nodoc:
|
5
|
+
attr_accessor :expires_at
|
6
|
+
attr_accessor :key
|
7
|
+
attr_accessor :value
|
8
|
+
|
9
|
+
def initialize(key, value, expires_at)
|
10
|
+
self.key = key
|
11
|
+
self.value = value
|
12
|
+
self.expires_at = expires_at
|
13
|
+
end
|
14
|
+
|
15
|
+
def expired?
|
16
|
+
return Time.now > self.expires_at
|
17
|
+
end
|
18
|
+
|
19
|
+
end # StoreObject
|
20
|
+
|
21
|
+
end # Cache
|
22
|
+
end # Cachetastic
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: markbates-cachetastic-three
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.9.9.20090525090948
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Bates
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-25 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: configatron
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.3.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: memcache-client
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.5.0
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: activesupport
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.2.2
|
44
|
+
version:
|
45
|
+
description: A very simple, yet very powerful caching framework for Ruby.
|
46
|
+
email: mark@mackframework.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README
|
53
|
+
files:
|
54
|
+
- lib/cachetastic/adapters/base.rb
|
55
|
+
- lib/cachetastic/adapters/file.rb
|
56
|
+
- lib/cachetastic/adapters/local_memory.rb
|
57
|
+
- lib/cachetastic/adapters/memcached.rb
|
58
|
+
- lib/cachetastic/cache.rb
|
59
|
+
- lib/cachetastic/cacheable.rb
|
60
|
+
- lib/cachetastic/extensions/string.rb
|
61
|
+
- lib/cachetastic/logger.rb
|
62
|
+
- lib/cachetastic/store_object.rb
|
63
|
+
- lib/cachetastic.rb
|
64
|
+
- README
|
65
|
+
has_rdoc: true
|
66
|
+
homepage: http://www.mackframework.com
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project: cachetastic
|
87
|
+
rubygems_version: 1.2.0
|
88
|
+
signing_key:
|
89
|
+
specification_version: 2
|
90
|
+
summary: A very simple, yet very powerful caching framework for Ruby.
|
91
|
+
test_files: []
|
92
|
+
|