crystal_sdk 0.0.4 → 1.0.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/Gemfile.lock +1 -1
- data/lib/crystal_sdk/api.rb +19 -0
- data/lib/crystal_sdk/base.rb +1 -1
- data/lib/crystal_sdk/profile/request.rb +60 -0
- data/lib/crystal_sdk/version.rb +1 -1
- data/spec/crystal_sdk/api_spec.rb +95 -0
- data/spec/crystal_sdk/base_spec.rb +1 -1
- data/spec/crystal_sdk/profile/request_spec.rb +252 -0
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed49b547a11579d80d9aa3c96dab61019d0dd47b
|
4
|
+
data.tar.gz: 49afdf1d21487a6d4def81f564feb3eec54dfc54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55a5a0ca2e44a4df1cf4b3455703da564ffc32a39fd22e2d020c5c2a05ab9ef8b7f89e0f0559c371e64ae84bb2b5f5270ac5043efed0ea92ec7a05703519e68d
|
7
|
+
data.tar.gz: 13a84fc643b862bde2f5f3a7f7cf8cd3cf292379233d23e13324ba1a05c76ec00f919fe0b4d01a94e57bd4d8914abf1ce745b226de9d5652be19bcc5c4e2a8e7
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
module CrystalSDK
|
2
|
+
class Api
|
3
|
+
def self.make_request(type, endpoint, params: {}, headers: {})
|
4
|
+
headers = headers.merge(
|
5
|
+
'X-Org-Token' => Base.key!,
|
6
|
+
'X-Sdk-Version' => VERSION
|
7
|
+
)
|
8
|
+
|
9
|
+
opts = {
|
10
|
+
method: type,
|
11
|
+
headers: headers,
|
12
|
+
params: params,
|
13
|
+
format: :json
|
14
|
+
}
|
15
|
+
|
16
|
+
Nestful::Request.new("#{Base::API_URL}/#{endpoint}", opts).execute
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/crystal_sdk/base.rb
CHANGED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'recursive-open-struct'
|
2
|
+
require 'crystal_sdk/api'
|
3
|
+
|
4
|
+
module CrystalSDK
|
5
|
+
class Profile
|
6
|
+
class Request
|
7
|
+
attr_reader :id
|
8
|
+
|
9
|
+
def initialize(id)
|
10
|
+
@id = id
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_search(query)
|
14
|
+
resp = Api.make_request(:post, 'profile_search/async', params: query)
|
15
|
+
body = JSON.parse(resp.body || '{}', symbolize_names: true)
|
16
|
+
|
17
|
+
Profile::Request.new(body[:request_id])
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch_request_info
|
21
|
+
return @cached_data if @cached_data
|
22
|
+
|
23
|
+
resp = Api.make_request(:get, "results/#{@id}")
|
24
|
+
body = resp.body ? JSON.parse(resp.body, symbolize_names: true) : nil
|
25
|
+
|
26
|
+
if body[:status] == 'complete' || body[:status] == 'error'
|
27
|
+
@cached_data = body
|
28
|
+
end
|
29
|
+
|
30
|
+
body
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch_status
|
34
|
+
fetch_request_info[:status]
|
35
|
+
end
|
36
|
+
|
37
|
+
def did_finish?
|
38
|
+
status = fetch_status
|
39
|
+
status == 'complete' || status == 'error'
|
40
|
+
end
|
41
|
+
|
42
|
+
def did_find_profile?
|
43
|
+
return false unless did_finish? && fetch_status == 'complete'
|
44
|
+
|
45
|
+
info = fetch_request_info
|
46
|
+
!info[:data][:info][:error]
|
47
|
+
end
|
48
|
+
|
49
|
+
def profile_info
|
50
|
+
return nil unless did_find_profile?
|
51
|
+
|
52
|
+
req_info = fetch_request_info
|
53
|
+
profile_info = RecursiveOpenStruct.new(req_info[:data][:info])
|
54
|
+
recommendations = RecursiveOpenStruct.new(req_info[:data][:recommendations])
|
55
|
+
|
56
|
+
{ info: profile_info, recommendations: recommendations }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/crystal_sdk/version.rb
CHANGED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CrystalSDK::Api do
|
4
|
+
subject { CrystalSDK::Api }
|
5
|
+
|
6
|
+
describe '.make_request' do
|
7
|
+
context 'without api key' do
|
8
|
+
it 'should raise an error' do
|
9
|
+
expect { subject.make_request(:post, 'test') }
|
10
|
+
.to raise_error(CrystalSDK::Base::ApiKeyNotSet)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with api key' do
|
15
|
+
subject { CrystalSDK::Api.make_request(:post, 'test_endpoint') }
|
16
|
+
|
17
|
+
let(:headers) do
|
18
|
+
{
|
19
|
+
'X-Org-Token' => 'SomeToken',
|
20
|
+
'X-Sdk-Version' => CrystalSDK::VERSION
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:stubbed_req) do
|
25
|
+
stub_request(:post, "#{CrystalSDK::Base::API_URL}/test_endpoint")
|
26
|
+
.with(headers: headers)
|
27
|
+
end
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
allow(CrystalSDK::Base).to receive(:key).and_return('SomeToken')
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'got 4xx response code' do
|
34
|
+
it 'should raise an error' do
|
35
|
+
stubbed_req
|
36
|
+
.to_return(status: 404, body: '{}', headers: {})
|
37
|
+
|
38
|
+
expect { subject }.to raise_error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'got 5xx response code' do
|
43
|
+
it 'should raise error on 5xx responses' do
|
44
|
+
stubbed_req
|
45
|
+
.to_return(status: 500, body: '{}', headers: {})
|
46
|
+
|
47
|
+
expect { subject }.to raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'got 2xx response code' do
|
52
|
+
it 'should return correct response' do
|
53
|
+
stubbed_req
|
54
|
+
.to_return(status: 200, body: 'stubbed', headers: {})
|
55
|
+
|
56
|
+
expect(subject.code).to eql(200)
|
57
|
+
expect(subject.body).to eql('stubbed')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'given params' do
|
62
|
+
subject do
|
63
|
+
CrystalSDK::Api
|
64
|
+
.make_request(:post, 'test_endpoint', params: params)
|
65
|
+
end
|
66
|
+
let(:params) { { some_param: '123'} }
|
67
|
+
|
68
|
+
it 'should turn params into json body' do
|
69
|
+
stubbed_req
|
70
|
+
.with(body: params.to_json)
|
71
|
+
.to_return(status: 200, body: 'stubbed', headers: {})
|
72
|
+
|
73
|
+
expect { subject }.to_not raise_error
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
context 'given headers' do
|
79
|
+
subject do
|
80
|
+
CrystalSDK::Api
|
81
|
+
.make_request(:post, 'test_endpoint', headers: headers)
|
82
|
+
end
|
83
|
+
let(:headers) { { 'X-Some-Header' => '123' } }
|
84
|
+
|
85
|
+
it 'should turn params into json body' do
|
86
|
+
stubbed_req
|
87
|
+
.with(headers: headers)
|
88
|
+
.to_return(status: 200, body: 'stubbed', headers: {})
|
89
|
+
|
90
|
+
expect { subject }.to_not raise_error
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -11,7 +11,7 @@ describe CrystalSDK::Base do
|
|
11
11
|
subject { CrystalSDK::Base::API_URL }
|
12
12
|
|
13
13
|
it { is_expected.to include '.crystalknows.com' }
|
14
|
-
|
14
|
+
it { is_expected.to start_with 'https://' }
|
15
15
|
it { is_expected.to_not end_with '/' }
|
16
16
|
end
|
17
17
|
|
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CrystalSDK::Profile::Request do
|
4
|
+
subject { CrystalSDK::Profile::Request }
|
5
|
+
|
6
|
+
it 'should initialize properly' do
|
7
|
+
req = subject.new("an_id")
|
8
|
+
expect(req.id).to eql("an_id")
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.from_search' do
|
12
|
+
subject { CrystalSDK::Profile::Request.from_search(query) }
|
13
|
+
let(:query) { { first_name: 'Test', last_name: 'Test' } }
|
14
|
+
let(:request_type) { :post }
|
15
|
+
let(:endpoint) { 'profile_search/async' }
|
16
|
+
|
17
|
+
context 'CrystalSDK::Api raises exception' do
|
18
|
+
it 'should not suppress it' do
|
19
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
20
|
+
.with(request_type, endpoint, params: query)
|
21
|
+
.and_raise('SomeRandomError')
|
22
|
+
|
23
|
+
expect { subject }.to raise_error('SomeRandomError')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'CrystalSDK::Api returns invalid json body' do
|
28
|
+
it 'should raise error' do
|
29
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
30
|
+
.with(request_type, endpoint, params: query)
|
31
|
+
.and_return(double(body: 'pie'))
|
32
|
+
|
33
|
+
expect { subject }.to raise_error
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'CrystalSDK::Api returns valid json body' do
|
38
|
+
it 'should return request object' do
|
39
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
40
|
+
.with(request_type, endpoint, params: query)
|
41
|
+
.and_return(double(body: '{}'))
|
42
|
+
|
43
|
+
expect(subject).to be_kind_of(CrystalSDK::Profile::Request)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#fetch_request_info' do
|
49
|
+
subject { CrystalSDK::Profile::Request.new('my_id').fetch_request_info() }
|
50
|
+
let(:request_type) { :get }
|
51
|
+
let(:endpoint) { 'results/my_id' }
|
52
|
+
|
53
|
+
context 'CrystalSDK::Api raises exception' do
|
54
|
+
it 'should not suppress it' do
|
55
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
56
|
+
.with(request_type, endpoint)
|
57
|
+
.and_raise('SomeRandomError')
|
58
|
+
|
59
|
+
expect { subject }.to raise_error('SomeRandomError')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'CrystalSDK::Api returns invalid json body' do
|
64
|
+
it 'should raise error' do
|
65
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
66
|
+
.with(request_type, endpoint)
|
67
|
+
.and_return(double(body: 'pie'))
|
68
|
+
|
69
|
+
expect { subject }.to raise_error
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'CrystalSDK::Api returns valid json body' do
|
74
|
+
it 'should return request object' do
|
75
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
76
|
+
.with(request_type, endpoint)
|
77
|
+
.and_return(double(body: '{"something": true}'))
|
78
|
+
|
79
|
+
expect(subject).to eql({ something: true })
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'status is "complete"' do
|
83
|
+
it 'should cache' do
|
84
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
85
|
+
.with(request_type, endpoint)
|
86
|
+
.and_return(double(body: '{"status": "complete"}'))
|
87
|
+
|
88
|
+
expect(subject).to eql({ status: 'complete' })
|
89
|
+
|
90
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
91
|
+
.with(request_type, endpoint)
|
92
|
+
.and_return(double(body: '{"status": "failure"}'))
|
93
|
+
|
94
|
+
expect(subject).to eql({ status: 'complete' })
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'status is "error"' do
|
99
|
+
it 'should cache' do
|
100
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
101
|
+
.with(request_type, endpoint)
|
102
|
+
.and_return(double(body: '{"status": "error"}'))
|
103
|
+
|
104
|
+
expect(subject).to eql({ status: 'error' })
|
105
|
+
|
106
|
+
allow(CrystalSDK::Api).to receive(:make_request)
|
107
|
+
.with(request_type, endpoint)
|
108
|
+
.and_return(double(body: '{"status": "failure"}'))
|
109
|
+
|
110
|
+
expect(subject).to eql({ status: 'error' })
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#fetch_status' do
|
117
|
+
let(:request) { CrystalSDK::Profile::Request.new('my_id') }
|
118
|
+
subject { request.fetch_status }
|
119
|
+
|
120
|
+
it 'should pull :status from #fetch_request_info' do
|
121
|
+
allow(request).to receive(:fetch_request_info)
|
122
|
+
.and_return({status: 'testing'})
|
123
|
+
|
124
|
+
expect(subject).to eql('testing')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#did_finish?' do
|
129
|
+
let(:request) { CrystalSDK::Profile::Request.new('my_id') }
|
130
|
+
subject { request.did_finish? }
|
131
|
+
|
132
|
+
context '#fetch_status returns "complete"' do
|
133
|
+
before(:each) do
|
134
|
+
allow(request).to receive(:fetch_status).and_return('complete')
|
135
|
+
end
|
136
|
+
|
137
|
+
it { is_expected.to eql(true) }
|
138
|
+
end
|
139
|
+
|
140
|
+
context '#fetch_status returns "error"' do
|
141
|
+
before(:each) do
|
142
|
+
allow(request).to receive(:fetch_status).and_return('error')
|
143
|
+
end
|
144
|
+
|
145
|
+
it { is_expected.to eql(true) }
|
146
|
+
end
|
147
|
+
|
148
|
+
context '#fetch_status returns something else' do
|
149
|
+
before(:each) do
|
150
|
+
allow(request).to receive(:fetch_status).and_return('something')
|
151
|
+
end
|
152
|
+
|
153
|
+
it { is_expected.to eql(false) }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe '#did_find_profile?' do
|
158
|
+
let(:request) { CrystalSDK::Profile::Request.new('my_id') }
|
159
|
+
subject { request.did_find_profile? }
|
160
|
+
|
161
|
+
context '#did_finish? is false' do
|
162
|
+
it 'should return false' do
|
163
|
+
allow(request).to receive(:did_finish?).and_return(false)
|
164
|
+
|
165
|
+
expect(subject).to eql(false)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context '#did_finish? is true' do
|
170
|
+
before(:each) do
|
171
|
+
allow(request).to receive(:did_finish?).and_return(true)
|
172
|
+
end
|
173
|
+
|
174
|
+
context '#fetch_status is not "complete"' do
|
175
|
+
before(:each) do
|
176
|
+
allow(request).to receive(:fetch_status).and_return('something')
|
177
|
+
end
|
178
|
+
|
179
|
+
it { is_expected.to eql(false) }
|
180
|
+
end
|
181
|
+
|
182
|
+
context '#fetch_status is "complete"' do
|
183
|
+
before(:each) do
|
184
|
+
allow(request).to receive(:fetch_status).and_return('complete')
|
185
|
+
end
|
186
|
+
|
187
|
+
context '#fetch_request_info error is not nil' do
|
188
|
+
before(:each) do
|
189
|
+
allow(request).to receive(:fetch_request_info).and_return({
|
190
|
+
data: { info: { error: 'error' } }
|
191
|
+
})
|
192
|
+
end
|
193
|
+
|
194
|
+
it { is_expected.to eql(false) }
|
195
|
+
end
|
196
|
+
|
197
|
+
context '#fetch_request_info error is nil' do
|
198
|
+
before(:each) do
|
199
|
+
allow(request).to receive(:fetch_request_info).and_return({
|
200
|
+
data: { info: { error: nil } }
|
201
|
+
})
|
202
|
+
end
|
203
|
+
|
204
|
+
it { is_expected.to eql(true) }
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe '#profile_info' do
|
211
|
+
let(:request) { CrystalSDK::Profile::Request.new('my_id') }
|
212
|
+
subject { request.profile_info }
|
213
|
+
|
214
|
+
context '#did_find_profile? is false' do
|
215
|
+
before(:each) do
|
216
|
+
allow(request).to receive(:did_find_profile?).and_return(false)
|
217
|
+
end
|
218
|
+
|
219
|
+
it { is_expected.to eql(nil) }
|
220
|
+
end
|
221
|
+
|
222
|
+
context '#did_find_profile? is true' do
|
223
|
+
before(:each) do
|
224
|
+
allow(request).to receive(:did_find_profile?).and_return(true)
|
225
|
+
allow(request).to receive(:fetch_request_info).and_return({
|
226
|
+
data: {
|
227
|
+
info: {
|
228
|
+
some_info: 'some_info',
|
229
|
+
deep_info: {
|
230
|
+
info: 'deep_info'
|
231
|
+
}
|
232
|
+
},
|
233
|
+
|
234
|
+
recommendations: {
|
235
|
+
some_recs: 'some_recs',
|
236
|
+
deep_recs: {
|
237
|
+
recs: 'deep_recs'
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
})
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should return hash with deep openstruct values' do
|
245
|
+
expect(subject[:info].some_info).to eql('some_info')
|
246
|
+
expect(subject[:info].deep_info.info).to eql('deep_info')
|
247
|
+
expect(subject[:recommendations].some_recs).to eql('some_recs')
|
248
|
+
expect(subject[:recommendations].deep_recs.recs).to eql('deep_recs')
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crystal_sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cory Finger
|
@@ -83,10 +83,14 @@ files:
|
|
83
83
|
- Rakefile
|
84
84
|
- crystal_sdk.gemspec
|
85
85
|
- lib/crystal_sdk.rb
|
86
|
+
- lib/crystal_sdk/api.rb
|
86
87
|
- lib/crystal_sdk/base.rb
|
87
88
|
- lib/crystal_sdk/profile.rb
|
89
|
+
- lib/crystal_sdk/profile/request.rb
|
88
90
|
- lib/crystal_sdk/version.rb
|
91
|
+
- spec/crystal_sdk/api_spec.rb
|
89
92
|
- spec/crystal_sdk/base_spec.rb
|
93
|
+
- spec/crystal_sdk/profile/request_spec.rb
|
90
94
|
- spec/crystal_sdk/profile_spec.rb
|
91
95
|
- spec/crystal_sdk/version_spec.rb
|
92
96
|
- spec/crystal_sdk_spec.rb
|
@@ -116,7 +120,9 @@ signing_key:
|
|
116
120
|
specification_version: 4
|
117
121
|
summary: Access the largest and most accurate personality database!
|
118
122
|
test_files:
|
123
|
+
- spec/crystal_sdk/api_spec.rb
|
119
124
|
- spec/crystal_sdk/base_spec.rb
|
125
|
+
- spec/crystal_sdk/profile/request_spec.rb
|
120
126
|
- spec/crystal_sdk/profile_spec.rb
|
121
127
|
- spec/crystal_sdk/version_spec.rb
|
122
128
|
- spec/crystal_sdk_spec.rb
|