blockscore 4.0.0 → 4.1.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/.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
|