piplapis-ruby 5.0.5 → 5.2.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 +5 -5
- data/LICENSE +10 -10
- data/README.md +22 -25
- data/lib/pipl/client.rb +201 -177
- data/lib/pipl/configurable.rb +61 -58
- data/lib/pipl/consts.rb +76 -76
- data/lib/pipl/containers.rb +301 -294
- data/lib/pipl/default.rb +71 -66
- data/lib/pipl/errors.rb +62 -62
- data/lib/pipl/fields.rb +804 -732
- data/lib/pipl/response.rb +228 -220
- data/lib/pipl/utils.rb +68 -68
- data/lib/pipl/version.rb +3 -3
- data/lib/pipl.rb +35 -35
- data/pipl.gemspec +18 -18
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 113f611d2dd082289e53720edc079b6397493f344f7cbbcb7a86136fb17eb7a0
|
4
|
+
data.tar.gz: '06916e4e2a57b73b55c05c34d0eeb89a52436d6b19fd8178f682bfaff1149d3f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 645882962cf240ced9465bda799ab0620058a5eca2dbc0f409568e7dabe8f41d29b8d7b0ccc6881a33d025609c0a61b18d3c3146675eaa30da64d171f49c0cee
|
7
|
+
data.tar.gz: bb0261752d58e65c4887077f44f7ccc0abb8bd5c0eadd563d94973d6e9e671e02ee0484630394ac89257ca346ed915127922e02fe563d04e5a2e8ce39dabb542
|
data/LICENSE
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
2
|
-
you may not use this file except in compliance with the License.
|
3
|
-
You may obtain a copy of the License at
|
4
|
-
|
5
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
6
|
-
|
7
|
-
Unless required by applicable law or agreed to in writing, software
|
8
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
-
See the License for the specific language governing permissions and
|
1
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
2
|
+
you may not use this file except in compliance with the License.
|
3
|
+
You may obtain a copy of the License at
|
4
|
+
|
5
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
|
7
|
+
Unless required by applicable law or agreed to in writing, software
|
8
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
See the License for the specific language governing permissions and
|
11
11
|
limitations under the License.
|
data/README.md
CHANGED
@@ -1,25 +1,22 @@
|
|
1
|
-
Pipl API Ruby Library
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
-------
|
24
|
-
|
25
|
-
Thanks to [srochy](https://github.com/srochy) for writing the first version this library!
|
1
|
+
# Pipl API Ruby Library
|
2
|
+
|
3
|
+
This is a Ruby client library for easily integrating Pipl's APIs into your application.
|
4
|
+
|
5
|
+
- Full details about Pipl's APIs - [https://pipl.com/api](https://pipl.com/api)
|
6
|
+
- This library is available in other languages - [https://docs.pipl.com/docs/code-libraries](https://docs.pipl.com/docs/code-libraries)
|
7
|
+
|
8
|
+
## Library Requirements
|
9
|
+
|
10
|
+
- From Ruby SDK version 5.2.0 and above, Ruby 3.0 and above is supported
|
11
|
+
|
12
|
+
## Getting Started & Code Snippets
|
13
|
+
|
14
|
+
**Pipl's Search API**
|
15
|
+
|
16
|
+
- API Portal - [https://pipl.com/api/](https://pipl.com/api/)
|
17
|
+
- Code snippets - [https://docs.pipl.com/docs/code-snippets](https://docs.pipl.com/docs/code-snippets)
|
18
|
+
- Full reference - [https://docs.pipl.com/reference/](https://docs.pipl.com/reference/)
|
19
|
+
|
20
|
+
## Credits
|
21
|
+
|
22
|
+
Thanks to [srochy](https://github.com/srochy) for writing the first version this library!
|
data/lib/pipl/client.rb
CHANGED
@@ -1,177 +1,201 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'net/http'
|
3
|
-
|
4
|
-
require_relative 'configurable'
|
5
|
-
require_relative 'containers'
|
6
|
-
require_relative 'errors'
|
7
|
-
require_relative 'fields'
|
8
|
-
require_relative 'response'
|
9
|
-
|
10
|
-
|
11
|
-
module Pipl
|
12
|
-
|
13
|
-
class Client
|
14
|
-
|
15
|
-
include Pipl::Configurable
|
16
|
-
|
17
|
-
QUERY_PARAMS = %w(
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
if opts[:
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
if opts[:
|
73
|
-
person.add_field Pipl::
|
74
|
-
end
|
75
|
-
|
76
|
-
opts[:
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
if opts[:
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
raise ArgumentError.new('
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
require_relative 'configurable'
|
5
|
+
require_relative 'containers'
|
6
|
+
require_relative 'errors'
|
7
|
+
require_relative 'fields'
|
8
|
+
require_relative 'response'
|
9
|
+
|
10
|
+
|
11
|
+
module Pipl
|
12
|
+
|
13
|
+
class Client
|
14
|
+
|
15
|
+
include Pipl::Configurable
|
16
|
+
|
17
|
+
QUERY_PARAMS = %w(
|
18
|
+
minimum_probability
|
19
|
+
minimum_match
|
20
|
+
hide_sponsored
|
21
|
+
live_feeds
|
22
|
+
show_sources
|
23
|
+
match_requirements
|
24
|
+
source_category_requirements
|
25
|
+
infer_persons
|
26
|
+
top_match
|
27
|
+
api_version
|
28
|
+
)
|
29
|
+
|
30
|
+
def initialize(options = {})
|
31
|
+
Pipl::Configurable.keys.each do |key|
|
32
|
+
instance_variable_set(:"@#{key}", options[key] || Pipl.instance_variable_get(:"@#{key}"))
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def same_options?(opts)
|
38
|
+
opts.hash == options.hash
|
39
|
+
end
|
40
|
+
|
41
|
+
def search(params={})
|
42
|
+
opts = options.merge params
|
43
|
+
create_search_person(opts)
|
44
|
+
validate_search_params(opts)
|
45
|
+
http, req = create_http_request(opts)
|
46
|
+
if opts.key? :callback
|
47
|
+
do_send_async http, req, opts[:callback]
|
48
|
+
elsif opts[:async] && block_given?
|
49
|
+
do_send_async http, req, Proc.new
|
50
|
+
else
|
51
|
+
do_send http, req
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def create_search_person(opts)
|
58
|
+
return if opts.key? :search_pointer
|
59
|
+
|
60
|
+
person = opts[:person] || Pipl::Person.new
|
61
|
+
person.add_field Pipl::Name.new(raw: opts[:raw_name]) if opts[:raw_name]
|
62
|
+
person.add_field Pipl::Email.new(address: opts[:email]) if opts[:email]
|
63
|
+
person.add_field Pipl::Username.new(content: opts[:username]) if opts[:username]
|
64
|
+
person.add_field Pipl::Address.new(raw: opts[:raw_address]) if opts[:raw_address]
|
65
|
+
person.add_field Pipl::Url.new(url: opts[:url]) if opts[:url]
|
66
|
+
person.add_field Pipl::Vehicle.new(vin: opts[:vin]) if opts[:vin]
|
67
|
+
|
68
|
+
if opts[:first_name] || opts[:middle_name] || opts[:last_name]
|
69
|
+
person.add_field Pipl::Name.new(first: opts[:first_name], middle: opts[:middle_name], last: opts[:last_name])
|
70
|
+
end
|
71
|
+
|
72
|
+
if opts[:country] || opts[:state] || opts[:city]
|
73
|
+
person.add_field Pipl::Address.new(country: opts[:country], state: opts[:state], city: opts[:city])
|
74
|
+
end
|
75
|
+
|
76
|
+
if opts[:phone]
|
77
|
+
if opts[:phone].is_a? String
|
78
|
+
person.add_field Pipl::Phone.new(raw: opts[:phone])
|
79
|
+
else
|
80
|
+
person.add_field Pipl::Phone.new(number: opts[:phone])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
if opts[:from_age] || opts[:to_age]
|
85
|
+
person.add_field Pipl::DOB.from_age_range((opts[:from_age] || 0).to_i, (opts[:to_age].to_i || 1000).to_i)
|
86
|
+
end
|
87
|
+
|
88
|
+
opts[:person] = person
|
89
|
+
end
|
90
|
+
|
91
|
+
def validate_search_params(opts)
|
92
|
+
unless opts[:api_key] && !opts[:api_key].empty?
|
93
|
+
raise ArgumentError.new('API key is missing')
|
94
|
+
end
|
95
|
+
|
96
|
+
if opts[:search_pointer] && opts[:search_pointer].empty?
|
97
|
+
raise ArgumentError.new('Given search pointer is empty')
|
98
|
+
end
|
99
|
+
|
100
|
+
unless opts.key? :search_pointer
|
101
|
+
unless opts[:person] && opts[:person].is_searchable?
|
102
|
+
raise ArgumentError.new('No valid name/username/user_id/phone/email/address/vin or search pointer in request')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if opts[:strict_validation]
|
107
|
+
if opts[:minimum_probability] && !(0..1).include?(opts[:minimum_probability])
|
108
|
+
raise ArgumentError.new('minimum_probability must be a float in 0..1')
|
109
|
+
end
|
110
|
+
|
111
|
+
if opts[:minimum_match] && !(0..1).include?(opts[:minimum_match])
|
112
|
+
raise ArgumentError.new('minimum_match must be a float in 0..1')
|
113
|
+
end
|
114
|
+
|
115
|
+
unless [Pipl::Configurable::SHOW_SOURCES_ALL,
|
116
|
+
Pipl::Configurable::SHOW_SOURCES_MATCHING,
|
117
|
+
Pipl::Configurable::SHOW_SOURCES_NONE, nil, true, false].include? opts[:show_sources]
|
118
|
+
raise ArgumentError.new('show_sources must be one of all, matching, false or a boolean value')
|
119
|
+
end
|
120
|
+
|
121
|
+
if opts[:match_requirements] && !opts[:match_requirements].is_a?(String)
|
122
|
+
raise ArgumentError.new('match_requirements must be a String')
|
123
|
+
end
|
124
|
+
|
125
|
+
if opts[:source_category_requirements] && !opts[:source_category_requirements].is_a?(String)
|
126
|
+
raise ArgumentError.new('source_category_requirements must be a String')
|
127
|
+
end
|
128
|
+
|
129
|
+
if opts[:infer_persons] && ! [nil, false, true].include?(opts[:infer_persons])
|
130
|
+
raise ArgumentError.new('infer_persons must be true, false or nil')
|
131
|
+
end
|
132
|
+
|
133
|
+
if opts[:top_match] && ! [nil, false, true].include?(opts[:top_match])
|
134
|
+
raise ArgumentError.new('top_match must be true, false or nil')
|
135
|
+
end
|
136
|
+
|
137
|
+
unless opts.key? :search_pointer
|
138
|
+
unsearchable = opts[:person].unsearchable_fields
|
139
|
+
if unsearchable && ! unsearchable.empty?
|
140
|
+
raise ArgumentError.new("Some fields are unsearchable: #{unsearchable}")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_api_version(opts)
|
147
|
+
api_version = opts[:api_version].to_s.gsub(/\.0$/, "") unless opts[:api_version].nil?
|
148
|
+
api_version ? api_version : DEFAULT_API_VERSION
|
149
|
+
end
|
150
|
+
|
151
|
+
def create_http_request(opts)
|
152
|
+
api_version = get_api_version(opts)
|
153
|
+
uri = URI("#{opts[:api_endpoint]}v#{api_version}/")
|
154
|
+
query_params = ["key=#{opts[:api_key]}"]
|
155
|
+
QUERY_PARAMS.each do |k|
|
156
|
+
query_params << "#{k}=#{URI.encode_www_form_component(opts[k.to_sym])}" unless opts[k.to_sym].nil?
|
157
|
+
end
|
158
|
+
query_params << opts[:extra]
|
159
|
+
query_params << uri.query
|
160
|
+
uri.query = query_params.compact.join('&')
|
161
|
+
|
162
|
+
req = Net::HTTP::Post.new(uri.request_uri)
|
163
|
+
req['User-Agent'] = opts[:user_agent]
|
164
|
+
if opts.key? :search_pointer
|
165
|
+
req.set_form_data search_pointer: opts[:search_pointer]
|
166
|
+
else
|
167
|
+
h = opts[:person].to_hash
|
168
|
+
req.set_form_data person: h.reject { |_, value| value.nil? }.to_json
|
169
|
+
end
|
170
|
+
|
171
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
172
|
+
http.use_ssl = uri.scheme == 'https'
|
173
|
+
http.open_timeout = opts[:http_timeout]
|
174
|
+
|
175
|
+
[http, req]
|
176
|
+
end
|
177
|
+
|
178
|
+
def do_send(http, req)
|
179
|
+
response = http.request(req)
|
180
|
+
if response.is_a? Net::HTTPSuccess
|
181
|
+
SearchResponse.from_http_response(response)
|
182
|
+
else
|
183
|
+
raise Pipl::Client::APIError.from_http_response(response)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def do_send_async(http, req, callback)
|
188
|
+
Thread.new do
|
189
|
+
begin
|
190
|
+
response = do_send http, req
|
191
|
+
callback.call response: response
|
192
|
+
rescue Pipl::Client::APIError => err
|
193
|
+
callback.call error: err
|
194
|
+
rescue Exception => msg
|
195
|
+
callback.call error: msg
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
end
|
data/lib/pipl/configurable.rb
CHANGED
@@ -1,58 +1,61 @@
|
|
1
|
-
module Pipl
|
2
|
-
|
3
|
-
module Configurable
|
4
|
-
|
5
|
-
SHOW_SOURCES_ALL = 'all'
|
6
|
-
SHOW_SOURCES_MATCHING = 'matching'
|
7
|
-
SHOW_SOURCES_NONE = 'false'
|
8
|
-
|
9
|
-
|
10
|
-
attr_accessor :
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
1
|
+
module Pipl
|
2
|
+
|
3
|
+
module Configurable
|
4
|
+
|
5
|
+
SHOW_SOURCES_ALL = 'all'
|
6
|
+
SHOW_SOURCES_MATCHING = 'matching'
|
7
|
+
SHOW_SOURCES_NONE = 'false'
|
8
|
+
DEFAULT_API_VERSION = 5
|
9
|
+
|
10
|
+
attr_accessor :api_key, :minimum_probability, :minimum_match, :hide_sponsored, :live_feeds, :show_sources
|
11
|
+
attr_accessor :match_requirements, :source_category_requirements, :infer_persons, :strict_validation, :user_agent
|
12
|
+
attr_accessor :top_match
|
13
|
+
attr_writer :api_endpoint
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
def keys
|
18
|
+
@keys ||= [
|
19
|
+
:api_key,
|
20
|
+
:minimum_probability,
|
21
|
+
:minimum_match,
|
22
|
+
:hide_sponsored,
|
23
|
+
:live_feeds,
|
24
|
+
:show_sources,
|
25
|
+
:match_requirements,
|
26
|
+
:source_category_requirements,
|
27
|
+
:infer_persons,
|
28
|
+
:strict_validation,
|
29
|
+
:api_endpoint,
|
30
|
+
:user_agent,
|
31
|
+
:top_match
|
32
|
+
]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def configure
|
38
|
+
yield self
|
39
|
+
end
|
40
|
+
|
41
|
+
def reset!
|
42
|
+
Pipl::Configurable.keys.each do |key|
|
43
|
+
instance_variable_set(:"@#{key}", Pipl::Default.options[key])
|
44
|
+
end
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
alias setup reset!
|
49
|
+
|
50
|
+
def api_endpoint
|
51
|
+
File.join(@api_endpoint, '')
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def options
|
57
|
+
Hash[Pipl::Configurable.keys.map { |key| [key, instance_variable_get(:"@#{key}")] }]
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|