attune 1.0.3 → 1.0.5
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 +5 -5
- data/attune.gemspec +3 -3
- data/lib/attune.rb +14 -0
- data/lib/attune/api/anonymous.rb +131 -0
- data/lib/attune/api/entities.rb +195 -0
- data/lib/attune/call_dropping.rb +1 -0
- data/lib/attune/client.rb +20 -170
- data/lib/attune/configurable.rb +1 -0
- data/lib/attune/default.rb +1 -0
- data/lib/attune/json_logger.rb +1 -0
- data/lib/attune/models/anonymousresult.rb +41 -0
- data/lib/attune/models/batchrankingrequest.rb +44 -0
- data/lib/attune/models/batchrankingresult.rb +44 -0
- data/lib/attune/models/blacklist.rb +111 -0
- data/lib/attune/models/blacklistgetresponse.rb +44 -0
- data/lib/attune/models/blacklistparams.rb +87 -0
- data/lib/attune/models/blacklistsaveresponse.rb +41 -0
- data/lib/attune/models/customer.rb +41 -0
- data/lib/attune/models/rankedentities.rb +60 -0
- data/lib/attune/models/rankingparams.rb +103 -0
- data/lib/attune/models/scopeentry.rb +49 -0
- data/lib/attune/net_http_persistent.rb +1 -0
- data/lib/attune/param_flattener.rb +1 -0
- data/lib/attune/version.rb +2 -1
- data/spec/attune/client_spec.rb +51 -59
- data/spec/remote_spec.rb +27 -27
- metadata +40 -25
@@ -0,0 +1,60 @@
|
|
1
|
+
module Attune
|
2
|
+
module Model
|
3
|
+
#
|
4
|
+
class RankedEntities
|
5
|
+
attr_accessor :message
|
6
|
+
|
7
|
+
|
8
|
+
attr_accessor :status
|
9
|
+
|
10
|
+
|
11
|
+
attr_accessor :ranking
|
12
|
+
|
13
|
+
|
14
|
+
# :internal => :external
|
15
|
+
def self.attribute_map
|
16
|
+
{
|
17
|
+
:message => :message,
|
18
|
+
:status => :status,
|
19
|
+
:ranking => :ranking
|
20
|
+
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(attributes = {})
|
25
|
+
return if attributes.empty?
|
26
|
+
# Morph attribute keys into undescored rubyish style
|
27
|
+
if self.class.attribute_map[:"message"]
|
28
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
29
|
+
@message = attributes["message"] || attributes[:"message"]
|
30
|
+
end
|
31
|
+
if self.class.attribute_map[:"status"]
|
32
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
33
|
+
@status = attributes["status"] || attributes[:"status"]
|
34
|
+
end
|
35
|
+
if self.class.attribute_map[:"ranking"]
|
36
|
+
value = attributes["ranking"] || attributes[:"ranking"]
|
37
|
+
if value.is_a?(Array)
|
38
|
+
@ranking = value
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_body
|
47
|
+
body = {}
|
48
|
+
self.class.attribute_map.each_pair do |key, value|
|
49
|
+
body[value] = self.send(key) unless self.send(key).nil?
|
50
|
+
end
|
51
|
+
body
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_json(options = {})
|
55
|
+
to_body.to_json
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Attune
|
2
|
+
module Model
|
3
|
+
#
|
4
|
+
class RankingParams
|
5
|
+
attr_accessor :view
|
6
|
+
|
7
|
+
|
8
|
+
attr_accessor :entity_type
|
9
|
+
|
10
|
+
|
11
|
+
attr_accessor :ids
|
12
|
+
|
13
|
+
|
14
|
+
attr_accessor :scope
|
15
|
+
|
16
|
+
|
17
|
+
attr_accessor :ip
|
18
|
+
|
19
|
+
|
20
|
+
attr_accessor :user_agent
|
21
|
+
|
22
|
+
|
23
|
+
attr_accessor :customer
|
24
|
+
|
25
|
+
|
26
|
+
attr_accessor :anonymous
|
27
|
+
|
28
|
+
|
29
|
+
# :internal => :external
|
30
|
+
def self.attribute_map
|
31
|
+
{
|
32
|
+
:view => :view,
|
33
|
+
:entity_type => :entityType,
|
34
|
+
:ids => :ids,
|
35
|
+
:scope => :scope,
|
36
|
+
:ip => :ip,
|
37
|
+
:user_agent => :userAgent,
|
38
|
+
:customer => :customer,
|
39
|
+
:anonymous => :anonymous
|
40
|
+
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(attributes = {})
|
45
|
+
return if attributes.empty?
|
46
|
+
# Morph attribute keys into undescored rubyish style
|
47
|
+
if self.class.attribute_map[:"view"]
|
48
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
49
|
+
@view = attributes["view"] || attributes[:"view"]
|
50
|
+
end
|
51
|
+
if self.class.attribute_map[:"entity_type"]
|
52
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
53
|
+
@entity_type = attributes["entityType"] || attributes[:"entity_type"]
|
54
|
+
end
|
55
|
+
if self.class.attribute_map[:"ids"]
|
56
|
+
value = attributes["ids"] || attributes[:"ids"]
|
57
|
+
if value.is_a?(Array)
|
58
|
+
@ids = value
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
if self.class.attribute_map[:"scope"]
|
63
|
+
value = attributes["scope"] || attributes[:"scope"]
|
64
|
+
if value.is_a?(Array)
|
65
|
+
@scope = value.map{ |v| ScopeEntry.new(v) }
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
if self.class.attribute_map[:"ip"]
|
70
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
71
|
+
@ip = attributes["ip"] || attributes[:"ip"]
|
72
|
+
end
|
73
|
+
if self.class.attribute_map[:"user_agent"]
|
74
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
75
|
+
@user_agent = attributes["userAgent"] || attributes[:"user_agent"]
|
76
|
+
end
|
77
|
+
if self.class.attribute_map[:"customer"]
|
78
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
79
|
+
@customer = attributes["customer"] || attributes[:"customer"]
|
80
|
+
end
|
81
|
+
if self.class.attribute_map[:"anonymous"]
|
82
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
83
|
+
@anonymous = attributes["anonymous"] || attributes[:"anonymous"]
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_body
|
90
|
+
body = {}
|
91
|
+
self.class.attribute_map.each_pair do |key, value|
|
92
|
+
body[value] = self.send(key) unless self.send(key).nil?
|
93
|
+
end
|
94
|
+
body
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_json(options = {})
|
98
|
+
to_body.to_json
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Attune
|
2
|
+
module Model
|
3
|
+
#
|
4
|
+
class ScopeEntry
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
|
8
|
+
attr_accessor :value
|
9
|
+
|
10
|
+
|
11
|
+
# :internal => :external
|
12
|
+
def self.attribute_map
|
13
|
+
{
|
14
|
+
:name => :name,
|
15
|
+
:value => :value
|
16
|
+
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(attributes = {})
|
21
|
+
return if attributes.empty?
|
22
|
+
# Morph attribute keys into undescored rubyish style
|
23
|
+
if self.class.attribute_map[:"name"]
|
24
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
25
|
+
@name = attributes["name"] || attributes[:"name"]
|
26
|
+
end
|
27
|
+
if self.class.attribute_map[:"value"]
|
28
|
+
# Workaround since JSON.parse has accessors as strings rather than symbols
|
29
|
+
@value = attributes["value"] || attributes[:"value"]
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_body
|
36
|
+
body = {}
|
37
|
+
self.class.attribute_map.each_pair do |key, value|
|
38
|
+
body[value] = self.send(key) unless self.send(key).nil?
|
39
|
+
end
|
40
|
+
body
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_json(options = {})
|
44
|
+
to_body.to_json
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
data/lib/attune/version.rb
CHANGED
data/spec/attune/client_spec.rb
CHANGED
@@ -26,23 +26,23 @@ describe Attune::Client do
|
|
26
26
|
|
27
27
|
describe "API errors" do
|
28
28
|
it "will raise timeout" do
|
29
|
-
stubs.post("anonymous",
|
29
|
+
stubs.post("anonymous", nil){ raise Faraday::Error::TimeoutError.new("test") }
|
30
30
|
expect {
|
31
|
-
client.
|
31
|
+
client.anonymous.create
|
32
32
|
}.to raise_exception(Faraday::Error::TimeoutError)
|
33
33
|
stubs.verify_stubbed_calls
|
34
34
|
end
|
35
35
|
it "will raise ConnectionFailed" do
|
36
|
-
stubs.post("anonymous",
|
36
|
+
stubs.post("anonymous", nil){ raise Faraday::Error::ConnectionFailed.new("test") }
|
37
37
|
expect {
|
38
|
-
client.
|
38
|
+
client.anonymous.create
|
39
39
|
}.to raise_exception(Faraday::Error::ConnectionFailed)
|
40
40
|
stubs.verify_stubbed_calls
|
41
41
|
end
|
42
42
|
it "will raise ConnectionFailed on Errno::ENOENT" do
|
43
|
-
stubs.post("anonymous",
|
43
|
+
stubs.post("anonymous", nil){ raise Errno::ENOENT.new("test") }
|
44
44
|
expect {
|
45
|
-
client.
|
45
|
+
client.anonymous.create
|
46
46
|
}.to raise_exception(Faraday::Error::ConnectionFailed)
|
47
47
|
end
|
48
48
|
it "will raise AuthenticationException" do
|
@@ -61,7 +61,7 @@ describe Attune::Client do
|
|
61
61
|
let(:options){ {disabled: true, exception_handler: :raise} }
|
62
62
|
it "will raise DisalbedException" do
|
63
63
|
expect {
|
64
|
-
client.
|
64
|
+
client.anonymous.create
|
65
65
|
}.to raise_exception(Attune::DisabledException)
|
66
66
|
end
|
67
67
|
end
|
@@ -73,11 +73,11 @@ describe Attune::Client do
|
|
73
73
|
expect(result).to match(/^[a-z0-9\-]+$/)
|
74
74
|
end
|
75
75
|
it "mocks create_anonymous with an id" do
|
76
|
-
result = client.
|
76
|
+
result = client.anonymous.create(id: '12345', user_agent: 'Mozilla/5.0')
|
77
77
|
expect(result).to eq('12345')
|
78
78
|
end
|
79
79
|
it "mocks create_anonymous with no id" do
|
80
|
-
result = client.
|
80
|
+
result = client.anonymous.create(user_agent: 'Mozilla/5.0')
|
81
81
|
expect(result).to match(/^[a-z0-9\-]+$/)
|
82
82
|
end
|
83
83
|
describe "mocks get_rankings" do
|
@@ -90,7 +90,7 @@ describe Attune::Client do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
before(:each) do
|
93
|
-
@result = client.get_rankings(
|
93
|
+
@result = client.entities.get_rankings(
|
94
94
|
id: 'abcd123',
|
95
95
|
view: 'b/mens-pants',
|
96
96
|
collection: 'products',
|
@@ -157,59 +157,66 @@ describe Attune::Client do
|
|
157
157
|
end
|
158
158
|
|
159
159
|
it "can create_anonymous generating an id" do
|
160
|
-
stubs.post("anonymous",
|
161
|
-
|
160
|
+
stubs.post("anonymous", nil){ [200, {location: 'urn:id:abcd123'}, %[{"id": "abcd123"}]] }
|
161
|
+
result = client.anonymous.create
|
162
162
|
stubs.verify_stubbed_calls
|
163
163
|
|
164
|
-
expect(id).to eq('abcd123')
|
164
|
+
expect(result.id).to eq('abcd123')
|
165
165
|
end
|
166
166
|
|
167
167
|
it "can bind" do
|
168
|
-
stubs.put("
|
169
|
-
client.
|
168
|
+
stubs.put("anonymous/abcd123", %[{"customer":"foobar"}]){ [200, {}, nil] }
|
169
|
+
client.anonymous.update('abcd123', Attune::Model::Customer.new(customer:'foobar'))
|
170
170
|
stubs.verify_stubbed_calls
|
171
171
|
end
|
172
172
|
|
173
|
-
it "
|
174
|
-
stubs.
|
175
|
-
|
173
|
+
it "get anonymous using existing id" do
|
174
|
+
stubs.get("anonymous/abcd123"){ [200, {}, %[{"customer":"foobar"}]] }
|
175
|
+
response = client.anonymous.get('abcd123')
|
176
176
|
stubs.verify_stubbed_calls
|
177
177
|
|
178
|
-
expect(
|
178
|
+
expect(response.customer).to eq('foobar')
|
179
179
|
end
|
180
180
|
|
181
181
|
describe "get_rankings" do
|
182
182
|
before(:each) do
|
183
|
-
|
184
|
-
|
185
|
-
id: 'abcd123',
|
183
|
+
ranking_request = {
|
184
|
+
anonymous: 'abcd123',
|
186
185
|
view: 'b/mens-pants',
|
187
|
-
|
188
|
-
|
189
|
-
|
186
|
+
entity_type: 'products',
|
187
|
+
ids: %w[1001, 1002, 1003, 1004]
|
188
|
+
}
|
189
|
+
stubs.post("entities/ranking", ranking_request.to_json){ [200, nil, %[{"ranking":["1004","1003","1002","1001"]}]] }
|
190
|
+
@rankings = client.entities.get_rankings(ranking_request)
|
190
191
|
stubs.verify_stubbed_calls
|
191
192
|
end
|
192
193
|
|
193
194
|
it "can get ranked entities" do
|
194
|
-
expect(@rankings
|
195
|
-
end
|
196
|
-
|
197
|
-
it "can get ranking headers" do
|
198
|
-
expect(@rankings[:headers]).to eq({"attune-ranking"=>"test", "attune-cell"=>"test"})
|
195
|
+
expect(@rankings.ranking).to eq(%W[1004 1003 1002 1001])
|
199
196
|
end
|
200
197
|
end
|
201
198
|
|
202
199
|
describe "multi_get_rankings" do
|
203
|
-
let(:req1){ CGI::escape 'anonymous=0cddbc0-6114-11e3-949a-0800200c9a66&view=b%2Fmens-pants&entity_collection=products&entities=1001%2C%2C1002%2C%2C1003%2C%2C1004&ip=none' }
|
204
|
-
let(:req2){ CGI::escape 'anonymous=0cddbc0-6114-11e3-949a-0800200c9a66&view=b%2Fmens-pants&entity_collection=products&entities=2001%2C%2C2002%2C%2C2003%2C%2C2004&ip=none' }
|
205
|
-
|
206
200
|
before(:each) do
|
207
|
-
|
208
|
-
|
201
|
+
batch_request = {requests: [
|
202
|
+
{
|
203
|
+
anonymous: '0cddbc0-6114-11e3-949a-0800200c9a66',
|
204
|
+
view: 'b/mens-pants',
|
205
|
+
entity_type: 'products',
|
206
|
+
ids: %w[1001, 1002, 1003, 1004]
|
207
|
+
},
|
208
|
+
{
|
209
|
+
anonymous: '0cddbc0-6114-11e3-949a-0800200c9a66',
|
210
|
+
view: 'b/mens-pants',
|
211
|
+
entity_type: 'products',
|
212
|
+
ids: %w[2001, 2002, 2003, 2004]
|
213
|
+
}
|
214
|
+
]}
|
215
|
+
stubs.post("entities/ranking/many", batch_request.to_json) do
|
216
|
+
[200, nil, <<-JSON]
|
209
217
|
{
|
210
|
-
"
|
211
|
-
|
212
|
-
"anonymous=0cddbc0-6114-11e3-949a-0800200c9a66&entities=1001%2C%2C1002%2C%2C1003%2C%2C1004&entity_collection=products&ip=none&view=b%2Fmens-pants": {
|
218
|
+
"results": [
|
219
|
+
{
|
213
220
|
"ranking": [
|
214
221
|
"1004",
|
215
222
|
"1003",
|
@@ -217,7 +224,7 @@ describe Attune::Client do
|
|
217
224
|
"1001"
|
218
225
|
]
|
219
226
|
},
|
220
|
-
|
227
|
+
{
|
221
228
|
"ranking": [
|
222
229
|
"2004",
|
223
230
|
"2003",
|
@@ -225,36 +232,21 @@ describe Attune::Client do
|
|
225
232
|
"2001"
|
226
233
|
]
|
227
234
|
}
|
228
|
-
|
235
|
+
]
|
229
236
|
}
|
230
237
|
JSON
|
231
238
|
end
|
232
|
-
@
|
233
|
-
{
|
234
|
-
id: '0cddbc0-6114-11e3-949a-0800200c9a66',
|
235
|
-
view: 'b/mens-pants',
|
236
|
-
collection: 'products',
|
237
|
-
entities: %w[1001, 1002, 1003, 1004]
|
238
|
-
},
|
239
|
-
{
|
240
|
-
id: '0cddbc0-6114-11e3-949a-0800200c9a66',
|
241
|
-
view: 'b/mens-pants',
|
242
|
-
collection: 'products',
|
243
|
-
entities: %w[2001, 2002, 2003, 2004]
|
244
|
-
}
|
245
|
-
])
|
239
|
+
@results = client.entities.batch_get_rankings(batch_request)
|
246
240
|
stubs.verify_stubbed_calls
|
247
241
|
end
|
248
242
|
|
249
243
|
it "can get ranked entities" do
|
250
|
-
|
244
|
+
rankings = @results.results.map {|r| r.ranking }
|
245
|
+
expect(rankings).to eq [
|
251
246
|
%W[1004 1003 1002 1001],
|
252
247
|
%W[2004 2003 2002 2001]
|
253
248
|
]
|
254
249
|
end
|
255
|
-
|
256
|
-
it "can get ranking headers" do
|
257
|
-
expect(@rankings[:headers]).to eq({"attune-ranking"=>"test", "attune-cell"=>"test"})
|
258
|
-
end
|
259
250
|
end
|
260
251
|
end
|
252
|
+
|
data/spec/remote_spec.rb
CHANGED
@@ -21,49 +21,49 @@ describe "remote requests" do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it "can create an anonymous user" do
|
24
|
-
|
25
|
-
id.should =~ /[a-z0-9\-]+/
|
24
|
+
result = client.anonymous.create
|
25
|
+
result.id.should =~ /[a-z0-9\-]+/
|
26
26
|
end
|
27
27
|
|
28
|
-
it "can
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
it "can bind an anonymous user" do
|
34
|
-
id = client.create_anonymous(id: '123456', user_agent: 'Mozilla/5.0')
|
35
|
-
client.bind(id, '654321')
|
28
|
+
it "can bind and get an anonymous user" do
|
29
|
+
client.anonymous.update('654321', Attune::Model::Customer.new(customer:'foobar'))
|
30
|
+
customer = client.anonymous.get('654321')
|
31
|
+
customer.customer.should == 'foobar'
|
36
32
|
end
|
37
33
|
|
38
34
|
let(:entities){ [202875,202876,202874,202900,202902,202898,202905,200182,200181,185940,188447,185932,190589,1238689589] }
|
39
35
|
describe "get_rankings" do
|
40
36
|
before(:each) do
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
anonymous_result = client.anonymous.create
|
38
|
+
params = Attune::Model::RankingParams.new
|
39
|
+
params.anonymous = anonymous_result.id
|
40
|
+
params.view = 'b/mens-pants'
|
41
|
+
params.entity_type = 'products'
|
42
|
+
params.ids = entities
|
43
|
+
@result = client.entities.get_rankings(params)
|
44
44
|
end
|
45
45
|
it "can get ranked entities" do
|
46
|
-
@result
|
47
|
-
@result
|
46
|
+
@result.ranking.should be_an Array
|
47
|
+
@result.ranking.sort.should == entities.map(&:to_s).sort
|
48
48
|
end
|
49
|
-
specify { expect(@result[:headers]).to be_a Hash }
|
50
|
-
specify { expect(@result[:headers]).to have_key "attune-ranking" }
|
51
|
-
specify { expect(@result[:headers]).to have_key "attune-cell" }
|
52
49
|
end
|
53
50
|
|
54
51
|
describe "multi_get_rankings" do
|
55
52
|
before(:each) do
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
anonymous_result = client.anonymous.create
|
54
|
+
params = Attune::Model::RankingParams.new
|
55
|
+
params.anonymous = anonymous_result.id
|
56
|
+
params.view = 'b/mens-pants'
|
57
|
+
params.entity_type = 'products'
|
58
|
+
params.ids = entities
|
59
|
+
batch_request = Attune::Model::BatchRankingRequest.new
|
60
|
+
batch_request.requests = [params]
|
61
|
+
@results = client.entities.batch_get_rankings(batch_request)
|
59
62
|
end
|
60
63
|
it "can batch get rankings" do
|
61
|
-
@results
|
62
|
-
|
63
|
-
|
64
|
+
@results.results.should be_an Array
|
65
|
+
ranking = @results.results[0].ranking
|
66
|
+
ranking.sort.should == entities.map(&:to_s).sort
|
64
67
|
end
|
65
|
-
specify { expect(@results[:headers]).to be_a Hash }
|
66
|
-
specify { expect(@results[:headers]).to have_key "attune-ranking" }
|
67
|
-
specify { expect(@results[:headers]).to have_key "attune-cell" }
|
68
68
|
end
|
69
69
|
end
|