crystal_sdk 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fd4e7ecf961055dfbc0bf3b455c2783b86a2eb67
4
- data.tar.gz: e86384b92510c84344039a3e3c25d3eb21d55b2d
3
+ metadata.gz: 5bacb9a91dadcdcc60eb24dd15eedcd61d25c5f3
4
+ data.tar.gz: 33b610a788337ff076b128d651bf1a7150c8c2ef
5
5
  SHA512:
6
- metadata.gz: c47c7d9b915132174469e933a0ff2a0cdff481293aa26a7845fc589bedaa9f79a10d9d2345fa2fb6c8d96fc87ae19bff5ddc02af06e77485408832e7172b1520
7
- data.tar.gz: 737e642ecf5b811cde11a799af584c587bfd9af5fe515fcb89c05a1eadb23914393a09421720a6a10b834cfdf8e1dfa3347ea105753694fb42f1ac3684c19470
6
+ metadata.gz: 966cc07acc85cfd463c7f33b021294519c4d92f0d6cebe7bc1db209c036c1091c53b74cce502405c8e862295fe0db41385f822d7d1475373317227171f5d77e2
7
+ data.tar.gz: c75662264040de042eca6e8034e054eb2da837c5be5f948aa4c4727e59be4551a206b5c65240d7f2d3b2f49eb415fd9802c78ea62f29595c35239f461109c704
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- crystal_sdk (0.0.2)
4
+ crystal_sdk (0.0.3)
5
5
  nestful (~> 1.1)
6
+ recursive-open-struct (~> 1.0)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -15,6 +16,7 @@ GEM
15
16
  hashdiff (0.3.2)
16
17
  nestful (1.1.1)
17
18
  public_suffix (2.0.5)
19
+ recursive-open-struct (1.0.2)
18
20
  rspec (3.5.0)
19
21
  rspec-core (~> 3.5.0)
20
22
  rspec-expectations (~> 3.5.0)
data/crystal_sdk.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ['lib']
20
20
 
21
21
  s.add_dependency 'nestful', '~> 1.1'
22
+ s.add_dependency 'recursive-open-struct', '~> 1.0'
22
23
  s.add_development_dependency 'rspec'
23
24
  s.add_development_dependency 'webmock'
24
25
  end
data/lib/crystal_sdk.rb CHANGED
@@ -3,6 +3,7 @@ require 'crystal_sdk/version'
3
3
 
4
4
  module CrystalSDK
5
5
  autoload :Base, 'crystal_sdk/base'
6
+ autoload :Api, 'crystal_sdk/api'
6
7
  autoload :Profile, 'crystal_sdk/profile'
7
8
 
8
9
  crystal_env_key = ENV['CRYSTAL_KEY']
@@ -1,11 +1,22 @@
1
+ require 'timeout'
2
+ require_relative 'profile/request'
3
+
1
4
  module CrystalSDK
2
5
  class Profile
3
6
  class NotFoundError < StandardError; end
4
- class NotFoundYetError < StandardError; end
5
7
  class NotAuthedError < StandardError; end
6
8
  class RateLimitHitError < StandardError; end
7
9
  class UnexpectedError < StandardError; end
8
10
 
11
+ class NotFoundYetError < StandardError
12
+ attr_reader :request
13
+
14
+ def initialize(request, msg = 'Profile not found in time')
15
+ @request = request
16
+ super(msg)
17
+ end
18
+ end
19
+
9
20
  attr_reader :info, :recommendations
10
21
 
11
22
  def initialize(info, recommendations)
@@ -14,46 +25,40 @@ module CrystalSDK
14
25
  end
15
26
 
16
27
  class << self
17
- def search(query)
28
+ def from_request(req)
29
+ return nil unless req.did_find_profile?
30
+
31
+ profile_info = req.profile_info
32
+ Profile.new(profile_info[:info], profile_info[:recommendations])
33
+ end
34
+
35
+ def search(query, timeout: 30)
36
+ request = nil
37
+
18
38
  begin
19
- resp = make_request(:post, 'person_search', params: query)
20
- body = resp.body ? JSON.parse(resp.body, symbolize_names: true) : nil
39
+ Timeout.timeout(timeout) do
40
+ request = Profile::Request.from_search(query)
41
+
42
+ loop do
43
+ sleep(2) && next unless request.did_finish?
44
+
45
+ raise NotFoundError unless request.did_find_profile?
46
+ return Profile.from_request(request)
47
+ end
48
+ end
49
+ rescue Timeout::Error
50
+ raise NotFoundYetError.new(request)
21
51
 
22
52
  rescue Nestful::ResponseError => e
23
53
  check_for_error(e.response)
24
54
  raise e
25
55
  end
26
-
27
- check_for_error(resp)
28
- new(body[:info], body[:recommendations])
29
56
  end
30
57
 
31
58
  def check_for_error(resp)
32
- body = resp.body ? JSON.parse(resp.body, symbolize_names: true) : nil
33
- not_found = body && body[:status] == 'profile_not_found'
34
- not_found_yet = body && body[:status] == 'profile_not_found_yet'
35
-
36
59
  raise RateLimitHitError if resp.code == '429'
37
60
  raise NotAuthedError if resp.code == '401'
38
- raise NotFoundError if resp.code == '404' || not_found
39
- raise NotFoundYetError if resp.code == '202' || not_found_yet
40
- raise UnexpectedError unless resp.code == '200'
41
- end
42
-
43
- def make_request(type, endpoint, params: {}, headers: {})
44
- headers = headers.merge(
45
- 'X-Org-Token' => Base.key!,
46
- 'X-Sdk-Version' => VERSION
47
- )
48
-
49
- opts = {
50
- method: type,
51
- headers: headers,
52
- params: params,
53
- format: :json
54
- }
55
-
56
- Nestful::Request.new("#{Base::API_URL}/#{endpoint}", opts).execute
61
+ raise NotFoundError if resp.code == '404'
57
62
  end
58
63
  end
59
64
  end
@@ -1,3 +1,3 @@
1
1
  module CrystalSDK
2
- VERSION = '0.0.3'.freeze
2
+ VERSION = '0.0.4'.freeze
3
3
  end
@@ -6,26 +6,27 @@ describe CrystalSDK::Profile do
6
6
  describe '.search' do
7
7
  subject { CrystalSDK::Profile.search(query) }
8
8
  let(:query) { { some_param: 'a_param' } }
9
- let(:endpoint) { 'person_search' }
10
- let(:request_type) { :post }
11
9
 
12
10
  it 'should use the correct request' do
13
- expect(CrystalSDK::Profile).to receive(:make_request)
14
- .with(request_type, endpoint, params: query)
15
- .and_return(double(code: '200', body: {
16
- info: 'info',
17
- recommendations: 'recs'
18
- }.to_json))
11
+ resp = double(
12
+ did_finish?: true,
13
+ did_find_profile?: true,
14
+ profile_info: { info: 'info', recommendations: 'recs' }
15
+ )
16
+
17
+ expect(CrystalSDK::Profile::Request).to receive(:from_search)
18
+ .with(query)
19
+ .and_return(resp)
19
20
 
20
21
  expect(subject.info).to eql('info')
21
22
  expect(subject.recommendations).to eql('recs')
22
23
  end
23
24
 
24
- context 'make_request raised unexpected error' do
25
+ context 'request creation raised unexpected error' do
25
26
  before(:each) do
26
- allow(CrystalSDK::Profile).to receive(:make_request)
27
- .with(request_type, endpoint, params: query)
28
- .and_raise("SomeRandomError")
27
+ expect(CrystalSDK::Profile::Request).to receive(:from_search)
28
+ .with(query)
29
+ .and_raise('SomeRandomError')
29
30
  end
30
31
 
31
32
  it 'should not suppress the error' do
@@ -33,10 +34,15 @@ describe CrystalSDK::Profile do
33
34
  end
34
35
  end
35
36
 
36
- context 'make_request raised expected error' do
37
+ context 'request info raised expected error' do
38
+ let(:req) { double() }
39
+
37
40
  before(:each) do
38
- allow(CrystalSDK::Profile).to receive(:make_request)
39
- .with(request_type, endpoint, params: query)
41
+ allow(CrystalSDK::Profile::Request).to receive(:from_search)
42
+ .with(query)
43
+ .and_return(req)
44
+
45
+ allow(req).to receive(:did_finish?)
40
46
  .and_raise(Nestful::ResponseError.new(nil, double()))
41
47
  end
42
48
 
@@ -55,23 +61,37 @@ describe CrystalSDK::Profile do
55
61
  end
56
62
  end
57
63
 
58
- context 'make_request raised no error' do
64
+ context 'request did not find profile' do
59
65
  before(:each) do
60
- allow(CrystalSDK::Profile).to receive(:make_request)
61
- .with(request_type, endpoint, params: query)
66
+ allow(CrystalSDK::Profile::Request).to receive(:from_search)
67
+ .with(query)
62
68
  .and_return(response)
63
69
  end
64
70
 
65
71
  let(:response) do
66
- double(code: '200', body: { resp: 'some_resp' }.to_json)
72
+ double(did_finish?: true, did_find_profile?: false)
67
73
  end
68
74
 
69
- it 'should still pass through check_for_error' do
70
- expect(CrystalSDK::Profile).to receive(:check_for_error)
71
- .with(response)
72
- .and_raise('CheckForErrorCalled')
75
+ it 'should raise NotFoundError' do
76
+ expect { subject }.to raise_error(CrystalSDK::Profile::NotFoundError)
77
+ end
78
+ end
73
79
 
74
- expect { subject }.to raise_error('CheckForErrorCalled')
80
+ context 'request did not finish before timeout expired' do
81
+ subject { CrystalSDK::Profile.search(query, timeout: 1) }
82
+
83
+ before(:each) do
84
+ allow(CrystalSDK::Profile::Request).to receive(:from_search)
85
+ .with(query)
86
+ .and_return(response)
87
+ end
88
+
89
+ let(:response) do
90
+ double(did_finish?: false)
91
+ end
92
+
93
+ it 'should raise NotFoundYetError' do
94
+ expect { subject }.to raise_error(CrystalSDK::Profile::NotFoundYetError)
75
95
  end
76
96
  end
77
97
  end
@@ -81,8 +101,7 @@ describe CrystalSDK::Profile do
81
101
 
82
102
  context '200' do
83
103
  let(:resp) do
84
- body = { status: 'profile_found', info: nil, recommendations: nil }
85
- double(body: body.to_json, code: '200')
104
+ double(code: '200')
86
105
  end
87
106
 
88
107
  it 'should raise no error' do
@@ -91,15 +110,15 @@ describe CrystalSDK::Profile do
91
110
  end
92
111
 
93
112
  context '202' do
94
- let(:resp) { double(body: nil, code: '202') }
113
+ let(:resp) { double(code: '202') }
95
114
 
96
- it 'should raise NotFoundYetError' do
97
- expect { subject }.to raise_error(CrystalSDK::Profile::NotFoundYetError)
115
+ it 'should raise no error' do
116
+ expect { subject }.to_not raise_error
98
117
  end
99
118
  end
100
119
 
101
120
  context '401' do
102
- let(:resp) { double(body: nil, code: '401') }
121
+ let(:resp) { double(code: '401') }
103
122
 
104
123
  it 'should raise NotAuthedError' do
105
124
  expect { subject }.to raise_error(CrystalSDK::Profile::NotAuthedError)
@@ -107,7 +126,7 @@ describe CrystalSDK::Profile do
107
126
  end
108
127
 
109
128
  context '404' do
110
- let(:resp) { double(body: nil, code: '404') }
129
+ let(:resp) { double(code: '404') }
111
130
 
112
131
  it 'should raise NotFoundError' do
113
132
  expect { subject }.to raise_error(CrystalSDK::Profile::NotFoundError)
@@ -115,101 +134,11 @@ describe CrystalSDK::Profile do
115
134
  end
116
135
 
117
136
  context '429' do
118
- let(:resp) { double(body: nil, code: '429') }
137
+ let(:resp) { double(code: '429') }
119
138
 
120
139
  it 'should raise RateLimitHitError' do
121
140
  expect { subject }.to raise_error(CrystalSDK::Profile::RateLimitHitError)
122
141
  end
123
142
  end
124
143
  end
125
-
126
- describe '.make_request' do
127
- context 'without api key' do
128
- it 'should raise an error' do
129
- expect { subject.make_request(:post, 'test') }
130
- .to raise_error(CrystalSDK::Base::ApiKeyNotSet)
131
- end
132
- end
133
-
134
- context 'with api key' do
135
- subject { CrystalSDK::Profile.make_request(:post, 'test_endpoint') }
136
-
137
- let(:headers) do
138
- {
139
- 'X-Org-Token' => 'SomeToken',
140
- 'X-Sdk-Version' => CrystalSDK::VERSION
141
- }
142
- end
143
-
144
- let(:stubbed_req) do
145
- stub_request(:post, "#{CrystalSDK::Base::API_URL}/test_endpoint")
146
- .with(headers: headers)
147
- end
148
-
149
- before(:each) do
150
- allow(CrystalSDK::Base).to receive(:key).and_return('SomeToken')
151
- end
152
-
153
- context 'got 4xx response code' do
154
- it 'should raise an error' do
155
- stubbed_req
156
- .to_return(status: 404, body: '{}', headers: {})
157
-
158
- expect { subject }.to raise_error
159
- end
160
- end
161
-
162
- context 'got 5xx response code' do
163
- it 'should raise error on 5xx responses' do
164
- stubbed_req
165
- .to_return(status: 500, body: '{}', headers: {})
166
-
167
- expect { subject }.to raise_error
168
- end
169
- end
170
-
171
- context 'got 2xx response code' do
172
- it 'should return correct response' do
173
- stubbed_req
174
- .to_return(status: 200, body: 'stubbed', headers: {})
175
-
176
- expect(subject.code).to eql(200)
177
- expect(subject.body).to eql('stubbed')
178
- end
179
- end
180
-
181
- context 'given params' do
182
- subject do
183
- CrystalSDK::Profile
184
- .make_request(:post, 'test_endpoint', params: params)
185
- end
186
- let(:params) { { some_param: '123'} }
187
-
188
- it 'should turn params into json body' do
189
- stubbed_req
190
- .with(body: params.to_json)
191
- .to_return(status: 200, body: 'stubbed', headers: {})
192
-
193
- expect { subject }.to_not raise_error
194
- end
195
- end
196
-
197
-
198
- context 'given headers' do
199
- subject do
200
- CrystalSDK::Profile
201
- .make_request(:post, 'test_endpoint', headers: headers)
202
- end
203
- let(:headers) { { 'X-Some-Header' => '123' } }
204
-
205
- it 'should turn params into json body' do
206
- stubbed_req
207
- .with(headers: headers)
208
- .to_return(status: 200, body: 'stubbed', headers: {})
209
-
210
- expect { subject }.to_not raise_error
211
- end
212
- end
213
- end
214
- end
215
144
  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.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cory Finger
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '1.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: recursive-open-struct
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.0'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: rspec
30
44
  requirement: !ruby/object:Gem::Requirement