looksist 0.2.3 → 0.2.4
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/features/support/env.rb +2 -1
- data/lib/looksist.rb +2 -2
- data/lib/looksist/redis_service.rb +17 -5
- data/lib/looksist/version.rb +1 -1
- data/spec/looksist/hashed_spec.rb +0 -1
- data/spec/looksist/looksist_spec.rb +226 -164
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fb62a2a0b2778134b40201016d38980393ee389
|
4
|
+
data.tar.gz: 6621c86b40473717e6e077c004506d0f79482d88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bca80bd21a7a699b332930bdc5396f52e60a23b8e61acee6df1b0f42e92685a64b0a7c1658710a4f9aa610b83db50ed7ebc9fb8b50fa1d4ace9a2a257d4414f
|
7
|
+
data.tar.gz: 35937a98b7ff7e8e2edf52aa49424b04c8ec95eb0186b7c4e0b0bf3b8b2adce85374f69365ac3b5c261b907964eaa8ca84a24f9d937c728ff438c8fafc2ae080
|
data/features/support/env.rb
CHANGED
data/lib/looksist.rb
CHANGED
@@ -15,13 +15,13 @@ module Looksist
|
|
15
15
|
include Hashed
|
16
16
|
|
17
17
|
class << self
|
18
|
-
attr_accessor :lookup_store, :driver, :cache_buffer_size, :redis_service
|
18
|
+
attr_accessor :lookup_store, :driver, :cache_buffer_size, :redis_service, :l2_cache
|
19
19
|
|
20
20
|
def configure
|
21
21
|
yield self
|
22
22
|
self.redis_service = Looksist::RedisService.instance do |lookup|
|
23
23
|
lookup.client = self.lookup_store
|
24
|
-
lookup.buffer_size = self.cache_buffer_size || 50000
|
24
|
+
lookup.buffer_size = (self.l2_cache == :no_cache) ? 0 : (self.cache_buffer_size || 50000)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -32,14 +32,22 @@ module Looksist
|
|
32
32
|
private
|
33
33
|
|
34
34
|
def find_all(entity, ids)
|
35
|
-
raise 'Buffer overflow! Increase buffer size' if
|
35
|
+
raise 'Buffer overflow! Increase buffer size' if ids.length > @buffer_size && @buffer_size != 0
|
36
36
|
keys = ids.collect { |id| redis_key(entity, id) }
|
37
|
-
missed_keys = (keys - @cache.keys).uniq
|
37
|
+
missed_keys = cache_op(proc_from { keys.uniq }) { (keys - @cache.keys).uniq }
|
38
38
|
unless missed_keys.empty?
|
39
39
|
values = @client.mget *missed_keys
|
40
|
-
@cache.merge!(Hash[*missed_keys.zip(values).flatten])
|
40
|
+
cache_op { @cache.merge!(Hash[*missed_keys.zip(values).flatten]) }
|
41
|
+
end
|
42
|
+
(cache_op(proc_from { values }) { @cache.mslice(keys) })
|
43
|
+
end
|
44
|
+
|
45
|
+
def cache_op(computed = nil)
|
46
|
+
if @buffer_size == 0
|
47
|
+
return computed.call if computed
|
48
|
+
else
|
49
|
+
yield
|
41
50
|
end
|
42
|
-
@cache.mslice(keys)
|
43
51
|
end
|
44
52
|
|
45
53
|
def find(entity, id)
|
@@ -50,11 +58,15 @@ module Looksist
|
|
50
58
|
end
|
51
59
|
|
52
60
|
def fetch(key, &block)
|
53
|
-
@cache[key] ||= block.call
|
61
|
+
(cache_op(proc_from { block.call }) { @cache[key] ||= block.call })
|
54
62
|
end
|
55
63
|
|
56
64
|
def redis_key(entity, id)
|
57
65
|
"#{entity.pluralize}/#{id}"
|
58
66
|
end
|
67
|
+
|
68
|
+
def proc_from
|
69
|
+
Proc.new
|
70
|
+
end
|
59
71
|
end
|
60
72
|
end
|
data/lib/looksist/version.rb
CHANGED
@@ -2,232 +2,294 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
|
4
4
|
describe Looksist do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
context 'no l2 cache' do
|
6
|
+
before(:each) do
|
7
|
+
@mock = {}
|
8
|
+
Looksist.configure do |looksist|
|
9
|
+
looksist.lookup_store = @mock
|
10
|
+
looksist.l2_cache = :no_cache
|
11
|
+
looksist.driver = Looksist::Serializers::Her
|
12
|
+
end
|
10
13
|
end
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
super(opts).merge(another_attr: 'Hello World')
|
14
|
+
context 'Serialization Support' do
|
15
|
+
it 'should decorate for her models' do
|
16
|
+
module Her
|
17
|
+
class NoCacheEmployee
|
18
|
+
include Her::Model
|
19
|
+
use_api TEST_API
|
20
|
+
include Looksist
|
21
|
+
|
22
|
+
lookup :name, using: :employee_id
|
23
|
+
|
24
|
+
def as_json(opts)
|
25
|
+
super(opts).merge(another_attr: 'Hello World')
|
26
|
+
end
|
25
27
|
end
|
26
28
|
end
|
29
|
+
|
30
|
+
expect(@mock).to receive(:get).twice.with('employees/1').and_return('Employee Name')
|
31
|
+
e = Her::NoCacheEmployee.new({employee_id: 1})
|
32
|
+
expect(e.name).to eq('Employee Name')
|
33
|
+
expect(e.to_json).to eq({:employee_id => 1, :name => 'Employee Name', :another_attr => 'Hello World'}.to_json)
|
27
34
|
end
|
28
|
-
expect(@mock).to receive(:get).once.with('employees/1').and_return('Employee Name')
|
29
|
-
e = Her::Employee.new({employee_id: 1})
|
30
|
-
expect(e.name).to eq('Employee Name')
|
31
|
-
expect(e.to_json).to eq({:employee_id => 1, :name => 'Employee Name', :another_attr => 'Hello World'}.to_json)
|
32
35
|
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context 'Store Lookup' do
|
36
|
-
it 'should consider bucket key when provided' do
|
37
|
-
module ExplicitBucket
|
38
|
-
class Employee
|
39
|
-
include Looksist
|
40
|
-
attr_accessor :id
|
41
|
-
lookup :name, using: :id, bucket_name: 'employees'
|
42
36
|
|
43
|
-
|
44
|
-
|
37
|
+
context 'Alias Lookup' do
|
38
|
+
it 'should fetch attributes and use the alias for specific attributes in the api' do
|
39
|
+
module AliasSpecificLookup
|
40
|
+
class NoCacheEmployee
|
41
|
+
include Her::Model
|
42
|
+
use_api TEST_API
|
43
|
+
include Looksist
|
44
|
+
attr_accessor :id
|
45
|
+
lookup [:name, :age], using: :id, as: {name: 'nome'}
|
46
|
+
|
47
|
+
def initialize(id)
|
48
|
+
@id = id
|
49
|
+
end
|
50
|
+
|
51
|
+
def as_json(opts)
|
52
|
+
super(opts).merge(id: @id)
|
53
|
+
end
|
45
54
|
end
|
46
55
|
end
|
56
|
+
expect(@mock).to receive(:get).exactly(4).times.with('ids/1').and_return({name: 'Rajini', age: 16}.to_json)
|
57
|
+
e = AliasSpecificLookup::NoCacheEmployee.new(1)
|
58
|
+
expect(e.nome).to eq('Rajini')
|
59
|
+
expect(e.age).to eq(16)
|
60
|
+
expect(e.to_json).to eq("{\"nome\":\"Rajini\",\"age\":16,\"id\":1}")
|
47
61
|
end
|
48
|
-
expect(@mock).to receive(:get).once.with('employees/1').and_return('Employee Name')
|
49
|
-
e = ExplicitBucket::Employee.new(1)
|
50
|
-
expect(e.name).to eq('Employee Name')
|
51
62
|
end
|
52
63
|
end
|
64
|
+
context 'with l2 cache' do
|
65
|
+
before(:each) do
|
66
|
+
@mock = {}
|
67
|
+
Looksist.configure do |looksist|
|
68
|
+
looksist.lookup_store = @mock
|
69
|
+
looksist.l2_cache = :cached
|
70
|
+
looksist.driver = Looksist::Serializers::Her
|
71
|
+
end
|
72
|
+
end
|
53
73
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
74
|
+
context 'Serialization Support' do
|
75
|
+
it 'should decorate for her models' do
|
76
|
+
module Her
|
77
|
+
class Employee
|
78
|
+
include Her::Model
|
79
|
+
use_api TEST_API
|
80
|
+
include Looksist
|
61
81
|
|
62
|
-
|
82
|
+
lookup :name, using: :employee_id
|
63
83
|
|
64
|
-
|
65
|
-
|
84
|
+
def as_json(opts)
|
85
|
+
super(opts).merge(another_attr: 'Hello World')
|
86
|
+
end
|
66
87
|
end
|
67
88
|
end
|
89
|
+
expect(@mock).to receive(:get).once.with('employees/1').and_return('Employee Name')
|
90
|
+
e = Her::Employee.new({employee_id: 1})
|
91
|
+
expect(e.name).to eq('Employee Name')
|
92
|
+
expect(e.to_json).to eq({:employee_id => 1, :name => 'Employee Name', :another_attr => 'Hello World'}.to_json)
|
68
93
|
end
|
69
|
-
expect(@mock).to receive(:get).never.with('employees_/1')
|
70
|
-
e = TolerantLookUp::Employee.new
|
71
|
-
expect(e.to_json).to eq('{}')
|
72
94
|
end
|
73
|
-
end
|
74
|
-
|
75
|
-
context 'Alias support for lookup' do
|
76
|
-
it 'should fetch attributes and use the alias specified in the api' do
|
77
|
-
module AliasLookup
|
78
|
-
class Employee
|
79
|
-
include Her::Model
|
80
|
-
use_api TEST_API
|
81
|
-
include Looksist
|
82
|
-
attr_accessor :id
|
83
|
-
lookup :name, using: :id, bucket_name: 'employees', as: {name: 'nome'}
|
84
|
-
|
85
|
-
def initialize(id)
|
86
|
-
@id = id
|
87
|
-
end
|
88
95
|
|
89
|
-
|
90
|
-
|
96
|
+
context 'Store Lookup' do
|
97
|
+
it 'should consider bucket key when provided' do
|
98
|
+
module ExplicitBucket
|
99
|
+
class Employee
|
100
|
+
include Looksist
|
101
|
+
attr_accessor :id
|
102
|
+
lookup :name, using: :id, bucket_name: 'employees'
|
103
|
+
|
104
|
+
def initialize(id)
|
105
|
+
@id = id
|
106
|
+
end
|
91
107
|
end
|
92
108
|
end
|
109
|
+
expect(@mock).to receive(:get).once.with('employees/1').and_return('Employee Name')
|
110
|
+
e = ExplicitBucket::Employee.new(1)
|
111
|
+
expect(e.name).to eq('Employee Name')
|
93
112
|
end
|
94
|
-
expect(@mock).to receive(:get).once.with('employees/1').and_return('Rajini')
|
95
|
-
e = AliasLookup::Employee.new(1)
|
96
|
-
expect(e.nome).to eq('Rajini')
|
97
|
-
expect(e.to_json).to eq("{\"nome\":\"Rajini\",\"id\":1}")
|
98
113
|
end
|
99
114
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
lookup [:name, :age], using: :id, as: {name: 'nome'}
|
115
|
+
context 'Tolerant lookup' do
|
116
|
+
it 'should not do a lookup when the key attribute is not defined' do
|
117
|
+
module TolerantLookUp
|
118
|
+
class Employee
|
119
|
+
include Her::Model
|
120
|
+
use_api TEST_API
|
121
|
+
include Looksist
|
108
122
|
|
109
|
-
|
110
|
-
@id = id
|
111
|
-
end
|
123
|
+
lookup :name, using: :employee_id
|
112
124
|
|
113
|
-
|
114
|
-
|
125
|
+
def as_json(opts)
|
126
|
+
super(opts)
|
127
|
+
end
|
115
128
|
end
|
116
129
|
end
|
130
|
+
expect(@mock).to receive(:get).never.with('employees_/1')
|
131
|
+
e = TolerantLookUp::Employee.new
|
132
|
+
expect(e.to_json).to eq('{}')
|
117
133
|
end
|
118
|
-
expect(@mock).to receive(:get).once.with('ids/1').and_return({name: 'Rajini', age: 16}.to_json)
|
119
|
-
e = AliasSpecificLookup::Employee.new(1)
|
120
|
-
expect(e.nome).to eq('Rajini')
|
121
|
-
expect(e.age).to eq(16)
|
122
|
-
expect(e.to_json).to eq("{\"nome\":\"Rajini\",\"age\":16,\"id\":1}")
|
123
134
|
end
|
124
|
-
end
|
125
|
-
|
126
|
-
context 'Lazy Evaluation' do
|
127
|
-
module LazyEval
|
128
|
-
class HerEmployee
|
129
|
-
include Her::Model
|
130
|
-
use_api TEST_API
|
131
|
-
include Looksist
|
132
|
-
|
133
|
-
lookup :name, using: :employee_id
|
134
135
|
|
135
|
-
|
136
|
-
|
136
|
+
context 'Alias support for lookup' do
|
137
|
+
it 'should fetch attributes and use the alias specified in the api' do
|
138
|
+
module AliasLookup
|
139
|
+
class Employee
|
140
|
+
include Her::Model
|
141
|
+
use_api TEST_API
|
142
|
+
include Looksist
|
143
|
+
attr_accessor :id
|
144
|
+
lookup :name, using: :id, bucket_name: 'employees', as: {name: 'nome'}
|
145
|
+
|
146
|
+
def initialize(id)
|
147
|
+
@id = id
|
148
|
+
end
|
149
|
+
|
150
|
+
def as_json(opts)
|
151
|
+
super(opts).merge(id: @id)
|
152
|
+
end
|
153
|
+
end
|
137
154
|
end
|
155
|
+
expect(@mock).to receive(:get).once.with('employees/1').and_return('Rajini')
|
156
|
+
e = AliasLookup::Employee.new(1)
|
157
|
+
expect(e.nome).to eq('Rajini')
|
158
|
+
expect(e.to_json).to eq("{\"nome\":\"Rajini\",\"id\":1}")
|
138
159
|
end
|
139
|
-
class Employee
|
140
|
-
include Looksist
|
141
|
-
attr_accessor :id
|
142
|
-
lookup :name, using: :id, bucket_name: 'employees'
|
143
160
|
|
144
|
-
|
145
|
-
|
161
|
+
it 'should fetch attributes and use the alias for specific attributes in the api' do
|
162
|
+
module AliasSpecificLookup
|
163
|
+
class Employee
|
164
|
+
include Her::Model
|
165
|
+
use_api TEST_API
|
166
|
+
include Looksist
|
167
|
+
attr_accessor :id
|
168
|
+
lookup [:name, :age], using: :id, as: {name: 'nome'}
|
169
|
+
|
170
|
+
def initialize(id)
|
171
|
+
@id = id
|
172
|
+
end
|
173
|
+
|
174
|
+
def as_json(opts)
|
175
|
+
super(opts).merge(id: @id)
|
176
|
+
end
|
177
|
+
end
|
146
178
|
end
|
179
|
+
expect(@mock).to receive(:get).once.with('ids/1').and_return({name: 'Rajini', age: 16}.to_json)
|
180
|
+
e = AliasSpecificLookup::Employee.new(1)
|
181
|
+
expect(e.nome).to eq('Rajini')
|
182
|
+
expect(e.age).to eq(16)
|
183
|
+
expect(e.to_json).to eq("{\"nome\":\"Rajini\",\"age\":16,\"id\":1}")
|
147
184
|
end
|
148
185
|
end
|
149
|
-
it 'should not eager evaluate' do
|
150
|
-
expect(@mock).to_not receive(:get)
|
151
|
-
LazyEval::Employee.new(1)
|
152
|
-
LazyEval::HerEmployee.new(employee_id: 1)
|
153
|
-
end
|
154
|
-
end
|
155
186
|
|
156
|
-
|
157
|
-
|
158
|
-
|
187
|
+
context 'Lazy Evaluation' do
|
188
|
+
module LazyEval
|
189
|
+
class HerEmployee
|
190
|
+
include Her::Model
|
191
|
+
use_api TEST_API
|
192
|
+
include Looksist
|
193
|
+
|
194
|
+
lookup :name, using: :employee_id
|
195
|
+
|
196
|
+
def as_json(opts)
|
197
|
+
super(opts).merge(another_attr: 'Hello World')
|
198
|
+
end
|
199
|
+
end
|
159
200
|
class Employee
|
160
201
|
include Looksist
|
161
|
-
attr_accessor :id
|
162
|
-
lookup :name, using:
|
163
|
-
lookup :unavailable, using: :employee_id
|
202
|
+
attr_accessor :id
|
203
|
+
lookup :name, using: :id, bucket_name: 'employees'
|
164
204
|
|
165
205
|
def initialize(id)
|
166
|
-
@id =
|
206
|
+
@id = id
|
167
207
|
end
|
168
208
|
end
|
169
209
|
end
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
expect(e.unavailable).to be(nil)
|
210
|
+
it 'should not eager evaluate' do
|
211
|
+
expect(@mock).to_not receive(:get)
|
212
|
+
LazyEval::Employee.new(1)
|
213
|
+
LazyEval::HerEmployee.new(employee_id: 1)
|
214
|
+
end
|
176
215
|
end
|
177
216
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
217
|
+
context 'lookup attributes' do
|
218
|
+
it 'should generate declarative attributes on the model with simple lookup value' do
|
219
|
+
module SimpleLookup
|
220
|
+
class Employee
|
221
|
+
include Looksist
|
222
|
+
attr_accessor :id, :employee_id
|
223
|
+
lookup :name, using: :id
|
224
|
+
lookup :unavailable, using: :employee_id
|
225
|
+
|
226
|
+
def initialize(id)
|
227
|
+
@id = @employee_id = id
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
183
231
|
|
184
|
-
|
185
|
-
|
186
|
-
|
232
|
+
expect(@mock).to receive(:get).once.with('ids/1').and_return('Employee Name')
|
233
|
+
expect(@mock).to receive(:get).once.with('employees/1').and_return(nil)
|
234
|
+
e = SimpleLookup::Employee.new(1)
|
235
|
+
expect(e.name).to eq('Employee Name')
|
236
|
+
expect(e.unavailable).to be(nil)
|
237
|
+
end
|
187
238
|
|
188
|
-
|
189
|
-
|
239
|
+
it 'should generate declarative attributes on the model with object based lookup value' do
|
240
|
+
module CompositeLookup
|
241
|
+
class Employee
|
242
|
+
include Looksist
|
243
|
+
attr_accessor :id, :employee_id, :contact_id
|
244
|
+
|
245
|
+
lookup [:name, :location], using: :id
|
246
|
+
lookup [:age, :sex], using: :employee_id
|
247
|
+
lookup [:pager, :cell], using: :contact_id
|
248
|
+
|
249
|
+
def initialize(id)
|
250
|
+
@contact_id = @id = @employee_id = id
|
251
|
+
end
|
190
252
|
end
|
191
253
|
end
|
192
|
-
end
|
193
254
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
255
|
+
expect(@mock).to receive(:get).once.with('ids/1').and_return({name: 'Employee Name', location: 'Chennai'}.to_json)
|
256
|
+
expect(@mock).to receive(:get).once.with('contacts/1').and_return({pager: 'pager', cell: 'cell'}.to_json)
|
257
|
+
expect(@mock).to receive(:get).twice.with('employees/1').and_return(nil)
|
258
|
+
e = CompositeLookup::Employee.new(1)
|
198
259
|
|
199
|
-
|
200
|
-
|
260
|
+
expect(e.name).to eq('Employee Name')
|
261
|
+
expect(e.location).to eq('Chennai')
|
201
262
|
|
202
|
-
|
203
|
-
|
263
|
+
expect(e.age).to eq(nil)
|
264
|
+
expect(e.sex).to eq(nil)
|
204
265
|
|
205
|
-
|
206
|
-
|
266
|
+
expect(e.pager).to eq('pager')
|
267
|
+
expect(e.cell).to eq('cell')
|
268
|
+
end
|
207
269
|
end
|
208
|
-
end
|
209
270
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
271
|
+
context 'share storage between instances' do
|
272
|
+
class Employee
|
273
|
+
include Looksist
|
274
|
+
attr_accessor :id
|
214
275
|
|
215
|
-
|
276
|
+
lookup [:name, :location], using: :id
|
216
277
|
|
217
|
-
|
218
|
-
|
278
|
+
def initialize(id)
|
279
|
+
@id = id
|
280
|
+
end
|
219
281
|
end
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
employee_first_instance.name
|
282
|
+
it 'should share storage between instances to improve performance' do
|
283
|
+
employee_first_instance = Employee.new(1)
|
284
|
+
expect(@mock).to receive(:get).once.with('ids/1')
|
285
|
+
.and_return({name: 'Employee Name', location: 'Chennai'}.to_json)
|
286
|
+
employee_first_instance.name
|
226
287
|
|
227
|
-
|
228
|
-
|
288
|
+
employee_second_instance = Employee.new(1)
|
289
|
+
expect(@mock).not_to receive(:get).with('ids/1')
|
229
290
|
|
230
|
-
|
291
|
+
employee_second_instance.name
|
292
|
+
end
|
231
293
|
end
|
232
294
|
end
|
233
295
|
end
|