Module: GenCache
- Defined in:
- lib/gen_cache.rb,
lib/gen_cache/keys.rb,
lib/gen_cache/caches.rb,
lib/gen_cache/expiry.rb,
lib/gen_cache/cache_io/parsing.rb,
lib/gen_cache/cache_io/fetching.rb,
lib/gen_cache/cache_io/formatting.rb,
lib/gen_cache/cache_types/key_cache.rb,
lib/gen_cache/cache_types/method_cache.rb,
lib/gen_cache/cache_types/attribute_cache.rb,
lib/gen_cache/cache_types/association_cache.rb,
lib/gen_cache/cache_types/class_method_cache.rb
Defined Under Namespace
Modules: AssocationCache, AttributeCache, Caches, ClassMethodCache, ClassMethods, KeyCache, MethodCache
Class Method Summary
collapse
-
.all_class_method_keys(klass) ⇒ Object
-
.association_key(instance, association) ⇒ Object
> “users/5821759535148822589/64/12126514016877773284/association”.
-
.attribute_key(klass, attribute, args, options = {}) ⇒ Object
> “users/5821759535148822589/attribute/value” => “users/5821759535148822589/all/attribute/value”.
-
.class_method_key(klass, method) ⇒ Object
> “users/5821759535148822589/method”.
-
.coder_from_record(record) ⇒ Object
-
.data_parse(result) ⇒ Object
-
.detect_coder(data) ⇒ Object
-
.detect_object(data) ⇒ Object
-
.escape_punctuation(string) ⇒ Object
-
.expire(object) ⇒ Object
Manual expiry initiated by an object after commit only has to worry about key_cache, attribute_cache, and class_method_cache.
-
.expire_attribute_keys(object) ⇒ Object
cached attributes are stored like: { attribute => [value1, value2] }.
-
.expire_class_method_keys(object) ⇒ Object
-
.expire_instance_key(object) ⇒ Object
-
.fetch(key_blob, options = {}, &block) ⇒ Object
-
.format_data(result) ⇒ Object
-
.format_method(result) ⇒ Object
-
.format_object(object) ⇒ Object
-
.format_with_key(result, key_type) ⇒ Object
-
.hash_inspect(hash) ⇒ Object
-
.included(base) ⇒ Object
-
.instance_key(klass, id) ⇒ Object
> “users/5821759535148822589/64”.
-
.instance_prefix(instance) ⇒ Object
HASH generated from ATTRIBUTES to indicate INSTANCE GENERATIONS => “users/5821759535148822589/64/12126514016877773284”.
-
.method_key(instance, method) ⇒ Object
> “users/5821759535148822589/64/12126514016877773284/method”.
-
.method_parse(result) ⇒ Object
-
.model_prefix(klass) ⇒ Object
HASH generated from SCHEMA to indicate MODEL GENERATIONS => “users/5821759535148822589”.
-
.multiple_fetch(key_blobs, &block) ⇒ Object
-
.object_parse(result) ⇒ Object
-
.parse_with_key(result, key_type) ⇒ Object
-
.read_from_cache(key_blob) ⇒ Object
-
.read_multi_from_cache(key_blobs) ⇒ Object
-
.record_from_coder(coder) ⇒ Object
-
.single_fetch(key_blob, options, &block) ⇒ Object
-
.symbolize_args(args) ⇒ Object
-
.write_multi_to_cache(keys_and_results) ⇒ Object
-
.write_to_cache(key_blob, result) ⇒ Object
Instance Method Summary
collapse
Class Method Details
.all_class_method_keys(klass) ⇒ Object
44
45
46
|
# File 'lib/gen_cache/keys.rb', line 44
def self.all_class_method_keys(klass)
klass.cached_class_methods.map { |c_method| class_method_key(klass, c_method) }
end
|
.association_key(instance, association) ⇒ Object
> “users/5821759535148822589/64/12126514016877773284/association”
66
67
68
69
|
# File 'lib/gen_cache/keys.rb', line 66
def self.association_key(instance, association)
{ type: :association,
key: [instance_prefix(instance), association].join("/") }
end
|
.attribute_key(klass, attribute, args, options = {}) ⇒ Object
> “users/5821759535148822589/attribute/value”
> “users/5821759535148822589/all/attribute/value”
27
28
29
30
31
32
33
34
35
36
|
# File 'lib/gen_cache/keys.rb', line 27
def self.attribute_key(klass, attribute, args, options={})
att_args = [attribute, symbolize_args([args])].join("/")
unless options[:all]
{ type: :object,
key: [model_prefix(klass), att_args].join("/") }
else
{ type: :object,
key: [model_prefix(klass), "all", att_args].join("/") }
end
end
|
.class_method_key(klass, method) ⇒ Object
> “users/5821759535148822589/method”
39
40
41
42
|
# File 'lib/gen_cache/keys.rb', line 39
def self.class_method_key(klass, method)
{ type: :method,
key: [model_prefix(klass), method].join("/") }
end
|
.coder_from_record(record) ⇒ Object
24
25
26
27
28
29
30
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 24
def self.coder_from_record(record)
unless record.nil?
coder = { :class => record.class }
record.encode_with(coder)
coder
end
end
|
.data_parse(result) ⇒ Object
59
60
61
62
63
64
65
|
# File 'lib/gen_cache/cache_io/parsing.rb', line 59
def self.data_parse(result)
if detect_coder(result)
object_parse(result)
else
result
end
end
|
.detect_coder(data) ⇒ Object
METHOD PARSING ##
METHOD STORE FORMATTING
{ args.to_string.to_symbol => answer }
36
37
38
39
|
# File 'lib/gen_cache/cache_io/parsing.rb', line 36
def self.detect_coder(data)
(data.is_a?(Hash) && hash_inspect(data)) ||
(data.is_a?(Array) && data[0].is_a?(Hash) && hash_inspect(data[0]))
end
|
.detect_object(data) ⇒ Object
50
51
52
53
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 50
def self.detect_object(data)
data.is_a?(ActiveRecord::Base) ||
(data.is_a?(Array) && data[0].is_a?(ActiveRecord::Base))
end
|
.escape_punctuation(string) ⇒ Object
46
47
48
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 46
def self.escape_punctuation(string)
string.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')
end
|
.expire(object) ⇒ Object
Manual expiry initiated by an object after commit only has to worry about key_cache, attribute_cache, and class_method_cache
9
10
11
12
13
|
# File 'lib/gen_cache/expiry.rb', line 9
def self.expire(object)
expire_instance_key(object)
expire_class_method_keys(object)
expire_attribute_keys(object)
end
|
.expire_attribute_keys(object) ⇒ Object
cached attributes are stored like: { attribute => [value1, value2] }
30
31
32
33
34
35
36
|
# File 'lib/gen_cache/expiry.rb', line 30
def self.expire_attribute_keys(object)
object.class.cached_indices.map do |index, values|
values.map { |v| attribute_key(object.class, index, v) }
end.flatten.each do |attribute_key|
Rails.cache.delete(attribute_key[:key])
end
end
|
.expire_class_method_keys(object) ⇒ Object
20
21
22
23
24
25
26
|
# File 'lib/gen_cache/expiry.rb', line 20
def self.expire_class_method_keys(object)
object.class.cached_class_methods.map do |class_method|
key = class_method_key(object.class, class_method)
end.each do |method_key|
Rails.cache.delete(method_key[:key])
end
end
|
.expire_instance_key(object) ⇒ Object
15
16
17
18
|
# File 'lib/gen_cache/expiry.rb', line 15
def self.expire_instance_key(object)
key = instance_key(object.class, object.id)
Rails.cache.delete(key[:key])
end
|
.fetch(key_blob, options = {}, &block) ⇒ Object
3
4
5
6
7
8
9
|
# File 'lib/gen_cache/cache_io/fetching.rb', line 3
def self.fetch(key_blob, options={}, &block)
unless key_blob.is_a?(Array)
single_fetch(key_blob, options) { yield if block_given? }
else
multiple_fetch(key_blob) { yield if block_given? }
end
end
|
67
68
69
70
71
72
73
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 67
def self.format_data(result)
if detect_object(result)
format_object(result)
else
result
end
end
|
55
56
57
58
59
60
61
62
63
64
65
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 55
def self.format_method(result)
if detect_object(result)
format_object(result)
elsif result.is_a?(Hash)
result.each do |arg_key, value|
result[arg_key] = format_data(value)
end
else
format_data(result)
end
end
|
16
17
18
19
20
21
22
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 16
def self.format_object(object)
if object.is_a?(Array)
object.map { |obj| coder_from_record(obj) }
else
coder_from_record(object)
end
end
|
3
4
5
6
7
8
9
10
11
12
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 3
def self.format_with_key(result, key_type)
return if result.nil?
if key_type == :association
result
elsif key_type == :object
formatted_result = format_object(result)
else
formatted_result = format_method(result)
end
end
|
.hash_inspect(hash) ⇒ Object
41
42
43
|
# File 'lib/gen_cache/cache_io/parsing.rb', line 41
def self.hash_inspect(hash)
hash.has_key?(:class) && hash.has_key?('attributes')
end
|
.included(base) ⇒ Object
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# File 'lib/gen_cache.rb', line 12
def self.included(base)
base.extend(GenCache::Caches)
base.extend(GenCache::ClassMethods)
base.class_eval do
class_attribute :cached_key,
:cached_indices,
:cached_methods,
:cached_class_methods,
:cached_associations
after_commit :expire_all
end
end
|
.instance_key(klass, id) ⇒ Object
> “users/5821759535148822589/64”
20
21
22
23
|
# File 'lib/gen_cache/keys.rb', line 20
def self.instance_key(klass, id)
{type: :object,
key: [model_prefix(klass), id].join("/") }
end
|
.instance_prefix(instance) ⇒ Object
HASH generated from ATTRIBUTES to indicate INSTANCE GENERATIONS
> “users/5821759535148822589/64/12126514016877773284”
52
53
54
55
56
57
|
# File 'lib/gen_cache/keys.rb', line 52
def self.instance_prefix(instance)
atts = instance.attributes
att_string = atts.sort.map { |k, v| [k,v].join(":") }.join(",")
generation = CityHash.hash64(att_string)
[model_prefix(instance.class), instance.id, generation].join("/")
end
|
.method_key(instance, method) ⇒ Object
> “users/5821759535148822589/64/12126514016877773284/method”
60
61
62
63
|
# File 'lib/gen_cache/keys.rb', line 60
def self.method_key(instance, method)
{ type: :method,
key: [instance_prefix(instance), method].join("/") }
end
|
.method_parse(result) ⇒ Object
45
46
47
48
49
50
51
52
53
54
55
|
# File 'lib/gen_cache/cache_io/parsing.rb', line 45
def self.method_parse(result)
if detect_coder(result)
object_parse(result)
elsif result.is_a?(Hash)
result.each do |k,v|
result[k] = data_parse(v)
end
else
data_parse(result)
end
end
|
.model_prefix(klass) ⇒ Object
HASH generated from SCHEMA to indicate MODEL GENERATIONS
> “users/5821759535148822589”
11
12
13
14
15
16
17
|
# File 'lib/gen_cache/keys.rb', line 11
def self.model_prefix(klass)
columns = klass.try(:columns)
return if columns.nil?
schema_string = columns.sort_by(&:name).map{|c| "#{c.name}:#{c.type}"}.join(',')
generation = CityHash.hash64(schema_string)
[klass.name.tableize, generation].join("/")
end
|
.multiple_fetch(key_blobs, &block) ⇒ Object
32
33
34
35
36
37
38
39
40
41
|
# File 'lib/gen_cache/cache_io/fetching.rb', line 32
def self.multiple_fetch(key_blobs, &block)
results = read_multi_from_cache(key_blobs)
if results.nil?
if block_given?
results = yield
write_multi_to_cache(results)
end
end
results.values
end
|
.object_parse(result) ⇒ Object
16
17
18
19
20
21
22
|
# File 'lib/gen_cache/cache_io/parsing.rb', line 16
def self.object_parse(result)
if result.is_a?(Array)
result.map {|obj| record_from_coder(obj)}
else
record_from_coder(result)
end
end
|
.parse_with_key(result, key_type) ⇒ Object
3
4
5
6
7
8
9
10
11
12
|
# File 'lib/gen_cache/cache_io/parsing.rb', line 3
def self.parse_with_key(result, key_type)
return if result.nil?
if key_type == :association
result
elsif key_type == :object
object_parse(result)
else
method_parse(result)
end
end
|
.read_from_cache(key_blob) ⇒ Object
47
48
49
50
51
|
# File 'lib/gen_cache/cache_io/fetching.rb', line 47
def self.read_from_cache(key_blob)
result = Rails.cache.read key_blob[:key]
return result if result.nil?
parse_with_key(result, key_blob[:type])
end
|
.read_multi_from_cache(key_blobs) ⇒ Object
53
54
55
56
57
58
59
60
61
62
|
# File 'lib/gen_cache/cache_io/fetching.rb', line 53
def self.read_multi_from_cache(key_blobs)
keys = key_blobs.map { |blob| blob[:key] }
results = Rails.cache.read_multi(*keys)
return nil if results.values.all?(&:nil?)
results.each do |key, value|
type = key_blobs.select {|kb| kb.has_value?(key) }.first[:type]
results[key] = parse_with_key(value, type)
end
results
end
|
.record_from_coder(coder) ⇒ Object
24
25
26
27
28
|
# File 'lib/gen_cache/cache_io/parsing.rb', line 24
def self.record_from_coder(coder)
record = coder[:class].allocate
record.init_with(coder)
record
end
|
.single_fetch(key_blob, options, &block) ⇒ Object
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/gen_cache/cache_io/fetching.rb', line 11
def self.single_fetch(key_blob, options, &block)
result = read_from_cache(key_blob)
method_args = symbolize_args(options[:args])
should_write = false
if block_given?
if method_args != :no_args && (result.nil? || result[method_args].nil?)
result ||= {}
result[method_args] = yield
should_write = true
elsif method_args == :no_args && result.nil?
result = yield
should_write = true
end
end
write_to_cache(key_blob, result) if should_write
result = (method_args == :no_args) ? result : result[method_args]
end
|
.symbolize_args(args) ⇒ Object
33
34
35
36
37
38
39
40
41
42
43
44
|
# File 'lib/gen_cache/cache_io/formatting.rb', line 33
def self.symbolize_args(args)
return :no_args if args.nil? || args.empty?
args.map do |arg|
if arg.is_a?(Hash)
arg.map {|k,v| "#{k}:#{v}"}.join(",")
elsif arg.is_a?(Array)
arg.join(",")
else
arg.to_s.split(" ").join("_")
end
end.join("+").to_sym
end
|
.write_multi_to_cache(keys_and_results) ⇒ Object
68
69
70
71
72
|
# File 'lib/gen_cache/cache_io/fetching.rb', line 68
def self.write_multi_to_cache(keys_and_results)
keys_and_results.each do |key, result|
write_to_cache(key, result)
end
end
|
.write_to_cache(key_blob, result) ⇒ Object
74
75
76
77
|
# File 'lib/gen_cache/cache_io/fetching.rb', line 74
def self.write_to_cache(key_blob, result)
formatted_result = format_with_key(result, key_blob[:type])
Rails.cache.write key_blob[:key], formatted_result
end
|
Instance Method Details
#expire_all ⇒ Object
3
4
5
|
# File 'lib/gen_cache/expiry.rb', line 3
def expire_all
GenCache.expire(self)
end
|