smartystreets_ruby_sdk 3.1.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Makefile +1 -1
- data/examples/international_example.rb +3 -3
- data/examples/us_autocomplete_example.rb +3 -3
- data/examples/us_extract_example.rb +3 -3
- data/examples/us_street_multiple_address_example.rb +6 -5
- data/examples/us_street_single_address_example.rb +5 -5
- data/examples/us_zipcode_multiple_lookup_example.rb +6 -5
- data/examples/us_zipcode_single_lookup_example.rb +4 -4
- data/lib/smartystreets_ruby_sdk.rb +26 -4
- data/lib/smartystreets_ruby_sdk/batch.rb +44 -41
- data/lib/smartystreets_ruby_sdk/client_builder.rb +115 -113
- data/lib/smartystreets_ruby_sdk/custom_header_sender.rb +10 -8
- data/lib/smartystreets_ruby_sdk/errors.rb +13 -11
- data/lib/smartystreets_ruby_sdk/exceptions.rb +27 -23
- data/lib/smartystreets_ruby_sdk/international_street.rb +3 -1
- data/lib/smartystreets_ruby_sdk/international_street/analysis.rb +11 -9
- data/lib/smartystreets_ruby_sdk/international_street/candidate.rb +28 -26
- data/lib/smartystreets_ruby_sdk/international_street/client.rb +45 -43
- data/lib/smartystreets_ruby_sdk/international_street/components.rb +53 -51
- data/lib/smartystreets_ruby_sdk/international_street/language_mode.rb +7 -3
- data/lib/smartystreets_ruby_sdk/international_street/lookup.rb +63 -61
- data/lib/smartystreets_ruby_sdk/international_street/metadata.rb +12 -10
- data/lib/smartystreets_ruby_sdk/json_able.rb +13 -11
- data/lib/smartystreets_ruby_sdk/logger.rb +2 -2
- data/lib/smartystreets_ruby_sdk/native_sender.rb +58 -56
- data/lib/smartystreets_ruby_sdk/native_serializer.rb +9 -7
- data/lib/smartystreets_ruby_sdk/proxy.rb +2 -2
- data/lib/smartystreets_ruby_sdk/request.rb +11 -9
- data/lib/smartystreets_ruby_sdk/response.rb +9 -7
- data/lib/smartystreets_ruby_sdk/retry_sender.rb +26 -24
- data/lib/smartystreets_ruby_sdk/shared_credentials.rb +11 -9
- data/lib/smartystreets_ruby_sdk/signing_sender.rb +11 -9
- data/lib/smartystreets_ruby_sdk/sleeper.rb +1 -1
- data/lib/smartystreets_ruby_sdk/static_credentials.rb +11 -9
- data/lib/smartystreets_ruby_sdk/status_code_sender.rb +31 -29
- data/lib/smartystreets_ruby_sdk/url_prefix_sender.rb +11 -9
- data/lib/smartystreets_ruby_sdk/us_autocomplete.rb +3 -1
- data/lib/smartystreets_ruby_sdk/us_autocomplete/client.rb +47 -45
- data/lib/smartystreets_ruby_sdk/us_autocomplete/geolocation_type.rb +9 -5
- data/lib/smartystreets_ruby_sdk/us_autocomplete/lookup.rb +26 -24
- data/lib/smartystreets_ruby_sdk/us_autocomplete/suggestion.rb +11 -9
- data/lib/smartystreets_ruby_sdk/us_extract.rb +4 -2
- data/lib/smartystreets_ruby_sdk/us_extract/address.rb +18 -16
- data/lib/smartystreets_ruby_sdk/us_extract/client.rb +34 -32
- data/lib/smartystreets_ruby_sdk/us_extract/lookup.rb +16 -14
- data/lib/smartystreets_ruby_sdk/us_extract/metadata.rb +13 -11
- data/lib/smartystreets_ruby_sdk/us_extract/result.rb +13 -11
- data/lib/smartystreets_ruby_sdk/us_street.rb +4 -2
- data/lib/smartystreets_ruby_sdk/us_street/analysis.rb +19 -17
- data/lib/smartystreets_ruby_sdk/us_street/candidate.rb +19 -17
- data/lib/smartystreets_ruby_sdk/us_street/client.rb +51 -49
- data/lib/smartystreets_ruby_sdk/us_street/components.rb +32 -30
- data/lib/smartystreets_ruby_sdk/us_street/lookup.rb +27 -26
- data/lib/smartystreets_ruby_sdk/us_street/match_type.rb +9 -5
- data/lib/smartystreets_ruby_sdk/us_street/metadata.rb +26 -24
- data/lib/smartystreets_ruby_sdk/us_zipcode.rb +4 -2
- data/lib/smartystreets_ruby_sdk/us_zipcode/alternate_county.rb +12 -10
- data/lib/smartystreets_ruby_sdk/us_zipcode/city.rb +13 -11
- data/lib/smartystreets_ruby_sdk/us_zipcode/client.rb +46 -44
- data/lib/smartystreets_ruby_sdk/us_zipcode/lookup.rb +16 -13
- data/lib/smartystreets_ruby_sdk/us_zipcode/result.rb +33 -31
- data/lib/smartystreets_ruby_sdk/us_zipcode/zip_code.rb +24 -21
- data/lib/smartystreets_ruby_sdk/version.rb +2 -2
- data/smartystreets_ruby_sdk.gemspec +1 -1
- metadata +2 -2
@@ -1,80 +1,82 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
module SmartyStreets
|
2
|
+
module InternationalStreet
|
3
|
+
# In addition to holding all of the input data for this lookup, this class also will contain the
|
4
|
+
# result of the lookup after it comes back from the API.
|
5
|
+
#
|
6
|
+
# Note: Lookups must have certain required fields set with non-blank values.
|
7
|
+
# These can be found at the URL below.
|
8
|
+
#
|
9
|
+
# See "https://smartystreets.com/docs/cloud/international-street-api#http-input-fields"
|
10
|
+
#
|
11
|
+
# @geocode:: Disabled by default. Set to true to enable.
|
12
|
+
# @language:: When not set, the output language will match the language of the input values.
|
13
|
+
# When set to language_mode.NATIVE, the results will always be in the language of the output country.
|
14
|
+
# When set to language_mode.LATIN, the results will always be provided using a Latin character set.
|
15
|
+
class Lookup
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
attr_accessor :freeform, :locality, :postal_code, :address3, :address2, :inputId, :address1,
|
18
|
+
:geocode, :administrative_area, :country, :organization, :language, :address4, :result
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
def initialize(freeform=nil, country=nil)
|
21
|
+
@result = []
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
23
|
+
@inputId = nil
|
24
|
+
@country = country
|
25
|
+
@geocode = nil
|
26
|
+
@language = nil
|
27
|
+
@freeform = freeform
|
28
|
+
@address1 = nil
|
29
|
+
@address2 = nil
|
30
|
+
@address3 = nil
|
31
|
+
@address4 = nil
|
32
|
+
@organization = nil
|
33
|
+
@locality = nil
|
34
|
+
@administrative_area = nil
|
35
|
+
@postal_code = nil
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
def missing_country
|
39
|
+
field_is_missing(@country)
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
def has_freeform
|
43
|
+
field_is_set(@freeform)
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
def missing_address1
|
47
|
+
field_is_missing(@address1)
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
def has_postal_code
|
51
|
+
field_is_set(@postal_code)
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
def missing_locality_or_administrative_area
|
55
|
+
field_is_missing(@locality) or field_is_missing(@administrative_area)
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
def field_is_missing(field)
|
59
|
+
field.nil? or field.empty?
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
def field_is_set(field)
|
63
|
+
not field_is_missing(field)
|
64
|
+
end
|
64
65
|
|
65
|
-
|
66
|
-
|
66
|
+
def ensure_enough_info
|
67
|
+
raise UnprocessableEntityError, 'Country field is required.' if missing_country
|
67
68
|
|
68
|
-
|
69
|
+
return true if has_freeform
|
69
70
|
|
70
|
-
|
71
|
+
raise UnprocessableEntityError, 'Either freeform or address1 is required.' if missing_address1
|
71
72
|
|
72
|
-
|
73
|
+
return true if has_postal_code
|
73
74
|
|
74
|
-
|
75
|
-
|
75
|
+
if missing_locality_or_administrative_area
|
76
|
+
raise UnprocessableEntityError, 'Insufficient information:'\
|
76
77
|
'One or more required fields were not set on the lookup.'
|
78
|
+
end
|
77
79
|
end
|
78
80
|
end
|
79
81
|
end
|
80
|
-
end
|
82
|
+
end
|
@@ -1,14 +1,16 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
1
|
+
module SmartyStreets
|
2
|
+
module InternationalStreet
|
3
|
+
# See "https://smartystreets.com/docs/cloud/international-street-api#metadata"
|
4
|
+
class Metadata
|
4
5
|
|
5
|
-
|
6
|
+
attr_reader :longitude, :geocode_precision, :max_geocode_precision, :latitude
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def initialize(obj)
|
9
|
+
@latitude = obj.fetch('latitude', nil)
|
10
|
+
@longitude = obj.fetch('longitude', nil)
|
11
|
+
@geocode_precision = obj.fetch('geocode_precision', nil)
|
12
|
+
@max_geocode_precision = obj.fetch('max_geocode_precision', nil)
|
13
|
+
end
|
12
14
|
end
|
13
15
|
end
|
14
|
-
end
|
16
|
+
end
|
@@ -1,17 +1,19 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module SmartyStreets
|
4
|
+
class JSONAble
|
5
|
+
def to_json(options={})
|
6
|
+
hash = {}
|
7
|
+
instance_variables.each do |var|
|
8
|
+
hash[var.to_s.delete('@')] = instance_variable_get var
|
9
|
+
end
|
10
|
+
hash.to_json
|
8
11
|
end
|
9
|
-
hash.to_json
|
10
|
-
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def from_json!(string)
|
14
|
+
JSON.load(string).each do |var, val|
|
15
|
+
instance_variable_set var, val
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
|
-
end
|
19
|
+
end
|
@@ -2,81 +2,83 @@ require 'net/http'
|
|
2
2
|
require_relative 'version'
|
3
3
|
require_relative 'response'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
module SmartyStreets
|
6
|
+
class NativeSender
|
7
|
+
def initialize(max_timeout = 10_000, proxy = nil)
|
8
|
+
@max_timeout = max_timeout
|
9
|
+
@proxy = proxy
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
def send(smarty_request)
|
13
|
+
request = self.class.build_request(smarty_request)
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
begin
|
16
|
+
http = build_http(request)
|
17
|
+
http.use_ssl = true
|
18
|
+
http.ssl_version = :TLSv1_2
|
19
|
+
http.read_timeout = @max_timeout
|
19
20
|
|
20
|
-
|
21
|
+
response = http.request(request)
|
22
|
+
|
23
|
+
http.finish if http.started?
|
24
|
+
rescue StandardError => err
|
25
|
+
return Response.new(nil, nil, err)
|
26
|
+
end
|
21
27
|
|
22
|
-
|
23
|
-
rescue StandardError => err
|
24
|
-
return Response.new(nil, nil, err)
|
28
|
+
build_smarty_response(response)
|
25
29
|
end
|
26
30
|
|
27
|
-
|
28
|
-
|
31
|
+
def self.build_request(smarty_request)
|
32
|
+
query = create_query(smarty_request)
|
29
33
|
|
30
|
-
|
31
|
-
|
34
|
+
if smarty_request.payload.nil?
|
35
|
+
request = Net::HTTP::Get.new(URI.parse("#{smarty_request.url_prefix}?#{query}"))
|
36
|
+
else
|
37
|
+
request = Net::HTTP::Post.new(URI.parse("#{smarty_request.url_prefix}?#{query}"))
|
38
|
+
end
|
32
39
|
|
33
|
-
|
34
|
-
request =
|
35
|
-
|
36
|
-
request =
|
40
|
+
request.content_type = 'application/json'
|
41
|
+
request.body = smarty_request.payload
|
42
|
+
request['User-Agent'] = "smartystreets (sdk:ruby@#{SmartyStreets::VERSION})"
|
43
|
+
request['Referer'] = smarty_request.referer unless smarty_request.referer.nil?
|
44
|
+
set_custom_headers(smarty_request.headers, request)
|
45
|
+
request
|
37
46
|
end
|
38
47
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
request['Referer'] = smarty_request.referer unless smarty_request.referer.nil?
|
43
|
-
set_custom_headers(smarty_request.headers, request)
|
44
|
-
request
|
45
|
-
end
|
48
|
+
def build_smarty_response(native_response)
|
49
|
+
Response.new(native_response.body, native_response.code)
|
50
|
+
end
|
46
51
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
52
|
+
def build_http(request)
|
53
|
+
uri = request.uri
|
50
54
|
|
51
|
-
|
52
|
-
|
55
|
+
if @proxy.nil?
|
56
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
57
|
+
else
|
58
|
+
http = Net::HTTP.new(uri.hostname, uri.port, @proxy.host,
|
59
|
+
@proxy.port, @proxy.username, @proxy.password)
|
60
|
+
end
|
53
61
|
|
54
|
-
|
55
|
-
http = Net::HTTP.new(uri.hostname, uri.port)
|
56
|
-
else
|
57
|
-
http = Net::HTTP.new(uri.hostname, uri.port, @proxy.host,
|
58
|
-
@proxy.port, @proxy.username, @proxy.password)
|
62
|
+
http
|
59
63
|
end
|
60
64
|
|
61
|
-
|
62
|
-
|
65
|
+
def self.create_query(smarty_request)
|
66
|
+
query_string = ''
|
63
67
|
|
64
|
-
|
65
|
-
|
68
|
+
smarty_request.parameters.each do |key, value|
|
69
|
+
query_string.concat("&#{key}=#{value}")
|
70
|
+
end
|
66
71
|
|
67
|
-
|
68
|
-
query_string
|
72
|
+
query_string[0] = ''
|
73
|
+
query_string
|
69
74
|
end
|
70
75
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
smarty_headers.each do |key, values|
|
77
|
-
values.each do |value|
|
78
|
-
request.add_field(key, value)
|
76
|
+
def self.set_custom_headers(smarty_headers, request)
|
77
|
+
smarty_headers.each do |key, values|
|
78
|
+
values.each do |value|
|
79
|
+
request.add_field(key, value)
|
80
|
+
end
|
79
81
|
end
|
80
82
|
end
|
81
83
|
end
|
82
|
-
end
|
84
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
obj
|
6
|
-
|
3
|
+
module SmartyStreets
|
4
|
+
class NativeSerializer
|
5
|
+
def serialize(obj)
|
6
|
+
obj.to_json
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
def deserialize(payload)
|
10
|
+
JSON.load(payload)
|
11
|
+
end
|
10
12
|
end
|
11
|
-
end
|
13
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module SmartyStreets
|
2
2
|
# Contains information about the proxy through which all requests will be sent.
|
3
3
|
#
|
4
4
|
# host should not include a scheme
|
@@ -13,4 +13,4 @@ module SmartystreetsRubySdk
|
|
13
13
|
@password = password
|
14
14
|
end
|
15
15
|
end
|
16
|
-
end
|
16
|
+
end
|
@@ -1,12 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module SmartyStreets
|
2
|
+
class Request
|
3
|
+
attr_accessor :parameters, :payload, :url_prefix, :referer, :headers, :content_type
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
def initialize
|
6
|
+
@parameters = {}
|
7
|
+
@payload = nil
|
8
|
+
@url_prefix = nil
|
9
|
+
@referer = nil
|
10
|
+
@headers = {}
|
11
|
+
@content_type = 'application/json'
|
12
|
+
end
|
11
13
|
end
|
12
14
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module SmartyStreets
|
2
|
+
class Response
|
3
|
+
attr_accessor :payload, :status_code, :error
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
def initialize(payload, status_code, error = nil)
|
6
|
+
@payload = payload
|
7
|
+
@status_code = status_code
|
8
|
+
@error = error
|
9
|
+
end
|
8
10
|
end
|
9
|
-
end
|
11
|
+
end
|
@@ -1,32 +1,34 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
module SmartyStreets
|
2
|
+
class RetrySender
|
3
|
+
MAX_BACKOFF_DURATION = 10
|
4
|
+
STATUS_OK = '200'.freeze
|
5
|
+
|
6
|
+
def initialize(max_retries, inner, sleeper, logger)
|
7
|
+
@max_retries = max_retries
|
8
|
+
@inner = inner
|
9
|
+
@sleeper = sleeper
|
10
|
+
@logger = logger
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
def send(request)
|
14
|
+
response = @inner.send(request)
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
(0..@max_retries-1).each do |i|
|
17
|
+
break if response.status_code == STATUS_OK
|
17
18
|
|
18
|
-
|
19
|
+
backoff(i)
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
response = @inner.send(request)
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
response
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
def backoff(attempt)
|
28
|
+
backoff_duration = [attempt, MAX_BACKOFF_DURATION].min
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
@logger.log("There was an error processing the request. Retrying in #{backoff_duration} seconds...")
|
31
|
+
@sleeper.sleep(backoff_duration)
|
32
|
+
end
|
31
33
|
end
|
32
|
-
end
|
34
|
+
end
|