active_cash 0.1.0 → 0.1.2
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 +4 -4
- data/README.md +25 -2
- data/lib/active_cash.rb +1 -1
- data/lib/active_cash/adapter.rb +18 -2
- data/lib/active_cash/cache.rb +30 -18
- data/lib/active_cash/errors.rb +3 -0
- data/lib/active_cash/utils.rb +70 -16
- data/lib/active_cash/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ce7a48da4376ed48bcaf90d9b56d270cad0d646
|
4
|
+
data.tar.gz: 689beea4558ef5b39f18d3cf0c1d12585085028d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fc6f6e25239b5facaafc71341cda2e89a0a3e94b29adff8b3119b5835d09ea28412e9e00e27e2334570e2d1ec05fc6c7bbfa925af969da53c0722579383d835
|
7
|
+
data.tar.gz: 049e2153e2fbd3ed201924af45d0bf85794abcfd01f0458204ba5c273936e26ad4110a4958a7f7dac604cce306052fa60652522004925bc48537c3cef9937193
|
data/README.md
CHANGED
@@ -30,7 +30,7 @@ class Like < ActiveRecord::Base
|
|
30
30
|
|
31
31
|
# type # matched conditions # cache name (default is strategy name)
|
32
32
|
caches :existence, find_by: [:user_id, :video_id]
|
33
|
-
caches :existence, find_by: [:user_id, :video_id, :hidden], name: :hidden
|
33
|
+
caches :existence, find_by: [:user_id, :video_id, :hidden], as: :hidden #also name: :hidden is supported
|
34
34
|
end
|
35
35
|
|
36
36
|
# Check if Like exists for specific :user_id, :video_id.
|
@@ -45,7 +45,11 @@ end
|
|
45
45
|
I am open for better naming conventions :)
|
46
46
|
|
47
47
|
Cache will be created and updated on every object creation, update and deletion
|
48
|
-
using an `after_commit` callback.
|
48
|
+
using an `after_commit` callback. Only a string value is saved (true or false)
|
49
|
+
in Redis (using [redis-objects](https://github.com/nateware/redis-objects) underneath)
|
50
|
+
making it extremely efficient.
|
51
|
+
|
52
|
+
If you want to have a read-driven cache (which could
|
49
53
|
enhance your hit ratio depending on your read/writes ratio) you can provide an
|
50
54
|
empty `update_on` array (by default it includes `[:create, :update, :destroy]`):
|
51
55
|
|
@@ -68,13 +72,32 @@ end
|
|
68
72
|
|
69
73
|
Now cache will be created and updated ONLY IF there is a reference to Redis.
|
70
74
|
|
75
|
+
You can also specify the return value (the symbol must be a method defined in the class instance):
|
76
|
+
``` ruby
|
77
|
+
class Like < ActiveRecord::Base
|
78
|
+
include ActiveCash
|
79
|
+
|
80
|
+
caches :existence, find_by: [:user_id, :video_id, :state], as: :state, returns: :state
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check if Like exists for specific :user_id, :video_id.
|
84
|
+
# returns the state
|
85
|
+
# returns false if state.nil?
|
86
|
+
@like = Like.cached_existence_by(user_id: 1, video_id: 2)
|
87
|
+
```
|
88
|
+
|
89
|
+
Not though that cache will return false if state is nil.
|
90
|
+
|
91
|
+
|
71
92
|
## Todo
|
72
93
|
Only existence strategy is supported at the moment but the code is designed to
|
73
94
|
support other kind of caching strategies as well, like caching the whole object
|
74
95
|
or some parts of it. Also:
|
75
96
|
|
97
|
+
* Refactor a bit :(
|
76
98
|
* We should provide named callbacks
|
77
99
|
* It's super easy to extend for Mongoid
|
100
|
+
* Add memcached adapter
|
78
101
|
|
79
102
|
## Relevant projects
|
80
103
|
There is [identity_cache](https://github.com/Shopify/identity_cache) built by Shopify.
|
data/lib/active_cash.rb
CHANGED
@@ -13,7 +13,7 @@ module ActiveCash
|
|
13
13
|
end
|
14
14
|
module ClassMethods
|
15
15
|
def caches(type, opts = {})
|
16
|
-
name = opts[:name] || type.to_sym
|
16
|
+
name = opts[:name] || opts[:as] || type.to_sym
|
17
17
|
@cache_opts = Utils.build_cache_opts(type, opts, @cache_opts, self.to_s)
|
18
18
|
Utils.set_callbacks(self, @cache_opts[name])
|
19
19
|
Utils.create_methods(self, @cache_opts[name])
|
data/lib/active_cash/adapter.rb
CHANGED
@@ -2,22 +2,38 @@ module ActiveCash::Adapter #fix boolean and make it generic
|
|
2
2
|
extend self
|
3
3
|
|
4
4
|
def get_value(key_name)
|
5
|
-
|
5
|
+
value = Redis::Value.new(key_name).value
|
6
|
+
is_boolean?(value) ? boolean(value) : value
|
6
7
|
end
|
7
8
|
|
8
9
|
def set_value(key_name, value)
|
9
10
|
Redis::Value.new(key_name).value = value
|
10
11
|
|
11
|
-
boolean(value)
|
12
|
+
is_boolean?(value) ? boolean(value) : value
|
12
13
|
end
|
13
14
|
|
14
15
|
def delete_value(key_name)
|
15
16
|
Redis::Value.new(key_name).delete
|
16
17
|
end
|
17
18
|
|
19
|
+
def set_value_with_return(key_name, exists, returns)
|
20
|
+
if exists
|
21
|
+
returns.nil? ? set_value(key_name, true) : set_value(key_name, returns)
|
22
|
+
else
|
23
|
+
set_value(key_name, false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
18
27
|
def boolean(value)
|
19
28
|
return nil if value.nil?
|
20
29
|
|
21
30
|
[true, 1, '1', 't', 'T', 'true', 'TRUE'].include? value
|
22
31
|
end
|
32
|
+
|
33
|
+
def is_boolean?(value)
|
34
|
+
[
|
35
|
+
true, false, 1, 0, 'true', 'false', '1', '0', 't', 'f', 'TRUE', 'FALSE',
|
36
|
+
'T', 'F'
|
37
|
+
].include? value
|
38
|
+
end
|
23
39
|
end
|
data/lib/active_cash/cache.rb
CHANGED
@@ -1,74 +1,86 @@
|
|
1
1
|
module ActiveCash::Cache
|
2
2
|
extend self
|
3
3
|
|
4
|
-
def exists?(find_by:, method_name:,
|
4
|
+
def exists?(find_by:, method_name:, returns:, klass:)
|
5
5
|
key_name = get_key_name(klass, method_name, find_by)
|
6
6
|
cached_value = adapter.get_value(key_name)
|
7
7
|
return cached_value unless cached_value.nil?
|
8
8
|
|
9
|
-
|
9
|
+
instance = klass.to_s.constantize.find_by(find_by)
|
10
|
+
adapter.set_value_with_return(
|
11
|
+
key_name, !instance.nil?, instance.try(returns)
|
12
|
+
)
|
10
13
|
end
|
11
14
|
|
12
|
-
def instance_exists?(find_by:, method_name:, instance:,
|
15
|
+
def instance_exists?(find_by:, method_name:, instance:, returns:)
|
13
16
|
key_name = get_key_name(instance.class, method_name, find_by)
|
14
17
|
cached_value = adapter.get_value(key_name)
|
15
18
|
return cached_value unless cached_value.nil?
|
16
19
|
|
17
|
-
instance_update(
|
20
|
+
instance_update(
|
21
|
+
find_by: find_by, method_name: method_name, instance: instance,
|
22
|
+
returns: returns
|
23
|
+
)
|
18
24
|
end
|
19
25
|
|
20
|
-
def instance_update(find_by:, method_name:,
|
26
|
+
def instance_update(find_by:, method_name:, returns:, instance:)
|
21
27
|
key_name = get_key_name(instance.class, method_name, find_by)
|
22
28
|
|
23
29
|
find_by.keys.each_with_index do |key, i|
|
24
30
|
if instance.send(key) != find_by.values[i]
|
25
|
-
return adapter.
|
31
|
+
return adapter.set_value_with_return(key_name, false, returns)
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
29
|
-
adapter.
|
35
|
+
adapter.set_value_with_return(key_name, true, returns)#instance.try(returns))
|
30
36
|
end
|
31
37
|
|
32
|
-
def instance_updated?(find_by:, instance:)
|
38
|
+
def instance_updated?(find_by:, instance:, returns:)
|
39
|
+
changes = OpenStruct.new(instance.previous_changes)
|
40
|
+
return true if changes.send(returns) != nil
|
41
|
+
|
33
42
|
find_by.keys.each_with_index do |key, i|
|
34
|
-
if
|
43
|
+
if changes.send(key) != nil
|
35
44
|
return true
|
36
45
|
end
|
37
46
|
end
|
38
47
|
end
|
39
48
|
|
40
|
-
def old_instance_update(find_by:, method_name:,
|
49
|
+
def old_instance_update(find_by:, method_name:, returns:, instance:)
|
41
50
|
#old values
|
42
51
|
instance_update_if_exists(
|
43
52
|
find_by: Hash[find_by.map {|k, v| ["#{k}_was", v] }],
|
44
53
|
method_name: method_name,
|
45
|
-
|
54
|
+
returns: returns,
|
46
55
|
instance: instance
|
47
56
|
)
|
48
57
|
end
|
49
58
|
|
50
|
-
def instance_update_if_exists(find_by:, method_name:,
|
59
|
+
def instance_update_if_exists(find_by:, method_name:, returns:, instance:)
|
51
60
|
key_name = get_key_name(instance.class, method_name, find_by)
|
52
61
|
|
53
62
|
cached_value = adapter.get_value(key_name)
|
54
63
|
return true if cached_value.nil?
|
55
64
|
|
56
|
-
instance_update(
|
65
|
+
instance_update(
|
66
|
+
find_by: find_by, method_name: method_name, instance: instance,
|
67
|
+
returns: returns
|
68
|
+
)
|
57
69
|
end
|
58
70
|
|
59
|
-
def delete(find_by:, method_name:,
|
71
|
+
def delete(find_by:, method_name:, returns:, klass:)
|
60
72
|
key_name = get_key_name(klass, method_name, find_by)
|
61
73
|
adapter.delete_value(key_name)
|
62
74
|
end
|
63
75
|
|
64
|
-
def set_false(find_by:, method_name:,
|
76
|
+
def set_false(find_by:, method_name:, returns:, klass:)
|
65
77
|
key_name = get_key_name(klass, method_name, find_by)
|
66
|
-
adapter.
|
78
|
+
adapter.set_value_with_return(key_name, false, returns)
|
67
79
|
end
|
68
80
|
|
69
|
-
def set_true(find_by:, method_name:,
|
81
|
+
def set_true(find_by:, method_name:, returns:, klass:)
|
70
82
|
key_name = get_key_name(klass, method_name, find_by)
|
71
|
-
adapter.
|
83
|
+
adapter.set_value_with_return(key_name, true, returns)
|
72
84
|
end
|
73
85
|
|
74
86
|
def get_key_name(klass, method_name, hash_params)
|
data/lib/active_cash/errors.rb
CHANGED
data/lib/active_cash/utils.rb
CHANGED
@@ -5,32 +5,52 @@ module ActiveCash::Utils
|
|
5
5
|
if (opts[:update_on] & [:create]).blank?
|
6
6
|
model.send(:after_commit, on: [:create]) do
|
7
7
|
ActiveCash::Cache.instance_update_if_exists(
|
8
|
-
ActiveCash::Utils.extract_instance_args(opts, self)
|
8
|
+
ActiveCash::Utils.extract_instance_args(opts, self).merge(
|
9
|
+
returns: self.try(opts[:returns])
|
10
|
+
)
|
9
11
|
)
|
10
12
|
end
|
11
13
|
else
|
12
14
|
model.send(:after_commit, on: [:create]) do
|
13
15
|
ActiveCash::Cache.instance_update(
|
14
|
-
ActiveCash::Utils.extract_instance_args(opts, self)
|
16
|
+
ActiveCash::Utils.extract_instance_args(opts, self).merge(
|
17
|
+
returns: self.try(opts[:returns])
|
18
|
+
)
|
15
19
|
)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
19
23
|
if (opts[:update_on] & [:update]).blank?
|
20
24
|
model.send(:after_commit, on: [:update]) do
|
21
|
-
if instance_updated?(
|
22
|
-
|
25
|
+
if ActiveCash::Cache.instance_updated?(
|
26
|
+
find_by: opts[:find_by], instance: self, returns: opts[:returns]
|
27
|
+
)
|
28
|
+
ActiveCash::Cache.delete(
|
29
|
+
ActiveCash::Utils.extract_instance_old_args(opts, self).merge(
|
30
|
+
returns: self.try(opts[:returns])
|
31
|
+
)
|
32
|
+
)
|
23
33
|
ActiveCash::Cache.instance_update_if_exists(
|
24
|
-
ActiveCash::Utils.extract_instance_args(opts, self)
|
34
|
+
ActiveCash::Utils.extract_instance_args(opts, self).merge(
|
35
|
+
returns: self.try(opts[:returns])
|
36
|
+
)
|
25
37
|
)
|
26
38
|
end
|
27
39
|
end
|
28
40
|
else
|
29
41
|
model.send(:after_commit, on: [:update]) do
|
30
|
-
if instance_updated?(
|
31
|
-
|
42
|
+
if ActiveCash::Cache.instance_updated?(
|
43
|
+
find_by: opts[:find_by], instance: self, returns: opts[:returns]
|
44
|
+
)
|
45
|
+
ActiveCash::Cache.delete(
|
46
|
+
ActiveCash::Utils.extract_instance_old_args(opts, self).merge(
|
47
|
+
returns: self.try(opts[:returns])
|
48
|
+
)
|
49
|
+
)
|
32
50
|
ActiveCash::Cache.instance_update(
|
33
|
-
ActiveCash::Utils.extract_instance_args(opts, self)
|
51
|
+
ActiveCash::Utils.extract_instance_args(opts, self).merge(
|
52
|
+
returns: self.try(opts[:returns])
|
53
|
+
)
|
34
54
|
)
|
35
55
|
end
|
36
56
|
end
|
@@ -39,13 +59,17 @@ module ActiveCash::Utils
|
|
39
59
|
if (opts[:update_on] & [:destroy]).blank?
|
40
60
|
model.send(:after_commit, on: [:destroy]) do
|
41
61
|
ActiveCash::Cache.delete(
|
42
|
-
ActiveCash::Utils.extract_args(opts, self)
|
62
|
+
ActiveCash::Utils.extract_args(opts, self).merge(
|
63
|
+
returns: self.try(opts[:returns])
|
64
|
+
)
|
43
65
|
)
|
44
66
|
end
|
45
67
|
else
|
46
68
|
model.send(:after_commit, on: [:destroy]) do
|
47
69
|
ActiveCash::Cache.set_false(
|
48
|
-
ActiveCash::Utils.extract_args(opts, self)
|
70
|
+
ActiveCash::Utils.extract_args(opts, self).merge(
|
71
|
+
returns: self.try(opts[:returns])
|
72
|
+
)
|
49
73
|
)
|
50
74
|
end
|
51
75
|
end
|
@@ -53,7 +77,21 @@ module ActiveCash::Utils
|
|
53
77
|
|
54
78
|
def create_methods(model, opts) #raise error when arg not given
|
55
79
|
model.send(:define_singleton_method, "cached_#{opts[:name]}_by") do |args = {}|
|
56
|
-
|
80
|
+
xor_array = ((args.keys | opts[:find_by]) - (args.keys & opts[:find_by]))
|
81
|
+
if xor_array.empty?
|
82
|
+
return ActiveCash::Cache.exists?(
|
83
|
+
find_by: opts[:find_by].inject({}) {|h, arg| h[arg] = args[arg]; h},
|
84
|
+
method_name: opts[:name],
|
85
|
+
klass: opts[:klass],
|
86
|
+
returns: opts[:returns]
|
87
|
+
)
|
88
|
+
else
|
89
|
+
ActiveCash::Utils.raise_find_by_options_mismatch(xor_array, opts[:find_by])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
model.send(:define_singleton_method, "delete_cached_#{opts[:name]}_by") do |args = {}|
|
94
|
+
return ActiveCash::Cache.delete(
|
57
95
|
find_by: opts[:find_by].inject({}) {|h, arg| h[arg] = args[arg]; h},
|
58
96
|
method_name: opts[:name],
|
59
97
|
klass: opts[:klass]
|
@@ -61,6 +99,15 @@ module ActiveCash::Utils
|
|
61
99
|
end
|
62
100
|
end
|
63
101
|
|
102
|
+
def raise_find_by_options_mismatch(invalid, valid)
|
103
|
+
if (invalid & valid).any?
|
104
|
+
raise(FindByOptionsMismatchError, "Missing find_by options: #{invalid}")
|
105
|
+
else
|
106
|
+
raise(FindByOptionsMismatchError, "Not registerd find_by options: #{invalid}")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
|
64
111
|
def raise_unknown_cache_type(type)
|
65
112
|
raise(
|
66
113
|
UnknownCacheTypeError,
|
@@ -98,13 +145,20 @@ module ActiveCash::Utils
|
|
98
145
|
end
|
99
146
|
|
100
147
|
#and this
|
101
|
-
def
|
148
|
+
def extract_instance_old_args(opts, instance)
|
149
|
+
changes = OpenStruct.new(instance.previous_changes)
|
150
|
+
|
102
151
|
{
|
103
152
|
find_by: opts[:find_by].inject({}){|h, arg|
|
104
|
-
|
153
|
+
if changes.arg != nil
|
154
|
+
h[arg] = changes.send(arg).first
|
155
|
+
else
|
156
|
+
h[arg] = instance.send(arg)
|
157
|
+
end
|
158
|
+
h
|
105
159
|
},
|
106
160
|
method_name: opts[:name],
|
107
|
-
|
161
|
+
klass: instance.class
|
108
162
|
}
|
109
163
|
end
|
110
164
|
|
@@ -112,13 +166,13 @@ module ActiveCash::Utils
|
|
112
166
|
#add procs/lambdas for better finds
|
113
167
|
raise_unknown_cache_type(type) unless type.to_sym == :existence
|
114
168
|
cache_opts ||= {}
|
115
|
-
name = opts[:name] || type.to_sym
|
169
|
+
name = opts[:name] || opts[:as] || type.to_sym
|
116
170
|
raise_redefined_cache_error(name) unless cache_opts[name].nil?
|
117
171
|
cache_opts[name] = {}
|
118
172
|
cache_opts[name][:name] = name
|
119
173
|
cache_opts[name][:type] = type.to_sym
|
120
174
|
cache_opts[name][:find_by] = opts[:find_by]
|
121
|
-
cache_opts[name][:
|
175
|
+
cache_opts[name][:returns] = opts[:returns] || :nil
|
122
176
|
cache_opts[name][:update_on] = opts[:update_on] || [:create, :update, :destroy]
|
123
177
|
cache_opts[name][:klass] = klass
|
124
178
|
|
data/lib/active_cash/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_cash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Filippos Vasilakis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-objects
|