usps_standardizer 0.1.2 → 0.2.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 -0
- data/README.rdoc +11 -0
- data/lib/usps_standardizer/cache.rb +50 -0
- data/lib/usps_standardizer/configuration.rb +33 -0
- data/lib/usps_standardizer/version.rb +2 -2
- data/lib/usps_standardizer/zip_lookup.rb +25 -4
- data/lib/usps_standardizer.rb +18 -3
- data/spec/usps_standardizer_spec.rb +18 -0
- metadata +10 -8
data/README.rdoc
CHANGED
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
$ require 'usps_standardizer'
|
|
6
6
|
$ gem install usps_standardizer
|
|
7
7
|
|
|
8
|
+
== Configuration
|
|
9
|
+
|
|
10
|
+
=== Caching
|
|
11
|
+
|
|
12
|
+
It’s a good idea, when relying on any external service, to cache retrieved data.
|
|
13
|
+
When implemented correctly it improves your app’s response time and stability.
|
|
14
|
+
It’s easy to cache usps results with USPSStandardizer, just configure a cache store:
|
|
15
|
+
|
|
16
|
+
$ USPSStandardizer::Configuration.cache = Redis.new
|
|
17
|
+
$ USPSStandardizer::Configuration.cache_prefix = "wyw"
|
|
18
|
+
|
|
8
19
|
== Usage
|
|
9
20
|
|
|
10
21
|
$ result = USPSStandardizer.lookup_for(:address => '6216 eddington drive', :state => 'oh', :city => 'middletown')
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module USPSStandardizer
|
|
2
|
+
class Cache
|
|
3
|
+
|
|
4
|
+
def initialize(store, prefix)
|
|
5
|
+
@store = store
|
|
6
|
+
@prefix = prefix
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def [](url)
|
|
10
|
+
interpret store[key_for(url)]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def []=(url, value)
|
|
14
|
+
store[key_for(url)] = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def expire(url)
|
|
18
|
+
if url == :all
|
|
19
|
+
urls.each{ |u| expire(u) }
|
|
20
|
+
else
|
|
21
|
+
expire_single_url(url)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :prefix, :store
|
|
29
|
+
|
|
30
|
+
def key_for(url)
|
|
31
|
+
[prefix, url].join
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def keys
|
|
35
|
+
store.keys.select{ |k| k.match /^#{prefix}/ and interpret(store[k]) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def urls
|
|
39
|
+
keys.map{ |k| k[/^#{prefix}(.*)/, 1] }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def interpret(value)
|
|
43
|
+
value == "" ? nil : value
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def expire_single_url(url)
|
|
47
|
+
store.del(key_for(url))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module USPSStandardizer
|
|
2
|
+
class Configuration
|
|
3
|
+
|
|
4
|
+
def self.options_and_defaults
|
|
5
|
+
[
|
|
6
|
+
[:timeout, 5],
|
|
7
|
+
|
|
8
|
+
# cache object (must respond to #[], #[]=, and #keys)
|
|
9
|
+
[:cache, nil],
|
|
10
|
+
|
|
11
|
+
# prefix (string) to use for all cache keys
|
|
12
|
+
[:cache_prefix, "usps:"]
|
|
13
|
+
]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# define getters and setters for all configuration settings
|
|
17
|
+
self.options_and_defaults.each do |option, default|
|
|
18
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
19
|
+
|
|
20
|
+
@@#{option} = default unless defined? @@#{option}
|
|
21
|
+
|
|
22
|
+
def self.#{option}
|
|
23
|
+
@@#{option}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.#{option}=(obj)
|
|
27
|
+
@@#{option} = obj
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
END
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -4,6 +4,9 @@ require 'mechanize'
|
|
|
4
4
|
|
|
5
5
|
module USPSStandardizer
|
|
6
6
|
|
|
7
|
+
#TODO: Change from 'mechanize' to 'net/hhtp'
|
|
8
|
+
#TODO: Implement 'timeout'
|
|
9
|
+
|
|
7
10
|
class ZipLookup
|
|
8
11
|
|
|
9
12
|
attr_accessor :address, :state, :city, :zipcode
|
|
@@ -17,6 +20,12 @@ module USPSStandardizer
|
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def std_address
|
|
23
|
+
|
|
24
|
+
if(cache and response = cache[redis_key(@address)])
|
|
25
|
+
address, city, state, county, zipcode = response.split('::')
|
|
26
|
+
return {:address => address, :city => city, :state => state, :county => county, :zipcode => zipcode}
|
|
27
|
+
end
|
|
28
|
+
|
|
20
29
|
return {} unless (content = get_std_address_content)
|
|
21
30
|
|
|
22
31
|
content.gsub!(/\t|\n|\r/, '')
|
|
@@ -26,18 +35,21 @@ module USPSStandardizer
|
|
|
26
35
|
|
|
27
36
|
raw_matches.inject({}) do |results, raw_match|
|
|
28
37
|
if raw_match[0] =~ /mailingIndustryPopup2\(([^\)]*)/i
|
|
29
|
-
@
|
|
38
|
+
@r_county = $1.split(',')[1].gsub(/'/, '')
|
|
30
39
|
end
|
|
31
40
|
|
|
32
|
-
@
|
|
41
|
+
@r_address, city_state_zipcode = Sanitize.clean(raw_match[0],
|
|
33
42
|
:remove_contents => true,
|
|
34
43
|
:elements => %w[br]
|
|
35
44
|
).strip.split('<br>')
|
|
36
45
|
if city_state_zipcode.sub_nonascii(' ').squeeze!(' ') =~ /^(.*)\s+(\w\w)\s(\d{5})(-\d{4})?/i
|
|
37
|
-
@
|
|
46
|
+
@r_city, @r_state, @r_zipcode = $1, $2, $3
|
|
38
47
|
end
|
|
39
48
|
|
|
40
|
-
results = {:address => @
|
|
49
|
+
results = {:address => @r_address, :city => @r_city, :state => @r_state, :county => @r_county, :zipcode => @r_zipcode}
|
|
50
|
+
if cache
|
|
51
|
+
cache[redis_key(@address)] = "#{@r_address}::#{@r_city}::#{@r_state}::#{@r_county}::#{@r_zipcode}"
|
|
52
|
+
end
|
|
41
53
|
results
|
|
42
54
|
end
|
|
43
55
|
end
|
|
@@ -56,6 +68,15 @@ module USPSStandardizer
|
|
|
56
68
|
return false unless @mechanize.page.search('p.mainRed').empty?
|
|
57
69
|
@mechanize.page.body
|
|
58
70
|
end
|
|
71
|
+
|
|
72
|
+
def cache
|
|
73
|
+
USPSStandardizer.cache
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
def redis_key(address)
|
|
78
|
+
address.downcase.gsub(' ', '_')
|
|
79
|
+
end
|
|
59
80
|
end
|
|
60
81
|
end
|
|
61
82
|
|
data/lib/usps_standardizer.rb
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
|
2
2
|
require 'mechanize'
|
|
3
|
+
|
|
4
|
+
#TODO: Improve documentation
|
|
3
5
|
module USPSStandardizer
|
|
4
6
|
autoload :Version, "usps_standardizer/version"
|
|
5
7
|
autoload :ZipLookup, "usps_standardizer/zip_lookup"
|
|
8
|
+
autoload :Configuration, "usps_standardizer/configuration"
|
|
9
|
+
autoload :Cache, "usps_standardizer/cache"
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
|
|
13
|
+
def lookup_for(options, mechanize = Mechanize.new)
|
|
14
|
+
z = ZipLookup.new(options, mechanize)
|
|
15
|
+
z.std_address
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def cache
|
|
19
|
+
if @cache.nil? and store = Configuration.cache
|
|
20
|
+
@cache = Cache.new(store, Configuration.cache_prefix)
|
|
21
|
+
end
|
|
22
|
+
@cache
|
|
23
|
+
end
|
|
6
24
|
|
|
7
|
-
def self.lookup_for(options, mechanize = Mechanize.new)
|
|
8
|
-
z = USPSStandardizer::ZipLookup.new(options, mechanize)
|
|
9
|
-
z.std_address
|
|
10
25
|
end
|
|
11
26
|
|
|
12
27
|
end
|
|
@@ -6,6 +6,24 @@ describe USPSStandardizer do
|
|
|
6
6
|
USPSStandardizer::Version::STRING.should match(/^\d+\.\d+\.\d+$/)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
describe "configuration" do
|
|
10
|
+
context "cache" do
|
|
11
|
+
it " should be nil as default" do
|
|
12
|
+
USPSStandardizer::Configuration.cache.should == nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
context "cache prefix" do
|
|
16
|
+
it "should be usps: as default" do
|
|
17
|
+
USPSStandardizer::Configuration.cache_prefix.should == 'usps:'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
context "timeout" do
|
|
21
|
+
it "should be 5 seconds as default" do
|
|
22
|
+
USPSStandardizer::Configuration.timeout.should == 5
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
9
27
|
it "standards an address on usps website" do
|
|
10
28
|
result = USPSStandardizer.lookup_for(:address => '6216 eddington drive', :state => 'oh', :city => 'middletown')
|
|
11
29
|
result[:address].should == '6216 EDDINGTON ST'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: usps_standardizer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,11 +9,11 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2011-10-
|
|
12
|
+
date: 2011-10-31 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: mechanize
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &72995970 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ~>
|
|
@@ -21,10 +21,10 @@ dependencies:
|
|
|
21
21
|
version: 2.0.1
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *72995970
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: sanitize
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &72995720 !ruby/object:Gem::Requirement
|
|
28
28
|
none: false
|
|
29
29
|
requirements:
|
|
30
30
|
- - ~>
|
|
@@ -32,10 +32,10 @@ dependencies:
|
|
|
32
32
|
version: 2.0.3
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
35
|
+
version_requirements: *72995720
|
|
36
36
|
- !ruby/object:Gem::Dependency
|
|
37
37
|
name: rspec
|
|
38
|
-
requirement: &
|
|
38
|
+
requirement: &72995490 !ruby/object:Gem::Requirement
|
|
39
39
|
none: false
|
|
40
40
|
requirements:
|
|
41
41
|
- - ~>
|
|
@@ -43,7 +43,7 @@ dependencies:
|
|
|
43
43
|
version: 2.6.0
|
|
44
44
|
type: :development
|
|
45
45
|
prerelease: false
|
|
46
|
-
version_requirements: *
|
|
46
|
+
version_requirements: *72995490
|
|
47
47
|
description: Ruby class to standardize U.S. postal addresses by referencing the U.S.
|
|
48
48
|
Postal Service's web site
|
|
49
49
|
email:
|
|
@@ -58,6 +58,8 @@ files:
|
|
|
58
58
|
- README.rdoc
|
|
59
59
|
- Rakefile
|
|
60
60
|
- lib/usps_standardizer.rb
|
|
61
|
+
- lib/usps_standardizer/cache.rb
|
|
62
|
+
- lib/usps_standardizer/configuration.rb
|
|
61
63
|
- lib/usps_standardizer/version.rb
|
|
62
64
|
- lib/usps_standardizer/zip_lookup.rb
|
|
63
65
|
- spec/fixtures/content.html
|