address_standardization 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,3 @@
1
+ .svn
1
2
  .DS_Store
2
- *.gemspec
3
3
  *.gem
@@ -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::USAddress.standardize(
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::MelissaData::USAddress`. If you store the instance, you can refer to the individual fields like so:
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::CanadianAddress.standardize(
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
- Note that we refer to the province as `province`, but `state` works too. The postal code may also be referred to as `zip`.
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::Address.standardize(
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::Address.standardize(
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.add_dependency "hpricot"
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 File.dirname(__FILE__)+'/address_standardization/ruby_ext'
5
- require File.dirname(__FILE__)+'/address_standardization/class_level_inheritable_attributes'
4
+ require 'mechanize'
6
5
 
7
- require File.dirname(__FILE__)+'/address_standardization/abstract_address'
8
- require File.dirname(__FILE__)+'/address_standardization/melissa_data'
9
- require File.dirname(__FILE__)+'/address_standardization/google_maps'
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 AbstractAddress
5
-
6
- extend ClassLevelInheritableAttributes
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.inject({}) {|h,(k,v)| h[k.to_s] = v; h } # stringify keys
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?(AbstractAddress) && @address_info == other.address_info
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
- module GoogleMaps
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
- class Address < AbstractAddress
11
- self.valid_keys = %w(street city state province postalcode zip country full_address precision)
12
-
13
- class << self
14
- # much of this code was borrowed from GeoKit, thanks...
15
- def standardize(address_info)
16
- raise "API key not specified.\nCall AddressStandardization::GoogleMaps.api_key = '...' before you call .standardize()." unless GoogleMaps.api_key
17
-
18
- address_str = "%s, %s, %s %s" % [
19
- address_info[:street],
20
- address_info[:city],
21
- (address_info[:state] || address_info[:province]),
22
- address_info[:zip]
23
- ]
24
- url = "http://maps.google.com/maps/geo?q=#{address_str.url_escape}&output=xml&key=#{GoogleMaps.api_key}&oe=utf-8"
25
- # puts url
26
- uri = URI.parse(url)
27
- res = Net::HTTP.get_response(uri)
28
- unless res.is_a?(Net::HTTPSuccess)
29
- File.open("test.xml", "w") {|f| f.write("(no response or response was unsuccessful)") }
30
- return nil
31
- end
32
- xml = res.body
33
- #File.open("test.xml", "w") {|f| f.write(xml) }
34
- xml = Hpricot::XML(xml)
35
-
36
- if xml.at("//kml/Response/Status/code").inner_text == "200"
37
- addr = {}
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
- private
53
- def get_inner_text(xml, xpath)
54
- lambda {|x| x && x.inner_text.upcase }.call(xml.at(xpath))
55
- end
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
- end # Address
58
- end # GoogleMaps
59
- end # AddressStandardization
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
- require 'rubygems'
2
- require 'mechanize'
1
+ # encoding: utf-8
3
2
 
4
3
  module AddressStandardization
5
- class MelissaData
6
- class BaseAddress < AbstractAddress
7
- cattr_inheritable :start_url
8
-
9
- def initialize(address_info)
10
- raise NotImplementedError, "You must define start_url" unless self.class.start_url
11
- super(address_info)
12
- end
13
-
14
- class << self
15
- protected
16
- def standardize(address_info, action, attrs_to_fields)
17
- is_canada = (action =~ /Canadian/)
18
- addr = new(address_info)
19
- fields = nil
20
- WWW::Mechanize.new do |ua|
21
- form_page = ua.get(start_url)
22
- form = form_page.form_with(:action => action) do |form|
23
- attrs_to_fields.each do |attr, field|
24
- form[field] = addr.send(attr)
25
- end
26
- end
27
- results_page = form.submit(form.buttons.first)
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
- table = results_page.search("table.Tableresultborder")[1]
30
- return unless table
31
- status_row = table.at("span.Titresultableok")
32
- return unless status_row && status_row.inner_text =~ /Address Verified/
33
- main_td = table.search("tr:eq(#{is_canada ? 2 : 3})/td:eq(2)")
34
- street_part, city_state_zip_part = main_td.inner_html.split("<br>")[0..1]
35
- street = street_part.strip_html.strip_whitespace
36
- city, state, zip = city_state_zip_part.strip_html.split("\240\240")
37
- #pp :main_td => main_td.to_s,
38
- # :street_part => street_part,
39
- # :city_state_zip_part => city_state_zip_part
40
- fields = [ street.upcase, city.upcase, state.upcase, zip.upcase ]
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?("&#160;&#160;") ? "&#160;&#160;" : "  "
45
+ else
46
+ # ruby 1.8
47
+ separator = "\240\240"
41
48
  end
42
- fields
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 self.standardize(address_info)
52
- if fields = super(address_info, "AddressVerify.asp", :street => 'Address', :city => 'city', :state => 'state', :zip => 'zip')
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 self.standardize(address_info)
64
- if fields = super(address_info, "CanadianAddressVerify.asp", :street => 'Street', :city => 'city', :province => 'Province', :postalcode => 'Postcode')
65
- street, city, province, postalcode = fields
66
- new(:street => street, :city => city, :province => province, :postalcode => postalcode)
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
@@ -14,4 +14,10 @@ class String
14
14
  '%' + $1.unpack('H2' * $1.size).join('%').upcase
15
15
  end.tr(' ', '+')
16
16
  end
17
+ end
18
+
19
+ class Hash
20
+ def stringify_keys
21
+ self.inject({}) {|h,(k,v)| h[k.to_s] = v; h }
22
+ end
17
23
  end
@@ -0,0 +1,3 @@
1
+ module AddressStandardization
2
+ VERSION = "0.4.0"
3
+ end
@@ -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
- test "A valid US address" do
7
- addr = AddressStandardization::GoogleMaps::Address.standardize(
8
- :street => "1600 Amphitheatre Parkway",
9
- :city => "Mountain View",
10
- :state => "CA"
11
- )
12
- addr.should == AddressStandardization::GoogleMaps::Address.new(
13
- "street" => "1600 AMPHITHEATRE PKWY",
14
- "city" => "MOUNTAIN VIEW",
15
- "state" => "CA",
16
- "province" => "CA",
17
- "postalcode" => "94043",
18
- "zip" => "94043",
19
- "country" => "USA"
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
- test "A valid Canadian address" do
24
- addr = AddressStandardization::GoogleMaps::Address.standardize(
25
- :street => "1770 Stenson Boulevard",
26
- :city => "Peterborough",
27
- :province => "ON"
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
- test "An invalid address" do
41
- addr = AddressStandardization::GoogleMaps::Address.standardize(
42
- :street => "123 Imaginary Lane",
43
- :city => "Some Town",
44
- :state => "AK"
45
- )
46
- addr.should == nil
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
@@ -1,49 +1,148 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class MelissaDataTest < Test::Unit::TestCase
4
- test "Valid US address" do
5
- addr = AddressStandardization::MelissaData::USAddress.standardize(
6
- :street => "1 Infinite Loop",
7
- :city => "Cupertino",
8
- :state => "CA"
9
- )
10
- addr.should == AddressStandardization::MelissaData::USAddress.new(
11
- "street" => "1 INFINITE LOOP",
12
- "city" => "CUPERTINO",
13
- "state" => "CA",
14
- "zip" => "95014-2083"
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
- test "Invalid US address" do
19
- addr = AddressStandardization::MelissaData::USAddress.standardize(
20
- :street => "123 Imaginary Lane",
21
- :city => "Some Town",
22
- :state => "AK"
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
- test "Valid Canadian address" do
28
- addr = AddressStandardization::MelissaData::CanadianAddress.standardize(
29
- :street => "3025 Clayhill Rd",
30
- :city => "Mississauga",
31
- :province => "ON"
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
- test "Invalid Canadian address" do
42
- addr = AddressStandardization::MelissaData::CanadianAddress.standardize(
43
- :street => "123 Imaginary Lane",
44
- :city => "Some Town",
45
- :province => "BC"
46
- )
47
- addr.should == nil
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.3.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-01-01 00:00:00 -06:00
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: hpricot
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.rdoc
52
+ - README.md
63
53
  - TODO
64
54
  files:
65
55
  - .gitignore
66
- - README.rdoc
56
+ - README.md
67
57
  - Rakefile
68
58
  - TODO
69
- - VERSION
59
+ - address_standardization.gemspec
70
60
  - lib/address_standardization.rb
71
- - lib/address_standardization/abstract_address.rb
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