smartystreets_ruby_sdk 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +1 -1
  3. data/Vagrantfile +4 -2
  4. data/examples/international_example.rb +31 -0
  5. data/examples/us_autocomplete_example.rb +38 -0
  6. data/examples/us_extract_example.rb +52 -0
  7. data/examples/us_street_multiple_address_example.rb +11 -9
  8. data/examples/us_street_single_address_example.rb +3 -3
  9. data/examples/us_zipcode_multiple_lookup_example.rb +7 -5
  10. data/examples/us_zipcode_single_lookup_example.rb +3 -3
  11. data/lib/smartystreets_ruby_sdk/batch.rb +7 -3
  12. data/lib/smartystreets_ruby_sdk/client_builder.rb +118 -0
  13. data/lib/smartystreets_ruby_sdk/errors.rb +15 -7
  14. data/lib/smartystreets_ruby_sdk/exceptions.rb +12 -5
  15. data/lib/smartystreets_ruby_sdk/international_street.rb +10 -0
  16. data/lib/smartystreets_ruby_sdk/international_street/analysis.rb +13 -0
  17. data/lib/smartystreets_ruby_sdk/international_street/candidate.rb +33 -0
  18. data/lib/smartystreets_ruby_sdk/international_street/client.rb +56 -0
  19. data/lib/smartystreets_ruby_sdk/international_street/components.rb +55 -0
  20. data/lib/smartystreets_ruby_sdk/international_street/language_mode.rb +5 -0
  21. data/lib/smartystreets_ruby_sdk/international_street/lookup.rb +80 -0
  22. data/lib/smartystreets_ruby_sdk/international_street/metadata.rb +14 -0
  23. data/lib/smartystreets_ruby_sdk/json_able.rb +3 -3
  24. data/lib/smartystreets_ruby_sdk/native_sender.rb +6 -2
  25. data/lib/smartystreets_ruby_sdk/request.rb +2 -1
  26. data/lib/smartystreets_ruby_sdk/retry_sender.rb +5 -7
  27. data/lib/smartystreets_ruby_sdk/us_autocomplete.rb +7 -0
  28. data/lib/smartystreets_ruby_sdk/us_autocomplete/client.rb +66 -0
  29. data/lib/smartystreets_ruby_sdk/us_autocomplete/geolocation_type.rb +5 -0
  30. data/lib/smartystreets_ruby_sdk/us_autocomplete/lookup.rb +34 -0
  31. data/lib/smartystreets_ruby_sdk/us_autocomplete/suggestion.rb +14 -0
  32. data/lib/smartystreets_ruby_sdk/us_extract.rb +8 -0
  33. data/lib/smartystreets_ruby_sdk/us_extract/address.rb +22 -0
  34. data/lib/smartystreets_ruby_sdk/us_extract/client.rb +46 -0
  35. data/lib/smartystreets_ruby_sdk/us_extract/lookup.rb +20 -0
  36. data/lib/smartystreets_ruby_sdk/us_extract/metadata.rb +15 -0
  37. data/lib/smartystreets_ruby_sdk/us_extract/result.rb +19 -0
  38. data/lib/smartystreets_ruby_sdk/us_street.rb +1 -1
  39. data/lib/smartystreets_ruby_sdk/us_street/analysis.rb +1 -0
  40. data/lib/smartystreets_ruby_sdk/us_street/candidate.rb +1 -0
  41. data/lib/smartystreets_ruby_sdk/us_street/client.rb +9 -5
  42. data/lib/smartystreets_ruby_sdk/us_street/components.rb +3 -0
  43. data/lib/smartystreets_ruby_sdk/us_street/lookup.rb +6 -0
  44. data/lib/smartystreets_ruby_sdk/us_street/match_type.rb +5 -0
  45. data/lib/smartystreets_ruby_sdk/us_street/metadata.rb +1 -0
  46. data/lib/smartystreets_ruby_sdk/us_zipcode.rb +1 -1
  47. data/lib/smartystreets_ruby_sdk/us_zipcode/alternate_county.rb +13 -0
  48. data/lib/smartystreets_ruby_sdk/us_zipcode/city.rb +2 -0
  49. data/lib/smartystreets_ruby_sdk/us_zipcode/client.rb +12 -4
  50. data/lib/smartystreets_ruby_sdk/us_zipcode/lookup.rb +4 -0
  51. data/lib/smartystreets_ruby_sdk/us_zipcode/result.rb +3 -2
  52. data/lib/smartystreets_ruby_sdk/us_zipcode/zip_code.rb +16 -3
  53. data/lib/smartystreets_ruby_sdk/version.rb +1 -1
  54. metadata +28 -7
  55. data/lib/smartystreets_ruby_sdk/core_client_builder.rb +0 -57
  56. data/lib/smartystreets_ruby_sdk/match_type.rb +0 -5
  57. data/lib/smartystreets_ruby_sdk/us_street/client_builder.rb +0 -15
  58. data/lib/smartystreets_ruby_sdk/us_zipcode/client_builder.rb +0 -15
@@ -4,25 +4,32 @@ end
4
4
  class BadCredentialsError < SmartyException
5
5
  end
6
6
 
7
- class PaymentRequiredError < SmartyException
7
+ class ForbiddenError < SmartyException
8
8
  end
9
9
 
10
+ class PaymentRequiredError < SmartyException
11
+ end
10
12
 
11
13
  class RequestEntityTooLargeError < SmartyException
12
14
  end
13
15
 
14
-
15
16
  class BadRequestError < SmartyException
16
17
  end
17
18
 
19
+ class UnprocessableEntityError < SmartyException
20
+ end
18
21
 
19
22
  class TooManyRequestsError < SmartyException
20
23
  end
21
24
 
22
-
23
25
  class InternalServerError < SmartyException
24
26
  end
25
27
 
26
-
27
28
  class ServiceUnavailableError < SmartyException
28
- end
29
+ end
30
+
31
+ class GatewayTimeoutError < SmartyException
32
+ end
33
+
34
+ class BatchFullError < SmartyException
35
+ end
@@ -0,0 +1,10 @@
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 InternationalStreet
10
+ end
@@ -0,0 +1,13 @@
1
+ module InternationalStreet
2
+ # See "https://smartystreets.com/docs/cloud/international-street-api#analysis"
3
+ class Analysis
4
+
5
+ attr_reader :max_address_precision, :verification_status, :address_precision
6
+
7
+ def initialize(obj)
8
+ @verification_status = obj.fetch('verification_status', nil)
9
+ @address_precision = obj.fetch('address_precision', nil)
10
+ @max_address_precision = obj.fetch('max_address_precision', nil)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'components'
2
+ require_relative 'metadata'
3
+ require_relative 'analysis'
4
+
5
+ module InternationalStreet
6
+ # A candidate is a possible match for an address that was submitted. A lookup can have multiple
7
+ # candidates if the address was ambiguous.
8
+ #
9
+ # See "https://smartystreets.com/docs/cloud/international-street-api#root"
10
+ class Candidate
11
+ attr_reader :metadata, :address3, :address11, :address2, :address12, :address1, :address10,
12
+ :address9, :address8, :address7, :organization, :address6, :address5, :address4, :components, :analysis
13
+
14
+ def initialize(obj)
15
+ @organization = obj.fetch('organization', nil)
16
+ @address1 = obj.fetch('address1', nil)
17
+ @address2 = obj.fetch('address2', nil)
18
+ @address3 = obj.fetch('address3', nil)
19
+ @address4 = obj.fetch('address4', nil)
20
+ @address5 = obj.fetch('address5', nil)
21
+ @address6 = obj.fetch('address6', nil)
22
+ @address7 = obj.fetch('address7', nil)
23
+ @address8 = obj.fetch('address8', nil)
24
+ @address9 = obj.fetch('address9', nil)
25
+ @address10 = obj.fetch('address10', nil)
26
+ @address11 = obj.fetch('address11', nil)
27
+ @address12 = obj.fetch('address12', nil)
28
+ @components = Components.new(obj.fetch('components', {}))
29
+ @metadata = Metadata.new(obj.fetch('metadata', {}))
30
+ @analysis = Analysis.new(obj.fetch('analysis', {}))
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ require_relative '../request'
2
+ require_relative 'candidate'
3
+
4
+ module InternationalStreet
5
+ # It is recommended to instantiate this class using ClientBuilder.build_international_street_api_client()
6
+ class Client
7
+ def initialize(sender, serializer)
8
+ @sender = sender
9
+ @serializer = serializer
10
+ end
11
+
12
+ # Sends a Lookup object to the International Street API and stores the result in the Lookup's result field.
13
+ def send(lookup)
14
+ lookup.ensure_enough_info
15
+ request = build_request(lookup)
16
+
17
+ response = @sender.send(request)
18
+
19
+ candidates = convert_candidates(@serializer.deserialize(response.payload))
20
+ lookup.result = candidates
21
+ end
22
+
23
+ def build_request(lookup)
24
+ request = Request.new
25
+
26
+ add_parameter(request, 'country', lookup.country)
27
+ add_parameter(request, 'geocode', lookup.geocode.to_s)
28
+ add_parameter(request, 'language', lookup.language)
29
+ add_parameter(request, 'freeform', lookup.freeform)
30
+ add_parameter(request, 'address1', lookup.address1)
31
+ add_parameter(request, 'address2', lookup.address2)
32
+ add_parameter(request, 'address3', lookup.address3)
33
+ add_parameter(request, 'address4', lookup.address4)
34
+ add_parameter(request, 'organization', lookup.organization)
35
+ add_parameter(request, 'locality', lookup.locality)
36
+ add_parameter(request, 'administrative_area', lookup.administrative_area)
37
+ add_parameter(request, 'postal_code', lookup.postal_code)
38
+
39
+ request
40
+ end
41
+
42
+ def add_parameter(request, key, value)
43
+ request.parameters[key] = value unless value.nil? or value.empty?
44
+ end
45
+
46
+ def convert_candidates(raw_candidates)
47
+ candidates = []
48
+
49
+ raw_candidates.each do |candidate|
50
+ candidates.push(Candidate.new(candidate))
51
+ end
52
+
53
+ candidates
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,55 @@
1
+ module InternationalStreet
2
+ # See "https://smartystreets.com/docs/cloud/international-street-api#components"
3
+ class Components
4
+ attr_reader :premise, :thoroughfare_trailing_type, :sub_building, :locality, :post_box_number,
5
+ :thoroughfare_name, :thoroughfare_postdirection, :dependent_thoroughfare,
6
+ :thoroughfare, :dependent_thoroughfare_name, :postal_code_short, :dependent_thoroughfare_trailing_type,
7
+ :administrative_area, :post_box, :building_leading_type, :dependent_locality_name, :thoroughfare_type,
8
+ :dependent_thoroughfare_postdirection, :double_dependent_locality, :premise_number,
9
+ :dependent_thoroughfare_type, :post_box_type, :building, :sub_administrative_area, :postal_code_extra,
10
+ :sub_building_name, :postal_code, :dependent_locality, :premise_type, :sub_building_number,
11
+ :super_administrative_area, :premise_extra, :dependent_thoroughfare_predirection,
12
+ :building_trailing_type, :thoroughfare_predirection, :building_name, :country_iso_3, :sub_building_type
13
+
14
+ def initialize(obj)
15
+ @country_iso_3 = obj.fetch('country_iso_3', nil)
16
+ @super_administrative_area = obj.fetch('super_administrative_area', nil)
17
+ @administrative_area = obj.fetch('administrative_area', nil)
18
+ @sub_administrative_area = obj.fetch('sub_administrative_area', nil)
19
+ @dependent_locality= obj.fetch('dependent_locality', nil)
20
+ @dependent_locality_name = obj.fetch('dependent_locality_name', nil)
21
+ @double_dependent_locality = obj.fetch('double_dependent_locality', nil)
22
+ @locality = obj.fetch('locality', nil)
23
+ @postal_code = obj.fetch('postal_code', nil)
24
+ @postal_code_short = obj.fetch('postal_code_short', nil)
25
+ @postal_code_extra = obj.fetch('postal_code_extra', nil)
26
+ @premise = obj.fetch('premise', nil)
27
+ @premise_extra = obj.fetch('premise_extra', nil)
28
+ @premise_number = obj.fetch('premise_number', nil)
29
+ @premise_type = obj.fetch('premise_type', nil)
30
+ @thoroughfare = obj.fetch('thoroughfare', nil)
31
+ @thoroughfare_predirection = obj.fetch('thoroughfare_predirection', nil)
32
+ @thoroughfare_postdirection = obj.fetch('thoroughfare_postdirection', nil)
33
+ @thoroughfare_name = obj.fetch('thoroughfare_name', nil)
34
+ @thoroughfare_trailing_type = obj.fetch('thoroughfare_trailing_type', nil)
35
+ @thoroughfare_type = obj.fetch('thoroughfare_type', nil)
36
+ @dependent_thoroughfare = obj.fetch('dependent_thoroughfare', nil)
37
+ @dependent_thoroughfare_predirection = obj.fetch('dependent_thoroughfare_predirection', nil)
38
+ @dependent_thoroughfare_postdirection = obj.fetch('dependent_thoroughfare_postdirection', nil)
39
+ @dependent_thoroughfare_name = obj.fetch('dependent_thoroughfare_name', nil)
40
+ @dependent_thoroughfare_trailing_type = obj.fetch('dependent_thoroughfare_trailing_type', nil)
41
+ @dependent_thoroughfare_type = obj.fetch('dependent_thoroughfare_type', nil)
42
+ @building = obj.fetch('building', nil)
43
+ @building_leading_type = obj.fetch('building_leading_type', nil)
44
+ @building_name = obj.fetch('building_name', nil)
45
+ @building_trailing_type = obj.fetch('building_trailing_type', nil)
46
+ @sub_building_type = obj.fetch('sub_building_type', nil)
47
+ @sub_building_number = obj.fetch('sub_building_number', nil)
48
+ @sub_building_name = obj.fetch('sub_building_name', nil)
49
+ @sub_building = obj.fetch('sub_building', nil)
50
+ @post_box = obj.fetch('post_box', nil)
51
+ @post_box_type = obj.fetch('post_box_type', nil)
52
+ @post_box_number = obj.fetch('post_box_number', nil)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ module LanguageMode
2
+ NATIVE = 'native'.freeze
3
+
4
+ LATIN = 'latin'.freeze
5
+ end
@@ -0,0 +1,80 @@
1
+ module InternationalStreet
2
+ # In addition to holding all of the input data for this lookup, this class also will contain the
3
+ # result of the lookup after it comes back from the API.
4
+ #
5
+ # Note: Lookups must have certain required fields set with non-blank values.
6
+ # These can be found at the URL below.
7
+ #
8
+ # See "https://smartystreets.com/docs/cloud/international-street-api#http-input-fields"
9
+ #
10
+ # @geocode:: Disabled by default. Set to true to enable.
11
+ # @language:: When not set, the output language will match the language of the input values.
12
+ # When set to language_mode.NATIVE, the results will always be in the language of the output country.
13
+ # When set to language_mode.LATIN, the results will always be provided using a Latin character set.
14
+ class Lookup
15
+
16
+ attr_accessor :freeform, :locality, :postal_code, :address3, :address2, :inputId, :address1,
17
+ :geocode, :administrative_area, :country, :organization, :language, :address4, :result
18
+
19
+ def initialize(freeform=nil, country=nil)
20
+ @result = []
21
+
22
+ @inputId = nil
23
+ @country = country
24
+ @geocode = nil
25
+ @language = nil
26
+ @freeform = freeform
27
+ @address1 = nil
28
+ @address2 = nil
29
+ @address3 = nil
30
+ @address4 = nil
31
+ @organization = nil
32
+ @locality = nil
33
+ @administrative_area = nil
34
+ @postal_code = nil
35
+ end
36
+
37
+ def missing_country
38
+ field_is_missing(@country)
39
+ end
40
+
41
+ def has_freeform
42
+ field_is_set(@freeform)
43
+ end
44
+
45
+ def missing_address1
46
+ field_is_missing(@address1)
47
+ end
48
+
49
+ def has_postal_code
50
+ field_is_set(@postal_code)
51
+ end
52
+
53
+ def missing_locality_or_administrative_area
54
+ field_is_missing(@locality) or field_is_missing(@administrative_area)
55
+ end
56
+
57
+ def field_is_missing(field)
58
+ field.nil? or field.empty?
59
+ end
60
+
61
+ def field_is_set(field)
62
+ not field_is_missing(field)
63
+ end
64
+
65
+ def ensure_enough_info
66
+ raise UnprocessableEntityError, 'Country field is required.' if missing_country
67
+
68
+ return true if has_freeform
69
+
70
+ raise UnprocessableEntityError, 'Either freeform or address1 is required.' if missing_address1
71
+
72
+ return true if has_postal_code
73
+
74
+ if missing_locality_or_administrative_area
75
+ raise UnprocessableEntityError, 'Insufficient information:'\
76
+ 'One or more required fields were not set on the lookup.'
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,14 @@
1
+ module InternationalStreet
2
+ # See "https://smartystreets.com/docs/cloud/international-street-api#metadata"
3
+ class Metadata
4
+
5
+ attr_reader :longitude, :geocode_precision, :max_geocode_precision, :latitude
6
+
7
+ def initialize(obj)
8
+ @latitude = obj.fetch('latitude', nil)
9
+ @longitude = obj.fetch('longitude', nil)
10
+ @geocode_precision = obj.fetch('geocode_precision', nil)
11
+ @max_geocode_precision = obj.fetch('max_geocode_precision', nil)
12
+ end
13
+ end
14
+ end
@@ -3,15 +3,15 @@ require 'json'
3
3
  class JSONAble
4
4
  def to_json(options={})
5
5
  hash = {}
6
- self.instance_variables.each do |var|
7
- hash[var.to_s.delete('@')] = self.instance_variable_get var
6
+ instance_variables.each do |var|
7
+ hash[var.to_s.delete('@')] = instance_variable_get var
8
8
  end
9
9
  hash.to_json
10
10
  end
11
11
 
12
12
  def from_json!(string)
13
13
  JSON.load(string).each do |var, val|
14
- self.instance_variable_set var, val
14
+ instance_variable_set var, val
15
15
  end
16
16
  end
17
17
  end
@@ -29,11 +29,15 @@ class NativeSender
29
29
 
30
30
  def self.build_request(smarty_request)
31
31
  query = create_query(smarty_request)
32
- request = Net::HTTP::Post.new(URI.parse("#{smarty_request.url_prefix}?#{query}"))
32
+ if smarty_request.payload.nil?
33
+ request = Net::HTTP::Get.new(URI.parse("#{smarty_request.url_prefix}?#{query}"))
34
+ else
35
+ request = Net::HTTP::Post.new(URI.parse("#{smarty_request.url_prefix}?#{query}"))
36
+ end
33
37
  request.content_type = 'application/json'
34
38
  request.body = smarty_request.payload
35
39
  request['User-Agent'] = "smartystreets (sdk:ruby@#{SmartystreetsRubySdk::VERSION})"
36
- request['Referer'] = smarty_request.referer if smarty_request.referer != nil
40
+ request['Referer'] = smarty_request.referer unless smarty_request.referer.nil?
37
41
  set_custom_headers(smarty_request.headers, request)
38
42
  request
39
43
  end
@@ -1,5 +1,5 @@
1
1
  class Request
2
- attr_accessor :parameters, :payload, :url_prefix, :referer, :headers
2
+ attr_accessor :parameters, :payload, :url_prefix, :referer, :headers, :content_type
3
3
 
4
4
  def initialize
5
5
  @parameters = {}
@@ -7,5 +7,6 @@ class Request
7
7
  @url_prefix = nil
8
8
  @referer = nil
9
9
  @headers = {}
10
+ @content_type = 'application/json'
10
11
  end
11
12
  end
@@ -1,6 +1,6 @@
1
1
  class RetrySender
2
2
  MAX_BACKOFF_DURATION = 10
3
- STATUS_OK = '200'
3
+ STATUS_OK = '200'.freeze
4
4
 
5
5
  def initialize(max_retries, inner, sleeper, logger)
6
6
  @max_retries = max_retries
@@ -12,17 +12,15 @@ class RetrySender
12
12
  def send(request)
13
13
  response = @inner.send(request)
14
14
 
15
- (0..@max_retries-1).each { |i|
16
- if response.status_code == STATUS_OK
17
- break
18
- end
15
+ (0..@max_retries-1).each do |i|
16
+ break if response.status_code == STATUS_OK
19
17
 
20
18
  backoff(i)
21
19
 
22
20
  response = @inner.send(request)
23
- }
21
+ end
24
22
 
25
- response
23
+ response
26
24
  end
27
25
 
28
26
  def backoff(attempt)
@@ -0,0 +1,7 @@
1
+ require_relative './us_autocomplete/lookup'
2
+ require_relative './us_autocomplete/geolocation_type'
3
+ require_relative './us_autocomplete/suggestion'
4
+ require_relative './us_autocomplete/client'
5
+
6
+ module USAutocomplete
7
+ end
@@ -0,0 +1,66 @@
1
+ require_relative '../request'
2
+ require_relative '../exceptions'
3
+ require_relative 'geolocation_type'
4
+ require_relative 'suggestion'
5
+
6
+ module USAutocomplete
7
+ # It is recommended to instantiate this class using ClientBuilder.build_us_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 US Autocomplete API and stores the result in the Lookup's result field.
15
+ def send(lookup)
16
+ if not lookup or not lookup.prefix
17
+ raise SmartyException, '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
+ result = @serializer.deserialize(response.payload)
25
+ suggestions = convert_suggestions(result.fetch('suggestions', []))
26
+ lookup.result = suggestions
27
+ end
28
+
29
+
30
+ def build_request(lookup)
31
+ request = Request.new
32
+
33
+ add_parameter(request, 'prefix', lookup.prefix)
34
+ add_parameter(request, 'suggestions', lookup.max_suggestions.to_s)
35
+ add_parameter(request, 'city_filter', build_filter_string(lookup.city_filter))
36
+ add_parameter(request, 'state_filter', build_filter_string(lookup.state_filter))
37
+ add_parameter(request, 'prefer', build_filter_string(lookup.prefer))
38
+ if lookup.geolocate_type != GeolocationType::NONE
39
+ request.parameters['geolocate'] = 'true'
40
+ request.parameters['geolocate_precision'] = lookup.geolocate_type
41
+ else
42
+ request.parameters['geolocate'] = 'false'
43
+ end
44
+
45
+ request
46
+ end
47
+
48
+ def build_filter_string(filter_list)
49
+ filter_list ? filter_list.join(',') : nil
50
+ end
51
+
52
+ def convert_suggestions(suggestion_hashes)
53
+ converted_suggestions = []
54
+
55
+ suggestion_hashes.each do |suggestion|
56
+ converted_suggestions.push(USAutocomplete::Suggestion.new(suggestion))
57
+ end
58
+
59
+ converted_suggestions
60
+ end
61
+
62
+ def add_parameter(request, key, value)
63
+ request.parameters[key] = value unless value.nil? or value.empty?
64
+ end
65
+ end
66
+ end