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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 91ab0c6412cf37cc084601eb3dc9fafb2f531b61
4
- data.tar.gz: 9de85f2eec73a3370ad39af6d3237b40744d1716
2
+ SHA256:
3
+ metadata.gz: 113f611d2dd082289e53720edc079b6397493f344f7cbbcb7a86136fb17eb7a0
4
+ data.tar.gz: '06916e4e2a57b73b55c05c34d0eeb89a52436d6b19fd8178f682bfaff1149d3f'
5
5
  SHA512:
6
- metadata.gz: f119adef4b2ee343cbcb6b08145b930659f5eaa48a8be30215a47d11d6ef5babcf768f5d3e0fcb8197764f5b0d0e99f3a0afd8b8e03e65e37f59ef3f43316abc
7
- data.tar.gz: 8a2bdecd2d313df8f1014163a33ac6973a5c6eee2022dd37d8bada6d392131fc022104da3b58c74d1b6f6a48b22c98005e4fbfc217beee3b75f855fa60907762
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
- This is the official Ruby client library for easily integrating Pipl's APIs into your application.
5
-
6
- * Full details about Pipl's API - [https://pipl.com/dev/](https://pipl.com/dev/)
7
- * This library is available in other languages - [https://pipl.com/dev/guide/code_libraries](https://pipl.com/dev/guide/code_libraries)
8
-
9
- Library Requirements
10
- --------------------
11
-
12
- * Ruby 1.9 and above.
13
-
14
- Getting Started & Code Snippets
15
- -------------------------------
16
-
17
- **Pipl's Search API**
18
- * Code snippets - [https://pipl.com/dev/guide/code_snippets](https://pipl.com/dev/guide/code_snippets)
19
- * Full reference - [https://pipl.com/dev/reference/](https://pipl.com/dev/reference/)
20
-
21
-
22
- Credits
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(minimum_probability minimum_match hide_sponsored live_feeds show_sources match_requirements
18
- source_category_requirements infer_persons)
19
-
20
- def initialize(options = {})
21
- Pipl::Configurable.keys.each do |key|
22
- instance_variable_set(:"@#{key}", options[key] || Pipl.instance_variable_get(:"@#{key}"))
23
- end
24
-
25
- end
26
-
27
- def same_options?(opts)
28
- opts.hash == options.hash
29
- end
30
-
31
- def search(params={})
32
- opts = options.merge params
33
- create_search_person(opts)
34
- validate_search_params(opts)
35
- http, req = create_http_request(opts)
36
- if opts.key? :callback
37
- do_send_async http, req, opts[:callback]
38
- elsif opts[:async] and block_given?
39
- do_send_async http, req, Proc.new
40
- else
41
- do_send http, req
42
- end
43
- end
44
-
45
- private
46
-
47
- def create_search_person(opts)
48
- return if opts.key? :search_pointer
49
-
50
- person = opts[:person] || Pipl::Person.new
51
- person.add_field Pipl::Name.new(raw: opts[:raw_name]) if opts[:raw_name]
52
- person.add_field Pipl::Email.new(address: opts[:email]) if opts[:email]
53
- person.add_field Pipl::Username.new(content: opts[:username]) if opts[:username]
54
- person.add_field Pipl::Address.new(raw: opts[:raw_address]) if opts[:raw_address]
55
-
56
- if opts[:first_name] || opts[:middle_name] || opts[:last_name]
57
- person.add_field Pipl::Name.new(first: opts[:first_name], middle: opts[:middle_name], last: opts[:last_name])
58
- end
59
-
60
- if opts[:country] || opts[:state] || opts[:city]
61
- person.add_field Pipl::Address.new(country: opts[:country], state: opts[:state], city: opts[:city])
62
- end
63
-
64
- if opts[:phone]
65
- if opts[:phone].is_a? String
66
- person.add_field Pipl::Phone.new(raw: opts[:phone])
67
- else
68
- person.add_field Pipl::Phone.new(number: opts[:phone])
69
- end
70
- end
71
-
72
- if opts[:from_age] || opts[:to_age]
73
- person.add_field Pipl::DOB.from_age_range((opts[:from_age] || 0).to_i, (opts[:to_age].to_i || 1000).to_i)
74
- end
75
-
76
- opts[:person] = person
77
- end
78
-
79
- def validate_search_params(opts)
80
- unless opts[:api_key] and not opts[:api_key].empty?
81
- raise ArgumentError.new('API key is missing')
82
- end
83
-
84
- if opts[:search_pointer] and opts[:search_pointer].empty?
85
- raise ArgumentError.new('Given search pointer is empty')
86
- end
87
-
88
- unless opts.key? :search_pointer
89
- unless opts[:person] and opts[:person].is_searchable?
90
- raise ArgumentError.new('No valid name/username/user_id/phone/email/address or search pointer in request')
91
- end
92
- end
93
-
94
- if opts[:strict_validation]
95
- if opts[:minimum_probability] and not (0..1).include? opts[:minimum_probability]
96
- raise ArgumentError.new('minimum_probability must be a float in 0..1')
97
- end
98
-
99
- if opts[:minimum_match] and not (0..1).include? opts[:minimum_match]
100
- raise ArgumentError.new('minimum_match must be a float in 0..1')
101
- end
102
-
103
- unless [Pipl::Configurable::SHOW_SOURCES_ALL,
104
- Pipl::Configurable::SHOW_SOURCES_MATCHING,
105
- Pipl::Configurable::SHOW_SOURCES_NONE, nil, true, false].include? opts[:show_sources]
106
- raise ArgumentError.new('show_sources must be one of all, matching, false or a boolean value')
107
- end
108
-
109
- if opts[:match_requirements] and not opts[:match_requirements].is_a? String
110
- raise ArgumentError.new('match_requirements must be a String')
111
- end
112
-
113
- if opts[:source_category_requirements] and not opts[:source_category_requirements].is_a? String
114
- raise ArgumentError.new('source_category_requirements must be a String')
115
- end
116
-
117
- if opts[:infer_persons] and not [nil, false, true].include? opts[:infer_persons]
118
- raise ArgumentError.new('infer_persons must be true, false or nil')
119
- end
120
-
121
- unless opts.key? :search_pointer
122
- unsearchable = opts[:person].unsearchable_fields
123
- if unsearchable and not unsearchable.empty?
124
- raise ArgumentError.new("Some fields are unsearchable: #{unsearchable}")
125
- end
126
- end
127
- end
128
- end
129
-
130
- def create_http_request(opts)
131
- uri = URI(opts[:api_endpoint])
132
- query_params = ["key=#{opts[:api_key]}"] +
133
- QUERY_PARAMS.map { |k| "#{k}=#{opts[k.to_sym]}" unless opts[k.to_sym].nil? }
134
- query_params << opts[:extra] or []
135
- query_params << uri.query
136
- uri.query = URI.escape(query_params.compact.join('&'))
137
-
138
- req = Net::HTTP::Post.new(uri.request_uri)
139
- req['User-Agent'] = opts[:user_agent]
140
- if opts.key? :search_pointer
141
- req.set_form_data search_pointer: opts[:search_pointer]
142
- else
143
- h = opts[:person].to_hash
144
- req.set_form_data person: h.reject { |_, value| value.nil? }.to_json
145
- end
146
-
147
- http = Net::HTTP.new(uri.host, uri.port)
148
- http.use_ssl = uri.scheme == 'https'
149
- http.open_timeout = opts[:http_timeout]
150
-
151
- [http, req]
152
- end
153
-
154
- def do_send(http, req)
155
- response = http.request(req)
156
- if response.is_a? Net::HTTPSuccess
157
- SearchResponse.from_http_response(response)
158
- else
159
- raise Pipl::Client::APIError.from_http_response(response)
160
- end
161
- end
162
-
163
- def do_send_async(http, req, callback)
164
- Thread.new do
165
- begin
166
- response = do_send http, req
167
- callback.call response: response
168
- rescue Pipl::Client::APIError => err
169
- callback.call error: err
170
- rescue Exception => msg
171
- callback.call error: msg
172
- end
173
- end
174
- end
175
-
176
- end
177
- end
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
@@ -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
- attr_accessor :api_key, :minimum_probability, :minimum_match, :hide_sponsored, :live_feeds, :show_sources
10
- attr_accessor :match_requirements, :source_category_requirements, :infer_persons, :strict_validation, :user_agent
11
- attr_writer :api_endpoint
12
-
13
- class << self
14
-
15
- def keys
16
- @keys ||= [
17
- :api_key,
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
- :strict_validation,
27
- :api_endpoint,
28
- :user_agent
29
- ]
30
- end
31
-
32
- end
33
-
34
- def configure
35
- yield self
36
- end
37
-
38
- def reset!
39
- Pipl::Configurable.keys.each do |key|
40
- instance_variable_set(:"@#{key}", Pipl::Default.options[key])
41
- end
42
- self
43
- end
44
-
45
- alias setup reset!
46
-
47
- def api_endpoint
48
- File.join(@api_endpoint, '')
49
- end
50
-
51
- private
52
-
53
- def options
54
- Hash[Pipl::Configurable.keys.map { |key| [key, instance_variable_get(:"@#{key}")] }]
55
- end
56
-
57
- end
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