simple_cacheable 1.3.2 → 1.3.3

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b46d1110354d90d106fe5abdfed1eaa6801dd7e4
4
+ data.tar.gz: 763dac9a0c34135095974d09bb2575fbc5106ed2
5
+ SHA512:
6
+ metadata.gz: f0fd40d41856c6efb7ecdfa1d8263ab2178b98c4cc8656d5bde2f3e67d71029c8cdebacf72a9d127abd775867d1d452fe86e8b122ec8f8adb315b9fab444999b
7
+ data.tar.gz: 322aad0ed21db8769cc06557df6461f8e8a29ddad18597922a4410480dc71a3d639217ea07a88b3c861db899802b4cf05c615242dc5069a9aab55325bfb0983a
data/.gitignore CHANGED
@@ -1,5 +1,4 @@
1
1
  *.gem
2
2
  .bundle
3
- Gemfile.lock
4
3
  pkg/
5
4
  bin/
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ cacheable
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0
data/ChangeLog ADDED
@@ -0,0 +1,7 @@
1
+ 1.3.3
2
+ * File Reorganization
3
+ * Rails 4 Compatibility
4
+ * Class Method Caching can accept arguments
5
+ * Class Method Caching
6
+ * has_one through association caching
7
+ * has_and_belongs_to_many association caching
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "http://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  platforms :ruby do
7
- gem "sqlite3-ruby"
7
+ gem "sqlite3"
8
8
  gem "memcached"
9
9
  end
10
10
 
@@ -12,6 +12,4 @@ platforms :jruby do
12
12
  gem "activerecord-jdbc-adapter"
13
13
  gem "activerecord-jdbcsqlite3-adapter"
14
14
  gem "jruby-memcached"
15
- end
16
-
17
- gem "debugger"
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,115 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ simple_cacheable (1.3.2)
5
+ rails (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ actionmailer (4.0.0)
11
+ actionpack (= 4.0.0)
12
+ mail (~> 2.5.3)
13
+ actionpack (4.0.0)
14
+ activesupport (= 4.0.0)
15
+ builder (~> 3.1.0)
16
+ erubis (~> 2.7.0)
17
+ rack (~> 1.5.2)
18
+ rack-test (~> 0.6.2)
19
+ activemodel (4.0.0)
20
+ activesupport (= 4.0.0)
21
+ builder (~> 3.1.0)
22
+ activerecord (4.0.0)
23
+ activemodel (= 4.0.0)
24
+ activerecord-deprecated_finders (~> 1.0.2)
25
+ activesupport (= 4.0.0)
26
+ arel (~> 4.0.0)
27
+ activerecord-deprecated_finders (1.0.3)
28
+ activerecord-jdbc-adapter (1.2.2.1)
29
+ activerecord-jdbcsqlite3-adapter (1.2.2.1)
30
+ activerecord-jdbc-adapter (~> 1.2.2.1)
31
+ jdbc-sqlite3 (~> 3.7.2)
32
+ activesupport (4.0.0)
33
+ i18n (~> 0.6, >= 0.6.4)
34
+ minitest (~> 4.2)
35
+ multi_json (~> 1.3)
36
+ thread_safe (~> 0.1)
37
+ tzinfo (~> 0.3.37)
38
+ arel (4.0.0)
39
+ atomic (1.1.10)
40
+ atomic (1.1.10-java)
41
+ builder (3.1.4)
42
+ diff-lcs (1.1.3)
43
+ erubis (2.7.0)
44
+ hike (1.2.3)
45
+ i18n (0.6.4)
46
+ jdbc-sqlite3 (3.7.2)
47
+ jruby-memcached (0.5.1)
48
+ mail (2.5.4)
49
+ mime-types (~> 1.16)
50
+ treetop (~> 1.4.8)
51
+ memcached (1.4.6)
52
+ metaclass (0.0.1)
53
+ mime-types (1.23)
54
+ minitest (4.7.5)
55
+ mocha (0.10.5)
56
+ metaclass (~> 0.0.1)
57
+ multi_json (1.7.7)
58
+ polyglot (0.3.3)
59
+ rack (1.5.2)
60
+ rack-test (0.6.2)
61
+ rack (>= 1.0)
62
+ rails (4.0.0)
63
+ actionmailer (= 4.0.0)
64
+ actionpack (= 4.0.0)
65
+ activerecord (= 4.0.0)
66
+ activesupport (= 4.0.0)
67
+ bundler (>= 1.3.0, < 2.0)
68
+ railties (= 4.0.0)
69
+ sprockets-rails (~> 2.0.0)
70
+ railties (4.0.0)
71
+ actionpack (= 4.0.0)
72
+ activesupport (= 4.0.0)
73
+ rake (>= 0.8.7)
74
+ thor (>= 0.18.1, < 2.0)
75
+ rake (10.1.0)
76
+ rspec (2.8.0)
77
+ rspec-core (~> 2.8.0)
78
+ rspec-expectations (~> 2.8.0)
79
+ rspec-mocks (~> 2.8.0)
80
+ rspec-core (2.8.0)
81
+ rspec-expectations (2.8.0)
82
+ diff-lcs (~> 1.1.2)
83
+ rspec-mocks (2.8.0)
84
+ sprockets (2.10.0)
85
+ hike (~> 1.2)
86
+ multi_json (~> 1.0)
87
+ rack (~> 1.0)
88
+ tilt (~> 1.1, != 1.3.0)
89
+ sprockets-rails (2.0.0)
90
+ actionpack (>= 3.0)
91
+ activesupport (>= 3.0)
92
+ sprockets (~> 2.8)
93
+ sqlite3 (1.3.7)
94
+ thor (0.18.1)
95
+ thread_safe (0.1.0)
96
+ atomic
97
+ tilt (1.4.1)
98
+ treetop (1.4.14)
99
+ polyglot
100
+ polyglot (>= 0.3.1)
101
+ tzinfo (0.3.37)
102
+
103
+ PLATFORMS
104
+ java
105
+ ruby
106
+
107
+ DEPENDENCIES
108
+ activerecord-jdbc-adapter
109
+ activerecord-jdbcsqlite3-adapter
110
+ jruby-memcached
111
+ memcached
112
+ mocha
113
+ rspec
114
+ simple_cacheable!
115
+ sqlite3
data/README.md CHANGED
@@ -76,7 +76,7 @@ Gotchas
76
76
 
77
77
  Caching, and caching invalidation specifically, can be hard and confusing. Simple Cacheable methods should
78
78
  expire correctly in most cases. Be careful using `with_method` and `with_class_method`, they should
79
- specifically not be used to return collections. This is demonstrated well Tobias Lutke's presentation: [Rockstar Memcaching][2].
79
+ specifically not be used to return collections. This is demonstrated well in Tobias Lutke's presentation: [Rockstar Memcaching][2].
80
80
 
81
81
  Copyright © 2011 Richard Huang (flyerhzm@gmail.com), released under the MIT license
82
82
 
@@ -0,0 +1,15 @@
1
+ require "cacheable/types/key_cache"
2
+ require "cacheable/types/attribute_cache"
3
+ require "cacheable/types/method_cache"
4
+ require "cacheable/types/class_method_cache"
5
+ require "cacheable/types/association_cache"
6
+
7
+ module Cacheable
8
+ module Caches
9
+ include Cacheable::KeyCache
10
+ include Cacheable::AttributeCache
11
+ include Cacheable::MethodCache
12
+ include Cacheable::ClassMethodCache
13
+ include Cacheable::AssocationCache
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ module Cacheable
2
+ module Expiry
3
+ def expire_model_cache
4
+ expire_key_cache if self.class.cached_key
5
+ expire_attribute_cache if self.class.cached_indices.present?
6
+ expire_all_attribute_cache if self.class.cached_indices.present?
7
+ expire_method_cache if self.class.cached_methods.present?
8
+ expire_class_method_cache if self.class.cached_class_methods.present?
9
+
10
+ if self.class.cached_associations.present?
11
+ self.class.cached_associations.each do |assoc|
12
+ expire_association_cache(assoc)
13
+ end
14
+ end
15
+ end
16
+
17
+ def expire_key_cache
18
+ Rails.cache.delete model_cache_key
19
+ end
20
+
21
+ def expire_attribute_cache
22
+ self.class.cached_indices.each do |attribute, values|
23
+ value = self.send(attribute)
24
+ Rails.cache.delete self.class.attribute_cache_key(attribute, value)
25
+ end
26
+ end
27
+
28
+ def expire_all_attribute_cache
29
+ self.class.cached_indices.each do |attribute, values|
30
+ value = self.send(attribute)
31
+ Rails.cache.delete self.class.all_attribute_cache_key(attribute, value)
32
+ end
33
+ end
34
+
35
+ def expire_method_cache
36
+ self.class.cached_methods.each do |meth|
37
+ Rails.cache.delete method_cache_key(meth)
38
+ end
39
+ end
40
+
41
+ def expire_class_method_cache
42
+ self.class.cached_class_methods.each do |meth, args|
43
+ args.each do |arg|
44
+ Rails.cache.delete self.class.class_method_cache_key(meth, arg)
45
+ end
46
+ end
47
+ end
48
+
49
+ def expire_association_cache(name)
50
+ Rails.cache.delete have_association_cache_key(name)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,54 @@
1
+ module Cacheable
2
+ module Keys
3
+
4
+ def self.included(base)
5
+ base.extend(Cacheable::Keys::ClassKeys)
6
+ base.send :include, Cacheable::Keys::InstanceKeys
7
+ end
8
+
9
+ module ClassKeys
10
+
11
+ def attribute_cache_key(attribute, value)
12
+ "#{name.tableize}/attribute/#{attribute}/#{URI.escape(value.to_s)}"
13
+ end
14
+
15
+ def all_attribute_cache_key(attribute, value)
16
+ "#{name.tableize}/attribute/#{attribute}/all/#{URI.escape(value.to_s)}"
17
+ end
18
+
19
+ def class_method_cache_key(meth, *args)
20
+ key = "#{name.tableize}/class_method/#{meth}"
21
+ args.flatten!
22
+ key += "/#{args.join('+')}" if args.any?
23
+ return key
24
+ end
25
+
26
+ end
27
+
28
+ module InstanceKeys
29
+
30
+ def model_cache_key
31
+ "#{self.class.name.tableize}/#{self.id.to_i}"
32
+ end
33
+
34
+ def method_cache_key(meth)
35
+ "#{model_cache_key}/method/#{meth}"
36
+ end
37
+
38
+ def belong_association_cache_key(name, polymorphic=nil)
39
+ name = name.to_s if name.is_a?(Symbol)
40
+ if polymorphic
41
+ "#{self.send("#{name}_type").tableize}/#{self.send("#{name}_id")}"
42
+ else
43
+ "#{name.tableize}/#{self.send(name + "_id")}"
44
+ end
45
+ end
46
+
47
+ def have_association_cache_key(name)
48
+ "#{model_cache_key}/association/#{name}"
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,92 @@
1
+ module Cacheable
2
+ module AssocationCache
3
+
4
+ def with_association(*association_names)
5
+ self.cached_associations = association_names
6
+
7
+ association_names.each do |association_name|
8
+ association = reflect_on_association(association_name)
9
+
10
+ if :belongs_to == association.macro
11
+ polymorphic = association.options[:polymorphic]
12
+ polymorphic ||= false
13
+
14
+ define_method("cached_#{association_name}") do
15
+ Rails.cache.fetch belong_association_cache_key(association_name, polymorphic) do
16
+ send(association_name)
17
+ end
18
+ end
19
+ else
20
+ if through_reflection_name = association.options[:through]
21
+ through_association = self.reflect_on_association(through_reflection_name)
22
+
23
+ # FIXME it should be the only reflection but I'm not 100% positive
24
+ reverse_through_association = through_association.klass.reflect_on_all_associations(:belongs_to).first
25
+
26
+ # In a through association it doesn't have to be a belongs_to
27
+ reverse_association = association.klass.reflect_on_all_associations(:belongs_to).find { |reverse_association|
28
+ reverse_association.options[:polymorphic] ? reverse_association.name == association.source_reflection.options[:as] : reverse_association.klass == self
29
+ }
30
+ if reverse_association
31
+ association.klass.class_eval do
32
+ after_commit "expire_#{association_name}_cache".to_sym
33
+
34
+ define_method("expire_#{association_name}_cache") do
35
+ if respond_to? "expire_#{reverse_association.name}_cache".to_sym
36
+ # cached_viewable.expire_association_cache
37
+ send("cached_#{reverse_association.name}").expire_association_cache(association_name)
38
+ else
39
+ send(reverse_association.name).send(reverse_through_association.name).expire_association_cache(association_name)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ elsif :has_and_belongs_to_many == association.macro
45
+ # No such thing as a polymorphic has_and_belongs_to_many
46
+ reverse_association = association.klass.reflect_on_all_associations(:has_and_belongs_to_many).find { |reverse_association|
47
+ reverse_association.klass == self
48
+ }
49
+
50
+ association.klass.class_eval do
51
+ after_commit "expire_#{association_name}_cache".to_sym
52
+
53
+ define_method "expire_#{association_name}_cache" do
54
+ if respond_to? "cached_#{reverse_association.name}".to_sym
55
+ # cached_viewable.expire_association_cache
56
+ send("cached_#{reverse_association.name}").expire_association_cache(association_name)
57
+ else
58
+ send("#{reverse_association.name}").each do |assoc|
59
+ assoc.expire_association_cache(association_name)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ else
65
+ reverse_association = association.klass.reflect_on_all_associations(:belongs_to).find { |reverse_association|
66
+ reverse_association.options[:polymorphic] ? reverse_association.name == association.options[:as] : reverse_association.klass == self
67
+ }
68
+
69
+ association.klass.class_eval do
70
+ after_commit "expire_#{association_name}_cache".to_sym
71
+
72
+ define_method "expire_#{association_name}_cache" do
73
+ if respond_to? "cached_#{reverse_association.name}".to_sym
74
+ send("cached_#{reverse_association.name}").expire_association_cache(association_name)
75
+ else
76
+ send("#{reverse_association.name}").expire_association_cache(association_name)
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ define_method("cached_#{association_name}") do
83
+ Rails.cache.fetch have_association_cache_key(association_name) do
84
+ send(association_name).respond_to?(:to_a) ? send(association_name).to_a : send(association_name)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,30 @@
1
+ module Cacheable
2
+ module AttributeCache
3
+ def with_attribute(*attributes)
4
+ self.cached_indices = attributes.inject({}) { |indices, attribute| indices[attribute] = {} }
5
+
6
+ class_eval do
7
+ after_commit :expire_attribute_cache, :on => :update
8
+ after_commit :expire_all_attribute_cache, :on => :update
9
+ end
10
+
11
+ attributes.each do |attribute|
12
+ define_singleton_method("find_cached_by_#{attribute}") do |value|
13
+ self.cached_indices["#{attribute}"] ||= []
14
+ self.cached_indices["#{attribute}"] << value
15
+ Rails.cache.fetch attribute_cache_key("#{attribute}", value) do
16
+ self.send("find_by_#{attribute}", value)
17
+ end
18
+ end
19
+
20
+ define_singleton_method("find_cached_all_by_#{attribute}") do |value|
21
+ self.cached_indices["#{attribute}"] ||= []
22
+ self.cached_indices["#{attribute}"] << value
23
+ Rails.cache.fetch all_attribute_cache_key("#{attribute}", value) do
24
+ self.send("find_all_by_#{attribute}", value)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ module Cacheable
2
+ module ClassMethodCache
3
+ # Cached class method
4
+ # Should expire on any instance save
5
+ def with_class_method(*methods)
6
+ self.cached_class_methods = methods.inject({}) { |indices, meth| indices[meth] = {} }
7
+
8
+ class_eval do
9
+ after_commit :expire_class_method_cache, on: :update
10
+ end
11
+
12
+ methods.each do |meth|
13
+ define_singleton_method("cached_#{meth}") do |*args|
14
+ self.cached_class_methods["#{meth}"] ||= []
15
+ self.cached_class_methods["#{meth}"] << args
16
+ Rails.cache.fetch class_method_cache_key(meth, args) do
17
+ self.method(meth).arity == 0 ? send(meth) : send(meth, *args)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ module Cacheable
2
+ module KeyCache
3
+ def with_key
4
+ self.cached_key = true
5
+
6
+ class_eval do
7
+ after_commit :expire_key_cache, on: :update
8
+ end
9
+
10
+ define_singleton_method("find_cached") do |id|
11
+ Rails.cache.fetch "#{name.tableize}/" + id.to_i.to_s do
12
+ self.find(id)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module Cacheable
2
+ module MethodCache
3
+ def with_method(*methods)
4
+ self.cached_methods = methods
5
+
6
+ class_eval do
7
+ after_commit :expire_method_cache, :on => :update
8
+ end
9
+
10
+ methods.each do |meth|
11
+ define_method("cached_#{meth}") do
12
+ Rails.cache.fetch method_cache_key(meth) do
13
+ send(meth)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Cacheable
2
- VERSION = "1.3.2"
2
+ VERSION = "1.3.3"
3
3
  end