smartystreets_ruby_sdk 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/gem-publish.yml +58 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +5 -0
- data/Dockerfile +10 -0
- data/Gemfile +4 -0
- data/LICENSE.md +202 -0
- data/Makefile +33 -0
- data/README.md +31 -0
- data/Rakefile +5 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docker-compose.yml +12 -0
- data/examples/international_autocomplete_example.rb +47 -0
- data/examples/international_example.rb +53 -0
- data/examples/us_autocomplete_pro_example.rb +56 -0
- data/examples/us_extract_example.rb +63 -0
- data/examples/us_reverse_geo_example.rb +47 -0
- data/examples/us_street_multiple_address_example.rb +87 -0
- data/examples/us_street_single_address_example.rb +67 -0
- data/examples/us_zipcode_multiple_lookup_example.rb +80 -0
- data/examples/us_zipcode_single_lookup_example.rb +55 -0
- data/lib/smartystreets_ruby_sdk/batch.rb +59 -0
- data/lib/smartystreets_ruby_sdk/client_builder.rb +188 -0
- data/lib/smartystreets_ruby_sdk/custom_header_sender.rb +13 -0
- data/lib/smartystreets_ruby_sdk/errors.rb +27 -0
- data/lib/smartystreets_ruby_sdk/exceptions.rb +39 -0
- data/lib/smartystreets_ruby_sdk/international_autocomplete/client.rb +61 -0
- data/lib/smartystreets_ruby_sdk/international_autocomplete/lookup.rb +21 -0
- data/lib/smartystreets_ruby_sdk/international_autocomplete/suggestion.rb +16 -0
- data/lib/smartystreets_ruby_sdk/international_street/analysis.rb +17 -0
- data/lib/smartystreets_ruby_sdk/international_street/candidate.rb +23 -0
- data/lib/smartystreets_ruby_sdk/international_street/changes.rb +15 -0
- data/lib/smartystreets_ruby_sdk/international_street/client.rb +63 -0
- data/lib/smartystreets_ruby_sdk/international_street/components.rb +58 -0
- data/lib/smartystreets_ruby_sdk/international_street/language_mode.rb +9 -0
- data/lib/smartystreets_ruby_sdk/international_street/lookup.rb +82 -0
- data/lib/smartystreets_ruby_sdk/international_street/metadata.rb +17 -0
- data/lib/smartystreets_ruby_sdk/international_street/rootlevel.rb +25 -0
- data/lib/smartystreets_ruby_sdk/international_street.rb +12 -0
- data/lib/smartystreets_ruby_sdk/json_able.rb +19 -0
- data/lib/smartystreets_ruby_sdk/license_sender.rb +15 -0
- data/lib/smartystreets_ruby_sdk/logger.rb +7 -0
- data/lib/smartystreets_ruby_sdk/native_sender.rb +85 -0
- data/lib/smartystreets_ruby_sdk/native_serializer.rb +13 -0
- data/lib/smartystreets_ruby_sdk/proxy.rb +16 -0
- data/lib/smartystreets_ruby_sdk/request.rb +14 -0
- data/lib/smartystreets_ruby_sdk/response.rb +11 -0
- data/lib/smartystreets_ruby_sdk/retry_sender.rb +39 -0
- data/lib/smartystreets_ruby_sdk/shared_credentials.rb +13 -0
- data/lib/smartystreets_ruby_sdk/signing_sender.rb +13 -0
- data/lib/smartystreets_ruby_sdk/sleeper.rb +7 -0
- data/lib/smartystreets_ruby_sdk/static_credentials.rb +13 -0
- data/lib/smartystreets_ruby_sdk/status_code_sender.rb +41 -0
- data/lib/smartystreets_ruby_sdk/url_prefix_sender.rb +14 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/client.rb +72 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/geolocation_type.rb +9 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/lookup.rb +38 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/suggestion.rb +16 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete.rb +9 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete_pro/client.rb +78 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete_pro/geolocation_type.rb +8 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete_pro/lookup.rb +63 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete_pro/suggestion.rb +18 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete_pro.rb +10 -0
- data/lib/smartystreets_ruby_sdk/us_extract/address.rb +24 -0
- data/lib/smartystreets_ruby_sdk/us_extract/client.rb +49 -0
- data/lib/smartystreets_ruby_sdk/us_extract/lookup.rb +22 -0
- data/lib/smartystreets_ruby_sdk/us_extract/metadata.rb +17 -0
- data/lib/smartystreets_ruby_sdk/us_extract/result.rb +21 -0
- data/lib/smartystreets_ruby_sdk/us_extract.rb +10 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/address.rb +16 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/client.rb +38 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/coordinate.rb +25 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/lookup.rb +21 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/result.rb +20 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/us_reverse_geo_response.rb +17 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo.rb +12 -0
- data/lib/smartystreets_ruby_sdk/us_street/analysis.rb +24 -0
- data/lib/smartystreets_ruby_sdk/us_street/candidate.rb +27 -0
- data/lib/smartystreets_ruby_sdk/us_street/client.rb +78 -0
- data/lib/smartystreets_ruby_sdk/us_street/components.rb +35 -0
- data/lib/smartystreets_ruby_sdk/us_street/lookup.rb +32 -0
- data/lib/smartystreets_ruby_sdk/us_street/match_type.rb +10 -0
- data/lib/smartystreets_ruby_sdk/us_street/metadata.rb +30 -0
- data/lib/smartystreets_ruby_sdk/us_street.rb +12 -0
- data/lib/smartystreets_ruby_sdk/us_zipcode/alternate_county.rb +15 -0
- data/lib/smartystreets_ruby_sdk/us_zipcode/city.rb +16 -0
- data/lib/smartystreets_ruby_sdk/us_zipcode/client.rb +72 -0
- data/lib/smartystreets_ruby_sdk/us_zipcode/lookup.rb +21 -0
- data/lib/smartystreets_ruby_sdk/us_zipcode/result.rb +47 -0
- data/lib/smartystreets_ruby_sdk/us_zipcode/zip_code.rb +33 -0
- data/lib/smartystreets_ruby_sdk/us_zipcode.rb +11 -0
- data/lib/smartystreets_ruby_sdk/version.rb +3 -0
- data/lib/smartystreets_ruby_sdk.rb +33 -0
- data/ruby-sdk-demo.json +354 -0
- data/smartystreets_ruby_sdk.gemspec +26 -0
- metadata +201 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../request'
|
2
|
+
require_relative '../exceptions'
|
3
|
+
require_relative 'suggestion'
|
4
|
+
|
5
|
+
module SmartyStreets
|
6
|
+
module InternationalAutocomplete
|
7
|
+
# It is recommended to instantiate this class using ClientBuilder.build_international_autocomplete_api_client
|
8
|
+
class Client
|
9
|
+
def initialize(sender, serializer)
|
10
|
+
@sender = sender
|
11
|
+
@serializer = serializer
|
12
|
+
end
|
13
|
+
|
14
|
+
# Sends a Lookup object to the International Autocomplete API and stores the result in the Lookup's result field.
|
15
|
+
def send(lookup)
|
16
|
+
if not lookup or not lookup.search
|
17
|
+
raise SmartyStreets::SmartyError, 'Send() must be passed a Lookup with the prefix field set.'
|
18
|
+
end
|
19
|
+
|
20
|
+
request = build_request(lookup)
|
21
|
+
|
22
|
+
response = @sender.send(request)
|
23
|
+
|
24
|
+
raise response.error if response.error
|
25
|
+
|
26
|
+
result = @serializer.deserialize(response.payload)
|
27
|
+
suggestions = convert_suggestions(result.fetch('candidates', []))
|
28
|
+
lookup.result = suggestions
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def build_request(lookup)
|
33
|
+
request = Request.new
|
34
|
+
|
35
|
+
add_parameter(request, 'search', lookup.search)
|
36
|
+
add_parameter(request, 'country', lookup.country)
|
37
|
+
add_parameter(request, 'include_only_administrative_area', lookup.administrative_area)
|
38
|
+
add_parameter(request, 'include_only_locality', lookup.locality)
|
39
|
+
add_parameter(request, 'include_only_postal_code', lookup.postal_code)
|
40
|
+
|
41
|
+
request
|
42
|
+
end
|
43
|
+
|
44
|
+
def convert_suggestions(suggestion_hashes)
|
45
|
+
converted_suggestions = []
|
46
|
+
return converted_suggestions if suggestion_hashes.nil?
|
47
|
+
|
48
|
+
suggestion_hashes.each do |suggestion|
|
49
|
+
converted_suggestions.push(InternationalAutocomplete::Suggestion.new(suggestion))
|
50
|
+
end
|
51
|
+
|
52
|
+
converted_suggestions
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_parameter(request, key, value)
|
56
|
+
request.parameters[key] = value unless value.nil? or value.empty?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative '../json_able'
|
2
|
+
|
3
|
+
module SmartyStreets
|
4
|
+
module InternationalAutocomplete
|
5
|
+
# In addition to holding all of the input data for this lookup, this class also will contain the result
|
6
|
+
# of the lookup after it comes back from the API.
|
7
|
+
class Lookup < JSONAble
|
8
|
+
|
9
|
+
attr_accessor :result, :search, :country, :administrative_area, :locality, :postal_code
|
10
|
+
|
11
|
+
def initialize(search=nil, country=nil, administrative_area=nil, locality=nil, postal_code=nil)
|
12
|
+
@result = []
|
13
|
+
@search = search
|
14
|
+
@country = country
|
15
|
+
@administrative_area = administrative_area
|
16
|
+
@locality = locality
|
17
|
+
@postal_code = postal_code
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
module InternationalAutocomplete
|
3
|
+
class Suggestion
|
4
|
+
|
5
|
+
attr_reader :street, :locality, :administrative_area, :postal_code, :country_iso3
|
6
|
+
|
7
|
+
def initialize(obj)
|
8
|
+
@street = obj.fetch('street', nil)
|
9
|
+
@locality = obj.fetch('locality', nil)
|
10
|
+
@administrative_area = obj.fetch('administrative_area', nil)
|
11
|
+
@postal_code = obj.fetch('postal_code', nil)
|
12
|
+
@country_iso3 = obj.fetch('country_iso3', nil)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'changes'
|
2
|
+
module SmartyStreets
|
3
|
+
module InternationalStreet
|
4
|
+
# See "https://smartystreets.com/docs/cloud/international-street-api#analysis"
|
5
|
+
class Analysis
|
6
|
+
|
7
|
+
attr_reader :max_address_precision, :verification_status, :address_precision, :changes
|
8
|
+
|
9
|
+
def initialize(obj)
|
10
|
+
@verification_status = obj.fetch('verification_status', nil)
|
11
|
+
@address_precision = obj.fetch('address_precision', nil)
|
12
|
+
@max_address_precision = obj.fetch('max_address_precision', nil)
|
13
|
+
@changes = Changes.new(obj.fetch('changes', {}))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'components'
|
2
|
+
require_relative 'metadata'
|
3
|
+
require_relative 'analysis'
|
4
|
+
require_relative 'rootlevel'
|
5
|
+
|
6
|
+
module SmartyStreets
|
7
|
+
module InternationalStreet
|
8
|
+
# A candidate is a possible match for an address that was submitted. A lookup can have multiple
|
9
|
+
# candidates if the address was ambiguous.
|
10
|
+
#
|
11
|
+
# See "https://smartystreets.com/docs/cloud/international-street-api#root"
|
12
|
+
class Candidate < RootLevel
|
13
|
+
attr_reader :metadata, :components, :analysis
|
14
|
+
|
15
|
+
def initialize(obj)
|
16
|
+
@components = Components.new(obj.fetch('components', {}))
|
17
|
+
@metadata = Metadata.new(obj.fetch('metadata', {}))
|
18
|
+
@analysis = Analysis.new(obj.fetch('analysis', {}))
|
19
|
+
super(obj)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'rootlevel'
|
2
|
+
require_relative 'components'
|
3
|
+
|
4
|
+
module SmartyStreets
|
5
|
+
module InternationalStreet
|
6
|
+
class Changes < RootLevel
|
7
|
+
attr_reader :components
|
8
|
+
|
9
|
+
def initialize(obj)
|
10
|
+
@components = Components.new(obj.fetch('components', {}))
|
11
|
+
super(obj)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative '../request'
|
2
|
+
require_relative 'candidate'
|
3
|
+
|
4
|
+
module SmartyStreets
|
5
|
+
module InternationalStreet
|
6
|
+
# It is recommended to instantiate this class using ClientBuilder.build_international_street_api_client()
|
7
|
+
class Client
|
8
|
+
def initialize(sender, serializer)
|
9
|
+
@sender = sender
|
10
|
+
@serializer = serializer
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sends a Lookup object to the International Street API and stores the result in the Lookup's result field.
|
14
|
+
def send(lookup)
|
15
|
+
lookup.ensure_enough_info
|
16
|
+
request = build_request(lookup)
|
17
|
+
|
18
|
+
response = @sender.send(request)
|
19
|
+
|
20
|
+
raise response.error if response.error
|
21
|
+
|
22
|
+
candidates = convert_candidates(@serializer.deserialize(response.payload))
|
23
|
+
lookup.result = candidates
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_request(lookup)
|
27
|
+
request = SmartyStreets::Request.new
|
28
|
+
|
29
|
+
add_parameter(request, 'input_id', lookup.input_id)
|
30
|
+
add_parameter(request, 'country', lookup.country)
|
31
|
+
add_parameter(request, 'geocode', lookup.geocode.to_s)
|
32
|
+
add_parameter(request, 'language', lookup.language)
|
33
|
+
add_parameter(request, 'freeform', lookup.freeform)
|
34
|
+
add_parameter(request, 'address1', lookup.address1)
|
35
|
+
add_parameter(request, 'address2', lookup.address2)
|
36
|
+
add_parameter(request, 'address3', lookup.address3)
|
37
|
+
add_parameter(request, 'address4', lookup.address4)
|
38
|
+
add_parameter(request, 'organization', lookup.organization)
|
39
|
+
add_parameter(request, 'locality', lookup.locality)
|
40
|
+
add_parameter(request, 'administrative_area', lookup.administrative_area)
|
41
|
+
add_parameter(request, 'postal_code', lookup.postal_code)
|
42
|
+
|
43
|
+
request
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_parameter(request, key, value)
|
47
|
+
request.parameters[key] = value unless value.nil? or value.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def convert_candidates(raw_candidates)
|
51
|
+
candidates = []
|
52
|
+
|
53
|
+
unless raw_candidates.nil?
|
54
|
+
raw_candidates.each do |candidate|
|
55
|
+
candidates.push(Candidate.new(candidate))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
candidates
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
module InternationalStreet
|
3
|
+
# See "https://smartystreets.com/docs/cloud/international-street-api#components"
|
4
|
+
class Components
|
5
|
+
attr_reader :premise, :thoroughfare_trailing_type, :sub_building, :locality, :post_box_number,
|
6
|
+
:thoroughfare_name, :thoroughfare_postdirection, :dependent_thoroughfare, :premise_prefix_number,
|
7
|
+
:thoroughfare, :dependent_thoroughfare_name, :postal_code_short, :dependent_thoroughfare_trailing_type,
|
8
|
+
:administrative_area, :post_box, :building_leading_type, :dependent_locality_name, :thoroughfare_type,
|
9
|
+
:dependent_thoroughfare_postdirection, :double_dependent_locality, :premise_number,
|
10
|
+
:dependent_thoroughfare_type, :post_box_type, :building, :sub_administrative_area, :postal_code_extra,
|
11
|
+
:sub_building_name, :postal_code, :dependent_locality, :premise_type, :sub_building_number,
|
12
|
+
:super_administrative_area, :premise_extra, :dependent_thoroughfare_predirection,
|
13
|
+
:building_trailing_type, :thoroughfare_predirection, :building_name, :country_iso_3, :sub_building_type
|
14
|
+
|
15
|
+
def initialize(obj)
|
16
|
+
@country_iso_3 = obj.fetch('country_iso_3', nil)
|
17
|
+
@super_administrative_area = obj.fetch('super_administrative_area', nil)
|
18
|
+
@administrative_area = obj.fetch('administrative_area', nil)
|
19
|
+
@sub_administrative_area = obj.fetch('sub_administrative_area', nil)
|
20
|
+
@dependent_locality= obj.fetch('dependent_locality', nil)
|
21
|
+
@dependent_locality_name = obj.fetch('dependent_locality_name', nil)
|
22
|
+
@double_dependent_locality = obj.fetch('double_dependent_locality', nil)
|
23
|
+
@locality = obj.fetch('locality', nil)
|
24
|
+
@postal_code = obj.fetch('postal_code', nil)
|
25
|
+
@postal_code_short = obj.fetch('postal_code_short', nil)
|
26
|
+
@postal_code_extra = obj.fetch('postal_code_extra', nil)
|
27
|
+
@premise = obj.fetch('premise', nil)
|
28
|
+
@premise_extra = obj.fetch('premise_extra', nil)
|
29
|
+
@premise_number = obj.fetch('premise_number', nil)
|
30
|
+
@premise_prefix_number = obj.fetch('premise_prefix_number', nil)
|
31
|
+
@premise_type = obj.fetch('premise_type', nil)
|
32
|
+
@thoroughfare = obj.fetch('thoroughfare', nil)
|
33
|
+
@thoroughfare_predirection = obj.fetch('thoroughfare_predirection', nil)
|
34
|
+
@thoroughfare_postdirection = obj.fetch('thoroughfare_postdirection', nil)
|
35
|
+
@thoroughfare_name = obj.fetch('thoroughfare_name', nil)
|
36
|
+
@thoroughfare_trailing_type = obj.fetch('thoroughfare_trailing_type', nil)
|
37
|
+
@thoroughfare_type = obj.fetch('thoroughfare_type', nil)
|
38
|
+
@dependent_thoroughfare = obj.fetch('dependent_thoroughfare', nil)
|
39
|
+
@dependent_thoroughfare_predirection = obj.fetch('dependent_thoroughfare_predirection', nil)
|
40
|
+
@dependent_thoroughfare_postdirection = obj.fetch('dependent_thoroughfare_postdirection', nil)
|
41
|
+
@dependent_thoroughfare_name = obj.fetch('dependent_thoroughfare_name', nil)
|
42
|
+
@dependent_thoroughfare_trailing_type = obj.fetch('dependent_thoroughfare_trailing_type', nil)
|
43
|
+
@dependent_thoroughfare_type = obj.fetch('dependent_thoroughfare_type', nil)
|
44
|
+
@building = obj.fetch('building', nil)
|
45
|
+
@building_leading_type = obj.fetch('building_leading_type', nil)
|
46
|
+
@building_name = obj.fetch('building_name', nil)
|
47
|
+
@building_trailing_type = obj.fetch('building_trailing_type', nil)
|
48
|
+
@sub_building_type = obj.fetch('sub_building_type', nil)
|
49
|
+
@sub_building_number = obj.fetch('sub_building_number', nil)
|
50
|
+
@sub_building_name = obj.fetch('sub_building_name', nil)
|
51
|
+
@sub_building = obj.fetch('sub_building', nil)
|
52
|
+
@post_box = obj.fetch('post_box', nil)
|
53
|
+
@post_box_type = obj.fetch('post_box_type', nil)
|
54
|
+
@post_box_number = obj.fetch('post_box_number', nil)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,82 @@
|
|
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
|
16
|
+
|
17
|
+
attr_accessor :input_id, :freeform, :locality, :postal_code, :address3, :address2, :inputId, :address1,
|
18
|
+
:geocode, :administrative_area, :country, :organization, :language, :address4, :result
|
19
|
+
|
20
|
+
def initialize(freeform=nil, country=nil)
|
21
|
+
@result = []
|
22
|
+
|
23
|
+
@input_id = 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
|
37
|
+
|
38
|
+
def missing_country
|
39
|
+
field_is_missing(@country)
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_freeform
|
43
|
+
field_is_set(@freeform)
|
44
|
+
end
|
45
|
+
|
46
|
+
def missing_address1
|
47
|
+
field_is_missing(@address1)
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_postal_code
|
51
|
+
field_is_set(@postal_code)
|
52
|
+
end
|
53
|
+
|
54
|
+
def missing_locality_or_administrative_area
|
55
|
+
field_is_missing(@locality) or field_is_missing(@administrative_area)
|
56
|
+
end
|
57
|
+
|
58
|
+
def field_is_missing(field)
|
59
|
+
field.nil? or field.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def field_is_set(field)
|
63
|
+
not field_is_missing(field)
|
64
|
+
end
|
65
|
+
|
66
|
+
def ensure_enough_info
|
67
|
+
raise UnprocessableEntityError, 'Country field is required.' if missing_country
|
68
|
+
|
69
|
+
return true if has_freeform
|
70
|
+
|
71
|
+
raise UnprocessableEntityError, 'Either freeform or address1 is required.' if missing_address1
|
72
|
+
|
73
|
+
return true if has_postal_code
|
74
|
+
|
75
|
+
if missing_locality_or_administrative_area
|
76
|
+
raise UnprocessableEntityError, 'Insufficient information:'\
|
77
|
+
'One or more required fields were not set on the lookup.'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
module InternationalStreet
|
3
|
+
# See "https://smartystreets.com/docs/cloud/international-street-api#metadata"
|
4
|
+
class Metadata
|
5
|
+
|
6
|
+
attr_reader :longitude, :geocode_precision, :max_geocode_precision, :latitude, :address_format
|
7
|
+
|
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
|
+
@address_format = obj.fetch('address_format', nil)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
module InternationalStreet
|
3
|
+
class RootLevel
|
4
|
+
attr_reader :input_id, :organization, :address1, :address2, :address3, :address4, :address5, :address6, :address7,
|
5
|
+
:address8, :address9, :address10, :address11, :address12
|
6
|
+
|
7
|
+
def initialize(obj)
|
8
|
+
@input_id = obj.fetch('input_id', nil)
|
9
|
+
@organization = obj.fetch('organization', nil)
|
10
|
+
@address1 = obj.fetch('address1', nil)
|
11
|
+
@address2 = obj.fetch('address2', nil)
|
12
|
+
@address3 = obj.fetch('address3', nil)
|
13
|
+
@address4 = obj.fetch('address4', nil)
|
14
|
+
@address5 = obj.fetch('address5', nil)
|
15
|
+
@address6 = obj.fetch('address6', nil)
|
16
|
+
@address7 = obj.fetch('address7', nil)
|
17
|
+
@address8 = obj.fetch('address8', nil)
|
18
|
+
@address9 = obj.fetch('address9', nil)
|
19
|
+
@address10 = obj.fetch('address10', nil)
|
20
|
+
@address11 = obj.fetch('address11', nil)
|
21
|
+
@address12 = obj.fetch('address12', nil)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative './international_street/lookup'
|
2
|
+
require_relative './international_street/metadata'
|
3
|
+
require_relative './international_street/analysis'
|
4
|
+
require_relative './international_street/components'
|
5
|
+
require_relative './international_street/candidate'
|
6
|
+
require_relative './international_street/client'
|
7
|
+
require_relative './international_street/language_mode'
|
8
|
+
|
9
|
+
module SmartyStreets
|
10
|
+
module InternationalStreet
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
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
|
11
|
+
end
|
12
|
+
|
13
|
+
def from_json!(string)
|
14
|
+
JSON.load(string).each do |var, val|
|
15
|
+
instance_variable_set var, val
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
class LicenseSender
|
3
|
+
def initialize(inner, licenses)
|
4
|
+
@inner = inner
|
5
|
+
@licenses = licenses
|
6
|
+
end
|
7
|
+
|
8
|
+
def send(request)
|
9
|
+
if @licenses.length > 0
|
10
|
+
request.parameters['license'] = @licenses.join(',')
|
11
|
+
end
|
12
|
+
@inner.send(request)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require_relative 'version'
|
3
|
+
require_relative 'response'
|
4
|
+
|
5
|
+
module SmartyStreets
|
6
|
+
class NativeSender
|
7
|
+
def initialize(max_timeout = 10, proxy = nil, debug = false)
|
8
|
+
@max_timeout = max_timeout
|
9
|
+
@proxy = proxy
|
10
|
+
@debug = debug
|
11
|
+
end
|
12
|
+
|
13
|
+
def send(smarty_request)
|
14
|
+
request = self.class.build_request(smarty_request)
|
15
|
+
|
16
|
+
begin
|
17
|
+
http = build_http(request)
|
18
|
+
http.use_ssl = true
|
19
|
+
http.ssl_version = :TLSv1_2
|
20
|
+
http.open_timeout = @max_timeout
|
21
|
+
http.read_timeout = @max_timeout
|
22
|
+
|
23
|
+
response = http.request(request)
|
24
|
+
|
25
|
+
http.finish if http.started?
|
26
|
+
rescue StandardError => err
|
27
|
+
return Response.new(nil, nil, err)
|
28
|
+
end
|
29
|
+
|
30
|
+
build_smarty_response(response)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.build_request(smarty_request)
|
34
|
+
query = create_query(smarty_request)
|
35
|
+
|
36
|
+
if smarty_request.payload.nil?
|
37
|
+
request = Net::HTTP::Get.new(URI.parse("#{smarty_request.url_prefix}?#{query}"))
|
38
|
+
else
|
39
|
+
request = Net::HTTP::Post.new(URI.parse("#{smarty_request.url_prefix}?#{query}"))
|
40
|
+
end
|
41
|
+
|
42
|
+
request.content_type = 'application/json'
|
43
|
+
request.body = smarty_request.payload
|
44
|
+
request['User-Agent'] = "smartystreets (sdk:ruby@#{SmartyStreets::VERSION})"
|
45
|
+
request['Referer'] = smarty_request.referer unless smarty_request.referer.nil?
|
46
|
+
set_custom_headers(smarty_request.headers, request)
|
47
|
+
request
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_smarty_response(native_response)
|
51
|
+
Response.new(native_response.body, native_response.code)
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_http(request)
|
55
|
+
uri = request.uri
|
56
|
+
|
57
|
+
if @proxy.nil?
|
58
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
59
|
+
else
|
60
|
+
http = Net::HTTP.new(uri.hostname, uri.port, @proxy.host,
|
61
|
+
@proxy.port, @proxy.username, @proxy.password)
|
62
|
+
end
|
63
|
+
|
64
|
+
http.set_debug_output($stdout) if @debug
|
65
|
+
|
66
|
+
http
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.create_query(smarty_request)
|
70
|
+
URI.encode_www_form(smarty_request.parameters)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.set_custom_headers(smarty_headers, request)
|
74
|
+
smarty_headers.each do |key, values|
|
75
|
+
if values.respond_to? :each
|
76
|
+
values.each do |value|
|
77
|
+
request.add_field(key, value)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
request.add_field(key, values)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
# Contains information about the proxy through which all requests will be sent.
|
3
|
+
#
|
4
|
+
# host should not include a scheme
|
5
|
+
class Proxy
|
6
|
+
|
7
|
+
attr_accessor :port, :host, :username, :password
|
8
|
+
|
9
|
+
def initialize(host, port, username = nil, password = nil)
|
10
|
+
@host = host
|
11
|
+
@port = port
|
12
|
+
@username = username
|
13
|
+
@password = password
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
class Request
|
3
|
+
attr_accessor :parameters, :payload, :url_prefix, :referer, :headers, :content_type
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@parameters = {}
|
7
|
+
@payload = nil
|
8
|
+
@url_prefix = nil
|
9
|
+
@referer = nil
|
10
|
+
@headers = {}
|
11
|
+
@content_type = 'application/json'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SmartyStreets
|
2
|
+
class RetrySender
|
3
|
+
MAX_BACKOFF_DURATION = 10
|
4
|
+
STATUS_INTERNAL_SERVER_ERROR = 500
|
5
|
+
STATUS_TOO_MANY_REQUESTS = 429
|
6
|
+
|
7
|
+
def initialize(max_retries, inner, sleeper, logger)
|
8
|
+
@max_retries = max_retries
|
9
|
+
@inner = inner
|
10
|
+
@sleeper = sleeper
|
11
|
+
@logger = logger
|
12
|
+
end
|
13
|
+
|
14
|
+
def send(request)
|
15
|
+
response = @inner.send(request)
|
16
|
+
|
17
|
+
(0..@max_retries-1).each do |i|
|
18
|
+
if response.status_code.to_i == STATUS_TOO_MANY_REQUESTS
|
19
|
+
backoff(5)
|
20
|
+
end
|
21
|
+
|
22
|
+
break if response.status_code.to_i < STATUS_INTERNAL_SERVER_ERROR
|
23
|
+
|
24
|
+
backoff(i)
|
25
|
+
|
26
|
+
response = @inner.send(request)
|
27
|
+
end
|
28
|
+
|
29
|
+
response
|
30
|
+
end
|
31
|
+
|
32
|
+
def backoff(attempt)
|
33
|
+
backoff_duration = [attempt, MAX_BACKOFF_DURATION].min
|
34
|
+
|
35
|
+
@logger.log("There was an error processing the request. Retrying in #{backoff_duration} seconds...")
|
36
|
+
@sleeper.sleep(backoff_duration)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|