cache-object 0.1.0 → 0.2.0
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/.gitignore +1 -0
- data/.travis.yml +10 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +0 -1
- data/README.md +2 -0
- data/cache-object.gemspec +16 -16
- data/gemfiles/Gemfile.Rails32 +7 -0
- data/gemfiles/Gemfile.Rails41 +7 -0
- data/gemfiles/Gemfile.Rails42 +7 -0
- data/lib/cache/object/active_record.rb +23 -6
- data/lib/cache/object/adapter.rb +1 -1
- data/lib/cache/object/version.rb +1 -1
- data/spec/cache/object/active_record_spec.rb +27 -27
- data/spec/cache/object/adapter_spec.rb +51 -51
- data/spec/cache/object/config_spec.rb +9 -9
- data/spec/cache/object/dtrace_provider_spec.rb +10 -10
- data/spec/cache/object/multi_get_spec.rb +17 -17
- data/spec/features/cache_object_spec.rb +29 -29
- data/spec/support/models.rb +4 -1
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8649b2dd01b782f1cf6825b5a30476b3a32472e0
|
4
|
+
data.tar.gz: 0c6f690cc791dbee837a559766d9e1c1db9b3fcd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d5b878fdc5924fded27f804d5739137c45f627465754a6355c9c9b8788587cb12e0a804be7e478a807294a793a4a835b4d007d642b67ea8d0fd6cdc7a3494fe
|
7
|
+
data.tar.gz: c266d30a7504657689049980a9155cf4290c2d44abb9d0af64fe9f151226a9f575002b86ff2db8d61ae532e7cb61ff09235122297ce7be1da8710a05d18268b5
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
data/cache-object.gemspec
CHANGED
@@ -4,32 +4,32 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'cache/object/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'cache-object'
|
8
8
|
spec.version = Cache::Object::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Matt Camuto']
|
10
|
+
spec.email = ['dev@wanelo.com']
|
11
11
|
spec.summary = %q{Object R/W Caching}
|
12
12
|
spec.description = %q{Object R/W Caching on top of ActiveRecord}
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
# spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency
|
22
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency 'activerecord', ['>= 3.0', '< 4.3']
|
22
|
+
spec.add_dependency 'ruby-usdt'
|
23
23
|
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
26
|
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
27
|
+
spec.add_development_dependency 'rspec', '>= 3.0'
|
28
|
+
spec.add_development_dependency 'rspec-collection_matchers', '>= 1.0'
|
29
|
+
spec.add_development_dependency 'rspec-its', '>= 1.0'
|
30
30
|
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
33
|
-
spec.add_development_dependency
|
31
|
+
spec.add_development_dependency 'guard'
|
32
|
+
spec.add_development_dependency 'guard-rspec'
|
33
|
+
spec.add_development_dependency 'sqlite3'
|
34
34
|
|
35
35
|
end
|
@@ -35,14 +35,10 @@ module Cache
|
|
35
35
|
send("#{key}=", attributes.delete(key.to_s))
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
_assign_attributes_from_cache(attributes)
|
39
39
|
@relation = nil
|
40
40
|
|
41
|
-
|
42
|
-
@association_cache = {}
|
43
|
-
@aggregation_cache = {}
|
44
|
-
@_start_transaction_state = {}
|
45
|
-
@readonly = @destroyed = @marked_for_destruction = false
|
41
|
+
_initialize_from_cache
|
46
42
|
@new_record = false
|
47
43
|
@column_types = self.class.column_types if self.class.respond_to?(:column_types)
|
48
44
|
@changed_attributes = {}
|
@@ -63,6 +59,27 @@ module Cache
|
|
63
59
|
Cache::Object::InstanceDecorator.new(self, self.class._object_cache_attr_mappings)
|
64
60
|
end
|
65
61
|
|
62
|
+
private
|
63
|
+
|
64
|
+
def _initialize_from_cache
|
65
|
+
@attributes_cache, @previously_changed, @changed_attributes = {}, {}, {}
|
66
|
+
@association_cache = {}
|
67
|
+
@aggregation_cache = {}
|
68
|
+
@_start_transaction_state = {}
|
69
|
+
@readonly = @destroyed = @marked_for_destruction = false
|
70
|
+
|
71
|
+
init_internals if respond_to?(:init_internals)
|
72
|
+
end
|
73
|
+
|
74
|
+
def _assign_attributes_from_cache(attributes)
|
75
|
+
if self.class.respond_to?(:initialize_attributes)
|
76
|
+
@attributes = self.class.initialize_attributes(attributes)
|
77
|
+
else
|
78
|
+
@attributes = self.class._default_attributes.dup
|
79
|
+
init_attributes(attributes, {})
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
66
83
|
module ClassMethods
|
67
84
|
def _load(args)
|
68
85
|
attributes = Marshal.load(args)
|
data/lib/cache/object/adapter.rb
CHANGED
data/lib/cache/object/version.rb
CHANGED
@@ -57,8 +57,8 @@ RSpec.describe Cache::Object::ActiveRecord do
|
|
57
57
|
allow(Cache::Object).to receive(:adapter).and_return(adapter_instance)
|
58
58
|
end
|
59
59
|
|
60
|
-
describe
|
61
|
-
it
|
60
|
+
describe '.included' do
|
61
|
+
it 'receives correct callbacks' do
|
62
62
|
expect(clazz).to receive(:after_save).with(:write_cache!).once
|
63
63
|
expect(clazz).to receive(:after_rollback).with(:expire_cache!).once
|
64
64
|
expect(clazz).to receive(:after_destroy).with(:expire_cache!).once
|
@@ -66,17 +66,17 @@ RSpec.describe Cache::Object::ActiveRecord do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
describe
|
70
|
-
describe
|
71
|
-
it
|
69
|
+
describe 'caching methods' do
|
70
|
+
describe '#write_cache' do
|
71
|
+
it 'calls write cache' do
|
72
72
|
expect(adapter_instance).to receive(:write).with(an_instance_of(Cache::Object::InstanceDecorator))
|
73
73
|
object = clazz.new
|
74
74
|
object.write_cache!
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
describe
|
79
|
-
it
|
78
|
+
describe '#expire_cache' do
|
79
|
+
it 'calls write cache' do
|
80
80
|
expect(adapter_instance).to receive(:delete).with(an_instance_of(Cache::Object::InstanceDecorator))
|
81
81
|
object = clazz.new
|
82
82
|
object.expire_cache!
|
@@ -84,19 +84,19 @@ RSpec.describe Cache::Object::ActiveRecord do
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
-
describe
|
88
|
-
describe
|
89
|
-
it
|
87
|
+
describe 'Finder class methods' do
|
88
|
+
describe '#respond_to?' do
|
89
|
+
it 'find' do
|
90
90
|
expect(clazz).to respond_to(:find)
|
91
91
|
end
|
92
|
-
it
|
92
|
+
it 'find_by_id' do
|
93
93
|
expect(clazz).to respond_to(:find_by_id)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
describe
|
98
|
-
describe
|
99
|
-
it
|
97
|
+
describe '.find' do
|
98
|
+
describe 'caching interactions' do
|
99
|
+
it 'yields to super with cache' do
|
100
100
|
allow(Cache::Object).to receive(:adapter).and_return(adapter.new)
|
101
101
|
expect(super_clazz).to receive(:find).with(12).once
|
102
102
|
clazz.find(12)
|
@@ -104,17 +104,17 @@ RSpec.describe Cache::Object::ActiveRecord do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
describe
|
108
|
-
describe
|
109
|
-
it
|
107
|
+
describe '.find_by_id' do
|
108
|
+
describe 'caching interactions' do
|
109
|
+
it 'yields to super with cache' do
|
110
110
|
expect(super_clazz).to receive(:where).with(:id => 12).once { double(first: true) }
|
111
111
|
clazz.find_by_id(12)
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
describe
|
117
|
-
it
|
116
|
+
describe '.fetch_all' do
|
117
|
+
it 'should call through to multi_get' do
|
118
118
|
multi_getter = double(fetch_all: true)
|
119
119
|
expect(Cache::Object::MultiGet).to receive(:new).with(clazz) { multi_getter }
|
120
120
|
expect(multi_getter).to receive(:fetch_all).with([1,2,4])
|
@@ -122,20 +122,20 @@ RSpec.describe Cache::Object::ActiveRecord do
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
describe
|
125
|
+
describe 'object_cache_on' do
|
126
126
|
|
127
|
-
it
|
127
|
+
it 'creates_finder_methods' do
|
128
128
|
expect(clazz).to respond_to(:find_by_name_and_age)
|
129
129
|
end
|
130
130
|
|
131
|
-
it
|
132
|
-
expect(adapter_instance).to receive(:fetch_mapping).with(clazz, name:
|
133
|
-
clazz.find_by_name_and_age(
|
131
|
+
it 'calls fetch_mapping on the adapter' do
|
132
|
+
expect(adapter_instance).to receive(:fetch_mapping).with(clazz, name: 'bob', age: 13).once
|
133
|
+
clazz.find_by_name_and_age('bob', 13)
|
134
134
|
end
|
135
135
|
|
136
|
-
it
|
137
|
-
expect(super_clazz).to receive(:find_by_name_and_age).with(
|
138
|
-
clazz.find_by_name_and_age(
|
136
|
+
it 'calls super' do
|
137
|
+
expect(super_clazz).to receive(:find_by_name_and_age).with('bob', 13)
|
138
|
+
clazz.find_by_name_and_age('bob', 13)
|
139
139
|
end
|
140
140
|
end
|
141
141
|
end
|
@@ -6,113 +6,113 @@ RSpec.describe Cache::Object::Adapter do
|
|
6
6
|
allow(Cache::Object.configuration).to receive(:ttl).and_return(118)
|
7
7
|
end
|
8
8
|
|
9
|
-
let(:cache_store) { double(
|
9
|
+
let(:cache_store) { double('CacheStore', write: true) }
|
10
10
|
let(:adapter) { Cache::Object::Adapter.new(cache_store) }
|
11
11
|
let(:instance) { double(class: double(name: "User"), id: "1") }
|
12
12
|
|
13
|
-
describe
|
14
|
-
it
|
15
|
-
expect(cache_store).to receive(:delete).with(
|
16
|
-
expect(cache_store).to receive(:delete).with(
|
13
|
+
describe '#delete' do
|
14
|
+
it 'dispatches to delete' do
|
15
|
+
expect(cache_store).to receive(:delete).with('User-1')
|
16
|
+
expect(cache_store).to receive(:delete).with('User-1-blah')
|
17
17
|
|
18
|
-
adapter.delete(double(instance: instance, keys:
|
18
|
+
adapter.delete(double(instance: instance, keys: %w(User-1 User-1-blah)))
|
19
19
|
end
|
20
20
|
|
21
|
-
describe
|
21
|
+
describe 'probes' do
|
22
22
|
before do
|
23
23
|
allow(cache_store).to receive(:delete)
|
24
24
|
end
|
25
25
|
|
26
|
-
it
|
27
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:delete,
|
28
|
-
adapter.delete(double(instance: instance, keys:
|
26
|
+
it 'fires the write probe' do
|
27
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:delete, 'User', '1')
|
28
|
+
adapter.delete(double(instance: instance, keys: %w(User-1 User-1-blah)))
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
describe
|
34
|
-
it
|
35
|
-
expect(cache_store).to receive(:write).with(
|
36
|
-
expect(cache_store).to receive(:write).with(
|
33
|
+
describe '#write' do
|
34
|
+
it 'dispatches to write' do
|
35
|
+
expect(cache_store).to receive(:write).with('User-1', instance, expires_in: 118)
|
36
|
+
expect(cache_store).to receive(:write).with('User-1-blah', instance, expires_in: 118)
|
37
37
|
|
38
|
-
adapter.write(double(instance: instance, keys:
|
38
|
+
adapter.write(double(instance: instance, keys: %w(User-1 User-1-blah)))
|
39
39
|
end
|
40
40
|
|
41
|
-
describe
|
41
|
+
describe 'probes' do
|
42
42
|
before do
|
43
43
|
allow(cache_store).to receive(:write)
|
44
44
|
end
|
45
45
|
|
46
|
-
it
|
47
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:write,
|
48
|
-
adapter.write(double(instance: instance, keys:
|
46
|
+
it 'fires the write probe' do
|
47
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:write, 'User', '1', '118')
|
48
|
+
adapter.write(double(instance: instance, keys: %w(User-1 User-1-blah)))
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
describe
|
54
|
-
it
|
55
|
-
expect(cache_store).to receive(:fetch).with(
|
53
|
+
describe '#fetch' do
|
54
|
+
it 'fetches the object from the cache_store' do
|
55
|
+
expect(cache_store).to receive(:fetch).with('User-1', expires_in: 118).and_yield
|
56
56
|
expect { |b|
|
57
57
|
adapter.fetch(instance.class, 1, &b)
|
58
58
|
}.to yield_control
|
59
59
|
end
|
60
60
|
|
61
|
-
describe
|
62
|
-
it
|
61
|
+
describe 'probes' do
|
62
|
+
it 'fires the fetch probe' do
|
63
63
|
allow(cache_store).to receive(:fetch)
|
64
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch,
|
64
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch, 'User', '1', '118')
|
65
65
|
adapter.fetch(instance.class, 1) {}
|
66
66
|
end
|
67
67
|
|
68
|
-
describe
|
69
|
-
it
|
68
|
+
describe 'when fetch is a miss' do
|
69
|
+
it 'fires the fetch and fetch_miss probes' do
|
70
70
|
allow(cache_store).to receive(:fetch).and_yield
|
71
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch,
|
72
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_miss,
|
71
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch, 'User', '1', '118')
|
72
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_miss, 'User', '1', '118')
|
73
73
|
adapter.fetch(instance.class, 1) {}
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
describe
|
80
|
-
it
|
81
|
-
expect(cache_store).to receive(:fetch).with(
|
79
|
+
describe '#fetch_mapping' do
|
80
|
+
it 'fetches the object from the cache store based on the attributes' do
|
81
|
+
expect(cache_store).to receive(:fetch).with('User-user_id-1-name-bob', expires_in: 118).and_yield
|
82
82
|
expect { |b|
|
83
|
-
adapter.fetch_mapping(instance.class, { user_id: 1, name:
|
83
|
+
adapter.fetch_mapping(instance.class, { user_id: 1, name: 'bob' }, &b)
|
84
84
|
}.to yield_control
|
85
85
|
end
|
86
86
|
|
87
|
-
describe
|
88
|
-
it
|
87
|
+
describe 'probes' do
|
88
|
+
it 'fires the fetch probe' do
|
89
89
|
allow(cache_store).to receive(:fetch)
|
90
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_mapping,
|
91
|
-
adapter.fetch_mapping(instance.class, { user_id: 1, name:
|
90
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_mapping, 'User', { user_id: 1, name: 'bob' }.inspect, '118')
|
91
|
+
adapter.fetch_mapping(instance.class, { user_id: 1, name: 'bob' }) {}
|
92
92
|
end
|
93
93
|
|
94
|
-
describe
|
95
|
-
it
|
94
|
+
describe 'when fetch is a miss' do
|
95
|
+
it 'fires the fetch and fetch_miss probes' do
|
96
96
|
allow(cache_store).to receive(:fetch).and_yield
|
97
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_mapping,
|
98
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_mapping_miss,
|
99
|
-
adapter.fetch_mapping(instance.class, { user_id: 1, name:
|
97
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_mapping, 'User', { user_id: 1, name: 'bob' }.inspect, '118')
|
98
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:fetch_mapping_miss, 'User', { user_id: 1, name: 'bob' }.inspect, '118')
|
99
|
+
adapter.fetch_mapping(instance.class, { user_id: 1, name: 'bob' }) {}
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
-
describe
|
106
|
-
it
|
107
|
-
expect(cache_store).to receive(:read_multi).with(
|
108
|
-
adapter.read_multi([
|
105
|
+
describe '#read_multi' do
|
106
|
+
it 'calls read_multi on the cache_store' do
|
107
|
+
expect(cache_store).to receive(:read_multi).with('blah').and_return({})
|
108
|
+
adapter.read_multi(['blah'])
|
109
109
|
end
|
110
110
|
|
111
|
-
describe
|
112
|
-
it
|
113
|
-
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:read_multi,
|
114
|
-
allow(cache_store).to receive(:read_multi).and_return({
|
115
|
-
adapter.read_multi(
|
111
|
+
describe 'probes' do
|
112
|
+
it 'fires the read_multi probe' do
|
113
|
+
expect(Cache::Object::DTraceProvider).to receive(:fire!).with(:read_multi, %w(blah blah2).inspect, 1, 1)
|
114
|
+
allow(cache_store).to receive(:read_multi).and_return({'blah2' => 1})
|
115
|
+
adapter.read_multi(%w(blah blah2))
|
116
116
|
end
|
117
117
|
end
|
118
118
|
end
|
@@ -3,34 +3,34 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
RSpec.describe Cache::Object do
|
5
5
|
|
6
|
-
describe
|
6
|
+
describe '.configure' do
|
7
7
|
let(:clazz) { Class.new }
|
8
8
|
|
9
|
-
describe
|
10
|
-
it
|
9
|
+
describe '#cache' do
|
10
|
+
it 'sets cache' do
|
11
11
|
Cache::Object.configure { |c| c.cache = clazz }
|
12
12
|
expect(Cache::Object.configuration.cache).to eq(clazz)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
describe
|
17
|
-
it
|
16
|
+
describe '#enabled' do
|
17
|
+
it 'is enabled by default' do
|
18
18
|
expect(Cache::Object.configuration.enabled).to eq(true)
|
19
19
|
end
|
20
20
|
|
21
21
|
|
22
|
-
it
|
22
|
+
it 'is disabled if set false' do
|
23
23
|
Cache::Object.configure { |c| c.enabled = false }
|
24
24
|
expect(Cache::Object.configuration.enabled).to eq(false)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
describe
|
29
|
-
it
|
28
|
+
describe '#ttl' do
|
29
|
+
it 'sets to time' do
|
30
30
|
Cache::Object.configure { |c| c.ttl = 1234 }
|
31
31
|
expect(Cache::Object.configuration.ttl).to eq(1234)
|
32
32
|
end
|
33
|
-
it
|
33
|
+
it 'is one day by default' do
|
34
34
|
expect(Cache::Object.configuration.ttl).to eq(86400)
|
35
35
|
end
|
36
36
|
end
|
@@ -63,28 +63,28 @@ RSpec.describe Cache::Object::DTraceProvider do
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
describe
|
67
|
-
it
|
68
|
-
expect { Cache::Object::DTraceProvider.fire!(:fake) }.to raise_error
|
66
|
+
describe '.fire!' do
|
67
|
+
it 'raises if no provider' do
|
68
|
+
expect { Cache::Object::DTraceProvider.fire!(:fake) }.to raise_error(StandardError)
|
69
69
|
end
|
70
70
|
|
71
|
-
describe
|
72
|
-
it
|
71
|
+
describe 'when probe is enabled' do
|
72
|
+
it 'receives event' do
|
73
73
|
probe = double(enabled?: true)
|
74
74
|
provider = double(probes: { boom: probe})
|
75
75
|
allow(Cache::Object::DTraceProvider).to receive(:provider).and_return(provider)
|
76
|
-
expect(probe).to receive(:fire).with(
|
77
|
-
Cache::Object::DTraceProvider.fire!(:boom,
|
76
|
+
expect(probe).to receive(:fire).with('hai')
|
77
|
+
Cache::Object::DTraceProvider.fire!(:boom, 'hai')
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
describe
|
82
|
-
it
|
81
|
+
describe 'when probe is disabled' do
|
82
|
+
it 'does not receives event' do
|
83
83
|
probe = double(enabled?: false)
|
84
84
|
provider = double(probes: { boom: probe})
|
85
85
|
allow(Cache::Object::DTraceProvider).to receive(:provider).and_return(provider)
|
86
86
|
expect(probe).to receive(:fire).never
|
87
|
-
Cache::Object::DTraceProvider.fire!(:boom,
|
87
|
+
Cache::Object::DTraceProvider.fire!(:boom, 'hai')
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -2,51 +2,51 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Cache::Object::MultiGet do
|
4
4
|
|
5
|
-
let(:fake_clazz) { double(name:
|
5
|
+
let(:fake_clazz) { double(name: 'MyObj', primary_key: :foo) }
|
6
6
|
let(:obj_arr) { 1.upto(3).map { |i| double(class: fake_clazz, id: i) } }
|
7
7
|
let(:multi_get) { Cache::Object::MultiGet.new(fake_clazz) }
|
8
|
-
let(:cache_store) { double(
|
8
|
+
let(:cache_store) { double('CacheStore', write: true) }
|
9
9
|
let(:adapter) { Cache::Object::Adapter.new(cache_store) }
|
10
10
|
|
11
|
-
describe
|
12
|
-
it
|
13
|
-
expect(multi_get.object_keys(1..3)).to eq(
|
11
|
+
describe '#object_keys' do
|
12
|
+
it 'maps keys correctly' do
|
13
|
+
expect(multi_get.object_keys(1..3)).to eq(%w(MyObj-1 MyObj-2 MyObj-3))
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
describe
|
18
|
-
it
|
17
|
+
describe '#cached_objects' do
|
18
|
+
it 'fetches all the mapped keys' do
|
19
19
|
expect(Cache::Object).to receive(:adapter) { adapter }
|
20
|
-
expect(adapter).to receive(:read_multi).with(
|
20
|
+
expect(adapter).to receive(:read_multi).with(%w(MyObj-1 MyObj-2 MyObj-3)) { double(values: true) }
|
21
21
|
multi_get.cached_objects(1..3)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
describe
|
25
|
+
describe '#missed_ids' do
|
26
26
|
let(:initial_ids) { [1, 2, 3, 4, 5, 6] }
|
27
|
-
it
|
27
|
+
it 'computes missed ids' do
|
28
28
|
expect(multi_get.missed_ids(initial_ids, obj_arr)).to eq([4, 5, 6])
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
describe
|
33
|
-
it
|
32
|
+
describe '#load_remaining' do
|
33
|
+
it 'performs missed queries' do
|
34
34
|
expect(fake_clazz).to receive(:where).with(:foo => [1, 2, 3]).once { [double(write_cache!: true)] }
|
35
35
|
multi_get.load_from_db([1, 2, 3])
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
describe
|
40
|
-
describe
|
41
|
-
it
|
39
|
+
describe '#fetch_all' do
|
40
|
+
describe 'with all expected ids' do
|
41
|
+
it 'never calls through to db' do
|
42
42
|
expect(multi_get).to receive(:cached_objects).with([1, 2, 3]) { obj_arr }
|
43
43
|
expect(multi_get).to receive(:load_from_db).never
|
44
44
|
multi_get.fetch_all([1, 2, 3])
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
describe
|
49
|
-
it
|
48
|
+
describe 'with a cache miss' do
|
49
|
+
it 'calls through to db' do
|
50
50
|
expect(multi_get).to receive(:cached_objects).with([1, 2, 3]) { [ obj_arr[0] ]}
|
51
51
|
expect(multi_get).to receive(:load_from_db).with([2, 3]) { [obj_arr[1], obj_arr[2]] }
|
52
52
|
expect(multi_get.fetch_all([1, 2, 3])).to have(3).items
|
@@ -3,7 +3,7 @@ require 'support/models'
|
|
3
3
|
|
4
4
|
# Only writing the features before all the units to see the semantics of
|
5
5
|
# using with actual AR finder methods
|
6
|
-
RSpec.describe
|
6
|
+
RSpec.describe 'Caching' do
|
7
7
|
|
8
8
|
before do
|
9
9
|
CreateModelsForTest.migrate(:up)
|
@@ -18,52 +18,52 @@ RSpec.describe "Caching" do
|
|
18
18
|
Cache::Object.instance_variable_set(:@configuration, nil)
|
19
19
|
end
|
20
20
|
|
21
|
-
let!(:user) { User.create(age: 13, name:
|
21
|
+
let!(:user) { User.create(age: 13, name: 'Bob') }
|
22
22
|
|
23
|
-
describe
|
24
|
-
it
|
23
|
+
describe '#find' do
|
24
|
+
it 'finds the object from the cache' do
|
25
25
|
expect {
|
26
26
|
expect(User.find(user.id)).to eq(user)
|
27
27
|
}.to change { ActiveRecord::QueryCounter.query_count }.by(0)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe
|
32
|
-
it
|
31
|
+
describe '#find_by_id' do
|
32
|
+
it 'finds the object from the cache' do
|
33
33
|
expect {
|
34
34
|
expect(User.find_by_id(user.id)).to eq(user)
|
35
35
|
}.to change { ActiveRecord::QueryCounter.query_count }.by(0)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
describe
|
40
|
-
it
|
39
|
+
describe '#find_by_name_and_age' do
|
40
|
+
it 'finds the object from the cache' do
|
41
41
|
expect {
|
42
|
-
expect(User.find_by_name_and_age(
|
42
|
+
expect(User.find_by_name_and_age('Bob', 13)).to eq(user)
|
43
43
|
}.to change { ActiveRecord::QueryCounter.query_count }.by(0)
|
44
44
|
end
|
45
45
|
|
46
|
-
describe
|
47
|
-
it
|
48
|
-
user.update_attributes(name:
|
46
|
+
describe 'when the name is changed' do
|
47
|
+
it 'writes the updated data into the cache' do
|
48
|
+
user.update_attributes(name: 'Sally')
|
49
49
|
expect {
|
50
|
-
fetched_user = User.find_by_name_and_age(
|
51
|
-
expect(fetched_user.name).to eq(
|
50
|
+
fetched_user = User.find_by_name_and_age('Sally', 13)
|
51
|
+
expect(fetched_user.name).to eq('Sally')
|
52
52
|
}.to change { ActiveRecord::QueryCounter.query_count }.by(0)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
describe
|
57
|
+
describe '#fetch_all' do
|
58
58
|
let!(:u1) { 1.upto(3).map { |i| User.create(age: 13, name: "name#{i}") } }
|
59
|
-
it
|
59
|
+
it 'Should call db once for all in one read' do
|
60
60
|
|
61
61
|
expect {
|
62
62
|
User.fetch_all(u1.map(&:id))
|
63
63
|
}.to change { ActiveRecord::QueryCounter.query_count }.by(0)
|
64
64
|
end
|
65
65
|
|
66
|
-
it
|
66
|
+
it 'Should call the db again after cache flush' do
|
67
67
|
Cache::Object.configuration.cache.clear
|
68
68
|
|
69
69
|
expect {
|
@@ -78,22 +78,22 @@ RSpec.describe "Caching" do
|
|
78
78
|
end
|
79
79
|
|
80
80
|
|
81
|
-
describe
|
82
|
-
it
|
81
|
+
describe 'when user id destroyed' do
|
82
|
+
it 'tries to run a query' do
|
83
83
|
user.destroy
|
84
84
|
expect {
|
85
85
|
expect {
|
86
86
|
User.find(user.id)
|
87
|
-
}.to raise_error
|
87
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
88
88
|
}.to change { ActiveRecord::QueryCounter.query_count }.by(1)
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
-
describe
|
93
|
-
it
|
92
|
+
describe 'rolling back a transaction' do
|
93
|
+
it 'expires the cache' do
|
94
94
|
expect {
|
95
|
-
user.update_attributes(name:
|
96
|
-
}.to raise_error
|
95
|
+
user.update_attributes(name: 'asplode')
|
96
|
+
}.to raise_error(User::SillyTestError)
|
97
97
|
|
98
98
|
expect {
|
99
99
|
User.find(user.id)
|
@@ -101,15 +101,15 @@ RSpec.describe "Caching" do
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
describe
|
105
|
-
it
|
104
|
+
describe 'when object is not persisted' do
|
105
|
+
it 'does not call the adapter' do
|
106
106
|
expect(Cache::Object.adapter).to receive(:write).never
|
107
|
-
User.new(name:
|
107
|
+
User.new(name: 'blah').write_cache!
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
|
-
describe
|
112
|
-
it
|
111
|
+
describe 'object_cache_include' do
|
112
|
+
it 'has expected additional attribute' do
|
113
113
|
user.shoe_size = '14'
|
114
114
|
user.write_cache!
|
115
115
|
|
data/spec/support/models.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_record'
|
2
|
+
require 'logger'
|
2
3
|
|
3
4
|
ActiveRecord::Migration.verbose = false
|
4
5
|
ActiveRecord::Base.logger = Logger.new($STDOUT)
|
@@ -38,6 +39,8 @@ class CreateModelsForTest < ActiveRecord::Migration
|
|
38
39
|
end
|
39
40
|
|
40
41
|
class User < ActiveRecord::Base
|
42
|
+
class SillyTestError < StandardError; end
|
43
|
+
|
41
44
|
include Cache::Object::ActiveRecord
|
42
45
|
|
43
46
|
object_cache_include :shoe_size
|
@@ -48,6 +51,6 @@ class User < ActiveRecord::Base
|
|
48
51
|
after_save :asplode_if_name_is_asplode
|
49
52
|
|
50
53
|
def asplode_if_name_is_asplode
|
51
|
-
raise
|
54
|
+
raise SillyTestError.new('WOAH') if name == 'asplode'
|
52
55
|
end
|
53
56
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache-object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Camuto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '3.0'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '4.
|
22
|
+
version: '4.3'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '3.0'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '4.
|
32
|
+
version: '4.3'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: ruby-usdt
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,14 +50,14 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '1.
|
53
|
+
version: '1.10'
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '1.
|
60
|
+
version: '1.10'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: rake
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,6 +165,8 @@ extra_rdoc_files: []
|
|
165
165
|
files:
|
166
166
|
- ".gitignore"
|
167
167
|
- ".rspec"
|
168
|
+
- ".travis.yml"
|
169
|
+
- CHANGELOG.md
|
168
170
|
- Gemfile
|
169
171
|
- Guardfile
|
170
172
|
- LICENSE.txt
|
@@ -181,6 +183,9 @@ files:
|
|
181
183
|
- bin/rspec
|
182
184
|
- bin/thor
|
183
185
|
- cache-object.gemspec
|
186
|
+
- gemfiles/Gemfile.Rails32
|
187
|
+
- gemfiles/Gemfile.Rails41
|
188
|
+
- gemfiles/Gemfile.Rails42
|
184
189
|
- lib/cache/object.rb
|
185
190
|
- lib/cache/object/active_record.rb
|
186
191
|
- lib/cache/object/adapter.rb
|