blockscore 4.0.0 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +58 -0
- data/.hound.yml +217 -0
- data/Gemfile +19 -7
- data/LICENSE +21 -0
- data/README.md +37 -33
- data/Rakefile +1 -15
- data/blockscore.gemspec +30 -81
- data/circle.yml +13 -0
- data/lib/blockscore.rb +43 -4
- data/lib/blockscore/actions/all.rb +27 -0
- data/lib/blockscore/actions/create.rb +34 -0
- data/lib/blockscore/actions/delete.rb +31 -0
- data/lib/blockscore/actions/retrieve.rb +24 -0
- data/lib/blockscore/actions/update.rb +46 -0
- data/lib/blockscore/base.rb +117 -0
- data/lib/blockscore/candidate.rb +32 -0
- data/lib/blockscore/collection.rb +12 -0
- data/lib/blockscore/company.rb +7 -0
- data/lib/blockscore/connection.rb +65 -0
- data/lib/blockscore/dispatch.rb +26 -0
- data/lib/blockscore/errors/api_connection_error.rb +6 -0
- data/lib/blockscore/errors/api_error.rb +33 -0
- data/lib/blockscore/errors/authentication_error.rb +4 -0
- data/lib/blockscore/errors/error.rb +4 -0
- data/lib/blockscore/errors/invalid_request_error.rb +29 -0
- data/lib/blockscore/errors/no_api_key_error.rb +4 -0
- data/lib/blockscore/errors/not_found_error.rb +4 -0
- data/lib/blockscore/fingerprint.rb +46 -0
- data/lib/blockscore/person.rb +14 -0
- data/lib/blockscore/question_set.rb +26 -0
- data/lib/blockscore/response.rb +29 -0
- data/lib/blockscore/util.rb +80 -0
- data/lib/blockscore/version.rb +3 -0
- data/lib/blockscore/watchlist_hit.rb +4 -0
- metadata +82 -48
- data/LICENSE.txt +0 -20
- data/VERSION +0 -1
- data/blockscore-ruby.sublime-project +0 -21
- data/lib/blockscore/candidates.rb +0 -49
- data/lib/blockscore/client.rb +0 -81
- data/lib/blockscore/companies.rb +0 -36
- data/lib/blockscore/error/authorization_error.rb +0 -13
- data/lib/blockscore/error/blockscore_error.rb +0 -26
- data/lib/blockscore/error/error_handler.rb +0 -141
- data/lib/blockscore/error/internal_server_error.rb +0 -19
- data/lib/blockscore/error/not_found_error.rb +0 -12
- data/lib/blockscore/error/parameter_error.rb +0 -12
- data/lib/blockscore/error/validation_error.rb +0 -28
- data/lib/blockscore/errors.rb +0 -3
- data/lib/blockscore/people.rb +0 -37
- data/lib/blockscore/question_sets.rb +0 -49
- data/lib/blockscore/watchlists.rb +0 -18
- data/test/helper.rb +0 -37
- data/test/test_blockscore.rb +0 -226
@@ -0,0 +1,32 @@
|
|
1
|
+
module BlockScore
|
2
|
+
class Candidate < BlockScore::Base
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
include BlockScore::Actions::Create
|
6
|
+
include BlockScore::Actions::Retrieve
|
7
|
+
include BlockScore::Actions::Update
|
8
|
+
include BlockScore::Actions::Delete
|
9
|
+
include BlockScore::Actions::All
|
10
|
+
|
11
|
+
def_delegators 'self.class', :api_url, :endpoint, :get, :post
|
12
|
+
|
13
|
+
def history
|
14
|
+
resource_member 'history'
|
15
|
+
end
|
16
|
+
|
17
|
+
def hits
|
18
|
+
resource_member 'hits'
|
19
|
+
end
|
20
|
+
|
21
|
+
def search(options = {})
|
22
|
+
options[:candidate_id] = id
|
23
|
+
post "#{api_url}watchlists", options
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def resource_member(member)
|
29
|
+
get "#{endpoint}/#{id}/#{member}", {}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module BlockScore
|
2
|
+
module Connection
|
3
|
+
def get(path, params)
|
4
|
+
request :get, path, params
|
5
|
+
end
|
6
|
+
|
7
|
+
def post(path, params)
|
8
|
+
request(:post, path, params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def patch(path, params)
|
12
|
+
request(:patch, path, params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def put(path, params)
|
16
|
+
request(:put, path, params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(path, params)
|
20
|
+
request(:delete, path, params)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def headers
|
26
|
+
@headers ||= {
|
27
|
+
'Accept' => "application/vnd.blockscore+json;version=#{BlockScore::VERSION.to_i}",
|
28
|
+
'User-Agent' => "blockscore-ruby/#{BlockScore::VERSION} (https://github.com/BlockScore/blockscore-ruby)",
|
29
|
+
'Content-Type' => 'application/json'
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def request(method, path, params)
|
34
|
+
fail NoAPIKeyError, 'No API key was provided.' unless BlockScore.api_key
|
35
|
+
|
36
|
+
begin
|
37
|
+
response = execute_request(method, path, params)
|
38
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
39
|
+
fail APIConnectionError, e.message
|
40
|
+
end
|
41
|
+
|
42
|
+
Response.handle_response(resource, response)
|
43
|
+
end
|
44
|
+
|
45
|
+
def execute_request(method, path, params)
|
46
|
+
auth = { :username => BlockScore.api_key, :password => '' }
|
47
|
+
|
48
|
+
if method == :get
|
49
|
+
path = encode_path_params(path, params)
|
50
|
+
params = nil
|
51
|
+
else
|
52
|
+
params = params.to_json
|
53
|
+
end
|
54
|
+
|
55
|
+
options = { :basic_auth => auth, :headers => headers, :body => params }
|
56
|
+
|
57
|
+
HTTParty.send(method, path, options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def encode_path_params(path, params)
|
61
|
+
encoded = URI.encode_www_form(params)
|
62
|
+
[path, encoded].join("?")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BlockScore
|
2
|
+
class Dispatch
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :@fingerprint, :builder, :data, :resource
|
6
|
+
|
7
|
+
def initialize(resource, response)
|
8
|
+
@fingerprint = Fingerprint.new(resource, response.body)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
Util.send(builder, resource, data)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def builder
|
18
|
+
resource_array? ? :create_array : :create_object
|
19
|
+
end
|
20
|
+
|
21
|
+
# array formatted response
|
22
|
+
def resource_array?
|
23
|
+
data.is_a?(Array)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module BlockScore
|
2
|
+
class APIError < Error
|
3
|
+
attr_reader :http_status
|
4
|
+
attr_reader :error_type
|
5
|
+
attr_reader :http_body
|
6
|
+
|
7
|
+
# Public: Creates a new instance of BlockScore::Error.
|
8
|
+
#
|
9
|
+
# rbody - The HTTP response body from HTTParty.
|
10
|
+
# rcode - The HTTP response code from HTTParty.
|
11
|
+
#
|
12
|
+
# While BlockScore::Error can be instantiated, the more meaningful
|
13
|
+
# error classes are its subclasses:
|
14
|
+
# InvalidRequestError - Indicates a malformed request (HTTP 400 or 404)
|
15
|
+
# APIError - Indicates an error on the server side (HTTP 5xx)
|
16
|
+
# AuthenticationError - Indicates an authentication error (HTTP 401)
|
17
|
+
def initialize(response)
|
18
|
+
body = JSON.parse(response.body, :symbolize_names => true)
|
19
|
+
|
20
|
+
@message = body[:error][:message]
|
21
|
+
@http_status = response.code
|
22
|
+
@error_type = body[:error][:type]
|
23
|
+
@http_body = body
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
status_string = @http_status ? "(Status: #{@http_status})" : ""
|
28
|
+
type_string = @error_type ? "(Type: #{@error_type})" : ""
|
29
|
+
|
30
|
+
"#{type_string} #{@message} #{status_string}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module BlockScore
|
2
|
+
class InvalidRequestError < APIError
|
3
|
+
attr_accessor :param
|
4
|
+
|
5
|
+
# Public: Creates a new instance of BlockScore::InvalidRequestError.
|
6
|
+
#
|
7
|
+
# responses - The HTTP response body from HTTParty.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# begin
|
12
|
+
# response = BlockScore::Person.create(...)
|
13
|
+
# rescue BlockScore::InvalidRequestError => e
|
14
|
+
# puts "ERROR: #{e.message} with code #{e.http_status}"
|
15
|
+
# end
|
16
|
+
def initialize(response)
|
17
|
+
super
|
18
|
+
@param = @http_body[:error][:param]
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
status_string = @http_status ? "(Status: #{@http_status})" : ""
|
23
|
+
type_string = @error_type ? "(Type: #{@error_type})" : ""
|
24
|
+
param_string = @param ? "(#{@param})" : ""
|
25
|
+
|
26
|
+
"#{type_string} #{@message} #{param_string} #{status_string}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module BlockScore
|
2
|
+
class Fingerprint
|
3
|
+
def initialize(resource, body)
|
4
|
+
@resource = resource
|
5
|
+
@body = Util.parse_json(body)
|
6
|
+
end
|
7
|
+
|
8
|
+
def data
|
9
|
+
@data ||= begin
|
10
|
+
if watchlist_search?
|
11
|
+
body[:matches]
|
12
|
+
elsif resource_index?
|
13
|
+
body[:data]
|
14
|
+
else
|
15
|
+
body
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def resource
|
21
|
+
if watchlist_search? || watchlist_hits?
|
22
|
+
'watchlist_hit'
|
23
|
+
else
|
24
|
+
@resource
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :body
|
31
|
+
|
32
|
+
# candidates#search endpoint
|
33
|
+
def watchlist_search?
|
34
|
+
body.respond_to?(:key?) && body.key?(:matches)
|
35
|
+
end
|
36
|
+
|
37
|
+
# hash style list format
|
38
|
+
def resource_index?
|
39
|
+
body.is_a?(Hash) && body[:object] == 'list'
|
40
|
+
end
|
41
|
+
|
42
|
+
def watchlist_hits?
|
43
|
+
data.first.is_a?(Hash) && data.first.key?(:matching_info)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module BlockScore
|
2
|
+
class Person < Base
|
3
|
+
include BlockScore::Actions::Create
|
4
|
+
include BlockScore::Actions::Retrieve
|
5
|
+
include BlockScore::Actions::All
|
6
|
+
|
7
|
+
attr_reader :question_sets
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
super
|
11
|
+
@question_sets = Collection.new(QuestionSet.new(:person => self))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BlockScore
|
2
|
+
class QuestionSet < Base
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
include BlockScore::Actions::Create
|
6
|
+
include BlockScore::Actions::Retrieve
|
7
|
+
include BlockScore::Actions::All
|
8
|
+
|
9
|
+
def_delegators 'self.class', :retrieve, :all, :post, :endpoint
|
10
|
+
|
11
|
+
def create
|
12
|
+
result = self.class.create(:person_id => person.id)
|
13
|
+
person.question_sets << result.id
|
14
|
+
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
def score(answers = nil)
|
19
|
+
if answers.nil? && attributes
|
20
|
+
attributes[:score]
|
21
|
+
else
|
22
|
+
post "#{endpoint}/#{id}/score", :answers => answers
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module BlockScore
|
2
|
+
module Response
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def handle_response(resource, response)
|
6
|
+
case response.code
|
7
|
+
when 200, 201
|
8
|
+
Dispatch.new(resource, response).call
|
9
|
+
else
|
10
|
+
api_error(response)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def api_error(response)
|
17
|
+
case response.code
|
18
|
+
when 400
|
19
|
+
fail InvalidRequestError.new(response)
|
20
|
+
when 401
|
21
|
+
fail AuthenticationError.new(response)
|
22
|
+
when 404
|
23
|
+
fail NotFoundError.new(response)
|
24
|
+
else
|
25
|
+
fail APIError.new(response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module BlockScore
|
2
|
+
module Util
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def parse_json!(json_obj)
|
6
|
+
JSON.parse(json_obj, :symbolize_names => true)
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_json(json_obj)
|
10
|
+
parse_json! json_obj
|
11
|
+
rescue JSON::ParserError
|
12
|
+
fail Error, "An error has occurred. If this problem persists, please message support@blockscore.com."
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_object(resource, options = {})
|
16
|
+
to_constant("BlockScore::#{to_camelcase(resource)}").new(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_array(resource, arr)
|
20
|
+
arr.map { |obj| create_object(resource, obj) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_plural(str)
|
24
|
+
if str.end_with? 'y'
|
25
|
+
str[0..-2] + 'ies'
|
26
|
+
elsif str.end_with? 'h'
|
27
|
+
str + 'es'
|
28
|
+
elsif str == 'person'
|
29
|
+
'people'
|
30
|
+
else
|
31
|
+
str + 's'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Taken from activesupport: http://git.io/vkWtR
|
36
|
+
def to_constant(camel_cased_word)
|
37
|
+
names = camel_cased_word.split('::')
|
38
|
+
|
39
|
+
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
40
|
+
Object.const_get(camel_cased_word) if names.empty?
|
41
|
+
|
42
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
43
|
+
names.shift if names.size > 1 && names.first.empty?
|
44
|
+
|
45
|
+
names.inject(Object) do |constant, name|
|
46
|
+
if constant == Object
|
47
|
+
constant.const_get(name)
|
48
|
+
else
|
49
|
+
candidate = constant.const_get(name)
|
50
|
+
next candidate if constant.const_defined?(name, false)
|
51
|
+
next candidate unless Object.const_defined?(name)
|
52
|
+
|
53
|
+
# Go down the ancestors to check if it is owned directly. The check
|
54
|
+
# stops when we reach Object or the end of ancestors tree.
|
55
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
56
|
+
break const if ancestor == Object
|
57
|
+
break ancestor if ancestor.const_defined?(name, false)
|
58
|
+
const
|
59
|
+
end
|
60
|
+
|
61
|
+
# owner is in Object, so raise
|
62
|
+
constant.const_get(name, false)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_camelcase(str)
|
68
|
+
str.split('_').map { |i| i.capitalize }.join('')
|
69
|
+
end
|
70
|
+
|
71
|
+
# Taken from Rulers: http://git.io/vkWqf
|
72
|
+
def to_underscore(str)
|
73
|
+
str.gsub(/::/, '/').
|
74
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
75
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
76
|
+
tr("-", "_").
|
77
|
+
downcase
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|