smarty_streets 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in smarty_streets.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Russ Smith
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.
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # SmartyStreets
2
+
3
+ A ruby library to integrate with the SmartyStreets API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'smarty_streets'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install smarty_streets
18
+
19
+ ## Usage
20
+
21
+ You must have valid tokens from http://www.smartystreets.com
22
+
23
+ ```ruby
24
+ SmartyStreets.configure do |c|
25
+ c.auth_id = 'MY-AUTH-ID'
26
+ c.auth_token = 'MY-AUTH-TOKEN'
27
+ c.number_of_candidates = 5
28
+ end
29
+
30
+ locations = SmartyStreets.standardize do |location|
31
+ location.street = '1 infinite loop'
32
+ location.city = 'cupertino'
33
+ location.state = 'california'
34
+ location.zip_code = '95014'
35
+ end
36
+
37
+ # #<SmartyStreets::Location:0x007fb4bbb507d0 @street="1 Infinite Loop", @city="Cupertino", @state="CA", @zip_code="95014-2083", @delivery_point_barcode="950142083017", @components={"primary_number"=>"1", "street_name"=>"Infinite", "street_suffix"=>"Loop", "city_name"=>"Cupertino", "state_abbreviation"=>"CA", "zipcode"=>"95014", "plus4_code"=>"2083", "delivery_point"=>"01", "delivery_point_check_digit"=>"7"}, @meta_data={"record_type"=>"S", "county_fips"=>"06085", "county_name"=>"Santa Clara", "carrier_route"=>"C067", "congressional_district"=>"18", "rdi"=>"Commercial", "elot_sequence"=>"0031", "elot_sort"=>"A", "latitude"=>37.33118, "longitude"=>-122.03062, "precision"=>"Zip9"}>
38
+ ```
39
+
40
+ ## Contributing
41
+
42
+ 1. Fork it
43
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
44
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
45
+ 4. Push to the branch (`git push origin my-new-feature`)
46
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake'
3
+ require 'rspec/core/rake_task'
4
+
5
+ namespace :spec do
6
+ RSpec::Core::RakeTask.new(:normal) do |t|
7
+ t.pattern ='spec/**/*_spec.rb'
8
+ t.rcov = false
9
+ end
10
+ end
11
+
12
+ desc 'RSpec tests'
13
+ task spec: 'spec:normal'
14
+
15
+ task default: 'spec'
@@ -0,0 +1,32 @@
1
+ require 'cgi'
2
+ require 'json'
3
+ require 'httparty'
4
+ require 'smarty_streets/version'
5
+ require 'smarty_streets/configuration'
6
+ require 'smarty_streets/location'
7
+ require 'smarty_streets/request'
8
+
9
+ module SmartyStreets
10
+ class << self
11
+ attr_accessor :configuration
12
+
13
+ # Call this method to set your configuration.
14
+ #
15
+ # SmartyStreets.configure do |config|
16
+ # config.auth_id = 'AUTHID'
17
+ # config.auth_token = 'AUTHTOKEN'
18
+ # config.number_of_candidates = 1
19
+ # end
20
+ def configure
21
+ self.configuration = Configuration.new
22
+ yield(configuration)
23
+ end
24
+
25
+ # Request standardization for an address
26
+ def standardize
27
+ location = Location.new
28
+ yield(location)
29
+ Request.new(location).standardize!
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ module SmartyStreets
2
+ class Configuration
3
+ # API url for SmartyStreets
4
+ attr_accessor :api_url
5
+
6
+ # AUTH ID from SmartyStreets
7
+ attr_accessor :auth_id
8
+
9
+ # AUTH TOKEN from SmartyStreets
10
+ attr_accessor :auth_token
11
+
12
+ # Number of candidates to provide when making a request.
13
+ attr_accessor :number_of_candidates
14
+
15
+ def initialize
16
+ @api_url = 'api.smartystreets.com'
17
+ @number_of_candidates = 1
18
+ end
19
+
20
+ # Returns a hash of all configurable options
21
+ def to_hash
22
+ OPTIONS.inject({}) do |hash, option|
23
+ hash.merge(option.to_sym => send(option))
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ module SmartyStreets
2
+ class Location
3
+ attr_accessor :street, :street2, :secondary
4
+ attr_accessor :city, :state, :zip_code
5
+ attr_accessor :last_line, :addressee, :urbanization
6
+ attr_accessor :delivery_point_barcode, :components, :meta_data
7
+ end
8
+ end
@@ -0,0 +1,70 @@
1
+ module SmartyStreets
2
+ class Request
3
+ class InvalidCredentials < Exception; end
4
+ class MalformedData < Exception; end
5
+ class PaymentRequired < Exception; end
6
+ class NoValidCandidates < Exception; end
7
+ class RemoteServerError < Exception; end
8
+
9
+ attr_accessor :location
10
+
11
+ def initialize(location)
12
+ @location = location
13
+ end
14
+
15
+ def standardize!
16
+ url = build_request_url(@location)
17
+ handle_response(send_request(url))
18
+ end
19
+
20
+ private
21
+
22
+ def handle_response(response)
23
+ raise InvalidCredentials if response.code == 401
24
+ raise MalformedData if response.code == 400
25
+ raise PaymentRequired if response.code == 402
26
+ raise RemoteServerError if response.code == 500
27
+ raise NoValidCandidates if response.body.nil?
28
+
29
+ JSON.parse(response.body).collect do |l|
30
+ location = Location.new
31
+ location.street = l['delivery_line_1']
32
+ location.city = l['components']['city_name']
33
+ location.state = l['components']['state_abbreviation']
34
+ location.zip_code = l['components']['zipcode'] + '-' + l['components']['plus4_code']
35
+ location.delivery_point_barcode = l['delivery_point_barcode']
36
+ location.components = l['components']
37
+ location.meta_data = l['metadata']
38
+ location
39
+ end
40
+ end
41
+
42
+ def send_request(url)
43
+ HTTParty.get(url)
44
+ end
45
+
46
+ def build_request_url(location)
47
+ parameters = {
48
+ street: location.street,
49
+ street2: location.street2,
50
+ secondary: location.secondary,
51
+ city: location.city,
52
+ state: location.state,
53
+ zip_code: location.zip_code,
54
+ last_line: location.last_line,
55
+ addressee: location.addressee,
56
+ urbanization: location.urbanization,
57
+ candidates: SmartyStreets.configuration.number_of_candidates,
58
+ auth_id: SmartyStreets.configuration.auth_id,
59
+ auth_token: SmartyStreets.configuration.auth_token
60
+ }
61
+
62
+ parameter_string = parameters.collect { |k,v|
63
+ "#{k.to_s.gsub('_', '-')}=#{CGI.escape(v.to_s)}"
64
+ }.join('&')
65
+
66
+ 'http://' + SmartyStreets.configuration.api_url +
67
+ '/street-address/?' + parameter_string
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module SmartyStreets
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'smarty_streets/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "smarty_streets"
8
+ spec.version = SmartyStreets::VERSION
9
+ spec.authors = ["Russ Smith"]
10
+ spec.email = ["russ@bashme.org"]
11
+ spec.description = 'A ruby gem to integrate with http://www.smartystreets.com'
12
+ spec.summary = 'A ruby gem to integrate with http://www.smartystreets.com'
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "httparty", "~> 0.11"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe SmartyStreets::Configuration do
4
+ before do
5
+ SmartyStreets.configure do |c|
6
+ c.api_url = 'apiurl'
7
+ c.auth_id = 'MYAUTHID'
8
+ c.auth_token = 'MYAUTHTOKEN'
9
+ c.number_of_candidates = 1
10
+ end
11
+ end
12
+
13
+ it 'sets the api_url' do
14
+ expect(SmartyStreets.configuration.api_url).to eq 'apiurl'
15
+ end
16
+
17
+ it 'sets the auth_id' do
18
+ expect(SmartyStreets.configuration.auth_id).to eq 'MYAUTHID'
19
+ end
20
+
21
+ it 'sets the auth_token' do
22
+ expect(SmartyStreets.configuration.auth_token).to eq 'MYAUTHTOKEN'
23
+ end
24
+
25
+ it 'sets the number_of_candidates' do
26
+ expect(SmartyStreets.configuration.number_of_candidates).to eq 1
27
+ end
28
+ end
@@ -0,0 +1,171 @@
1
+ require 'spec_helper'
2
+
3
+ describe SmartyStreets do
4
+ before do
5
+ end
6
+
7
+ context SmartyStreets::Request do
8
+ context 'unauthorized request' do
9
+ let(:unauthorized_request) do
10
+ double(:response, code: 401)
11
+ end
12
+
13
+ before do
14
+ SmartyStreets.configure do |c|
15
+ c.auth_id = 'ERROR'
16
+ c.auth_token = 'ERROR'
17
+ end
18
+ HTTParty.stub(:get).and_return(unauthorized_request)
19
+ end
20
+
21
+ specify 'raises an InvalidCredentials error' do
22
+ expect {
23
+ locations = SmartyStreets.standardize do |location|
24
+ location.street = '1 infinite loop'
25
+ location.city = 'cupertino'
26
+ location.state = 'california'
27
+ location.zip_code = '95014'
28
+ end
29
+ }.to raise_error SmartyStreets::Request::InvalidCredentials
30
+ end
31
+ end
32
+
33
+ context 'malformed data' do
34
+ let(:malformed_data_request) do
35
+ double(:response, code: 400)
36
+ end
37
+
38
+ before do
39
+ SmartyStreets.configure do |c|
40
+ c.auth_id = 'ERROR'
41
+ c.auth_token = 'ERROR'
42
+ end
43
+ HTTParty.stub(:get).and_return(malformed_data_request)
44
+ end
45
+
46
+ specify 'raises an InvalidCredentials error' do
47
+ expect {
48
+ locations = SmartyStreets.standardize do |location|
49
+ location.street = '1 infinite loop'
50
+ location.city = 'cupertino'
51
+ location.state = 'california'
52
+ location.zip_code = '95014'
53
+ end
54
+ }.to raise_error SmartyStreets::Request::MalformedData
55
+ end
56
+ end
57
+
58
+ context 'payment required' do
59
+ let(:payment_required_request) do
60
+ double(:response, code: 402)
61
+ end
62
+
63
+ before do
64
+ SmartyStreets.configure do |c|
65
+ c.auth_id = 'ERROR'
66
+ c.auth_token = 'ERROR'
67
+ end
68
+ HTTParty.stub(:get).and_return(payment_required_request)
69
+ end
70
+
71
+ specify 'raises an InvalidCredentials error' do
72
+ expect {
73
+ locations = SmartyStreets.standardize do |location|
74
+ location.street = '1 infinite loop'
75
+ location.city = 'cupertino'
76
+ location.state = 'california'
77
+ location.zip_code = '95014'
78
+ end
79
+ }.to raise_error SmartyStreets::Request::PaymentRequired
80
+ end
81
+ end
82
+
83
+ context 'remote server error' do
84
+ let(:remote_server_error_request) do
85
+ double(:response, code: 500)
86
+ end
87
+
88
+ before do
89
+ SmartyStreets.configure do |c|
90
+ c.auth_id = 'ERROR'
91
+ c.auth_token = 'ERROR'
92
+ end
93
+ HTTParty.stub(:get).and_return(remote_server_error_request)
94
+ end
95
+
96
+ specify 'raises an InvalidCredentials error' do
97
+ expect {
98
+ locations = SmartyStreets.standardize do |location|
99
+ location.street = '1 infinite loop'
100
+ location.city = 'cupertino'
101
+ location.state = 'california'
102
+ location.zip_code = '95014'
103
+ end
104
+ }.to raise_error SmartyStreets::Request::RemoteServerError
105
+ end
106
+ end
107
+
108
+ context 'successful request' do
109
+ let(:successful_response) do
110
+ double(:response, code: 200, body: successful_response_data)
111
+ end
112
+
113
+ before do
114
+ SmartyStreets.configure do |c|
115
+ c.auth_id = 'MYAUTHID'
116
+ c.auth_token = 'MYAUTHTOKEN'
117
+ c.number_of_candidates = 5
118
+ end
119
+ HTTParty.stub(:get).and_return(successful_response)
120
+ end
121
+
122
+ specify 'makes a request for a standardized address' do
123
+ locations = SmartyStreets.standardize do |location|
124
+ location.street = '1 infinite loop'
125
+ location.city = 'cupertino'
126
+ location.state = 'calforna'
127
+ location.zip_code = '95014'
128
+ end
129
+
130
+ expect(locations.first.street).to eq '1 Infinite Loop'
131
+ expect(locations.first.city).to eq 'Cupertino'
132
+ expect(locations.first.state).to eq 'CA'
133
+ expect(locations.first.zip_code).to eq '95014-2083'
134
+ end
135
+ end
136
+
137
+ context 'address with no candidates' do
138
+ let(:unsuccessful_response) do
139
+ double(:response, code: 200, body: unsuccessful_response_data)
140
+ end
141
+
142
+ before do
143
+ SmartyStreets.configure do |c|
144
+ c.auth_id = 'MYAUTHID'
145
+ c.auth_token = 'MYAUTHTOKEN'
146
+ c.number_of_candidates = 5
147
+ end
148
+ HTTParty.stub(:get).and_return(unsuccessful_response)
149
+ end
150
+
151
+ specify 'makes a request for a standardized address' do
152
+ expect {
153
+ locations = SmartyStreets.standardize do |location|
154
+ location.street = '1234 Unicorn Lane'
155
+ location.city = 'earth'
156
+ location.state = 'galaxy'
157
+ location.zip_code = '1234923'
158
+ end
159
+ }.to raise_error SmartyStreets::Request::NoValidCandidates
160
+ end
161
+ end
162
+ end
163
+
164
+ def successful_response_data
165
+ '[{"input_index":0,"candidate_index":0,"delivery_line_1":"1 Infinite Loop","last_line":"Cupertino CA 95014-2083","delivery_point_barcode":"950142083017","components":{"primary_number":"1","street_name":"Infinite","street_suffix":"Loop","city_name":"Cupertino","state_abbreviation":"CA","zipcode":"95014","plus4_code":"2083","delivery_point":"01","delivery_point_check_digit":"7"},"metadata":{"record_type":"S","county_fips":"06085","county_name":"Santa Clara","carrier_route":"C067","congressional_district":"18","rdi":"Commercial","elot_sequence":"0031","elot_sort":"A","latitude":37.33118,"longitude":-122.03062,"precision":"Zip9"},"analysis":{"dpv_match_code":"Y","dpv_footnotes":"AABB","dpv_cmra":"N","dpv_vacant":"N","active":"Y"}},{"input_index":0,"candidate_index":1,"addressee":"Apple Computer","delivery_line_1":"1 Infinite Loop","last_line":"Cupertino CA 95014-2084","delivery_point_barcode":"950142084016","components":{"primary_number":"1","street_name":"Infinite","street_suffix":"Loop","city_name":"Cupertino","state_abbreviation":"CA","zipcode":"95014","plus4_code":"2084","delivery_point":"01","delivery_point_check_digit":"6"},"metadata":{"record_type":"F","county_fips":"06085","county_name":"Santa Clara","carrier_route":"C067","congressional_district":"18","rdi":"Commercial","elot_sequence":"0032","elot_sort":"A","latitude":37.33118,"longitude":-122.03062,"precision":"Zip9"},"analysis":{"dpv_match_code":"Y","dpv_footnotes":"AABB","dpv_cmra":"N","dpv_vacant":"N","active":"Y"}}]'
166
+ end
167
+
168
+ def unsuccessful_response_data
169
+ nil
170
+ end
171
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'smarty_streets'
5
+ require 'rspec'
6
+
7
+ RSpec.configure do |c|
8
+ c.mock_with(:rspec)
9
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smarty_streets
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Russ Smith
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.11'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.11'
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.3'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.3'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: A ruby gem to integrate with http://www.smartystreets.com
79
+ email:
80
+ - russ@bashme.org
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .rspec
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - lib/smarty_streets.rb
92
+ - lib/smarty_streets/configuration.rb
93
+ - lib/smarty_streets/location.rb
94
+ - lib/smarty_streets/request.rb
95
+ - lib/smarty_streets/version.rb
96
+ - smarty_streets.gemspec
97
+ - spec/configuration_spec.rb
98
+ - spec/smarty_streets_spec.rb
99
+ - spec/spec_helper.rb
100
+ homepage: ''
101
+ licenses:
102
+ - MIT
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 1.8.23
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: A ruby gem to integrate with http://www.smartystreets.com
125
+ test_files:
126
+ - spec/configuration_spec.rb
127
+ - spec/smarty_streets_spec.rb
128
+ - spec/spec_helper.rb