address_validator 0.1.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a5af87fb8d4f36b232617af62df65bfc65e5fd9a
4
+ data.tar.gz: ac831584b8e803d1c026faf83890e705d3854f74
5
+ SHA512:
6
+ metadata.gz: 06be75bc5fb2f47af0fdfc772bc44837c0b90c83b10d13e97f12b2b56209dafcf525f790a8900234a11a0f34c68b1b18e0acfa38df4ecadfbfdd45ff70ddc183
7
+ data.tar.gz: 07787078a406a37018ad7dc6db921daf6b0955d17c1248a1cb5fff7de29c91a004fc8afa89c79a1b940ae461cee4007c5d2a40c46428fa61b4c01a65400cbba6
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
19
+ spec/config.yml
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - 2.2.3
7
+ before_install:
8
+ - cp ./spec/config.yml.example ./spec/config.yml
9
+ script: bundle exec rspec
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in address_validator.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rspec', '~> 2.12.0'
8
+ gem 'webmock', '~> 1.9.0'
9
+ gem 'vcr', '~> 2.4.0'
10
+ gem 'mocha', '~> 0.10.5'
11
+ gem 'faker', '~> 1.1.2'
12
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 robhurring
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ [![Build Status](https://travis-ci.org/robhurring/address-validator.svg)](https://travis-ci.org/robhurring/address-validator)
2
+
3
+ # AddressValidator
4
+
5
+ Wrapper around the UPS street level validation API. Nowhere near a complete implementation. This will just give some basic information back, such as address classification (residential/commercial) and if it is valid or not.
6
+
7
+ This can be modified to include address suggestions pretty easily in the `Validator#build_request` method, but we have no need of this right now.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'address_validator', github: 'robhurring/address-validator'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ ## Usage
20
+
21
+ Configuring the client
22
+
23
+ ```ruby
24
+ AddressValidator.configure do |config|
25
+ config.key = 'youraccesskeyfromups'
26
+ config.username = 'username'
27
+ config.password = 'hunter2'
28
+ end
29
+ ```
30
+
31
+ Basic Example
32
+
33
+ ```ruby
34
+ address = AddressValidator::Address.new(
35
+ name: 'Yum',
36
+ street1: '33 St. Marks Place',
37
+ city: 'New York',
38
+ state: 'NY',
39
+ zip: '10003',
40
+ country: 'US'
41
+ )
42
+
43
+ validator = AddressValidator::Validator.new
44
+ response = validator.validate(address)
45
+
46
+ # check if address is valid
47
+ response.valid?
48
+
49
+ # get the returned address
50
+ new_address = response.address
51
+
52
+ # check if its a house
53
+ new_address.residential?
54
+ ```
55
+
56
+ You can also pass hashes directly into the validator if you want.
57
+
58
+ ```ruby
59
+ validator = AddressValidator::Validator.new
60
+ response = validator.validate(
61
+ name: 'Yum',
62
+ street1: '33 St. Marks Place',
63
+ city: 'New York',
64
+ state: 'NY',
65
+ zip: '10003',
66
+ country: 'US'
67
+ )
68
+
69
+ # check if address is valid
70
+ response.valid?
71
+ ```
72
+
73
+ ## Contributing
74
+
75
+ 1. Fork it
76
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
77
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
78
+ 4. Push to the branch (`git push origin my-new-feature`)
79
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'address_validator/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "address_validator"
8
+ gem.version = AddressValidator::VERSION
9
+ gem.authors = ["robhurring"]
10
+ gem.email = ["robhurring@gmail.com"]
11
+ gem.description = %q{UPS address validation gem}
12
+ gem.summary = %q{Simple address validator using the UPS address validation API}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'httparty', '>= 0.11.0'
21
+ gem.add_dependency 'builder', '>= 3.0.4'
22
+ end
@@ -0,0 +1,18 @@
1
+ require "address_validator/version"
2
+
3
+ require_relative './address_validator/config'
4
+ require_relative './address_validator/address'
5
+ require_relative './address_validator/response'
6
+ require_relative './address_validator/client'
7
+ require_relative './address_validator/validator'
8
+
9
+ module AddressValidator
10
+ class << self
11
+ attr_accessor :config
12
+ end
13
+
14
+ def self.configure(&block)
15
+ self.config = Config.new
16
+ yield self.config
17
+ end
18
+ end
@@ -0,0 +1,79 @@
1
+ require 'builder'
2
+
3
+ module AddressValidator
4
+ class Address
5
+ CLASSIFICATION_UNKNOWN = 0
6
+ CLASSIFICATION_COMMERCIAL = 1
7
+ CLASSIFICATION_RESIDENTIAL = 2
8
+
9
+ class << self
10
+ # Public: Build an address from the API's response xml.
11
+ #
12
+ # attrs - Hash of address attributes.
13
+ #
14
+ # Returns an address.
15
+ def from_xml(attrs = {})
16
+ classification = nil
17
+
18
+ if _classification = attrs['AddressClassification']
19
+ classification = _classification['Code']
20
+ end
21
+
22
+ # AddressLine can come in as a single element, or upto 3 elements according
23
+ # to the UPS docs, so we force it into an array and split them up
24
+ address_lines = Array(attrs['AddressLine'])
25
+
26
+ new(
27
+ street1: address_lines[0],
28
+ street2: address_lines[1],
29
+ street3: address_lines[2],
30
+ city: attrs['PoliticalDivision2'],
31
+ state: attrs['PoliticalDivision1'],
32
+ zip: attrs['PostcodePrimaryLow'],
33
+ country: attrs['CountryCode'],
34
+ classification: classification
35
+ )
36
+ end
37
+ end
38
+
39
+ attr_accessor :name, :street1, :street2, :street3, :city, :state, :zip, :country, :classification
40
+
41
+ def initialize(name: name(), street1: street1(), street2: street2(), street3: street3(), city: city(), state: state(), zip: zip(), country: country(), classification: classification())
42
+ @name = name
43
+ @street1 = street1
44
+ @street2 = street2
45
+ @street3 = street3
46
+ @city = city
47
+ @state = state
48
+ @zip = zip
49
+ @country = country
50
+ @classification = (classification || CLASSIFICATION_UNKNOWN).to_i
51
+ end
52
+
53
+ def residential?
54
+ classification == CLASSIFICATION_RESIDENTIAL
55
+ end
56
+
57
+ def commercial?
58
+ classification == CLASSIFICATION_COMMERCIAL
59
+ end
60
+
61
+ def to_xml(options={})
62
+
63
+ xml = Builder::XmlMarkup.new(options)
64
+
65
+ xml.AddressKeyFormat do
66
+ xml.ConsigneeName(self.name)
67
+ xml.tag! 'AddressLine', self.street1
68
+ xml.tag! 'AddressLine', self.street2 if self.street2
69
+ xml.tag! 'AddressLine', self.street3 if self.street3
70
+ xml.PoliticalDivision2(self.city)
71
+ xml.PoliticalDivision1(self.state)
72
+ xml.PostcodePrimaryLow(self.zip)
73
+ xml.CountryCode(self.country)
74
+ end
75
+
76
+ xml.target!
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,45 @@
1
+ require 'httparty'
2
+ require 'builder'
3
+
4
+ module AddressValidator
5
+ class Client
6
+ include HTTParty
7
+ format :xml
8
+
9
+ def initialize
10
+ @config = AddressValidator.config
11
+ set_base_uri
12
+ end
13
+
14
+ def access_request
15
+ xml = Builder::XmlMarkup.new
16
+
17
+ xml.instruct!
18
+ xml.AccessRequest do
19
+ xml.AccessLicenseNumber(@config.key)
20
+ xml.UserId(@config.username)
21
+ xml.Password(@config.password)
22
+ end
23
+ end
24
+
25
+ def set_base_uri
26
+ if @config.testing
27
+ endpoint = 'https://wwwcie.ups.com'
28
+ else
29
+ endpoint = 'https://onlinetools.ups.com'
30
+ end
31
+
32
+ self.class.base_uri(endpoint)
33
+ end
34
+
35
+ def post(request)
36
+ xml = Builder::XmlMarkup.new
37
+ xml << access_request
38
+ xml << request
39
+ body = xml.target!
40
+
41
+ api_response = self.class.post('/ups.app/xml/XAV', body: body)
42
+ Response.new(api_response)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module AddressValidator
2
+ class Config
3
+ attr_accessor :key, :username, :password, :testing
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ require 'forwardable'
2
+
3
+ module AddressValidator
4
+ class Response
5
+ extend Forwardable
6
+
7
+ attr_reader :api_response
8
+ def_delegators :api_response, :[]
9
+
10
+ def initialize(api_response)
11
+ @api_response = api_response
12
+ end
13
+
14
+ def ok?
15
+ @api_response.ok?
16
+ end
17
+
18
+ def success?
19
+ ok? && response['Response']['ResponseStatusCode'] == '1'
20
+ end
21
+
22
+ def response
23
+ @response ||= self['AddressValidationResponse']
24
+ end
25
+
26
+ def error
27
+ _error_container = response['Response']['Error']
28
+ _error_container && _error_container['ErrorDescription']
29
+ end
30
+
31
+ def valid?
32
+ response.has_key?('ValidAddressIndicator')
33
+ end
34
+
35
+ def ambiguous?
36
+ response.has_key?('AmbiguousAddressIndicator')
37
+ end
38
+
39
+ def no_canidates?
40
+ response.has_key?('NoCandidatesIndicator')
41
+ end
42
+
43
+ def address
44
+ AddressValidator::Address.from_xml(response['AddressKeyFormat'])
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ require 'builder'
2
+
3
+ module AddressValidator
4
+ class Validator
5
+ attr_reader :client
6
+
7
+ def initialize
8
+ @client = Client.new
9
+ end
10
+
11
+ def validate(address)
12
+ if address.is_a?(::Hash)
13
+ address = build_address(address)
14
+ end
15
+
16
+ request = build_request(address)
17
+ @client.post(request)
18
+ end
19
+
20
+ def build_address(attrs)
21
+ AddressValidator::Address.new(attrs)
22
+ end
23
+
24
+ def build_request(address)
25
+ xml = Builder::XmlMarkup.new
26
+
27
+ xml.instruct!
28
+ xml.AddressValidationRequest do
29
+ xml.Request do
30
+ xml.RequestAction 'XAV' # must be XAV
31
+ xml.RequestOption '3' # validation + classification
32
+ end
33
+ xml.MaximumListSize('1')
34
+ xml << address.to_xml
35
+ end
36
+
37
+ xml.target!
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module AddressValidator
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ # copy this file to spec/config.yml and place your username, password, apikey here
2
+
3
+ access_key: youraccesstoken
4
+ username: user
5
+ password: password
6
+ testing: true
@@ -0,0 +1,43 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://onlinetools.ups.com/ups.app/xml/XAV
6
+ body:
7
+ encoding: UTF-8
8
+ string: <?xml version="1.0" encoding="UTF-8"?><AccessRequest><AccessLicenseNumber>%{AccessLicenseNumber}</AccessLicenseNumber><UserId>%{UserId}</UserId><Password>%{Password}</Password></AccessRequest><?xml
9
+ version="1.0" encoding="UTF-8"?><AddressValidationRequest><Request><RequestAction>XAV</RequestAction><RequestOption>3</RequestOption></Request><MaximumListSize>1</MaximumListSize><AddressKeyFormat><ConsigneeName>Doctor
10
+ Daves Backyard Dentistry</ConsigneeName><AddressLine>1 Seseme Street</AddressLine><PoliticalDivision2>New
11
+ York</PoliticalDivision2><PoliticalDivision1>NY</PoliticalDivision1><PostcodePrimaryLow>10012</PostcodePrimaryLow><CountryCode>US</CountryCode></AddressKeyFormat></AddressValidationRequest>
12
+ headers:
13
+ Accept-Encoding:
14
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
15
+ Accept:
16
+ - '*/*'
17
+ User-Agent:
18
+ - Ruby
19
+ response:
20
+ status:
21
+ code: 200
22
+ message: OK
23
+ headers:
24
+ Date:
25
+ - Sun, 15 Nov 2015 00:36:42 GMT
26
+ Server:
27
+ - Apache
28
+ X-Frame-Options:
29
+ - SAMEORIGIN
30
+ Pragma:
31
+ - no-cache
32
+ Content-Length:
33
+ - '365'
34
+ X-Content-Type-Options:
35
+ - nosniff
36
+ Content-Type:
37
+ - application/xml
38
+ body:
39
+ encoding: UTF-8
40
+ string: <?xml version="1.0"?><AddressValidationResponse><Response><TransactionReference></TransactionReference><ResponseStatusCode>1</ResponseStatusCode><ResponseStatusDescription>Success</ResponseStatusDescription></Response><NoCandidatesIndicator/><AddressClassification><Code>0</Code><Description>Unknown</Description></AddressClassification></AddressValidationResponse>
41
+ http_version:
42
+ recorded_at: Sun, 15 Nov 2015 00:36:42 GMT
43
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,45 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://onlinetools.ups.com/ups.app/xml/XAV
6
+ body:
7
+ encoding: UTF-8
8
+ string: <?xml version="1.0" encoding="UTF-8"?><AccessRequest><AccessLicenseNumber>%{AccessLicenseNumber}</AccessLicenseNumber><UserId>%{UserId}</UserId><Password>%{Password}</Password></AccessRequest><?xml
9
+ version="1.0" encoding="UTF-8"?><AddressValidationRequest><Request><RequestAction>XAV</RequestAction><RequestOption>3</RequestOption></Request><MaximumListSize>1</MaximumListSize><AddressKeyFormat><ConsigneeName>Yum</ConsigneeName><AddressLine>33
10
+ St. Marks Place</AddressLine><AddressLine>Suite 3</AddressLine><AddressLine>C/O
11
+ Some Dude</AddressLine><PoliticalDivision2>New York</PoliticalDivision2><PoliticalDivision1>NY</PoliticalDivision1><PostcodePrimaryLow>10003</PostcodePrimaryLow><CountryCode>US</CountryCode></AddressKeyFormat></AddressValidationRequest>
12
+ headers:
13
+ Accept-Encoding:
14
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
15
+ Accept:
16
+ - '*/*'
17
+ User-Agent:
18
+ - Ruby
19
+ response:
20
+ status:
21
+ code: 200
22
+ message: OK
23
+ headers:
24
+ Date:
25
+ - Sun, 15 Nov 2015 00:36:44 GMT
26
+ Server:
27
+ - Apache
28
+ X-Frame-Options:
29
+ - SAMEORIGIN
30
+ Pragma:
31
+ - no-cache
32
+ Content-Length:
33
+ - '829'
34
+ X-Content-Type-Options:
35
+ - nosniff
36
+ Content-Type:
37
+ - application/xml
38
+ body:
39
+ encoding: UTF-8
40
+ string: <?xml version="1.0"?><AddressValidationResponse><Response><TransactionReference></TransactionReference><ResponseStatusCode>1</ResponseStatusCode><ResponseStatusDescription>Success</ResponseStatusDescription></Response><ValidAddressIndicator/><AddressClassification><Code>1</Code><Description>Commercial</Description></AddressClassification><AddressKeyFormat><AddressClassification><Code>1</Code><Description>Commercial</Description></AddressClassification><AddressLine>33
41
+ ST MARKS PL</AddressLine><AddressLine>APT 3</AddressLine><Region>NEW YORK
42
+ NY 10003-7832</Region><PoliticalDivision2>NEW YORK</PoliticalDivision2><PoliticalDivision1>NY</PoliticalDivision1><PostcodePrimaryLow>10003</PostcodePrimaryLow><PostcodeExtendedLow>7832</PostcodeExtendedLow><CountryCode>US</CountryCode></AddressKeyFormat></AddressValidationResponse>
43
+ http_version:
44
+ recorded_at: Sun, 15 Nov 2015 00:36:43 GMT
45
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,45 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://onlinetools.ups.com/ups.app/xml/XAV
6
+ body:
7
+ encoding: UTF-8
8
+ string: <?xml version="1.0" encoding="UTF-8"?><AccessRequest><AccessLicenseNumber>%{AccessLicenseNumber}</AccessLicenseNumber><UserId>%{UserId}</UserId><Password>%{Password}</Password></AccessRequest><?xml
9
+ version="1.0" encoding="UTF-8"?><AddressValidationRequest><Request><RequestAction>XAV</RequestAction><RequestOption>3</RequestOption></Request><MaximumListSize>1</MaximumListSize><AddressKeyFormat><ConsigneeName>Yum</ConsigneeName><AddressLine>33
10
+ St. Marks Place</AddressLine><AddressLine>Suite 3</AddressLine><PoliticalDivision2>New
11
+ York</PoliticalDivision2><PoliticalDivision1>NY</PoliticalDivision1><PostcodePrimaryLow>10003</PostcodePrimaryLow><CountryCode>US</CountryCode></AddressKeyFormat></AddressValidationRequest>
12
+ headers:
13
+ Accept-Encoding:
14
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
15
+ Accept:
16
+ - '*/*'
17
+ User-Agent:
18
+ - Ruby
19
+ response:
20
+ status:
21
+ code: 200
22
+ message: OK
23
+ headers:
24
+ Date:
25
+ - Sun, 15 Nov 2015 00:36:41 GMT
26
+ Server:
27
+ - Apache
28
+ X-Frame-Options:
29
+ - SAMEORIGIN
30
+ Pragma:
31
+ - no-cache
32
+ Content-Length:
33
+ - '829'
34
+ X-Content-Type-Options:
35
+ - nosniff
36
+ Content-Type:
37
+ - application/xml
38
+ body:
39
+ encoding: UTF-8
40
+ string: <?xml version="1.0"?><AddressValidationResponse><Response><TransactionReference></TransactionReference><ResponseStatusCode>1</ResponseStatusCode><ResponseStatusDescription>Success</ResponseStatusDescription></Response><ValidAddressIndicator/><AddressClassification><Code>1</Code><Description>Commercial</Description></AddressClassification><AddressKeyFormat><AddressClassification><Code>1</Code><Description>Commercial</Description></AddressClassification><AddressLine>33
41
+ ST MARKS PL</AddressLine><AddressLine>APT 3</AddressLine><Region>NEW YORK
42
+ NY 10003-7832</Region><PoliticalDivision2>NEW YORK</PoliticalDivision2><PoliticalDivision1>NY</PoliticalDivision1><PostcodePrimaryLow>10003</PostcodePrimaryLow><PostcodeExtendedLow>7832</PostcodeExtendedLow><CountryCode>US</CountryCode></AddressKeyFormat></AddressValidationResponse>
43
+ http_version:
44
+ recorded_at: Sun, 15 Nov 2015 00:36:41 GMT
45
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+
3
+ describe AddressValidator::Address do
4
+ describe 'properties' do
5
+ subject(:address) do
6
+ described_class.new(
7
+ name: 'rob',
8
+ street1: 'street1',
9
+ street2: 'street2',
10
+ street3: 'street3',
11
+ city: 'city',
12
+ state: 'state',
13
+ zip: '90210',
14
+ country: 'US'
15
+ )
16
+ end
17
+
18
+ its(:name) { should eq 'rob' }
19
+ its(:street1) { should eq 'street1' }
20
+ its(:street2) { should eq 'street2' }
21
+ its(:street3) { should eq 'street3' }
22
+ its(:city) { should eq 'city' }
23
+ its(:state) { should eq 'state' }
24
+ its(:zip) { should eq '90210' }
25
+ its(:country) { should eq 'US' }
26
+ end
27
+
28
+ describe '#to_xml' do
29
+ let(:address) do
30
+ described_class.new(
31
+ name: 'rob',
32
+ street1: 'street1',
33
+ street2: 'street2',
34
+ city: 'city',
35
+ state: 'state',
36
+ zip: '90210',
37
+ country: 'US'
38
+ )
39
+ end
40
+
41
+ let(:xml){ address.to_xml }
42
+
43
+ it 'should have a ConsigneeName' do
44
+ xml.should =~ /<ConsigneeName>rob<\/ConsigneeName>/
45
+ end
46
+
47
+ it 'should have a AddressLine for street1' do
48
+ xml.should =~ /<AddressLine>street1<\/AddressLine>/
49
+ end
50
+
51
+ it 'should have a AddressLine for street2' do
52
+ xml.should =~ /<AddressLine>street2<\/AddressLine>/
53
+ end
54
+
55
+ it 'should not have a AddressLine for street3' do
56
+ xml.should_not =~ /<AddressLine>street3<\/AddressLine>/
57
+ end
58
+
59
+ it 'should have a PoliticalDivision2' do
60
+ xml.should =~ /<PoliticalDivision2>city<\/PoliticalDivision2>/
61
+ end
62
+
63
+ it 'should have a PoliticalDivision1' do
64
+ xml.should =~ /<PoliticalDivision1>state<\/PoliticalDivision1>/
65
+ end
66
+
67
+ it 'should have a PostcodePrimaryLow' do
68
+ xml.should =~ /<PostcodePrimaryLow>90210<\/PostcodePrimaryLow>/
69
+ end
70
+
71
+ it 'should have a CountryCode' do
72
+ xml.should =~ /<CountryCode>US<\/CountryCode>/
73
+ end
74
+ end
75
+
76
+ describe '#from_xml' do
77
+ context 'when only a single AddressLine comes back' do
78
+ let!(:xml) do
79
+ MultiXml.parse %{
80
+ <AddressKeyFormat>
81
+ <AddressClassification>
82
+ <Code>1</Code>
83
+ <Description>Commercial</Description>
84
+ </AddressClassification>
85
+ <AddressLine>648 BROADWAY</AddressLine>
86
+ <Region>NEW YORK NY 10012-2348</Region>
87
+ <PoliticalDivision2>NEW YORK</PoliticalDivision2>
88
+ <PoliticalDivision1>NY</PoliticalDivision1>
89
+ <PostcodePrimaryLow>10012</PostcodePrimaryLow>
90
+ <PostcodeExtendedLow>2348</PostcodeExtendedLow>
91
+ <CountryCode>US</CountryCode>
92
+ </AddressKeyFormat>
93
+ }
94
+ end
95
+
96
+ subject(:address){ described_class.from_xml(xml['AddressKeyFormat']) }
97
+
98
+ its(:street1){ should eq '648 BROADWAY' }
99
+ its(:street2){ should be_nil }
100
+ its(:street3){ should be_nil }
101
+ its(:classification){ should eq described_class::CLASSIFICATION_COMMERCIAL }
102
+ its(:city){ should eq 'NEW YORK' }
103
+ its(:state){ should eq 'NY' }
104
+ its(:zip){ should eq '10012' }
105
+ its(:country){ should eq 'US' }
106
+ end
107
+
108
+ context 'when multiple AddressLines comes back' do
109
+ let!(:xml) do
110
+ MultiXml.parse %{
111
+ <AddressKeyFormat>
112
+ <AddressClassification>
113
+ <Code>1</Code>
114
+ <Description>Commercial</Description>
115
+ </AddressClassification>
116
+ <AddressLine>648 BROADWAY</AddressLine>
117
+ <AddressLine>SUITE 1</AddressLine>
118
+ <AddressLine>C/O SOME GUY</AddressLine>
119
+ <Region>NEW YORK NY 10012-2348</Region>
120
+ <PoliticalDivision2>NEW YORK</PoliticalDivision2>
121
+ <PoliticalDivision1>NY</PoliticalDivision1>
122
+ <PostcodePrimaryLow>10012</PostcodePrimaryLow>
123
+ <PostcodeExtendedLow>2348</PostcodeExtendedLow>
124
+ <CountryCode>US</CountryCode>
125
+ </AddressKeyFormat>
126
+ }
127
+ end
128
+
129
+ subject(:address){ described_class.from_xml(xml['AddressKeyFormat']) }
130
+
131
+ its(:street1){ should eq '648 BROADWAY' }
132
+ its(:street2){ should eq 'SUITE 1' }
133
+ its(:street3){ should eq 'C/O SOME GUY' }
134
+ its(:classification){ should eq described_class::CLASSIFICATION_COMMERCIAL }
135
+ its(:city){ should eq 'NEW YORK' }
136
+ its(:state){ should eq 'NY' }
137
+ its(:zip){ should eq '10012' }
138
+ its(:country){ should eq 'US' }
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ describe AddressValidator::Validator do
4
+ let(:validator){ described_class.new }
5
+
6
+ context 'with a valid address', vcr: {cassette_name: 'valid-address'} do
7
+ let(:address) do
8
+ AddressValidator::Address.new(
9
+ name: 'Yum',
10
+ street1: '33 St. Marks Place',
11
+ street2: 'Suite 3',
12
+ city: 'New York',
13
+ state: 'NY',
14
+ zip: '10003',
15
+ country: 'US'
16
+ )
17
+ end
18
+
19
+ describe '#validate' do
20
+ let(:response){ validator.validate(address) }
21
+
22
+ it 'should be HTTP ok' do
23
+ response.should be_ok
24
+ end
25
+
26
+ it 'should be a successful request' do
27
+ response.should be_success
28
+ end
29
+
30
+ it 'should be a valid address' do
31
+ response.should be_valid
32
+ end
33
+
34
+ it 'should have an address' do
35
+ response.address.should_not be_nil
36
+ end
37
+
38
+ it 'should have no errors' do
39
+ response.error.should be_nil
40
+ end
41
+ end
42
+ end
43
+
44
+ context 'with an invalid address', vcr: {cassette_name: 'invalid-address'} do
45
+ let(:address) do
46
+ AddressValidator::Address.new(
47
+ name: 'Doctor Daves Backyard Dentistry',
48
+ street1: '1 Seseme Street',
49
+ city: 'New York',
50
+ state: 'NY',
51
+ zip: '10012',
52
+ country: 'US'
53
+ )
54
+ end
55
+
56
+ describe '#validate' do
57
+ let(:response){ validator.validate(address) }
58
+
59
+ it 'should be HTTP ok' do
60
+ response.should be_ok
61
+ end
62
+
63
+ it 'should be a successful request' do
64
+ response.should be_success
65
+ end
66
+
67
+ it 'should not be a valid address' do
68
+ response.should_not be_valid
69
+ end
70
+ end
71
+ end
72
+
73
+ context 'when passing in address hashes', vcr: {cassette_name: 'valid-address-hash'} do
74
+ let(:address_hash) do
75
+ {
76
+ name: 'Yum',
77
+ street1: '33 St. Marks Place',
78
+ street2: 'Suite 3',
79
+ street3: 'C/O Some Dude',
80
+ city: 'New York',
81
+ state: 'NY',
82
+ zip: '10003',
83
+ country: 'US'
84
+ }
85
+ end
86
+
87
+ describe '#validate' do
88
+ let(:response){ validator.validate(address_hash) }
89
+
90
+ it 'should be HTTP ok' do
91
+ response.should be_ok
92
+ end
93
+
94
+ it 'should be a successful request' do
95
+ response.should be_success
96
+ end
97
+
98
+ it 'should be a valid address' do
99
+ response.should be_valid
100
+ end
101
+
102
+ it 'should have an address' do
103
+ response.address.should_not be_nil
104
+ end
105
+
106
+ it 'should have no errors' do
107
+ response.error.should be_nil
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe AddressValidator do
4
+ describe '.configure' do
5
+ it 'should set the key' do
6
+ described_class.configure do |config|
7
+ config.key = '90210'
8
+ end
9
+
10
+ described_class.config.key.should eq '90210'
11
+ end
12
+
13
+ it 'should set the username' do
14
+ described_class.configure do |config|
15
+ config.username = 'usr'
16
+ end
17
+
18
+ described_class.config.username.should eq 'usr'
19
+ end
20
+
21
+ it 'should set the password' do
22
+ described_class.configure do |config|
23
+ config.password = 's3cre7'
24
+ end
25
+
26
+ described_class.config.password.should eq 's3cre7'
27
+ end
28
+
29
+ it 'should set the testing flag' do
30
+ described_class.configure do |config|
31
+ config.testing = true
32
+ end
33
+
34
+ described_class.config.testing.should be_true
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,35 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ Bundler.require(:default, :test)
6
+ require 'faker'
7
+ require 'address_validator'
8
+
9
+ default_config = AddressValidator::Config.new
10
+ config_file = File.expand_path('../config.yml', __FILE__)
11
+ if File.exists?(config_file)
12
+ API_CONFIG = YAML.load_file(config_file)
13
+ default_config.key = API_CONFIG['access_key']
14
+ default_config.username = API_CONFIG['username']
15
+ default_config.password = API_CONFIG['password']
16
+ else
17
+ puts "ERROR!"
18
+ puts "No config file was found! Copy the config.yml.example file to spec/config.yml and fill out the details."
19
+ exit 1
20
+ end
21
+
22
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each{ |f| require f }
23
+
24
+ RSpec.configure do |config|
25
+ config.treat_symbols_as_metadata_keys_with_true_values = true
26
+ config.run_all_when_everything_filtered = true
27
+ config.filter_run :focus
28
+ config.order = "random"
29
+ config.mock_with :mocha
30
+
31
+ config.before(:each) do
32
+ # reset any config changes we've made
33
+ AddressValidator.config = default_config
34
+ end
35
+ end
@@ -0,0 +1,20 @@
1
+ VCR.configure do |c|
2
+ c.cassette_library_dir = 'spec/data/vcr_cassettes'
3
+ c.hook_into :webmock
4
+ c.ignore_localhost = true
5
+ c.configure_rspec_metadata!
6
+ c.default_cassette_options = {record: :new_episodes}
7
+ c.filter_sensitive_data('%{AccessLicenseNumber}'){ API_CONFIG['access_key'] }
8
+ c.filter_sensitive_data('%{UserId}'){ API_CONFIG['username'] }
9
+ c.filter_sensitive_data('%{Password}'){ API_CONFIG['password'] }
10
+ end
11
+
12
+ # Re-Record all VCR cassettes
13
+ # Usage: RERECORD=1 rspec
14
+ unless ENV['RERECORD'].to_i.zero?
15
+ $stderr << "Re-Recording...\n\n"
16
+
17
+ VCR.configure do |c|
18
+ c.default_cassette_options = {record: :all}
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: address_validator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - robhurring
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.11.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.11.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: builder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.4
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.4
41
+ description: UPS address validation gem
42
+ email:
43
+ - robhurring@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .rspec
50
+ - .travis.yml
51
+ - Gemfile
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - address_validator.gemspec
56
+ - lib/address_validator.rb
57
+ - lib/address_validator/address.rb
58
+ - lib/address_validator/client.rb
59
+ - lib/address_validator/config.rb
60
+ - lib/address_validator/response.rb
61
+ - lib/address_validator/validator.rb
62
+ - lib/address_validator/version.rb
63
+ - spec/config.yml.example
64
+ - spec/data/vcr_cassettes/invalid-address.yml
65
+ - spec/data/vcr_cassettes/valid-address-hash.yml
66
+ - spec/data/vcr_cassettes/valid-address.yml
67
+ - spec/lib/address_validator/address_spec.rb
68
+ - spec/lib/address_validator/validator_spec.rb
69
+ - spec/lib/address_validator_spec.rb
70
+ - spec/spec_helper.rb
71
+ - spec/support/vcr.rb
72
+ homepage: ''
73
+ licenses: []
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.4.8
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Simple address validator using the UPS address validation API
95
+ test_files:
96
+ - spec/config.yml.example
97
+ - spec/data/vcr_cassettes/invalid-address.yml
98
+ - spec/data/vcr_cassettes/valid-address-hash.yml
99
+ - spec/data/vcr_cassettes/valid-address.yml
100
+ - spec/lib/address_validator/address_spec.rb
101
+ - spec/lib/address_validator/validator_spec.rb
102
+ - spec/lib/address_validator_spec.rb
103
+ - spec/spec_helper.rb
104
+ - spec/support/vcr.rb