address_standardization 0.3.0 → 0.4.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.
- data/.gitignore +1 -1
- data/{README.rdoc → README.md} +13 -8
- data/Rakefile +5 -3
- data/address_standardization.gemspec +67 -0
- data/lib/address_standardization.rb +25 -6
- data/lib/address_standardization/abstract_service.rb +31 -0
- data/lib/address_standardization/{abstract_address.rb → address.rb} +8 -9
- data/lib/address_standardization/google_maps.rb +48 -53
- data/lib/address_standardization/melissa_data.rb +57 -57
- data/lib/address_standardization/ruby_ext.rb +6 -0
- data/lib/address_standardization/version.rb +3 -0
- data/test/google_maps_test.rb +111 -37
- data/test/melissa_data_test.rb +137 -38
- data/test/test_helper.rb +44 -8
- metadata +9 -17
- data/VERSION +0 -1
data/.gitignore
CHANGED
data/{README.rdoc → README.md}
RENAMED
@@ -22,36 +22,41 @@ Right now this library supports two services: MelissaData and Google Maps.
|
|
22
22
|
|
23
23
|
MelissaData provides two services itself: [US address lookup](http://www.melissadata.com/lookups/AddressVerify.asp) and [Canadian address lookup](http://www.melissadata.com/lookups/CanadianAddressVerify.asp). They both work the same way, however. First, here's how to standardize a US address:
|
24
24
|
|
25
|
-
addr = AddressStandardization::MelissaData
|
25
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
26
26
|
:street => "1 Infinite Loop",
|
27
27
|
:city => "Cupertino",
|
28
28
|
:state => "CA"
|
29
29
|
)
|
30
30
|
|
31
|
-
This submits the address to MelissaData. If the address can't be found, you'll get back `nil`. But if the address can be found (as in this case), you'll get an instance of `AddressStandardization::
|
31
|
+
This submits the address to MelissaData. If the address can't be found, you'll get back `nil`. But if the address can be found (as in this case), you'll get an instance of `AddressStandardization::Address`. If you store the instance, you can refer to the individual fields like so:
|
32
32
|
|
33
33
|
addr.street #=> "1 INFINITE LOOP"
|
34
34
|
addr.city #=> "CUPERTINO"
|
35
35
|
addr.state #=> "CA"
|
36
36
|
addr.zip #=> "95014-2083"
|
37
|
+
addr.country #=> "USA"
|
37
38
|
|
38
39
|
And standardizing a Canadian address:
|
39
40
|
|
40
|
-
addr = AddressStandardization::MelissaData
|
41
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
41
42
|
:street => "103 Metig St",
|
42
43
|
:city => "Sault Ste Marie",
|
43
|
-
:province => "ON"
|
44
|
+
:province => "ON",
|
45
|
+
:country => "Canada"
|
44
46
|
)
|
45
47
|
addr.street #=> "103 METIG ST RR 4"
|
46
48
|
addr.city #=> "SAULT STE MARIE"
|
47
49
|
addr.province #=> "ON"
|
48
50
|
addr.postalcode #=> "P6A 5K9"
|
51
|
+
addr.country #=> "CANADA"
|
52
|
+
|
53
|
+
Note that when standardizing a Canadian address, the `:country` must be "Canada" (or "CANADA", or anything like that). Otherwise it will be treated as a US address.
|
49
54
|
|
50
|
-
|
55
|
+
Also note that I'm referring to the address's province as `province`, but you can also use `state` if you like. Same goes for the postal code -- you can also refer to it as `zip`.
|
51
56
|
|
52
57
|
Using Google Maps to validate an address is just as easy:
|
53
58
|
|
54
|
-
addr = AddressStandardization::GoogleMaps
|
59
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
55
60
|
:street => "1600 Amphitheatre Parkway",
|
56
61
|
:city => "Mountain View",
|
57
62
|
:state => "CA"
|
@@ -64,7 +69,7 @@ Using Google Maps to validate an address is just as easy:
|
|
64
69
|
|
65
70
|
And, again, a Canadian address:
|
66
71
|
|
67
|
-
addr = AddressStandardization::GoogleMaps
|
72
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
68
73
|
:street => "1770 Stenson Blvd.",
|
69
74
|
:city => "Peterborough",
|
70
75
|
:province => "ON"
|
@@ -87,4 +92,4 @@ If you find any bugs with this plugin, feel free to:
|
|
87
92
|
|
88
93
|
## Author/License
|
89
94
|
|
90
|
-
(c) 2008 Elliot Winkler. Released under the MIT license.
|
95
|
+
(c) 2008-2010 Elliot Winkler. Released under the MIT license.
|
data/Rakefile
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
|
4
|
+
require File.dirname(__FILE__) + "/lib/address_standardization/version.rb"
|
5
|
+
|
4
6
|
begin
|
5
7
|
require 'jeweler'
|
6
8
|
Jeweler::Tasks.new do |gem|
|
9
|
+
gem.version = AddressStandardization::VERSION
|
7
10
|
gem.name = "address_standardization"
|
8
11
|
gem.summary = %Q{A tiny Ruby library to quickly standardize a postal address}
|
9
12
|
gem.description = %Q{A tiny Ruby library to quickly standardize a postal address}
|
@@ -11,8 +14,7 @@ begin
|
|
11
14
|
gem.email = "elliot.winkler@gmail.com"
|
12
15
|
gem.homepage = "http://github.com/mcmire/address_standardization"
|
13
16
|
gem.add_dependency "mechanize"
|
14
|
-
gem.
|
15
|
-
gem.add_development_dependency "mcmire-contest"
|
17
|
+
gem.add_development_dependency "mcmire-context"
|
16
18
|
gem.add_development_dependency "mcmire-matchy"
|
17
19
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
20
|
end
|
@@ -41,7 +43,7 @@ rescue LoadError
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
task :test => :check_dependencies
|
46
|
+
task :test => [:"check_dependencies:development", :check_dependencies]
|
45
47
|
|
46
48
|
task :default => :test
|
47
49
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{address_standardization}
|
8
|
+
s.version = "0.4.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Elliot Winkler"]
|
12
|
+
s.date = %q{2010-02-01}
|
13
|
+
s.description = %q{A tiny Ruby library to quickly standardize a postal address}
|
14
|
+
s.email = %q{elliot.winkler@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.md",
|
17
|
+
"TODO"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"README.md",
|
22
|
+
"Rakefile",
|
23
|
+
"TODO",
|
24
|
+
"address_standardization.gemspec",
|
25
|
+
"lib/address_standardization.rb",
|
26
|
+
"lib/address_standardization/abstract_service.rb",
|
27
|
+
"lib/address_standardization/address.rb",
|
28
|
+
"lib/address_standardization/class_level_inheritable_attributes.rb",
|
29
|
+
"lib/address_standardization/google_maps.rb",
|
30
|
+
"lib/address_standardization/melissa_data.rb",
|
31
|
+
"lib/address_standardization/ruby_ext.rb",
|
32
|
+
"lib/address_standardization/version.rb",
|
33
|
+
"test/google_maps_test.rb",
|
34
|
+
"test/melissa_data_test.rb",
|
35
|
+
"test/test_helper.rb"
|
36
|
+
]
|
37
|
+
s.homepage = %q{http://github.com/mcmire/address_standardization}
|
38
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = %q{1.3.5}
|
41
|
+
s.summary = %q{A tiny Ruby library to quickly standardize a postal address}
|
42
|
+
s.test_files = [
|
43
|
+
"test/google_maps_test.rb",
|
44
|
+
"test/melissa_data_test.rb",
|
45
|
+
"test/test_helper.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_runtime_dependency(%q<mechanize>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<mcmire-context>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<mcmire-matchy>, [">= 0"])
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<mechanize>, [">= 0"])
|
58
|
+
s.add_dependency(%q<mcmire-context>, [">= 0"])
|
59
|
+
s.add_dependency(%q<mcmire-matchy>, [">= 0"])
|
60
|
+
end
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<mechanize>, [">= 0"])
|
63
|
+
s.add_dependency(%q<mcmire-context>, [">= 0"])
|
64
|
+
s.add_dependency(%q<mcmire-matchy>, [">= 0"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -1,9 +1,28 @@
|
|
1
1
|
# address_standardization: A tiny Ruby library to quickly standardize a postal address.
|
2
|
-
# Copyright (C) 2008 Elliot Winkler. Released under the MIT license.
|
2
|
+
# Copyright (C) 2008-2010 Elliot Winkler. Released under the MIT license.
|
3
3
|
|
4
|
-
require
|
5
|
-
require File.dirname(__FILE__)+'/address_standardization/class_level_inheritable_attributes'
|
4
|
+
require 'mechanize'
|
6
5
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
|
6
|
+
require 'address_standardization/ruby_ext'
|
7
|
+
require 'address_standardization/class_level_inheritable_attributes'
|
8
|
+
|
9
|
+
require 'address_standardization/address'
|
10
|
+
require 'address_standardization/abstract_service'
|
11
|
+
require 'address_standardization/melissa_data'
|
12
|
+
require 'address_standardization/google_maps'
|
13
|
+
|
14
|
+
module AddressStandardization
|
15
|
+
class << self
|
16
|
+
attr_accessor :test_mode
|
17
|
+
alias_method :test_mode?, :test_mode
|
18
|
+
|
19
|
+
attr_accessor :debug_mode
|
20
|
+
alias_method :debug_mode?, :debug_mode
|
21
|
+
|
22
|
+
def debug(*args)
|
23
|
+
puts(*args) if debug_mode?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
self.test_mode = false
|
27
|
+
self.debug_mode = $DEBUG || ENV["DEBUG"] || false
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module AddressStandardization
|
2
|
+
class AbstractService
|
3
|
+
extend ClassLevelInheritableAttributes
|
4
|
+
cattr_inheritable :canned_response
|
5
|
+
self.canned_response = :success
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def standardize_address(address_info)
|
9
|
+
if AddressStandardization.test_mode?
|
10
|
+
get_canned_response(address_info)
|
11
|
+
else
|
12
|
+
get_live_response(address_info)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def with_canned_response(response, &block)
|
17
|
+
old_response = self.canned_response
|
18
|
+
self.canned_response = response
|
19
|
+
ret = yield
|
20
|
+
self.canned_response = old_response
|
21
|
+
ret
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
def get_canned_response(address_info)
|
26
|
+
response = (self.canned_response ||= :success)
|
27
|
+
response == :success ? Address.new(address_info) : nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,21 +1,20 @@
|
|
1
|
+
# TODO: Rename to address.rb
|
2
|
+
|
1
3
|
module AddressStandardization
|
2
4
|
class StandardizationError < StandardError; end
|
3
5
|
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
cattr_inheritable :valid_keys
|
8
|
-
|
9
|
-
def self.standardize
|
10
|
-
raise NotImplementedError, "You must override .standardize in a subclass"
|
6
|
+
class Address
|
7
|
+
class << self
|
8
|
+
attr_accessor :valid_keys
|
11
9
|
end
|
10
|
+
self.valid_keys = %w(street city state province zip postalcode country)
|
12
11
|
|
13
12
|
attr_reader :address_info
|
14
13
|
|
15
14
|
def initialize(address_info)
|
16
15
|
raise NotImplementedError, "You must define valid_keys" unless self.class.valid_keys
|
17
16
|
raise ArgumentError, "No address given!" if address_info.empty?
|
18
|
-
address_info = address_info.
|
17
|
+
address_info = address_info.stringify_keys
|
19
18
|
validate_keys(address_info)
|
20
19
|
standardize_values!(address_info)
|
21
20
|
@address_info = address_info
|
@@ -43,7 +42,7 @@ module AddressStandardization
|
|
43
42
|
end
|
44
43
|
|
45
44
|
def ==(other)
|
46
|
-
other.kind_of?(
|
45
|
+
other.kind_of?(self.class) && @address_info == other.address_info
|
47
46
|
end
|
48
47
|
|
49
48
|
private
|
@@ -1,59 +1,54 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'hpricot'
|
3
|
-
|
4
1
|
module AddressStandardization
|
5
|
-
|
2
|
+
# See <http://code.google.com/apis/maps/documentation/geocoding/>
|
3
|
+
class GoogleMaps < AbstractService
|
6
4
|
class << self
|
7
5
|
attr_accessor :api_key
|
8
|
-
end
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
addr[:street] = get_inner_text(xml, '//ThoroughfareName')
|
40
|
-
addr[:city] = get_inner_text(xml, '//LocalityName')
|
41
|
-
addr[:province] = addr[:state] = get_inner_text(xml, '//AdministrativeAreaName')
|
42
|
-
addr[:zip] = addr[:postalcode] = get_inner_text(xml, '//PostalCodeNumber')
|
43
|
-
addr[:country] = get_inner_text(xml, '//CountryName')
|
44
|
-
|
45
|
-
new(addr)
|
46
|
-
else
|
47
|
-
#File.open("test.xml", "w") {|f| f.write("(no response or response was unsuccessful)") }
|
48
|
-
nil
|
49
|
-
end
|
50
|
-
end
|
7
|
+
protected
|
8
|
+
# much of this code was borrowed from GeoKit, thanks...
|
9
|
+
def get_live_response(address_info)
|
10
|
+
raise "API key not specified.\nCall AddressStandardization::GoogleMaps.api_key = '...' before you call .standardize()." unless GoogleMaps.api_key
|
11
|
+
|
12
|
+
address_info = address_info.stringify_keys
|
13
|
+
|
14
|
+
address_str = [
|
15
|
+
address_info["street"],
|
16
|
+
address_info["city"],
|
17
|
+
(address_info["state"] || address_info["province"]),
|
18
|
+
address_info["zip"]
|
19
|
+
].join(" ")
|
20
|
+
url = "http://maps.google.com/maps/geo?q=#{address_str.url_escape}&output=xml&key=#{GoogleMaps.api_key}&oe=utf-8"
|
21
|
+
AddressStandardization.debug "[GoogleMaps] Hitting URL: #{url}"
|
22
|
+
uri = URI.parse(url)
|
23
|
+
res = Net::HTTP.get_response(uri)
|
24
|
+
return unless res.is_a?(Net::HTTPSuccess)
|
25
|
+
|
26
|
+
content = res.body
|
27
|
+
AddressStandardization.debug "[GoogleMaps] Response body:"
|
28
|
+
AddressStandardization.debug "--------------------------------------------------"
|
29
|
+
AddressStandardization.debug content
|
30
|
+
AddressStandardization.debug "--------------------------------------------------"
|
31
|
+
xml = Nokogiri::XML(content)
|
32
|
+
xml.remove_namespaces! # good or bad? I say good.
|
33
|
+
return unless xml.at("/kml/Response/Status/code").inner_text == "200"
|
34
|
+
|
35
|
+
addr = {}
|
51
36
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
37
|
+
addr[:street] = get_inner_text(xml, '//ThoroughfareName').to_s
|
38
|
+
addr[:city] = get_inner_text(xml, '//LocalityName').to_s
|
39
|
+
addr[:province] = addr[:state] = get_inner_text(xml, '//AdministrativeAreaName').to_s
|
40
|
+
addr[:zip] = addr[:postalcode] = get_inner_text(xml, '//PostalCodeNumber').to_s
|
41
|
+
addr[:country] = get_inner_text(xml, '//CountryName').to_s
|
42
|
+
|
43
|
+
return if addr[:street] =~ /^\s*$/ or addr[:city] =~ /^\s*$/
|
44
|
+
|
45
|
+
Address.new(addr)
|
56
46
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
47
|
+
|
48
|
+
private
|
49
|
+
def get_inner_text(xml, xpath)
|
50
|
+
lambda {|x| x && x.inner_text.upcase }.call(xml.at(xpath))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -1,69 +1,69 @@
|
|
1
|
-
|
2
|
-
require 'mechanize'
|
1
|
+
# encoding: utf-8
|
3
2
|
|
4
3
|
module AddressStandardization
|
5
|
-
class MelissaData
|
6
|
-
class
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
4
|
+
class MelissaData < AbstractService
|
5
|
+
class << self
|
6
|
+
protected
|
7
|
+
def get_live_response(address_info)
|
8
|
+
address_info = address_info.stringify_keys
|
9
|
+
|
10
|
+
is_canada = (address_info["country"].to_s.upcase == "CANADA")
|
11
|
+
addr = Address.new(address_info)
|
12
|
+
|
13
|
+
url = "http://www.melissadata.com/lookups/#{action(is_canada)}"
|
14
|
+
params = []
|
15
|
+
attrs_to_fields(is_canada).each do |attr, field|
|
16
|
+
key, val = field, address_info[attr]
|
17
|
+
params << "#{key}=#{val.url_escape}" if val
|
18
|
+
end
|
19
|
+
url << "?" + params.join("&")
|
20
|
+
url << "&FindAddress=Submit"
|
21
|
+
|
22
|
+
#puts "URL: <#{url}>"
|
23
|
+
|
24
|
+
attrs = {:country => (is_canada ? "CANADA" : "USA")}
|
25
|
+
WWW::Mechanize.new do |ua|
|
26
|
+
AddressStandardization.debug "[MelissaData] Hitting URL: #{url}"
|
27
|
+
results_page = ua.get(url)
|
28
|
+
AddressStandardization.debug "[MelissaData] Response body:"
|
29
|
+
AddressStandardization.debug "--------------------------------------------------"
|
30
|
+
AddressStandardization.debug results_page.body
|
31
|
+
AddressStandardization.debug "--------------------------------------------------"
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
|
33
|
+
table = results_page.search("table.Tableresultborder")[1]
|
34
|
+
return unless table
|
35
|
+
status_row = table.at("span.Titresultableok")
|
36
|
+
return unless status_row && status_row.inner_text =~ /Address Verified/
|
37
|
+
main_td = table.search("tr:eq(#{is_canada ? 2 : 3})/td:eq(2)")
|
38
|
+
main_td_s = main_td.inner_html
|
39
|
+
main_td_s.encode!("utf-8") if main_td_s.respond_to?(:encode!)
|
40
|
+
street_part, city_state_zip_part = main_td_s.split("<br>")[0..1]
|
41
|
+
street = street_part.strip_html.strip_whitespace
|
42
|
+
if main_td_s.respond_to?(:encode!)
|
43
|
+
# ruby 1.9
|
44
|
+
separator = city_state_zip_part.include?("  ") ? "  " : " "
|
45
|
+
else
|
46
|
+
# ruby 1.8
|
47
|
+
separator = "\240\240"
|
41
48
|
end
|
42
|
-
|
49
|
+
city, state, zip = city_state_zip_part.strip_html.split(separator)
|
50
|
+
attrs[:street] = street.upcase
|
51
|
+
attrs[:city] = city.upcase
|
52
|
+
attrs[:province] = attrs[:state] = state.upcase
|
53
|
+
attrs[:postalcode] = attrs[:zip] = zip.upcase
|
43
54
|
end
|
55
|
+
Address.new(attrs)
|
44
56
|
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class USAddress < BaseAddress
|
48
|
-
self.start_url = 'http://www.melissadata.com/lookups/AddressVerify.asp'
|
49
|
-
self.valid_keys = %w(street city state zip)
|
50
57
|
|
51
|
-
def
|
52
|
-
|
53
|
-
street, city, state, zip = fields
|
54
|
-
new(:street => street, :city => city, :state => state, :zip => zip)
|
55
|
-
end
|
58
|
+
def action(is_canada)
|
59
|
+
is_canada ? "CanadianAddressVerify.asp" : "AddressVerify.asp"
|
56
60
|
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class CanadianAddress < BaseAddress
|
60
|
-
self.start_url = 'http://www.melissadata.com/lookups/CanadianAddressVerify.asp'
|
61
|
-
self.valid_keys = %w(street city province postalcode)
|
62
61
|
|
63
|
-
def
|
64
|
-
if
|
65
|
-
street, city, province, postalcode
|
66
|
-
|
62
|
+
def attrs_to_fields(is_canada)
|
63
|
+
if is_canada
|
64
|
+
{"street" => 'Street', "city" => 'city', "province" => 'Province', "postalcode" => 'Postcode'}
|
65
|
+
else
|
66
|
+
{"street" => 'Address', "city" => 'city', "state" => 'state', "zip" => 'zip'}
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
data/test/google_maps_test.rb
CHANGED
@@ -3,46 +3,120 @@ require 'test_helper'
|
|
3
3
|
AddressStandardization::GoogleMaps.api_key = "ABQIAAAALHg3jKnK9wN9K3_ArJA6TxSTZ2OgdK08l2h0_gdsozNQ-6zpaxQvIY84J7Mh1fAHQrYGI4W27qKZaw"
|
4
4
|
|
5
5
|
class GoogleMapsTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
6
|
+
shared "production mode tests" do
|
7
|
+
test "A valid US address" do
|
8
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
9
|
+
"street" => "1600 Amphitheatre Parkway",
|
10
|
+
:city => "Mountain View",
|
11
|
+
:state => "CA"
|
12
|
+
)
|
13
|
+
addr.should == AddressStandardization::Address.new(
|
14
|
+
"street" => "1600 AMPHITHEATRE PKWY",
|
15
|
+
"city" => "MOUNTAIN VIEW",
|
16
|
+
"state" => "CA",
|
17
|
+
"province" => "CA",
|
18
|
+
"postalcode" => "94043",
|
19
|
+
"zip" => "94043",
|
20
|
+
"country" => "USA"
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
test "A valid Canadian address" do
|
25
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
26
|
+
:street => "1770 Stenson Boulevard",
|
27
|
+
:city => "Peterborough",
|
28
|
+
"province" => "ON"
|
29
|
+
)
|
30
|
+
addr.should == AddressStandardization::Address.new(
|
31
|
+
"street" => "1770 STENSON BLVD",
|
32
|
+
"city" => "PETERBOROUGH",
|
33
|
+
"state" => "ON",
|
34
|
+
"province" => "ON",
|
35
|
+
"postalcode" => "K9K",
|
36
|
+
"zip" => "K9K",
|
37
|
+
"country" => "CANADA"
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
test "An invalid address" do
|
42
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
43
|
+
:street => "123 Imaginary Lane",
|
44
|
+
:city => "Some Town",
|
45
|
+
:state => "AK"
|
46
|
+
)
|
47
|
+
addr.should == nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "With test mode explicitly false" do
|
52
|
+
setup do
|
53
|
+
AddressStandardization.test_mode = false
|
54
|
+
end
|
55
|
+
uses "production mode tests"
|
21
56
|
end
|
22
57
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
)
|
29
|
-
addr.should == AddressStandardization::GoogleMaps::Address.new(
|
30
|
-
"street" => "1770 STENSON BLVD",
|
31
|
-
"city" => "PETERBOROUGH",
|
32
|
-
"state" => "ON",
|
33
|
-
"province" => "ON",
|
34
|
-
"postalcode" => "K9K",
|
35
|
-
"zip" => "K9K",
|
36
|
-
"country" => "CANADA"
|
37
|
-
)
|
58
|
+
context "With test mode implicitly false" do
|
59
|
+
setup do
|
60
|
+
AddressStandardization.test_mode = nil
|
61
|
+
end
|
62
|
+
uses "production mode tests"
|
38
63
|
end
|
39
64
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
)
|
46
|
-
|
65
|
+
context "With test mode true" do
|
66
|
+
setup do
|
67
|
+
AddressStandardization.test_mode = true
|
68
|
+
end
|
69
|
+
|
70
|
+
test "Valid address (before and after)" do
|
71
|
+
AddressStandardization::GoogleMaps.canned_response = :success
|
72
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
73
|
+
:street => "123 Imaginary Lane",
|
74
|
+
:city => "Some Town",
|
75
|
+
:state => "AK"
|
76
|
+
)
|
77
|
+
addr.should == AddressStandardization::Address.new(
|
78
|
+
:street => "123 Imaginary Lane",
|
79
|
+
:city => "Some Town",
|
80
|
+
:state => "AK"
|
81
|
+
)
|
82
|
+
AddressStandardization::GoogleMaps.canned_response = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
test "Valid address (block)" do
|
86
|
+
AddressStandardization::GoogleMaps.with_canned_response(:success) do
|
87
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
88
|
+
:street => "123 Imaginary Lane",
|
89
|
+
:city => "Some Town",
|
90
|
+
:state => "AK"
|
91
|
+
)
|
92
|
+
addr.should == AddressStandardization::Address.new(
|
93
|
+
:street => "123 Imaginary Lane",
|
94
|
+
:city => "Some Town",
|
95
|
+
:state => "AK"
|
96
|
+
)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
test "Invalid address (before and after)" do
|
101
|
+
AddressStandardization::GoogleMaps.canned_response = :failure
|
102
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
103
|
+
:street => "123 Imaginary Lane",
|
104
|
+
:city => "Some Town",
|
105
|
+
:state => "AK"
|
106
|
+
)
|
107
|
+
addr.should == nil
|
108
|
+
AddressStandardization::GoogleMaps.canned_response = nil
|
109
|
+
end
|
110
|
+
|
111
|
+
test "Invalid address (block)" do
|
112
|
+
AddressStandardization::GoogleMaps.with_canned_response(:failure) do
|
113
|
+
addr = AddressStandardization::GoogleMaps.standardize_address(
|
114
|
+
:street => "123 Imaginary Lane",
|
115
|
+
:city => "Some Town",
|
116
|
+
:state => "AK"
|
117
|
+
)
|
118
|
+
addr.should == nil
|
119
|
+
end
|
120
|
+
end
|
47
121
|
end
|
48
122
|
end
|
data/test/melissa_data_test.rb
CHANGED
@@ -1,49 +1,148 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class MelissaDataTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
shared "production mode tests" do
|
5
|
+
test "Valid US address (implicit country)" do
|
6
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
7
|
+
:street => "1 Infinite Loop",
|
8
|
+
"city" => "Cupertino",
|
9
|
+
:state => "CA"
|
10
|
+
)
|
11
|
+
addr.should == AddressStandardization::Address.new(
|
12
|
+
"street" => "1 INFINITE LOOP",
|
13
|
+
"city" => "CUPERTINO",
|
14
|
+
"state" => "CA",
|
15
|
+
"province" => "CA",
|
16
|
+
"zip" => "95014-2083",
|
17
|
+
"postalcode" => "95014-2083",
|
18
|
+
"country" => "USA"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
test "Valid US address (explicit country)" do
|
23
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
24
|
+
:street => "1 Infinite Loop",
|
25
|
+
:city => "Cupertino",
|
26
|
+
"state" => "CA",
|
27
|
+
"country" => "USA"
|
28
|
+
)
|
29
|
+
addr.should == AddressStandardization::Address.new(
|
30
|
+
"street" => "1 INFINITE LOOP",
|
31
|
+
"city" => "CUPERTINO",
|
32
|
+
"state" => "CA",
|
33
|
+
"province" => "CA",
|
34
|
+
"zip" => "95014-2083",
|
35
|
+
"postalcode" => "95014-2083",
|
36
|
+
"country" => "USA"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
test "Invalid US address" do
|
41
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
42
|
+
:street => "123 Imaginary Lane",
|
43
|
+
:city => "Some Town",
|
44
|
+
:state => "AK"
|
45
|
+
)
|
46
|
+
addr.should == nil
|
47
|
+
end
|
48
|
+
|
49
|
+
test "Valid Canadian address" do
|
50
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
51
|
+
"street" => "3025 Clayhill Rd",
|
52
|
+
:city => "Mississauga",
|
53
|
+
"province" => "ON",
|
54
|
+
:country => "CANADA"
|
55
|
+
)
|
56
|
+
addr.should == AddressStandardization::Address.new(
|
57
|
+
"street" => "3025 CLAYHILL RD",
|
58
|
+
"state" => "ON",
|
59
|
+
"province" => "ON",
|
60
|
+
"city" => "MISSISSAUGA",
|
61
|
+
"zip" => "L5B 4L2",
|
62
|
+
"postalcode" => "L5B 4L2",
|
63
|
+
"country" => "CANADA"
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
test "Invalid Canadian address" do
|
68
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
69
|
+
:street => "123 Imaginary Lane",
|
70
|
+
:city => "Some Town",
|
71
|
+
:province => "BC"
|
72
|
+
)
|
73
|
+
addr.should == nil
|
74
|
+
end
|
16
75
|
end
|
17
76
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
)
|
24
|
-
addr.should == nil
|
77
|
+
context "With test mode explicitly false" do
|
78
|
+
setup do
|
79
|
+
AddressStandardization.test_mode = false
|
80
|
+
end
|
81
|
+
uses "production mode tests"
|
25
82
|
end
|
26
83
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
)
|
33
|
-
addr.should == AddressStandardization::MelissaData::CanadianAddress.new(
|
34
|
-
"street" => "3025 CLAYHILL RD",
|
35
|
-
"province" => "ON",
|
36
|
-
"city" => "MISSISSAUGA",
|
37
|
-
"postalcode" => "L5B 4L2"
|
38
|
-
)
|
84
|
+
context "With test mode implicitly false" do
|
85
|
+
setup do
|
86
|
+
AddressStandardization.test_mode = nil
|
87
|
+
end
|
88
|
+
uses "production mode tests"
|
39
89
|
end
|
40
90
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
)
|
47
|
-
|
91
|
+
context "With test mode true" do
|
92
|
+
setup do
|
93
|
+
AddressStandardization.test_mode = true
|
94
|
+
end
|
95
|
+
|
96
|
+
test "Valid address (before and after)" do
|
97
|
+
AddressStandardization::MelissaData.canned_response = :success
|
98
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
99
|
+
:street => "123 Imaginary Lane",
|
100
|
+
:city => "Some Town",
|
101
|
+
:province => "BC"
|
102
|
+
)
|
103
|
+
addr.should == AddressStandardization::Address.new(
|
104
|
+
:street => "123 Imaginary Lane",
|
105
|
+
:city => "Some Town",
|
106
|
+
:province => "BC"
|
107
|
+
)
|
108
|
+
AddressStandardization::MelissaData.canned_response = nil
|
109
|
+
end
|
110
|
+
|
111
|
+
test "Valid address (block)" do
|
112
|
+
AddressStandardization::MelissaData.with_canned_response(:success) do
|
113
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
114
|
+
:street => "123 Imaginary Lane",
|
115
|
+
:city => "Some Town",
|
116
|
+
:province => "BC"
|
117
|
+
)
|
118
|
+
addr.should == AddressStandardization::Address.new(
|
119
|
+
:street => "123 Imaginary Lane",
|
120
|
+
:city => "Some Town",
|
121
|
+
:province => "BC"
|
122
|
+
)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
test "Invalid address (before and after)" do
|
127
|
+
AddressStandardization::MelissaData.canned_response = :failure
|
128
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
129
|
+
:street => "123 Imaginary Lane",
|
130
|
+
:city => "Some Town",
|
131
|
+
:province => "BC"
|
132
|
+
)
|
133
|
+
addr.should == nil
|
134
|
+
AddressStandardization::MelissaData.canned_response = nil
|
135
|
+
end
|
136
|
+
|
137
|
+
test "Invalid address (block)" do
|
138
|
+
AddressStandardization::MelissaData.with_canned_response(:failure) do
|
139
|
+
addr = AddressStandardization::MelissaData.standardize_address(
|
140
|
+
:street => "123 Imaginary Lane",
|
141
|
+
:city => "Some Town",
|
142
|
+
:province => "BC"
|
143
|
+
)
|
144
|
+
addr.should == nil
|
145
|
+
end
|
146
|
+
end
|
48
147
|
end
|
49
148
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,12 +1,48 @@
|
|
1
|
-
# http://sneaq.net/textmate-wtf
|
2
|
-
#$LOAD_PATH.reject! { |e| e.include? 'TextMate' }
|
3
|
-
|
4
|
-
#dir = File.dirname(__FILE__)
|
5
|
-
#lib = dir + "/../lib"
|
6
|
-
#$LOAD_PATH.unshift(lib)
|
7
|
-
|
8
1
|
require 'rubygems'
|
2
|
+
gem 'mcmire-context'
|
9
3
|
require 'context'
|
4
|
+
gem 'mcmire-matchy'
|
10
5
|
require 'matchy'
|
11
6
|
|
12
|
-
require 'address_standardization'
|
7
|
+
require 'address_standardization'
|
8
|
+
|
9
|
+
module Context
|
10
|
+
class SharedBehavior < Module
|
11
|
+
# Fix this so that sharing a module twice within two sub-contexts
|
12
|
+
# doesn't fail with something like "'test: blah blah' is already defined"
|
13
|
+
def included(arg) # :nodoc:
|
14
|
+
arg.instance_eval(&@_behavior)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << Test::Unit::TestCase
|
20
|
+
# Modify this so that the constant is set within the current context (and sub-contexts)
|
21
|
+
def shared(name, &block)
|
22
|
+
case name.class.name
|
23
|
+
when "String"
|
24
|
+
name = name.to_module_name
|
25
|
+
when "Symbol"
|
26
|
+
name = name.to_s.to_module_name
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Provide a String or Symbol as the name of the shared behavior group"
|
29
|
+
end
|
30
|
+
const_set(name, Context::SharedBehavior.create_from_behavior(block))
|
31
|
+
end
|
32
|
+
%w(shared_behavior share_as share_behavior_as shared_examples_for).each {|m| alias_method m, :shared}
|
33
|
+
|
34
|
+
# Modify this so that we look in the current context (and any super-contexts) for the module
|
35
|
+
def use(shared_name)
|
36
|
+
case shared_name.class.name
|
37
|
+
when "Context::SharedBehavior", "Module"
|
38
|
+
include shared_name
|
39
|
+
when "String"
|
40
|
+
include const_get(shared_name.to_module_name)
|
41
|
+
when "Symbol"
|
42
|
+
include const_get(shared_name.to_s.to_module_name)
|
43
|
+
else
|
44
|
+
raise ArgumentError, "Provide a String or Symbol as the name of the shared behavior group or the module name"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
%w(uses it_should_behave_like behaves_like uses_examples_from).each {|m| alias_method m, :use}
|
48
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: address_standardization
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elliot Winkler
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-02-01 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -23,17 +23,7 @@ dependencies:
|
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
type: :runtime
|
28
|
-
version_requirement:
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: "0"
|
34
|
-
version:
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: mcmire-contest
|
26
|
+
name: mcmire-context
|
37
27
|
type: :development
|
38
28
|
version_requirement:
|
39
29
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -59,20 +49,22 @@ executables: []
|
|
59
49
|
extensions: []
|
60
50
|
|
61
51
|
extra_rdoc_files:
|
62
|
-
- README.
|
52
|
+
- README.md
|
63
53
|
- TODO
|
64
54
|
files:
|
65
55
|
- .gitignore
|
66
|
-
- README.
|
56
|
+
- README.md
|
67
57
|
- Rakefile
|
68
58
|
- TODO
|
69
|
-
-
|
59
|
+
- address_standardization.gemspec
|
70
60
|
- lib/address_standardization.rb
|
71
|
-
- lib/address_standardization/
|
61
|
+
- lib/address_standardization/abstract_service.rb
|
62
|
+
- lib/address_standardization/address.rb
|
72
63
|
- lib/address_standardization/class_level_inheritable_attributes.rb
|
73
64
|
- lib/address_standardization/google_maps.rb
|
74
65
|
- lib/address_standardization/melissa_data.rb
|
75
66
|
- lib/address_standardization/ruby_ext.rb
|
67
|
+
- lib/address_standardization/version.rb
|
76
68
|
- test/google_maps_test.rb
|
77
69
|
- test/melissa_data_test.rb
|
78
70
|
- test/test_helper.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.3.0
|