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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5bacb9a91dadcdcc60eb24dd15eedcd61d25c5f3
4
- data.tar.gz: 33b610a788337ff076b128d651bf1a7150c8c2ef
3
+ metadata.gz: ed49b547a11579d80d9aa3c96dab61019d0dd47b
4
+ data.tar.gz: 49afdf1d21487a6d4def81f564feb3eec54dfc54
5
5
  SHA512:
6
- metadata.gz: 966cc07acc85cfd463c7f33b021294519c4d92f0d6cebe7bc1db209c036c1091c53b74cce502405c8e862295fe0db41385f822d7d1475373317227171f5d77e2
7
- data.tar.gz: c75662264040de042eca6e8034e054eb2da837c5be5f948aa4c4727e59be4551a206b5c65240d7f2d3b2f49eb415fd9802c78ea62f29595c35239f461109c704
6
+ metadata.gz: 55a5a0ca2e44a4df1cf4b3455703da564ffc32a39fd22e2d020c5c2a05ab9ef8b7f89e0f0559c371e64ae84bb2b5f5270ac5043efed0ea92ec7a05703519e68d
7
+ data.tar.gz: 13a84fc643b862bde2f5f3a7f7cf8cd3cf292379233d23e13324ba1a05c76ec00f919fe0b4d01a94e57bd4d8914abf1ce745b226de9d5652be19bcc5c4e2a8e7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- crystal_sdk (0.0.3)
4
+ crystal_sdk (1.0.0)
5
5
  nestful (~> 1.1)
6
6
  recursive-open-struct (~> 1.0)
7
7
 
@@ -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
@@ -1,7 +1,7 @@
1
1
  module CrystalSDK
2
2
  class Base
3
3
  class ApiKeyNotSet < StandardError; end
4
- API_URL = 'http://enterprise-api.crystalknows.com/v1'.freeze
4
+ API_URL = 'https://connect.crystalknows.com/v1'.freeze
5
5
 
6
6
  class << self
7
7
  attr_accessor :key
@@ -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
@@ -1,3 +1,3 @@
1
1
  module CrystalSDK
2
- VERSION = '0.0.4'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -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
- # it { is_expected.to start_with 'https://' }
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
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