crystal_sdk 0.0.1 → 0.0.2

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: 0a041d19a7796ed4a2dc06aa2798af49c2d94ef6
4
- data.tar.gz: bdd26fd9c95f06931ad272b382dd0ab2c2ad3ab0
3
+ metadata.gz: de9532edb29d75171cadeca8e294db49601372e1
4
+ data.tar.gz: 31b742edfd168bec378d38a770c5b4609a6ba0ab
5
5
  SHA512:
6
- metadata.gz: 18dd7df0bf745dc6131d99d6dc389586b8957df1c65987c57fa171e696acd2de66f6f4aca9806ae1b784f180aaeb28fff695cda25b85a5748e4c7a3196384f27
7
- data.tar.gz: b6d3f998e694207ad8b156708ab6de998f73c5bee1ab99e816ee6db5a225c04582b0d05a4a67e715d4f6e77838fd190d25cacb6a538db963fc7b4ff2c9e571d3
6
+ metadata.gz: 158c383df20c0ccfff8704ec8ae353bc0a502c1b0dec7c113e22ac56f4bbd5ec4af52d236898ba3c65c7f3e16ca3f69da75dacd71136800daab7b822fe0f71c1
7
+ data.tar.gz: 4963b7be68b80060582d32857112909f1180443b7b652cef7ab0d333af37c1f0692f38f807a12f5287b6e12facc7e5f806d718027eda3326a1cd4bcb28c4e12d
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ crystal_sdk (0.0.1)
5
+ nestful (~> 1.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.5.0)
11
+ public_suffix (~> 2.0, >= 2.0.2)
12
+ crack (0.4.3)
13
+ safe_yaml (~> 1.0.0)
14
+ diff-lcs (1.3)
15
+ hashdiff (0.3.2)
16
+ nestful (1.1.1)
17
+ public_suffix (2.0.5)
18
+ rspec (3.5.0)
19
+ rspec-core (~> 3.5.0)
20
+ rspec-expectations (~> 3.5.0)
21
+ rspec-mocks (~> 3.5.0)
22
+ rspec-core (3.5.4)
23
+ rspec-support (~> 3.5.0)
24
+ rspec-expectations (3.5.0)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.5.0)
27
+ rspec-mocks (3.5.0)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.5.0)
30
+ rspec-support (3.5.0)
31
+ safe_yaml (1.0.4)
32
+ webmock (2.3.2)
33
+ addressable (>= 2.3.6)
34
+ crack (>= 0.3.2)
35
+ hashdiff
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ crystal_sdk!
42
+ rspec
43
+ webmock
44
+
45
+ BUNDLED WITH
46
+ 1.13.6
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright {yyyy} {name of copyright owner}
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Crystal Ruby SDK
2
+
3
+ This gem provides access to Crystal, the world's largest and most accurate personality database!
4
+
5
+ Here's how to install it:
6
+ ```bash
7
+ $ gem install crystal_sdk
8
+ ```
9
+
10
+ Here's how you use it:
11
+
12
+ ```ruby
13
+ require 'crystal_sdk'
14
+
15
+ CrystalSDK.key = "OrgKey"
16
+
17
+ begin
18
+ profile = CrystalSDK::Profile.search({
19
+ first_name: "Drew",
20
+ last_name: "D'Agostino"
21
+ })
22
+
23
+ print "Profile found!"
24
+ print "First Name: #{profile.info.first_name}"
25
+ print "Last Name: #{profile.info.last_name}"
26
+ print "Predicted DISC Type: #{profile.info.disc_type}"
27
+ print "Prediction Confidence: #{profile.info.confidence}"
28
+ print "Personality Overview: #{profile.info.overview}"
29
+
30
+ print "Recommendations: #{profile.recommendations}"
31
+
32
+ rescue CrystalSDK::Profile::NotFoundError
33
+ print "No profile was found"
34
+
35
+ rescue CrystalSDK::Profile::NotFoundYetError
36
+ print "Profile search exceeded time limit"
37
+
38
+ rescue CrystalSDK::Profile::RateLimitHitError
39
+ print "The organization's API rate limit was hit"
40
+
41
+ rescue CrystalSDK::Profile::NotAuthedError
42
+ print "Org key was invalid"
43
+
44
+ rescue StandardError => e
45
+ print "Unexpected error occurred: #{e}"
46
+
47
+ end
48
+ ```
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ task :console do
2
+ exec "irb -r crystal_sdk -I ./lib"
3
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'lib/crystal_sdk/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'crystal_sdk'
5
+ s.version = CrystalSDK::VERSION
6
+ s.date = '2017-02-22'
7
+ s.summary = 'Access the largest and most accurate personality database!'
8
+ s.description = 'The Enterprise SDK for https://www.crystalknows.com/ - the largest and most accurate personality database!'
9
+ s.authors = ['Cory Finger', 'Nicholas Picciuto']
10
+ s.email = 'hello@crystalknows.com'
11
+ s.files = ['lib/crystal_sdk.rb']
12
+ s.homepage =
13
+ 'https://github.com/crystal-project-inc/ruby_sdk'
14
+ s.license = 'Apache-2.0'
15
+
16
+ s.files = `git ls-files`.split($/)
17
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_dependency 'nestful', '~> 1.1'
22
+ s.add_development_dependency 'rspec'
23
+ s.add_development_dependency 'webmock'
24
+ end
@@ -0,0 +1,15 @@
1
+ module CrystalSDK
2
+ class Base
3
+ class ApiKeyNotSet < StandardError; end
4
+ API_URL = 'http://enterprise-api.crystalknows.com/v1'.freeze
5
+
6
+ class << self
7
+ attr_accessor :key
8
+
9
+ def key!
10
+ raise ApiKeyNotSet unless key
11
+ key
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ module CrystalSDK
2
+ class Profile
3
+ class NotFoundError < StandardError; end
4
+ class NotFoundYetError < StandardError; end
5
+ class NotAuthedError < StandardError; end
6
+ class RateLimitHitError < StandardError; end
7
+ class UnexpectedError < StandardError; end
8
+
9
+ attr_reader :info, :recommendations
10
+
11
+ def initialize(info, recommendations)
12
+ @info = info
13
+ @recommendations = recommendations
14
+ end
15
+
16
+ class << self
17
+ def search(query)
18
+ begin
19
+ resp = make_request(:post, 'person_search', params: query)
20
+ body = resp.body ? JSON.parse(resp.body, symbolize_names: true) : nil
21
+
22
+ rescue Nestful::ResponseError => e
23
+ check_for_error(e.response)
24
+ raise e
25
+ end
26
+
27
+ check_for_error(resp)
28
+ new(body[:info], body[:recommendations])
29
+ end
30
+
31
+ 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
+ raise RateLimitHitError if resp.code == '429'
37
+ 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
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ module CrystalSDK
2
+ VERSION = '0.0.2'.freeze
3
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe CrystalSDK::Base do
4
+ subject { CrystalSDK::Base }
5
+
6
+ it { is_expected.not_to be_nil }
7
+ it { is_expected.to respond_to(:key) }
8
+ it { is_expected.to respond_to(:key=) }
9
+
10
+ describe 'API_URL' do
11
+ subject { CrystalSDK::Base::API_URL }
12
+
13
+ it { is_expected.to include '.crystalknows.com' }
14
+ it { is_expected.to start_with 'https://' }
15
+ it { is_expected.to_not end_with '/' }
16
+ end
17
+
18
+ describe '.key!' do
19
+ subject { CrystalSDK::Base.key! }
20
+
21
+ context 'no key is set' do
22
+ before(:each) do
23
+ allow(CrystalSDK::Base).to receive(:key).and_return(nil)
24
+ end
25
+
26
+ it 'should raise ApiKeyNotSet' do
27
+ expect { subject }.to raise_error(CrystalSDK::Base::ApiKeyNotSet)
28
+ end
29
+ end
30
+
31
+ context 'key is set' do
32
+ before(:each) do
33
+ allow(CrystalSDK::Base).to receive(:key).and_return('SomeKey')
34
+ end
35
+
36
+ it { is_expected.to eql(CrystalSDK::Base.key) }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ describe CrystalSDK::Profile do
4
+ subject { CrystalSDK::Profile }
5
+
6
+ describe '.search' do
7
+ subject { CrystalSDK::Profile.search(query) }
8
+ let(:query) { { some_param: 'a_param' } }
9
+ let(:endpoint) { 'person_search' }
10
+ let(:request_type) { :post }
11
+
12
+ 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))
19
+
20
+ expect(subject.info).to eql('info')
21
+ expect(subject.recommendations).to eql('recs')
22
+ end
23
+
24
+ context 'make_request raised unexpected error' do
25
+ before(:each) do
26
+ allow(CrystalSDK::Profile).to receive(:make_request)
27
+ .with(request_type, endpoint, params: query)
28
+ .and_raise("SomeRandomError")
29
+ end
30
+
31
+ it 'should not suppress the error' do
32
+ expect { subject }.to raise_error('SomeRandomError')
33
+ end
34
+ end
35
+
36
+ context 'make_request raised expected error' do
37
+ before(:each) do
38
+ allow(CrystalSDK::Profile).to receive(:make_request)
39
+ .with(request_type, endpoint, params: query)
40
+ .and_raise(Nestful::ResponseError.new(nil, double()))
41
+ end
42
+
43
+ it 'should pass it off to check_for_error' do
44
+ expect(CrystalSDK::Profile).to receive(:check_for_error)
45
+ .and_raise('CheckForErrorCalled')
46
+
47
+ expect { subject }.to raise_error('CheckForErrorCalled')
48
+ end
49
+
50
+ it 'should still raise exception if passed check_for_error' do
51
+ expect(CrystalSDK::Profile).to receive(:check_for_error)
52
+ .and_return(nil)
53
+
54
+ expect { subject }.to raise_error
55
+ end
56
+ end
57
+
58
+ context 'make_request raised no error' do
59
+ before(:each) do
60
+ allow(CrystalSDK::Profile).to receive(:make_request)
61
+ .with(request_type, endpoint, params: query)
62
+ .and_return(response)
63
+ end
64
+
65
+ let(:response) do
66
+ double(code: '200', body: { resp: 'some_resp' }.to_json)
67
+ end
68
+
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')
73
+
74
+ expect { subject }.to raise_error('CheckForErrorCalled')
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '.check_for_error' do
80
+ subject { CrystalSDK::Profile.check_for_error(resp) }
81
+
82
+ context '200' do
83
+ let(:resp) do
84
+ body = { status: 'profile_found', info: nil, recommendations: nil }
85
+ double(body: body.to_json, code: '200')
86
+ end
87
+
88
+ it 'should raise no error' do
89
+ expect { subject }.to_not raise_error
90
+ end
91
+ end
92
+
93
+ context '202' do
94
+ let(:resp) { double(body: nil, code: '202') }
95
+
96
+ it 'should raise NotFoundYetError' do
97
+ expect { subject }.to raise_error(CrystalSDK::Profile::NotFoundYetError)
98
+ end
99
+ end
100
+
101
+ context '401' do
102
+ let(:resp) { double(body: nil, code: '401') }
103
+
104
+ it 'should raise NotAuthedError' do
105
+ expect { subject }.to raise_error(CrystalSDK::Profile::NotAuthedError)
106
+ end
107
+ end
108
+
109
+ context '404' do
110
+ let(:resp) { double(body: nil, code: '404') }
111
+
112
+ it 'should raise NotFoundError' do
113
+ expect { subject }.to raise_error(CrystalSDK::Profile::NotFoundError)
114
+ end
115
+ end
116
+
117
+ context '429' do
118
+ let(:resp) { double(body: nil, code: '429') }
119
+
120
+ it 'should raise RateLimitHitError' do
121
+ expect { subject }.to raise_error(CrystalSDK::Profile::RateLimitHitError)
122
+ end
123
+ end
124
+ 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
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'CrystalSDK::VERSION' do
4
+ subject { CrystalSDK::VERSION }
5
+
6
+ it 'should contain 2 dots' do
7
+ expect(subject.count('.')).to eql(2)
8
+ end
9
+
10
+ it 'should contain only numbers' do
11
+ numbers = subject.split('.')
12
+
13
+ expect { Float(numbers[0]) }.to_not raise_error
14
+ expect { Float(numbers[1]) }.to_not raise_error
15
+ expect { Float(numbers[2]) }.to_not raise_error
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe CrystalSDK do
4
+ it { is_expected.not_to be_nil }
5
+ it { is_expected.to respond_to(:key) }
6
+ it { is_expected.to respond_to(:key=) }
7
+ it { is_expected.to respond_to(:api_key) }
8
+ it { is_expected.to respond_to(:api_key=) }
9
+ end
@@ -0,0 +1,11 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'webmock/rspec'
5
+ require 'crystal_sdk'
6
+
7
+ WebMock.disable_net_connect!(allow_localhost: true)
8
+
9
+ RSpec.configure do |config|
10
+ # some (optional) config here
11
+ 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.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cory Finger
@@ -25,6 +25,34 @@ dependencies:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
27
  version: '1.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: webmock
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
28
56
  description: The Enterprise SDK for https://www.crystalknows.com/ - the largest and
29
57
  most accurate personality database!
30
58
  email: hello@crystalknows.com
@@ -32,7 +60,23 @@ executables: []
32
60
  extensions: []
33
61
  extra_rdoc_files: []
34
62
  files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - Gemfile
66
+ - Gemfile.lock
67
+ - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - crystal_sdk.gemspec
35
71
  - lib/crystal_sdk.rb
72
+ - lib/crystal_sdk/base.rb
73
+ - lib/crystal_sdk/profile.rb
74
+ - lib/crystal_sdk/version.rb
75
+ - spec/crystal_sdk/base_spec.rb
76
+ - spec/crystal_sdk/profile_spec.rb
77
+ - spec/crystal_sdk/version_spec.rb
78
+ - spec/crystal_sdk_spec.rb
79
+ - spec/spec_helper.rb
36
80
  homepage: https://github.com/crystal-project-inc/ruby_sdk
37
81
  licenses:
38
82
  - Apache-2.0
@@ -57,4 +101,9 @@ rubygems_version: 2.6.8
57
101
  signing_key:
58
102
  specification_version: 4
59
103
  summary: Access the largest and most accurate personality database!
60
- test_files: []
104
+ test_files:
105
+ - spec/crystal_sdk/base_spec.rb
106
+ - spec/crystal_sdk/profile_spec.rb
107
+ - spec/crystal_sdk/version_spec.rb
108
+ - spec/crystal_sdk_spec.rb
109
+ - spec/spec_helper.rb