address_validator 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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