smartystreets_ruby_sdk 8.1.1 → 9.1.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 +4 -4
- data/.github/workflows/ci.yml +10 -0
- data/.github/workflows/publish.yml +29 -0
- data/.github/workflows/test.yml +21 -0
- data/CLAUDE.md +2 -2
- data/Makefile +11 -5
- data/README.md +2 -0
- data/examples/us_autocomplete_example.rb +69 -0
- data/examples/us_autocomplete_pro_example.rb +3 -1
- data/examples/us_enrichment_business_name_search_example.rb +76 -0
- data/examples/us_enrichment_etag_example.rb +22 -14
- data/examples/us_enrichment_example.rb +1 -1
- data/examples/us_reverse_geo_example.rb +3 -0
- data/examples/us_street_match_strategy_example.rb +85 -0
- data/lib/smartystreets_ruby_sdk/client_builder.rb +7 -0
- data/lib/smartystreets_ruby_sdk/errors.rb +16 -11
- data/lib/smartystreets_ruby_sdk/exceptions.rb +6 -0
- data/lib/smartystreets_ruby_sdk/international_street/components.rb +8 -3
- data/lib/smartystreets_ruby_sdk/international_street/rootlevel.rb +1 -5
- data/lib/smartystreets_ruby_sdk/native_serializer.rb +1 -0
- data/lib/smartystreets_ruby_sdk/status_code_sender.rb +29 -25
- data/lib/smartystreets_ruby_sdk/us_autocomplete/client.rb +82 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/geolocation_type.rb +8 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/lookup.rb +73 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/source_type.rb +8 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete/suggestion.rb +21 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete.rb +10 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete_pro/source_type.rb +8 -0
- data/lib/smartystreets_ruby_sdk/us_autocomplete_pro.rb +1 -0
- data/lib/smartystreets_ruby_sdk/us_enrichment/client.rb +5 -2
- data/lib/smartystreets_ruby_sdk/us_enrichment/lookup.rb +3 -2
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/source_type.rb +8 -0
- data/lib/smartystreets_ruby_sdk/us_reverse_geo/us_reverse_geo_response.rb +1 -1
- data/lib/smartystreets_ruby_sdk/us_reverse_geo.rb +1 -0
- data/lib/smartystreets_ruby_sdk/version.rb +1 -1
- data/lib/smartystreets_ruby_sdk.rb +1 -0
- metadata +17 -4
- data/.github/workflows/gem-publish.yml +0 -27
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f033c107bfea0fb806b080faed0a58d7d9e2a062acc88f74b162fd0b2f4db73a
|
|
4
|
+
data.tar.gz: eb2ec5974ad3143e1abd197daea71fb6ac817eaf9bc2b4e84a1cd34d2c621012
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4d6cdd50b585f1bec44a2ca6cf8391613774c9bea95f6537343f9565f884fd56a976cc91ebb089c9d426b3f762e0fb4bf23ec3c2e0084bbadc3179234ab3108d
|
|
7
|
+
data.tar.gz: 2c45d8292d54cf45b2f1add26eecc7ba8de652f4668d448fcf404b9371910ba9e9638e5804fae06d8decd3e70dd1dbb95abe67c1e7ada889076cb4fe71adc90f
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Ruby Gem Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- '**'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
uses: ./.github/workflows/test.yml
|
|
11
|
+
|
|
12
|
+
publish:
|
|
13
|
+
needs: test
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- uses: ruby/setup-ruby@v1
|
|
21
|
+
with:
|
|
22
|
+
ruby-version: '3.3'
|
|
23
|
+
bundler-cache: false
|
|
24
|
+
|
|
25
|
+
- name: Publish
|
|
26
|
+
run: |
|
|
27
|
+
VERSION=${GITHUB_REF#refs/*/} make publish
|
|
28
|
+
env:
|
|
29
|
+
API_KEY: "${{ secrets.GEM_HOST_API_KEY }}"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Ruby Tests (reusable)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
test:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
ruby-version: ['3.3', '3.4', '4.0']
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
- uses: ruby/setup-ruby@v1
|
|
15
|
+
with:
|
|
16
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
17
|
+
bundler-cache: false
|
|
18
|
+
- name: Install dependencies
|
|
19
|
+
run: make dependencies
|
|
20
|
+
- name: Test
|
|
21
|
+
run: make test
|
data/CLAUDE.md
CHANGED
|
@@ -25,7 +25,7 @@ make examples
|
|
|
25
25
|
|
|
26
26
|
## Architecture
|
|
27
27
|
|
|
28
|
-
This is the official SmartyStreets Ruby SDK for address verification APIs. It uses pure Ruby with Net::HTTP (no external runtime dependencies).
|
|
28
|
+
This is the official SmartyStreets Ruby SDK for address verification APIs. It uses pure Ruby with Net::HTTP (no external runtime dependencies). Compatible with Ruby 3.3 and later.
|
|
29
29
|
|
|
30
30
|
### Core Design Patterns
|
|
31
31
|
|
|
@@ -58,7 +58,7 @@ URLPrefixSender → CustomQuerySender → LicenseSender → RetrySender → Sign
|
|
|
58
58
|
|
|
59
59
|
### Supported APIs
|
|
60
60
|
|
|
61
|
-
- US Street, US ZipCode, US Autocomplete Pro, US Extract, US Reverse Geo, US Enrichment
|
|
61
|
+
- US Street, US ZipCode, US Autocomplete, US Autocomplete Pro, US Extract, US Reverse Geo, US Enrichment
|
|
62
62
|
- International Street, International Autocomplete, International Postal Code
|
|
63
63
|
|
|
64
64
|
### Test Structure
|
data/Makefile
CHANGED
|
@@ -12,7 +12,7 @@ test:
|
|
|
12
12
|
dependencies:
|
|
13
13
|
gem install minitest
|
|
14
14
|
|
|
15
|
-
package: clean dependencies
|
|
15
|
+
package: clean dependencies
|
|
16
16
|
sed -i "s/0\.0\.0/${VERSION}/g" "$(VERSION_FILE)" \
|
|
17
17
|
&& gem build *.gemspec \
|
|
18
18
|
&& git checkout "$(VERSION_FILE)"
|
|
@@ -33,11 +33,14 @@ international_postal_code_api:
|
|
|
33
33
|
international_street_api:
|
|
34
34
|
cd examples && ruby international_example.rb
|
|
35
35
|
|
|
36
|
+
us_autocomplete_api:
|
|
37
|
+
cd examples && ruby us_autocomplete_example.rb
|
|
38
|
+
|
|
36
39
|
us_autocomplete_pro_api:
|
|
37
40
|
cd examples && ruby us_autocomplete_pro_example.rb
|
|
38
41
|
|
|
39
42
|
us_enrichment_api:
|
|
40
|
-
cd examples && ruby us_enrichment_example.rb && ruby us_enrichment_business_example.rb && ruby us_enrichment_etag_example.rb
|
|
43
|
+
cd examples && ruby us_enrichment_example.rb && ruby us_enrichment_business_example.rb && ruby us_enrichment_etag_example.rb && ruby us_enrichment_business_name_search_example.rb
|
|
41
44
|
|
|
42
45
|
us_extract_api:
|
|
43
46
|
cd examples && ruby us_extract_example.rb
|
|
@@ -46,11 +49,14 @@ us_reverse_geo_api:
|
|
|
46
49
|
cd examples && ruby us_reverse_geo_example.rb
|
|
47
50
|
|
|
48
51
|
us_street_api:
|
|
49
|
-
cd examples && ruby us_street_single_address_example.rb && ruby us_street_multiple_address_example.rb && ruby us_street_component_analysis_example.rb && ruby us_street_iana_timezone_example.rb
|
|
52
|
+
cd examples && ruby us_street_single_address_example.rb && ruby us_street_multiple_address_example.rb && ruby us_street_component_analysis_example.rb && ruby us_street_iana_timezone_example.rb && ruby us_street_match_strategy_example.rb
|
|
53
|
+
|
|
54
|
+
us_street_match_strategy_api:
|
|
55
|
+
cd examples && ruby us_street_match_strategy_example.rb
|
|
50
56
|
|
|
51
57
|
us_zipcode_api:
|
|
52
58
|
cd examples && ruby us_zipcode_single_lookup_example.rb && ruby us_zipcode_multiple_lookup_example.rb
|
|
53
59
|
|
|
54
|
-
examples: international_autocomplete_api international_postal_code_api international_street_api us_autocomplete_pro_api us_enrichment_api us_extract_api us_reverse_geo_api us_street_api us_zipcode_api
|
|
60
|
+
examples: international_autocomplete_api international_postal_code_api international_street_api us_autocomplete_pro_api us_autocomplete_api us_enrichment_api us_extract_api us_reverse_geo_api us_street_api us_zipcode_api
|
|
55
61
|
|
|
56
|
-
.PHONY: clean test dependencies package publish international_autocomplete_api international_postal_code_api international_street_api us_autocomplete_pro_api us_enrichment_api us_extract_api us_reverse_geo_api us_street_api us_zipcode_api examples
|
|
62
|
+
.PHONY: clean test dependencies package publish international_autocomplete_api international_postal_code_api international_street_api us_autocomplete_pro_api us_autocomplete_api us_enrichment_api us_extract_api us_reverse_geo_api us_street_api us_street_match_strategy_api us_zipcode_api examples
|
data/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
The official client libraries for accessing SmartyStreets APIs from Ruby
|
|
6
6
|
|
|
7
|
+
Compatible with Ruby 3.3 and later.
|
|
8
|
+
|
|
7
9
|
You may have noticed this page is curiously sparse. Don't panic, there's [documentation](https://smartystreets.com/docs/sdk/ruby) and [examples](examples).
|
|
8
10
|
|
|
9
11
|
[Apache 2.0 License](LICENSE.txt)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require '../lib/smartystreets_ruby_sdk/shared_credentials'
|
|
2
|
+
require '../lib/smartystreets_ruby_sdk/static_credentials'
|
|
3
|
+
require '../lib/smartystreets_ruby_sdk/basic_auth_credentials'
|
|
4
|
+
require '../lib/smartystreets_ruby_sdk/client_builder'
|
|
5
|
+
require '../lib/smartystreets_ruby_sdk/us_autocomplete/lookup'
|
|
6
|
+
require '../lib/smartystreets_ruby_sdk/us_autocomplete/source_type'
|
|
7
|
+
|
|
8
|
+
# This example is for US Autocomplete (V2). It has the same name as a previous product
|
|
9
|
+
# which has been deprecated since 2022, which we refer to as US Autocomplete Basic.
|
|
10
|
+
# If you are still using US Autocomplete Basic, this SDK will not work.
|
|
11
|
+
class USAutocompleteExample
|
|
12
|
+
Lookup = SmartyStreets::USAutocomplete::Lookup
|
|
13
|
+
SourceType = SmartyStreets::USAutocomplete::SourceType
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
# key = 'Your SmartyStreets Auth Key here'
|
|
17
|
+
# referer = 'Your host name here'
|
|
18
|
+
# We recommend storing your secret keys in environment variables instead---it's safer!
|
|
19
|
+
# key = ENV['SMARTY_AUTH_WEB']
|
|
20
|
+
# referer = ENV['SMARTY_AUTH_REFERER']
|
|
21
|
+
# credentials = SmartyStreets::SharedCredentials.new(key, referer)
|
|
22
|
+
|
|
23
|
+
id = ENV['SMARTY_AUTH_ID']
|
|
24
|
+
token = ENV['SMARTY_AUTH_TOKEN']
|
|
25
|
+
credentials = SmartyStreets::BasicAuthCredentials.new(id, token)
|
|
26
|
+
|
|
27
|
+
client = SmartyStreets::ClientBuilder.new(credentials).build_us_autocomplete_api_client
|
|
28
|
+
|
|
29
|
+
# Documentation for input fields can be found at:
|
|
30
|
+
# https://www.smarty.com/docs/apis/us-autocomplete-v2/reference#http-request-input-fields
|
|
31
|
+
|
|
32
|
+
lookup = Lookup.new('1042 W Center')
|
|
33
|
+
lookup.add_city_filter('Denver,Aurora,CO')
|
|
34
|
+
lookup.add_city_filter('Orem,UT')
|
|
35
|
+
lookup.max_results = 5
|
|
36
|
+
lookup.prefer_ratio = 3
|
|
37
|
+
lookup.source = SourceType::ALL
|
|
38
|
+
|
|
39
|
+
# lookup.add_custom_parameter('parameter', 'value')
|
|
40
|
+
|
|
41
|
+
suggestions = client.send(lookup) # The client will also return the suggestions directly
|
|
42
|
+
|
|
43
|
+
puts
|
|
44
|
+
puts '*** Result with some filters ***'
|
|
45
|
+
puts
|
|
46
|
+
|
|
47
|
+
entry_id = nil
|
|
48
|
+
suggestions.each do |suggestion|
|
|
49
|
+
puts "#{suggestion.street_line} #{suggestion.city}, #{suggestion.state}"
|
|
50
|
+
entry_id = suggestion.entry_id if suggestion.entry_id && !suggestion.entry_id.empty?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Expand the secondaries of a result that has an entry_id by passing it back as the selected address.
|
|
54
|
+
if entry_id && !entry_id.empty?
|
|
55
|
+
lookup.selected = entry_id
|
|
56
|
+
suggestions = client.send(lookup)
|
|
57
|
+
|
|
58
|
+
puts
|
|
59
|
+
puts '*** Secondaries ***'
|
|
60
|
+
puts
|
|
61
|
+
|
|
62
|
+
suggestions.each do |suggestion|
|
|
63
|
+
puts "#{suggestion.street_line} #{suggestion.city}, #{suggestion.state}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
USAutocompleteExample.new.run
|
|
@@ -3,9 +3,11 @@ require '../lib/smartystreets_ruby_sdk/static_credentials'
|
|
|
3
3
|
require '../lib/smartystreets_ruby_sdk/basic_auth_credentials'
|
|
4
4
|
require '../lib/smartystreets_ruby_sdk/client_builder'
|
|
5
5
|
require '../lib/smartystreets_ruby_sdk/us_autocomplete_pro/lookup'
|
|
6
|
+
require '../lib/smartystreets_ruby_sdk/us_autocomplete_pro/source_type'
|
|
6
7
|
|
|
7
8
|
class USAutocompleteProExample
|
|
8
9
|
Lookup = SmartyStreets::USAutocompletePro::Lookup
|
|
10
|
+
SourceType = SmartyStreets::USAutocompletePro::SourceType
|
|
9
11
|
|
|
10
12
|
def run
|
|
11
13
|
# key = 'Your SmartyStreets Auth Key here'
|
|
@@ -29,7 +31,7 @@ class USAutocompleteProExample
|
|
|
29
31
|
lookup.add_city_filter('Orem,UT')
|
|
30
32
|
lookup.max_results = 5
|
|
31
33
|
lookup.prefer_ratio = 3
|
|
32
|
-
lookup.source =
|
|
34
|
+
lookup.source = SourceType::ALL
|
|
33
35
|
|
|
34
36
|
# lookup.add_custom_parameter('parameter', 'value')
|
|
35
37
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require '../lib/smartystreets_ruby_sdk/static_credentials'
|
|
2
|
+
require '../lib/smartystreets_ruby_sdk/shared_credentials'
|
|
3
|
+
require '../lib/smartystreets_ruby_sdk/basic_auth_credentials'
|
|
4
|
+
require '../lib/smartystreets_ruby_sdk/client_builder'
|
|
5
|
+
require '../lib/smartystreets_ruby_sdk/us_enrichment/lookup'
|
|
6
|
+
|
|
7
|
+
class USEnrichmentBusinessNameSearchExample
|
|
8
|
+
def run
|
|
9
|
+
id = ENV['SMARTY_AUTH_ID']
|
|
10
|
+
token = ENV['SMARTY_AUTH_TOKEN']
|
|
11
|
+
credentials = SmartyStreets::BasicAuthCredentials.new(id, token)
|
|
12
|
+
|
|
13
|
+
client = SmartyStreets::ClientBuilder.new(credentials).build_us_enrichment_api_client
|
|
14
|
+
|
|
15
|
+
business_name = "delta air"
|
|
16
|
+
|
|
17
|
+
lookup = SmartyStreets::USEnrichment::Lookup.new
|
|
18
|
+
lookup.business_name = business_name
|
|
19
|
+
lookup.city = "atlanta"
|
|
20
|
+
|
|
21
|
+
begin
|
|
22
|
+
summary_results = client.send_business_lookup(lookup)
|
|
23
|
+
rescue SmartyStreets::SmartyError => err
|
|
24
|
+
puts err
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if summary_results.nil? || summary_results.empty?
|
|
29
|
+
puts "No response returned for business-name search"
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
summary = summary_results[0]
|
|
34
|
+
if summary.businesses.nil? || summary.businesses.empty?
|
|
35
|
+
puts "No businesses found for this business name search"
|
|
36
|
+
return
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
puts "Summary results for BusinessName: #{business_name}"
|
|
40
|
+
summary.businesses.each do |biz|
|
|
41
|
+
puts " - #{biz.company_name} (ID: #{biz.business_id})"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
first = summary.businesses[0]
|
|
45
|
+
puts
|
|
46
|
+
puts "Fetching details for business: #{first.company_name} (ID: #{first.business_id})"
|
|
47
|
+
|
|
48
|
+
begin
|
|
49
|
+
detail_result = client.send_business_detail_lookup(first.business_id)
|
|
50
|
+
rescue SmartyStreets::SmartyError => err
|
|
51
|
+
puts err
|
|
52
|
+
return
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if detail_result.nil?
|
|
56
|
+
puts "No detail result returned"
|
|
57
|
+
return
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
puts
|
|
61
|
+
puts "Detail result:"
|
|
62
|
+
puts " smarty_key: #{detail_result.smarty_key}"
|
|
63
|
+
puts " data_set_name: #{detail_result.data_set_name}"
|
|
64
|
+
puts " business_id: #{detail_result.business_id}"
|
|
65
|
+
attrs = detail_result.attributes
|
|
66
|
+
return if attrs.nil?
|
|
67
|
+
attrs.instance_variables.each do |var|
|
|
68
|
+
value = attrs.instance_variable_get(var)
|
|
69
|
+
next if value.nil?
|
|
70
|
+
puts " #{var.to_s.delete('@')}: #{value}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
example = USEnrichmentBusinessNameSearchExample.new
|
|
76
|
+
example.run
|
|
@@ -40,10 +40,12 @@ class USEnrichmentEtagExample
|
|
|
40
40
|
second = SmartyStreets::USEnrichment::Lookup.new(smarty_key, 'business')
|
|
41
41
|
second.request_etag = captured_etag
|
|
42
42
|
begin
|
|
43
|
-
@client.send_business_lookup(second)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
results = @client.send_business_lookup(second)
|
|
44
|
+
if results.empty?
|
|
45
|
+
puts " Call 2 (matching Etag): 304 not modified - cache is still valid. Refreshed Etag=#{display(second.response_etag)}"
|
|
46
|
+
else
|
|
47
|
+
puts " Call 2 (matching Etag): 200 - server did NOT honor the conditional. Etag=#{display(second.response_etag)}"
|
|
48
|
+
end
|
|
47
49
|
rescue SmartyStreets::SmartyError => err
|
|
48
50
|
puts " Call 2 unexpected failure: #{err.class}: #{err.message}"
|
|
49
51
|
return nil
|
|
@@ -52,10 +54,12 @@ class USEnrichmentEtagExample
|
|
|
52
54
|
third = SmartyStreets::USEnrichment::Lookup.new(smarty_key, 'business')
|
|
53
55
|
third.request_etag = captured_etag + "X"
|
|
54
56
|
begin
|
|
55
|
-
@client.send_business_lookup(third)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
results = @client.send_business_lookup(third)
|
|
58
|
+
if results.empty?
|
|
59
|
+
puts " Call 3 (mutated Etag): 304 - UNEXPECTED. Server treated a different Etag as matching."
|
|
60
|
+
else
|
|
61
|
+
puts " Call 3 (mutated Etag): 200 as expected. Etag=#{display(third.response_etag)}"
|
|
62
|
+
end
|
|
59
63
|
rescue SmartyStreets::SmartyError => err
|
|
60
64
|
puts " Call 3 unexpected failure: #{err.class}: #{err.message}"
|
|
61
65
|
end
|
|
@@ -86,9 +90,11 @@ class USEnrichmentEtagExample
|
|
|
86
90
|
second.request_etag = captured_etag
|
|
87
91
|
begin
|
|
88
92
|
@client.send_business_detail_lookup(second)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
if second.result.nil?
|
|
94
|
+
puts " Call 2 (matching Etag): 304 not modified - cache is still valid. Refreshed Etag=#{display(second.response_etag)}"
|
|
95
|
+
else
|
|
96
|
+
puts " Call 2 (matching Etag): 200 - server did NOT honor the conditional. Etag=#{display(second.response_etag)}"
|
|
97
|
+
end
|
|
92
98
|
rescue SmartyStreets::SmartyError => err
|
|
93
99
|
puts " Call 2 unexpected failure: #{err.class}: #{err.message}"
|
|
94
100
|
return
|
|
@@ -98,9 +104,11 @@ class USEnrichmentEtagExample
|
|
|
98
104
|
third.request_etag = captured_etag + "X"
|
|
99
105
|
begin
|
|
100
106
|
@client.send_business_detail_lookup(third)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
if third.result.nil?
|
|
108
|
+
puts " Call 3 (mutated Etag): 304 - UNEXPECTED. Server treated a different Etag as matching."
|
|
109
|
+
else
|
|
110
|
+
puts " Call 3 (mutated Etag): 200 as expected. Etag=#{display(third.response_etag)}"
|
|
111
|
+
end
|
|
104
112
|
rescue SmartyStreets::SmartyError => err
|
|
105
113
|
puts " Call 3 unexpected failure: #{err.class}: #{err.message}"
|
|
106
114
|
end
|
|
@@ -154,7 +154,7 @@ class USEnrichmentAddressExample
|
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
def one_liner(obj)
|
|
157
|
-
obj.instance_variables.
|
|
157
|
+
obj.instance_variables.filter do |var|
|
|
158
158
|
value = obj.instance_variable_get(var)
|
|
159
159
|
"#{var.to_s.delete('@')}=#{value}" unless value.nil?
|
|
160
160
|
end.join(' ')
|
|
@@ -3,9 +3,11 @@ require '../lib/smartystreets_ruby_sdk/shared_credentials'
|
|
|
3
3
|
require '../lib/smartystreets_ruby_sdk/basic_auth_credentials'
|
|
4
4
|
require '../lib/smartystreets_ruby_sdk/client_builder'
|
|
5
5
|
require '../lib/smartystreets_ruby_sdk/us_reverse_geo/lookup'
|
|
6
|
+
require '../lib/smartystreets_ruby_sdk/us_reverse_geo/source_type'
|
|
6
7
|
|
|
7
8
|
class USReverseGeoExample
|
|
8
9
|
Lookup = SmartyStreets::USReverseGeo::Lookup
|
|
10
|
+
SourceType = SmartyStreets::USReverseGeo::SourceType
|
|
9
11
|
|
|
10
12
|
def run
|
|
11
13
|
# key = 'Your SmartyStreets Auth Key here'
|
|
@@ -25,6 +27,7 @@ class USReverseGeoExample
|
|
|
25
27
|
# https://smartystreets.com/docs/cloud/us-reverse-geo-api#http-request-input-fields
|
|
26
28
|
|
|
27
29
|
lookup = Lookup.new(40.111111, -111.111111)
|
|
30
|
+
lookup.source = SourceType::ALL
|
|
28
31
|
|
|
29
32
|
# lookup.add_custom_parameter('parameter', 'value')
|
|
30
33
|
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require '../lib/smartystreets_ruby_sdk/static_credentials'
|
|
2
|
+
require '../lib/smartystreets_ruby_sdk/shared_credentials'
|
|
3
|
+
require '../lib/smartystreets_ruby_sdk/basic_auth_credentials'
|
|
4
|
+
require '../lib/smartystreets_ruby_sdk/client_builder'
|
|
5
|
+
require '../lib/smartystreets_ruby_sdk/batch'
|
|
6
|
+
require '../lib/smartystreets_ruby_sdk/us_street/lookup'
|
|
7
|
+
require '../lib/smartystreets_ruby_sdk/us_street/match_type'
|
|
8
|
+
|
|
9
|
+
class USStreetLookupsWithMatchStrategyExample
|
|
10
|
+
Lookup = SmartyStreets::USStreet::Lookup
|
|
11
|
+
MatchType = SmartyStreets::USStreet::MatchType
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
# We recommend storing your secret keys in environment variables instead---it's safer!
|
|
15
|
+
id = ENV['SMARTY_AUTH_ID']
|
|
16
|
+
token = ENV['SMARTY_AUTH_TOKEN']
|
|
17
|
+
credentials = SmartyStreets::BasicAuthCredentials.new(id, token)
|
|
18
|
+
client = SmartyStreets::ClientBuilder.new(credentials).build_us_street_api_client
|
|
19
|
+
|
|
20
|
+
# Each address is run through all three match strategies so you can compare how
|
|
21
|
+
# 'strict', 'enhanced', and 'invalid' each handle a valid, an invalid, and an
|
|
22
|
+
# ambiguous address.
|
|
23
|
+
# - strict: only returns candidates that are valid, mailable addresses.
|
|
24
|
+
# - enhanced: returns a more comprehensive dataset (requires a US Core or Rooftop license).
|
|
25
|
+
# - invalid: most permissive; always returns at least one candidate (a best-guess standardization).
|
|
26
|
+
# Documentation for input fields: https://smartystreets.com/docs/cloud/us-street-api
|
|
27
|
+
addresses = [
|
|
28
|
+
['valid (real, deliverable)', '1600 Amphitheatre Pkwy', 'Mountain View', 'CA', '94043'],
|
|
29
|
+
['invalid (no such address)', '9999 W 1150 S', 'Provo', 'UT', '84601'],
|
|
30
|
+
['ambiguous (missing ZIP/unit)', '1 Rosedale St', 'Baltimore', 'MD', '']
|
|
31
|
+
]
|
|
32
|
+
strategies = [MatchType::STRICT, MatchType::ENHANCED, MatchType::INVALID]
|
|
33
|
+
|
|
34
|
+
batch = SmartyStreets::Batch.new
|
|
35
|
+
cases = [] # parallel metadata for each lookup, in the order they are added to the batch
|
|
36
|
+
|
|
37
|
+
addresses.each do |label, street, city, state, zipcode|
|
|
38
|
+
strategies.each do |strategy|
|
|
39
|
+
lookup = Lookup.new
|
|
40
|
+
lookup.street = street
|
|
41
|
+
lookup.city = city
|
|
42
|
+
lookup.state = state
|
|
43
|
+
lookup.zipcode = zipcode
|
|
44
|
+
lookup.match = strategy
|
|
45
|
+
lookup.candidates = 10 # allow ambiguous addresses to return more than one match
|
|
46
|
+
batch.add(lookup)
|
|
47
|
+
cases << [label, "#{street}, #{city}, #{state}", strategy]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
begin
|
|
52
|
+
client.send_batch(batch)
|
|
53
|
+
rescue SmartyStreets::SmartyError => err
|
|
54
|
+
puts err
|
|
55
|
+
return
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
last_address = nil
|
|
59
|
+
batch.each_with_index do |lookup, i|
|
|
60
|
+
label, address_display, strategy = cases[i]
|
|
61
|
+
|
|
62
|
+
unless address_display == last_address
|
|
63
|
+
puts "\n" + ('=' * 70)
|
|
64
|
+
puts " Address: #{address_display} [#{label}]"
|
|
65
|
+
puts('=' * 70)
|
|
66
|
+
last_address = address_display
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
candidates = lookup.result
|
|
70
|
+
puts "\n--- '#{strategy}' strategy ---"
|
|
71
|
+
|
|
72
|
+
if candidates.empty?
|
|
73
|
+
puts ' 0 candidates - no match returned under this strategy.'
|
|
74
|
+
next
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
puts " #{candidates.length} candidate(s):"
|
|
78
|
+
candidates.each do |candidate|
|
|
79
|
+
puts " [#{candidate.candidate_index}] #{candidate.delivery_line_1} #{candidate.last_line}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
USStreetLookupsWithMatchStrategyExample.new.run
|
|
@@ -17,6 +17,7 @@ require_relative 'international_street/client'
|
|
|
17
17
|
require_relative 'international_autocomplete/client'
|
|
18
18
|
require_relative 'us_reverse_geo/client'
|
|
19
19
|
require_relative 'us_autocomplete_pro/client'
|
|
20
|
+
require_relative 'us_autocomplete/client'
|
|
20
21
|
require_relative 'us_enrichment/client'
|
|
21
22
|
require_relative 'international_postal_code/client'
|
|
22
23
|
|
|
@@ -28,6 +29,7 @@ module SmartyStreets
|
|
|
28
29
|
INTERNATIONAL_STREET_API_URL = 'https://international-street.api.smarty.com/verify'.freeze
|
|
29
30
|
INTERNATIONAL_AUTOCOMPLETE_API_URL = "https://international-autocomplete.api.smarty.com/v2/lookup".freeze
|
|
30
31
|
US_AUTOCOMPLETE_PRO_API_URL = 'https://us-autocomplete-pro.api.smarty.com/lookup'.freeze
|
|
32
|
+
US_AUTOCOMPLETE_API_URL = 'https://us-autocomplete.api.smarty.com/v2/lookup'.freeze
|
|
31
33
|
US_EXTRACT_API_URL = 'https://us-extract.api.smarty.com/'.freeze
|
|
32
34
|
US_STREET_API_URL = 'https://us-street.api.smarty.com/street-address'.freeze
|
|
33
35
|
US_ZIP_CODE_API_URL = 'https://us-zipcode.api.smarty.com/lookup'.freeze
|
|
@@ -185,6 +187,11 @@ module SmartyStreets
|
|
|
185
187
|
USAutocompletePro::Client.new(build_sender, @serializer)
|
|
186
188
|
end
|
|
187
189
|
|
|
190
|
+
def build_us_autocomplete_api_client
|
|
191
|
+
ensure_url_prefix_not_null(US_AUTOCOMPLETE_API_URL)
|
|
192
|
+
USAutocomplete::Client.new(build_sender, @serializer)
|
|
193
|
+
end
|
|
194
|
+
|
|
188
195
|
def build_us_extract_api_client
|
|
189
196
|
ensure_url_prefix_not_null(US_EXTRACT_API_URL)
|
|
190
197
|
USExtract::Client.new(build_sender, @serializer)
|
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
module SmartyStreets
|
|
2
|
-
NOT_MODIFIED = 'Not Modified:
|
|
2
|
+
NOT_MODIFIED = 'Not Modified: The requested record has not been modified since the previous request' \
|
|
3
|
+
' with the Etag value.'.freeze
|
|
3
4
|
|
|
4
|
-
BAD_CREDENTIALS = 'Unauthorized: The credentials were provided incorrectly or did not match any existing,
|
|
5
|
-
active credentials.'.freeze
|
|
5
|
+
BAD_CREDENTIALS = 'Unauthorized: The credentials were provided incorrectly or did not match any existing,' \
|
|
6
|
+
' active credentials.'.freeze
|
|
6
7
|
|
|
7
|
-
PAYMENT_REQUIRED = 'Payment Required: There is no active subscription
|
|
8
|
-
|
|
8
|
+
PAYMENT_REQUIRED = 'Payment Required: There is no active subscription for the account associated with the' \
|
|
9
|
+
' credentials submitted with the request.'.freeze
|
|
9
10
|
|
|
10
|
-
FORBIDDEN = '
|
|
11
|
-
|
|
11
|
+
FORBIDDEN = 'Forbidden: The request contained valid data and was understood by the server, but the server' \
|
|
12
|
+
' is refusing action.'.freeze
|
|
13
|
+
|
|
14
|
+
REQUEST_TIMEOUT = 'Request timeout error.'.freeze
|
|
12
15
|
|
|
13
16
|
REQUEST_ENTITY_TOO_LARGE = 'Request Entity Too Large: The request body has exceeded the maximum size.'.freeze
|
|
14
17
|
|
|
15
|
-
BAD_REQUEST = 'Bad Request (Malformed Payload): A GET request lacked a
|
|
16
|
-
POST request contained malformed JSON
|
|
18
|
+
BAD_REQUEST = 'Bad Request (Malformed Payload): A GET request lacked a required field or the request body' \
|
|
19
|
+
' of a POST request contained malformed JSON.'.freeze
|
|
17
20
|
|
|
18
21
|
UNPROCESSABLE_ENTITY = 'GET request lacked required fields.'.freeze
|
|
19
22
|
|
|
20
|
-
TOO_MANY_REQUESTS = 'The rate limit has been exceeded.'.freeze
|
|
23
|
+
TOO_MANY_REQUESTS = 'Too Many Requests: The rate limit for your account has been exceeded.'.freeze
|
|
21
24
|
|
|
22
25
|
INTERNAL_SERVER_ERROR = 'Internal Server Error.'.freeze
|
|
23
26
|
|
|
27
|
+
BAD_GATEWAY = 'Bad Gateway error.'.freeze
|
|
28
|
+
|
|
24
29
|
SERVICE_UNAVAILABLE = 'Service Unavailable. Try again later.'.freeze
|
|
25
30
|
|
|
26
31
|
GATEWAY_TIMEOUT = 'The upstream data provider did not respond in a timely fashion and the request failed. ' \
|
|
27
|
-
|
|
32
|
+
'A serious, yet rare occurrence indeed.'.freeze
|
|
28
33
|
end
|
|
@@ -5,11 +5,12 @@ module SmartyStreets
|
|
|
5
5
|
attr_reader :premise, :thoroughfare_trailing_type, :sub_building, :locality, :post_box_number,
|
|
6
6
|
:thoroughfare_name, :thoroughfare_postdirection, :dependent_thoroughfare, :premise_prefix_number,
|
|
7
7
|
:thoroughfare, :dependent_thoroughfare_name, :postal_code_short, :dependent_thoroughfare_trailing_type,
|
|
8
|
-
:administrative_area, :administrative_area_iso2
|
|
8
|
+
:administrative_area, :administrative_area_iso2, :attention, :post_box,
|
|
9
9
|
:building_leading_type, :dependent_locality_name, :thoroughfare_type,
|
|
10
10
|
:dependent_thoroughfare_postdirection, :double_dependent_locality, :premise_number,
|
|
11
11
|
:dependent_thoroughfare_type, :post_box_type, :building, :sub_administrative_area, :postal_code_extra,
|
|
12
12
|
:sub_building_name, :postal_code, :dependent_locality, :premise_type, :sub_building_number,
|
|
13
|
+
:short_address_code, :sub_building_leading_type, :sub_building_block, :sub_building_door, :sub_building_staircase,
|
|
13
14
|
:super_administrative_area, :premise_extra, :dependent_thoroughfare_predirection,
|
|
14
15
|
:building_trailing_type, :thoroughfare_predirection, :building_name, :level_type, :level_number,
|
|
15
16
|
:country_iso_3, :sub_building_type, :additional_content, :delivery_installation, :delivery_installation_type,
|
|
@@ -20,8 +21,7 @@ module SmartyStreets
|
|
|
20
21
|
@super_administrative_area = obj.fetch('super_administrative_area', nil)
|
|
21
22
|
@administrative_area = obj.fetch('administrative_area', nil)
|
|
22
23
|
@administrative_area_iso2 = obj.fetch('administrative_area_iso2', nil)
|
|
23
|
-
@
|
|
24
|
-
@administrative_area_long = obj.fetch('administrative_area_long', nil)
|
|
24
|
+
@attention = obj.fetch('attention', nil)
|
|
25
25
|
@sub_administrative_area = obj.fetch('sub_administrative_area', nil)
|
|
26
26
|
@dependent_locality= obj.fetch('dependent_locality', nil)
|
|
27
27
|
@dependent_locality_name = obj.fetch('dependent_locality_name', nil)
|
|
@@ -35,6 +35,11 @@ module SmartyStreets
|
|
|
35
35
|
@premise_number = obj.fetch('premise_number', nil)
|
|
36
36
|
@premise_prefix_number = obj.fetch('premise_prefix_number', nil)
|
|
37
37
|
@premise_type = obj.fetch('premise_type', nil)
|
|
38
|
+
@short_address_code = obj.fetch('short_address_code', nil)
|
|
39
|
+
@sub_building_leading_type = obj.fetch('sub_building_leading_type', nil)
|
|
40
|
+
@sub_building_block = obj.fetch('sub_building_block', nil)
|
|
41
|
+
@sub_building_door = obj.fetch('sub_building_door', nil)
|
|
42
|
+
@sub_building_staircase = obj.fetch('sub_building_staircase', nil)
|
|
38
43
|
@thoroughfare = obj.fetch('thoroughfare', nil)
|
|
39
44
|
@thoroughfare_predirection = obj.fetch('thoroughfare_predirection', nil)
|
|
40
45
|
@thoroughfare_postdirection = obj.fetch('thoroughfare_postdirection', nil)
|
|
@@ -2,7 +2,7 @@ module SmartyStreets
|
|
|
2
2
|
module InternationalStreet
|
|
3
3
|
class RootLevel
|
|
4
4
|
attr_reader :input_id, :organization, :address1, :address2, :address3, :address4, :address5, :address6, :address7,
|
|
5
|
-
:address8
|
|
5
|
+
:address8
|
|
6
6
|
|
|
7
7
|
def initialize(obj)
|
|
8
8
|
@input_id = obj.fetch('input_id', nil)
|
|
@@ -15,10 +15,6 @@ module SmartyStreets
|
|
|
15
15
|
@address6 = obj.fetch('address6', nil)
|
|
16
16
|
@address7 = obj.fetch('address7', nil)
|
|
17
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
18
|
end
|
|
23
19
|
end
|
|
24
20
|
end
|
|
@@ -22,38 +22,38 @@ module SmartyStreets
|
|
|
22
22
|
private
|
|
23
23
|
|
|
24
24
|
def parse_rate_limit_response(response)
|
|
25
|
-
|
|
26
|
-
if !response.payload.nil?
|
|
27
|
-
response_json = JSON.parse(response.payload)
|
|
28
|
-
response_json["errors"].each do |error|
|
|
29
|
-
error_message += (" " + error["message"])
|
|
30
|
-
end
|
|
31
|
-
error_message.strip!
|
|
32
|
-
end
|
|
33
|
-
if error_message == ""
|
|
34
|
-
error_message = TOO_MANY_REQUESTS
|
|
35
|
-
end
|
|
36
|
-
TooManyRequestsError.new(error_message)
|
|
25
|
+
TooManyRequestsError.new(from_message(response, TOO_MANY_REQUESTS))
|
|
37
26
|
end
|
|
38
27
|
|
|
39
28
|
def from_message(response, fallback)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
body = response.payload.nil? ? '' : response.payload.to_s.strip
|
|
30
|
+
unless body.empty?
|
|
31
|
+
begin
|
|
32
|
+
errors = JSON.parse(response.payload)["errors"]
|
|
33
|
+
rescue JSON::ParserError, TypeError
|
|
34
|
+
errors = nil
|
|
35
|
+
end
|
|
36
|
+
unless errors.nil? || errors.empty?
|
|
37
|
+
message = errors.map { |error| error["message"] }.join(" ")
|
|
38
|
+
return message unless message.empty?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
message.empty? ? fallback : message
|
|
42
|
+
"#{fallback} Body: #{body}".strip
|
|
47
43
|
end
|
|
48
44
|
|
|
49
45
|
def assign_exception(response)
|
|
50
|
-
response.error = case response.status_code
|
|
51
|
-
when '304'
|
|
52
|
-
|
|
46
|
+
response.error = case response.status_code.to_s
|
|
47
|
+
when '200', '304'
|
|
48
|
+
nil
|
|
53
49
|
when '401'
|
|
54
50
|
BadCredentialsError.new(from_message(response, BAD_CREDENTIALS))
|
|
55
51
|
when '402'
|
|
56
52
|
PaymentRequiredError.new(from_message(response, PAYMENT_REQUIRED))
|
|
53
|
+
when '403'
|
|
54
|
+
ForbiddenError.new(from_message(response, FORBIDDEN))
|
|
55
|
+
when '408'
|
|
56
|
+
RequestTimeoutError.new(from_message(response, REQUEST_TIMEOUT))
|
|
57
57
|
when '413'
|
|
58
58
|
RequestEntityTooLargeError.new(from_message(response, REQUEST_ENTITY_TOO_LARGE))
|
|
59
59
|
when '400'
|
|
@@ -61,13 +61,17 @@ module SmartyStreets
|
|
|
61
61
|
when '422'
|
|
62
62
|
UnprocessableEntityError.new(from_message(response, UNPROCESSABLE_ENTITY))
|
|
63
63
|
when '429'
|
|
64
|
-
TooManyRequestsError.new(TOO_MANY_REQUESTS)
|
|
64
|
+
TooManyRequestsError.new(from_message(response, TOO_MANY_REQUESTS))
|
|
65
65
|
when '500'
|
|
66
|
-
InternalServerError.new(INTERNAL_SERVER_ERROR)
|
|
66
|
+
InternalServerError.new(from_message(response, INTERNAL_SERVER_ERROR))
|
|
67
|
+
when '502'
|
|
68
|
+
BadGatewayError.new(from_message(response, BAD_GATEWAY))
|
|
67
69
|
when '503'
|
|
68
|
-
ServiceUnavailableError.new(SERVICE_UNAVAILABLE)
|
|
70
|
+
ServiceUnavailableError.new(from_message(response, SERVICE_UNAVAILABLE))
|
|
71
|
+
when '504'
|
|
72
|
+
GatewayTimeoutError.new(from_message(response, GATEWAY_TIMEOUT))
|
|
69
73
|
else
|
|
70
|
-
|
|
74
|
+
SmartyError.new(from_message(response, "The server returned an unexpected HTTP status code: #{response.status_code}"))
|
|
71
75
|
end
|
|
72
76
|
end
|
|
73
77
|
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require_relative '../request'
|
|
2
|
+
require_relative '../exceptions'
|
|
3
|
+
require_relative 'geolocation_type'
|
|
4
|
+
require_relative 'suggestion'
|
|
5
|
+
|
|
6
|
+
module SmartyStreets
|
|
7
|
+
module USAutocomplete
|
|
8
|
+
# It is recommended to instantiate this class using ClientBuilder.build_us_autocomplete_api_client
|
|
9
|
+
class Client
|
|
10
|
+
def initialize(sender, serializer)
|
|
11
|
+
@sender = sender
|
|
12
|
+
@serializer = serializer
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Sends a Lookup object to the US Autocomplete API and stores the result in the Lookup's result field.
|
|
16
|
+
def send(lookup)
|
|
17
|
+
if not lookup or not lookup.search
|
|
18
|
+
raise SmartyStreets::SmartyError, 'Send() must be passed a Lookup with the search field set.'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
request = build_request(lookup)
|
|
22
|
+
|
|
23
|
+
response = @sender.send(request)
|
|
24
|
+
|
|
25
|
+
raise response.error if response.error
|
|
26
|
+
|
|
27
|
+
result = @serializer.deserialize(response.payload)
|
|
28
|
+
suggestions = convert_suggestions(result.fetch('suggestions', []))
|
|
29
|
+
lookup.result = suggestions
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def build_request(lookup)
|
|
34
|
+
request = Request.new
|
|
35
|
+
|
|
36
|
+
add_parameter(request, 'search', lookup.search)
|
|
37
|
+
add_parameter(request, 'max_results', lookup.max_results.to_s)
|
|
38
|
+
add_parameter(request, 'include_only_cities', build_filter_string(lookup.city_filter))
|
|
39
|
+
add_parameter(request, 'include_only_states', build_filter_string(lookup.state_filter))
|
|
40
|
+
add_parameter(request, 'include_only_zip_codes', build_filter_string(lookup.zip_filter))
|
|
41
|
+
add_parameter(request, 'exclude_states', build_filter_string(lookup.exclude_states))
|
|
42
|
+
add_parameter(request, 'prefer_cities', build_filter_string(lookup.prefer_cities))
|
|
43
|
+
add_parameter(request, 'prefer_states', build_filter_string(lookup.prefer_states))
|
|
44
|
+
add_parameter(request, 'prefer_zip_codes', build_filter_string(lookup.prefer_zip_codes))
|
|
45
|
+
add_parameter(request, 'prefer_ratio', lookup.prefer_ratio.to_s)
|
|
46
|
+
add_parameter(request, 'source', lookup.source)
|
|
47
|
+
if lookup.prefer_zip_codes.any? || lookup.zip_filter.any?
|
|
48
|
+
request.parameters['prefer_geolocation'] = GeolocationType::NONE
|
|
49
|
+
else
|
|
50
|
+
add_parameter(request, 'prefer_geolocation', lookup.prefer_geolocation)
|
|
51
|
+
end
|
|
52
|
+
add_parameter(request, 'selected', lookup.selected)
|
|
53
|
+
add_parameter(request, 'exclude', build_filter_string(lookup.exclude, ','))
|
|
54
|
+
|
|
55
|
+
for key in lookup.custom_param_hash.keys do
|
|
56
|
+
add_parameter(request, key, lookup.custom_param_hash[key])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
request
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def build_filter_string(filter_list, separator=';')
|
|
63
|
+
filter_list ? filter_list.join(separator) : nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def convert_suggestions(suggestion_hashes)
|
|
67
|
+
converted_suggestions = []
|
|
68
|
+
return converted_suggestions if suggestion_hashes.nil?
|
|
69
|
+
|
|
70
|
+
suggestion_hashes.each do |suggestion|
|
|
71
|
+
converted_suggestions.push(USAutocomplete::Suggestion.new(suggestion))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
converted_suggestions
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def add_parameter(request, key, value)
|
|
78
|
+
request.parameters[key] = value unless value.nil? or value.empty?
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require_relative '../json_able'
|
|
2
|
+
|
|
3
|
+
module SmartyStreets
|
|
4
|
+
module USAutocomplete
|
|
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
|
+
#
|
|
8
|
+
# See "https://www.smarty.com/docs/apis/us-autocomplete-v2/reference#http-request-input-fields"
|
|
9
|
+
class Lookup < JSONAble
|
|
10
|
+
|
|
11
|
+
attr_accessor :result, :search, :max_results, :city_filter, :state_filter, :zip_filter,
|
|
12
|
+
:exclude_states, :prefer_cities, :prefer_states, :prefer_zip_codes, :prefer_ratio,
|
|
13
|
+
:prefer_geolocation, :selected, :exclude, :source, :custom_param_hash
|
|
14
|
+
|
|
15
|
+
def initialize(search=nil, max_results=nil, city_filter=nil, state_filter=nil, zip_filter=nil,
|
|
16
|
+
exclude_states=nil, prefer_cities=nil, prefer_states=nil, prefer_zips=nil, prefer_ratio=nil,
|
|
17
|
+
prefer_geolocation=nil, selected=nil, exclude=nil, source=nil, custom_param_hash=nil)
|
|
18
|
+
@result = []
|
|
19
|
+
@search = search
|
|
20
|
+
@max_results = max_results
|
|
21
|
+
@city_filter = city_filter ? city_filter : []
|
|
22
|
+
@state_filter = state_filter ? state_filter : []
|
|
23
|
+
@zip_filter = zip_filter ? zip_filter : []
|
|
24
|
+
@exclude_states = exclude_states ? exclude_states : []
|
|
25
|
+
@prefer_cities = prefer_cities ? prefer_cities : []
|
|
26
|
+
@prefer_states = prefer_states ? prefer_states : []
|
|
27
|
+
@prefer_zip_codes = prefer_zips ? prefer_zips : []
|
|
28
|
+
@prefer_ratio = prefer_ratio
|
|
29
|
+
@prefer_geolocation = prefer_geolocation
|
|
30
|
+
@selected = selected
|
|
31
|
+
@exclude = exclude ? exclude : []
|
|
32
|
+
@source = source
|
|
33
|
+
@custom_param_hash = {}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def add_custom_parameter(parameter, value)
|
|
37
|
+
@custom_param_hash[parameter] = value
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_city_filter(city)
|
|
41
|
+
@city_filter.push(city)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def add_state_filter(state)
|
|
45
|
+
@state_filter.push(state)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def add_zip_filter(zip)
|
|
49
|
+
@zip_filter.push(zip)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add_state_exclusion(state)
|
|
53
|
+
@exclude_states.push(state)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def add_preferred_city(city)
|
|
57
|
+
@prefer_cities.push(city)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def add_preferred_state(state)
|
|
61
|
+
@prefer_states.push(state)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def add_preferred_zip(zip)
|
|
65
|
+
@prefer_zip_codes.push(zip)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def add_exclude(exclude_type)
|
|
69
|
+
@exclude.push(exclude_type)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module SmartyStreets
|
|
2
|
+
module USAutocomplete
|
|
3
|
+
# See "https://www.smarty.com/docs/apis/us-autocomplete-v2/reference#http-response-status"
|
|
4
|
+
class Suggestion
|
|
5
|
+
|
|
6
|
+
attr_reader :smarty_key, :entry_id, :street_line, :secondary, :city, :state, :zipcode, :entries, :source
|
|
7
|
+
|
|
8
|
+
def initialize(obj)
|
|
9
|
+
@smarty_key = obj.fetch('smarty_key', nil)
|
|
10
|
+
@entry_id = obj.fetch('entry_id', nil)
|
|
11
|
+
@street_line = obj.fetch('street_line', nil)
|
|
12
|
+
@secondary = obj.fetch('secondary', nil)
|
|
13
|
+
@city = obj.fetch('city', nil)
|
|
14
|
+
@state = obj.fetch('state', nil)
|
|
15
|
+
@zipcode = obj.fetch('zipcode', nil)
|
|
16
|
+
@entries = obj.fetch('entries', 0)
|
|
17
|
+
@source = obj.fetch('source', nil)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require_relative './us_autocomplete/lookup'
|
|
2
|
+
require_relative './us_autocomplete/geolocation_type'
|
|
3
|
+
require_relative './us_autocomplete/source_type'
|
|
4
|
+
require_relative './us_autocomplete/suggestion'
|
|
5
|
+
require_relative './us_autocomplete/client'
|
|
6
|
+
|
|
7
|
+
module SmartyStreets
|
|
8
|
+
module USAutocomplete
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -84,6 +84,7 @@ module SmartyStreets
|
|
|
84
84
|
|
|
85
85
|
response = @sender.send(smarty_request)
|
|
86
86
|
capture_response_etag(response, lookup)
|
|
87
|
+
return lookup.result if response.status_code.to_s == '304'
|
|
87
88
|
results = @serializer.deserialize(response.payload)
|
|
88
89
|
|
|
89
90
|
results = [] if results.nil?
|
|
@@ -114,8 +115,8 @@ module SmartyStreets
|
|
|
114
115
|
private
|
|
115
116
|
|
|
116
117
|
def __send(lookup)
|
|
117
|
-
if lookup.nil? || (blank?(lookup.smarty_key) && blank?(lookup.street) && blank?(lookup.freeform))
|
|
118
|
-
raise SmartyError.new("Lookup requires one of '
|
|
118
|
+
if lookup.nil? || (blank?(lookup.smarty_key) && blank?(lookup.street) && blank?(lookup.freeform) && blank?(lookup.business_name))
|
|
119
|
+
raise SmartyError.new("Lookup requires one of 'smarty_key', 'street', 'freeform', or 'business_name' to be set")
|
|
119
120
|
end
|
|
120
121
|
|
|
121
122
|
smarty_request = Request.new
|
|
@@ -135,6 +136,7 @@ module SmartyStreets
|
|
|
135
136
|
add_parameter(smarty_request, 'city', lookup.city)
|
|
136
137
|
add_parameter(smarty_request, 'state', lookup.state)
|
|
137
138
|
add_parameter(smarty_request, 'zipcode', lookup.zipcode)
|
|
139
|
+
add_parameter(smarty_request, 'business_name', lookup.business_name)
|
|
138
140
|
else
|
|
139
141
|
if (lookup.data_sub_set.nil?)
|
|
140
142
|
smarty_request.url_components = '/' + lookup.smarty_key + '/' + lookup.data_set
|
|
@@ -147,6 +149,7 @@ module SmartyStreets
|
|
|
147
149
|
|
|
148
150
|
response = @sender.send(smarty_request)
|
|
149
151
|
capture_response_etag(response, lookup)
|
|
152
|
+
return [] if response.status_code.to_s == '304'
|
|
150
153
|
results = @serializer.deserialize(response.payload)
|
|
151
154
|
|
|
152
155
|
results = [] if results.nil?
|
|
@@ -28,9 +28,9 @@ module SmartyStreets
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
class Lookup < LookupBase
|
|
31
|
-
attr_accessor :smarty_key, :data_set, :data_sub_set, :freeform, :street, :city, :state, :zipcode
|
|
31
|
+
attr_accessor :smarty_key, :data_set, :data_sub_set, :freeform, :street, :city, :state, :zipcode, :business_name
|
|
32
32
|
|
|
33
|
-
def initialize(smarty_key=nil, data_set=nil, data_sub_set=nil, freeform=nil, street=nil, city=nil, state=nil, zipcode=nil, request_etag=nil, features=nil)
|
|
33
|
+
def initialize(smarty_key=nil, data_set=nil, data_sub_set=nil, freeform=nil, street=nil, city=nil, state=nil, zipcode=nil, request_etag=nil, features=nil, business_name=nil)
|
|
34
34
|
super()
|
|
35
35
|
@smarty_key = smarty_key
|
|
36
36
|
@data_set = data_set
|
|
@@ -42,6 +42,7 @@ module SmartyStreets
|
|
|
42
42
|
@zipcode = zipcode
|
|
43
43
|
@request_etag = request_etag
|
|
44
44
|
@features = features
|
|
45
|
+
@business_name = business_name
|
|
45
46
|
end
|
|
46
47
|
end
|
|
47
48
|
|
|
@@ -24,6 +24,7 @@ require 'smartystreets_ruby_sdk/us_extract'
|
|
|
24
24
|
require 'smartystreets_ruby_sdk/us_street'
|
|
25
25
|
require 'smartystreets_ruby_sdk/us_zipcode'
|
|
26
26
|
require 'smartystreets_ruby_sdk/us_autocomplete_pro'
|
|
27
|
+
require 'smartystreets_ruby_sdk/us_autocomplete'
|
|
27
28
|
require 'smartystreets_ruby_sdk/international_street'
|
|
28
29
|
require 'smartystreets_ruby_sdk/international_autocomplete'
|
|
29
30
|
require 'smartystreets_ruby_sdk/international_postal_code'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smartystreets_ruby_sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 9.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- SmartyStreets SDK Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -80,7 +80,9 @@ extensions: []
|
|
|
80
80
|
extra_rdoc_files: []
|
|
81
81
|
files:
|
|
82
82
|
- ".claude/settings.json"
|
|
83
|
-
- ".github/workflows/
|
|
83
|
+
- ".github/workflows/ci.yml"
|
|
84
|
+
- ".github/workflows/publish.yml"
|
|
85
|
+
- ".github/workflows/test.yml"
|
|
84
86
|
- ".gitignore"
|
|
85
87
|
- CHANGELOG.md
|
|
86
88
|
- CLAUDE.md
|
|
@@ -96,14 +98,17 @@ files:
|
|
|
96
98
|
- examples/international_autocomplete_example.rb
|
|
97
99
|
- examples/international_example.rb
|
|
98
100
|
- examples/international_postal_code_example.rb
|
|
101
|
+
- examples/us_autocomplete_example.rb
|
|
99
102
|
- examples/us_autocomplete_pro_example.rb
|
|
100
103
|
- examples/us_enrichment_business_example.rb
|
|
104
|
+
- examples/us_enrichment_business_name_search_example.rb
|
|
101
105
|
- examples/us_enrichment_etag_example.rb
|
|
102
106
|
- examples/us_enrichment_example.rb
|
|
103
107
|
- examples/us_extract_example.rb
|
|
104
108
|
- examples/us_reverse_geo_example.rb
|
|
105
109
|
- examples/us_street_component_analysis_example.rb
|
|
106
110
|
- examples/us_street_iana_timezone_example.rb
|
|
111
|
+
- examples/us_street_match_strategy_example.rb
|
|
107
112
|
- examples/us_street_multiple_address_example.rb
|
|
108
113
|
- examples/us_street_single_address_example.rb
|
|
109
114
|
- examples/us_zipcode_multiple_lookup_example.rb
|
|
@@ -149,10 +154,17 @@ files:
|
|
|
149
154
|
- lib/smartystreets_ruby_sdk/static_credentials.rb
|
|
150
155
|
- lib/smartystreets_ruby_sdk/status_code_sender.rb
|
|
151
156
|
- lib/smartystreets_ruby_sdk/url_prefix_sender.rb
|
|
157
|
+
- lib/smartystreets_ruby_sdk/us_autocomplete.rb
|
|
158
|
+
- lib/smartystreets_ruby_sdk/us_autocomplete/client.rb
|
|
159
|
+
- lib/smartystreets_ruby_sdk/us_autocomplete/geolocation_type.rb
|
|
160
|
+
- lib/smartystreets_ruby_sdk/us_autocomplete/lookup.rb
|
|
161
|
+
- lib/smartystreets_ruby_sdk/us_autocomplete/source_type.rb
|
|
162
|
+
- lib/smartystreets_ruby_sdk/us_autocomplete/suggestion.rb
|
|
152
163
|
- lib/smartystreets_ruby_sdk/us_autocomplete_pro.rb
|
|
153
164
|
- lib/smartystreets_ruby_sdk/us_autocomplete_pro/client.rb
|
|
154
165
|
- lib/smartystreets_ruby_sdk/us_autocomplete_pro/geolocation_type.rb
|
|
155
166
|
- lib/smartystreets_ruby_sdk/us_autocomplete_pro/lookup.rb
|
|
167
|
+
- lib/smartystreets_ruby_sdk/us_autocomplete_pro/source_type.rb
|
|
156
168
|
- lib/smartystreets_ruby_sdk/us_autocomplete_pro/suggestion.rb
|
|
157
169
|
- lib/smartystreets_ruby_sdk/us_enrichment.rb
|
|
158
170
|
- lib/smartystreets_ruby_sdk/us_enrichment/business/detail/attributes.rb
|
|
@@ -188,6 +200,7 @@ files:
|
|
|
188
200
|
- lib/smartystreets_ruby_sdk/us_reverse_geo/coordinate.rb
|
|
189
201
|
- lib/smartystreets_ruby_sdk/us_reverse_geo/lookup.rb
|
|
190
202
|
- lib/smartystreets_ruby_sdk/us_reverse_geo/result.rb
|
|
203
|
+
- lib/smartystreets_ruby_sdk/us_reverse_geo/source_type.rb
|
|
191
204
|
- lib/smartystreets_ruby_sdk/us_reverse_geo/us_reverse_geo_response.rb
|
|
192
205
|
- lib/smartystreets_ruby_sdk/us_street.rb
|
|
193
206
|
- lib/smartystreets_ruby_sdk/us_street/analysis.rb
|
|
@@ -227,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
227
240
|
- !ruby/object:Gem::Version
|
|
228
241
|
version: '0'
|
|
229
242
|
requirements: []
|
|
230
|
-
rubygems_version: 3.
|
|
243
|
+
rubygems_version: 3.5.22
|
|
231
244
|
signing_key:
|
|
232
245
|
specification_version: 4
|
|
233
246
|
summary: An official library for the SmartyStreets APIs
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: Ruby Gem Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- '*'
|
|
7
|
-
jobs:
|
|
8
|
-
publish:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
env:
|
|
11
|
-
GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
|
|
12
|
-
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v3
|
|
15
|
-
with:
|
|
16
|
-
fetch-depth: 0
|
|
17
|
-
|
|
18
|
-
- uses: ruby/setup-ruby@v1
|
|
19
|
-
with:
|
|
20
|
-
ruby-version: '3.2'
|
|
21
|
-
bundler-cache: false
|
|
22
|
-
|
|
23
|
-
- name: Publish
|
|
24
|
-
run: |
|
|
25
|
-
VERSION=${GITHUB_REF#refs/*/} API_KEY=${{ secrets.GEM_HOST_API_KEY }} make publish
|
|
26
|
-
env:
|
|
27
|
-
API_KEY: "${{ secrets.GEM_HOST_API_KEY }}"
|