ziplookup 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>ZipLookup</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ <buildCommand>
9
+ <name>org.rubypeople.rdt.core.rubybuilder</name>
10
+ <arguments>
11
+ </arguments>
12
+ </buildCommand>
13
+ </buildSpec>
14
+ <natures>
15
+ <nature>org.rubypeople.rdt.core.rubynature</nature>
16
+ </natures>
17
+ </projectDescription>
@@ -0,0 +1,9 @@
1
+ .project
2
+ bin/tryme.rb
3
+ lib/USPS/address.rb
4
+ lib/USPS/zip_lookup.rb
5
+ Manifest.txt
6
+ Rakefile
7
+ test/tc_address.rb
8
+ test/tc_standardize.rb
9
+ test/ts_zip_lookup.rb
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = 'ziplookup'
6
+ s.version = '1.0.0'
7
+ s.summary = 'Classes for standardizing addresses via the USPS web site.'
8
+ s.description = 'Classes for standardizing addresses via the USPS web site.'
9
+ s.author = 'Gregor N. Purdy'
10
+ s.email = 'gregor@focusresearch.com'
11
+
12
+ s.has_rdoc = true
13
+ s.files = File.read('Manifest.txt').split($/)
14
+ s.require_path = 'lib' # library files go here
15
+ s.executables = ['tryme.rb'] # must be in bin/
16
+ end
17
+
18
+ #desc 'Generate RDoc'
19
+ #Rake::RDocTask.new :rdoc do |rd|
20
+ # rd.rdoc_dir = 'doc'
21
+ # rd.rdoc_files.add 'lib', 'README', 'LICENSE' # add those files to your RDoc output
22
+ # rd.main = 'README' # the main page for the RDoc
23
+ #end
24
+
25
+ desc 'Build Gem'
26
+ Rake::GemPackageTask.new spec do |pkg|
27
+ pkg.need_tar = true
28
+ end
@@ -0,0 +1,28 @@
1
+ require "USPS/zip_lookup"
2
+ require "USPS/address"
3
+
4
+ delivery_address = "6216 Eddington Drive"
5
+ city = "Middletown"
6
+ state = "OH"
7
+
8
+ address = USPS::Address.new
9
+ address.delivery_address = delivery_address
10
+ address.city = city
11
+ address.state = state
12
+
13
+ zlu = USPS::ZipLookup.new()
14
+ #zlu.verbose = true
15
+
16
+ matches = zlu.std_addr(address)
17
+
18
+ if matches != nil && matches.size > 0
19
+ printf "\n%d matches:\n", matches.size
20
+ matches.each { |match|
21
+ print "-" * 39, "\n"
22
+ print match.to_dump
23
+ print "\n"
24
+ }
25
+ print "-" * 39, "\n"
26
+ else
27
+ print "No matches!\n"
28
+ end
@@ -0,0 +1,356 @@
1
+ =begin
2
+ = address.rb
3
+ Copyright (C) 2006 Gregor N. Purdy. All rights reserved.
4
+
5
+ This program is free software. It is subject to the same license as Ruby.
6
+
7
+ = Classes
8
+ * ((<Address>))
9
+
10
+ = Address
11
+
12
+ == Synopsis
13
+ require "USPS/ZipLookup"
14
+ require "USPS/Address"
15
+
16
+ address = USPS::Address.new(delivery_address, city, state)
17
+
18
+ zlu = USPS::ZipLookup.new()
19
+
20
+ matches = zlu.std_addr(address)
21
+
22
+ if matches.size > 0
23
+ printf "\n%d matches:\n", matches.size
24
+ matches.each { |match|
25
+ # print "-" x 39, "\n"
26
+ print match.to_dump
27
+ print "\n";
28
+ }
29
+ # print "-" x 39, "\n"
30
+ else
31
+ print "No matches!\n"
32
+ end
33
+
34
+ == Description
35
+
36
+ Results from USPS::ZipLookup calls are of this type.
37
+
38
+ Class to represent U.S. postal addresses for the purpose of
39
+ standardizing via the U.S. Postal Service's web site:
40
+
41
+ http://www.usps.com/zip4/
42
+
43
+ BE SURE TO READ AND UNDERSTAND THE TERMS OF USE SECTION IN THE
44
+ DOCUMENTATION, WHICH MAY BE FOUND AT THE END OF THIS SOURCE CODE.
45
+
46
+ == Class Methods
47
+
48
+ == Instance Methods
49
+ --- Address#dump()
50
+ --- Address#firm()
51
+ --- Address#urbanization()
52
+ --- Address#delivery_address()
53
+ --- Address#city()
54
+ --- Address#state()
55
+ --- Address#zip_code()
56
+ --- Address#carrier_route()
57
+ Detailed information (see the U.S. Postal Service web site for definitions at
58
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
59
+ --- Address#county()
60
+ Detailed information (see the U.S. Postal Service web site for definitions at
61
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
62
+ --- Address#delivery_point()
63
+ Detailed information (see the U.S. Postal Service web site for definitions at
64
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
65
+ --- Address#check_digit()
66
+ Detailed information (see the U.S. Postal Service web site for definitions at
67
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
68
+ --- Address#lac_indicator()
69
+ Detailed information (see the U.S. Postal Service web site for definitions at
70
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
71
+ --- Address#elot_sequence()
72
+ Detailed information (see the U.S. Postal Service web site for definitions at
73
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
74
+ --- Address#elot_indicator()
75
+ Detailed information (see the U.S. Postal Service web site for definitions at
76
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
77
+ --- Address#record_type()
78
+ Detailed information (see the U.S. Postal Service web site for definitions at
79
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
80
+ --- Address#pmb_designator()
81
+ Detailed information (see the U.S. Postal Service web site for definitions at
82
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
83
+ --- Address#pmb_number()
84
+ Detailed information (see the U.S. Postal Service web site for definitions at
85
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
86
+ --- Address#default_address()
87
+ Detailed information (see the U.S. Postal Service web site for definitions at
88
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
89
+ --- Address#early_warning()
90
+ Detailed information (see the U.S. Postal Service web site for definitions at
91
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
92
+ --- Address#valid()
93
+ Detailed information (see the U.S. Postal Service web site for definitions at
94
+ L<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>):
95
+
96
+ = History
97
+ $Id: address.rb 2255 2006-08-07 05:39:57Z gregor $
98
+
99
+ = TERMS OF USE
100
+
101
+ BE SURE TO READ AND FOLLOW THE UNITED STATES POSTAL SERVICE TERMS OF USE
102
+ PAGE AT C<http://www.usps.gov/disclaimer.html>. IN PARTICULAR, NOTE THAT THEY
103
+ DO NOT PERMIT THE USE OF THEIR WEB SITE'S FUNCTIONALITY FOR COMMERCIAL
104
+ PURPOSES. DO NOT USE THIS CODE IN A WAY THAT VIOLATES THE TERMS OF USE.
105
+
106
+ The author believes that the example usage given above does not violate
107
+ these terms, but sole responsibility for conforming to the terms of use
108
+ belongs to the user of this code, not the author.
109
+
110
+ = Author
111
+
112
+ Gregor N. Purdy, C<gregor@focusresearch.com>.
113
+
114
+ = Copyright
115
+
116
+ Copyright (C) 2006 Gregor N. Purdy. All rights reserved.
117
+ This program is free software; you can redistribute it and/or
118
+ modify it under the same terms as Ruby itself.
119
+
120
+ =end
121
+
122
+ module USPS
123
+
124
+ class Address
125
+
126
+ @firm = nil
127
+ @urbanization = nil
128
+ @delivery_address = nil
129
+ @city = nil
130
+ @state = nil
131
+ @zip_code = nil
132
+
133
+ @carrier_route = nil
134
+ @county = nil
135
+ @delivery_point = nil
136
+ @check_digit = nil
137
+ @lac_indicator = nil
138
+ @elot_sequence = nil
139
+ @elot_indicator = nil
140
+ @record_type = nil
141
+ @pmb_designator = nil
142
+ @pmb_number = nil
143
+ @default_address = nil
144
+ @early_warning = nil
145
+ @valid = nil
146
+
147
+ attr_reader :firm, :urbanization, :delivery_address, :city, :state, :zip_code,
148
+ :carrier_route, :county, :delivery_point, :check_digit, :lac_indicator, :elot_sequence,
149
+ :elot_indicator, :record_type, :pmb_designator, :pmb_number, :default_address, :early_warning,
150
+ :valid
151
+
152
+ attr_writer :firm, :urbanization, :delivery_address, :city, :state, :zip_code,
153
+ :carrier_route, :county, :delivery_point, :check_digit, :lac_indicator, :elot_sequence,
154
+ :elot_indicator, :record_type, :pmb_designator, :pmb_number, :default_address, :early_warning,
155
+ :valid
156
+
157
+ @@input_fields = {
158
+ 'Firm' => :firm,
159
+ 'Urbanization' => :urbanization,
160
+ 'Delivery Address' => :delivery_address,
161
+ 'City' => :city,
162
+ 'State' => :state,
163
+ 'Zip Code' => :zip_code,
164
+ }
165
+
166
+ @@output_fields = {
167
+ 'Carrier Route' => :carrier_route,
168
+ 'County' => :county,
169
+ 'Delivery Point' => :delivery_point,
170
+ 'Check Digit' => :check_digit,
171
+ 'LAC Indicator' => :lac_indicator,
172
+ 'eLOT Sequence' => :elot_sequence,
173
+ 'eLOT Indicator' => :elot_indicator,
174
+ 'Record Type' => :record_type,
175
+ 'PMB Designator' => :pmb_designator,
176
+ 'PMB Number' => :pmb_number,
177
+ 'Default Address' => :default_address,
178
+ 'Early Warning' => :early_warning,
179
+ 'Valid' => :valid,
180
+ }
181
+
182
+ @@field_order = [
183
+ "Firm",
184
+ "Urbanization",
185
+ "Delivery Address",
186
+ "City",
187
+ "State",
188
+ "Zip Code",
189
+ "Carrier Route",
190
+ "County",
191
+ "Delivery Point",
192
+ "Check Digit",
193
+ "LAC Indicator",
194
+ "eLot Sequence",
195
+ "eLot Indicator",
196
+ "Record Type",
197
+ "PMB Designator",
198
+ "PMB Number",
199
+ "Default Address",
200
+ "Early Warning",
201
+ "Valid",
202
+
203
+ ]
204
+
205
+ #
206
+ # initialize()
207
+ #
208
+ #
209
+ #def initialize(firm, urbanization, delivery_address, city, state, zip_code)
210
+ # @firm = firm
211
+ # @urbanization = urbanization
212
+ # @delivery_address = delivery_address
213
+ # @city = city
214
+ # @state = state
215
+ # @zip_code = zip_code
216
+ #end
217
+ #
218
+ #def initialize(firm, delivery_address, city, state, zip_code)
219
+ # @firm = firm
220
+ # @delivery_address = delivery_address
221
+ # @city = city
222
+ # @state = state
223
+ # @zip_code = zip_code
224
+ #end
225
+ #
226
+ #def initialize(delivery_address, city, state, zip_code)
227
+ # @delivery_address = delivery_address
228
+ # @city = city
229
+ # @state = state
230
+ # @zip_code = zip_code
231
+ #end
232
+ #
233
+ #def initialize(delivery_address, city, state)
234
+ # @delivery_address = delivery_address
235
+ # @city = city
236
+ # @state = state
237
+ #end
238
+ #
239
+ #def initialize(delivery_address, zip_code)
240
+ # @delivery_address = delivery_address
241
+ # @zip_code = zip_code
242
+ #end
243
+
244
+ #
245
+ # fields()
246
+ #
247
+
248
+ def fields
249
+ return {
250
+ "Firm" => @firm,
251
+ "Urbanization" => @urbanization,
252
+ "Delivery Address" => @delivery_address,
253
+ "City" => @city,
254
+ "State" => @state,
255
+ "Zip Code" => @zip_code,
256
+ "Carrier Route" => @carrier_route,
257
+ "County" => @county,
258
+ "Delivery Point" => @delivery_point,
259
+ "Check Digit" => @check_digit,
260
+ "LAC Indicator" => @lac_indicator,
261
+ "eLot Sequence" => @elot_sequence,
262
+ "eLot Indicator" => @elot_indicator,
263
+ "Record Type" => @record_type,
264
+ "PMB Designator" => @pmb_designator,
265
+ "PMB Number" => @pmb_number,
266
+ "Default Address" => @default_address,
267
+ "Early Warning" => @early_warning,
268
+ "Valid" => @valid,
269
+ }
270
+ end
271
+
272
+ #
273
+ # to_s()
274
+ #
275
+
276
+ def to_s(message = nil)
277
+ output = ''
278
+
279
+ if message != nil
280
+ output = sprintf "ADDRESS: %s\n", message
281
+ end
282
+
283
+ temp = fields
284
+
285
+ @@field_order.each { |key|
286
+ value = temp[key]
287
+ next if value == nil
288
+ line = sprintf " %s => '%s'\n", key, value
289
+ output += line
290
+ }
291
+
292
+ output += "\n"
293
+
294
+ return output
295
+ end
296
+
297
+ #
298
+ # dump()
299
+ #
300
+
301
+ def dump(message = nil)
302
+ print to_s(message)
303
+ end
304
+
305
+ #
306
+ # to_dump()
307
+ #
308
+
309
+ def to_dump
310
+ return to_s()
311
+ end
312
+
313
+ def query_string
314
+ require 'cgi'
315
+
316
+ args = [
317
+ [ 'visited' , '1' ], # NOTE: CGI.escape pukes if this doesn't have quotes. It isn't smart enough to convert to String on its own!
318
+ [ 'pagenumber' , 'all' ],
319
+ [ 'firmname' , '' ],
320
+ [ 'address1' , @delivery_address.upcase ],
321
+ # [ 'address1' , '' ],
322
+ # [ 'address2' , addr.delivery_address.upcase ],
323
+ [ 'address2' , '' ],
324
+ [ 'city' , @city.upcase ],
325
+ [ 'state' , @state.upcase ],
326
+ [ 'urbanization' , '' ],
327
+ [ 'zip5' , @zip_code == nil ? '' : @zip_code.upcase ],
328
+ ]
329
+
330
+ result = ''
331
+
332
+ args.each { |arg|
333
+ key = arg[0]
334
+ value = arg[1]
335
+
336
+ if value == nil
337
+ raise "Value is nil for key '" + key + "'!!!"
338
+ end
339
+
340
+ value = CGI.escape(arg[1])
341
+
342
+ temp = sprintf("%s=%s", key, value)
343
+
344
+ if result != ''
345
+ result += "&"
346
+ end
347
+
348
+ result += temp
349
+ }
350
+
351
+ return result
352
+ end
353
+
354
+ end # class Address
355
+
356
+ end # module USPS
@@ -0,0 +1,424 @@
1
+ =begin
2
+ = zip_lookup.rb
3
+ Copyright (C) 2006 Gregor N. Purdy. All rights reserved.
4
+
5
+ This program is free software. It is subject to the same license as Ruby.
6
+
7
+ = Classes
8
+ * ((<Address>))
9
+
10
+ = ZipLookup
11
+
12
+ == Synopsis
13
+
14
+ Ruby class to standardize U.S. postal addresses by referencing
15
+ the U.S. Postal Service's web site:
16
+
17
+ http://www.usps.com/zip4/
18
+
19
+ #! ruby
20
+ require "USPS/zip_lookup"
21
+ require "USPS/address"
22
+
23
+ delivery_address = "6216 Eddington Drive"
24
+ city = "Middletown"
25
+ state = "OH"
26
+
27
+ address = USPS::Address.new
28
+ address.delivery_address = delivery_address
29
+ address.city = city
30
+ address.state = state
31
+
32
+ zlu = USPS::ZipLookup.new()
33
+
34
+ matches = zlu.std_addr(address)
35
+
36
+ if matches != nil && matches.size > 0
37
+ printf "\n%d matches:\n", matches.size
38
+ matches.each { |match|
39
+ print "-" * 39, "\n"
40
+ print match.to_dump
41
+ print "\n"
42
+ }
43
+ print "-" * 39, "\n"
44
+ else
45
+ print "No matches!\n"
46
+ end
47
+
48
+ == Description
49
+
50
+ The United States Postal Service (USPS) has on its web site an HTML form at
51
+ C<http://www.usps.com/zip4/>
52
+ for standardizing an address. Given a firm, urbanization, street address,
53
+ city, state, and zip, it will put the address into standard form (provided
54
+ the address is in their database) and display a page with the resulting
55
+ address.
56
+
57
+ This Ruby module provides a programmatic interface to this service, so you
58
+ can write a program to process your entire personal address book without
59
+ having to manually type them all in to the form.
60
+
61
+ Because the USPS could change or remove this functionality at any time,
62
+ be prepared for the possibility that this code may fail to function. In
63
+ fact, as of this version, there is no error checking in place, so if they
64
+ do change things, this code will most likely fail in a noisy way. If you
65
+ discover that the service has changed, please email the author your findings.
66
+
67
+ If an error occurs in trying to standardize the address, then no array
68
+ will be returned. Otherwise, a four-element array will be returned.
69
+
70
+ To see debugging output, set zlu.verbose = true
71
+
72
+
73
+ == Fields
74
+
75
+ This page at the U.S. Postal Service web site contains definitions of some
76
+ of the fields: C<http://zip4.usps.com/zip4/pu_mailing_industry_def.htm>
77
+
78
+
79
+ = TERMS OF USE
80
+
81
+ BE SURE TO READ AND FOLLOW THE UNITED STATES POSTAL SERVICE TERMS OF USE PAGE
82
+ (AT C<http://www.usps.com/homearea/docs/termsofuse.htm> AT THE TIME THIS TEXT
83
+ WAS WRITTEN). IN PARTICULAR, NOTE THAT THEY DO NOT PERMIT THE USE OF THEIR WEB
84
+ SITE'S FUNCTIONALITY FOR COMMERCIAL PURPOSES. DO NOT USE THIS CODE IN A WAY
85
+ THAT VIOLATES THE TERMS OF USE.
86
+
87
+ As the user of this code, you are responsible for complying with the most
88
+ recent version of the Terms of Use, whether at the URL provided above or
89
+ elsewhere if the U.S. Postal Service moves it or updates it. As a convenience,
90
+ here is a copy of the most relevant paragraph of the Terms of Use as of
91
+ 2006-07-04:
92
+
93
+ Material on this site is the copyrighted property of the United States
94
+ Postal Service� (Postal Service�). All rights reserved. The information
95
+ and images presented here may not under any circumstances be reproduced
96
+ or used without prior written permission. Users may view and download
97
+ material from this site only for the following purposes: (a) for personal,
98
+ non-commercial home use; (b) where the materials clearly state that these
99
+ materials may be copied and reproduced according to the terms stated in
100
+ those particular pages; or (c) with the express written permission of the
101
+ Postal Service. In all other cases, you will need written permission from
102
+ the Postal Service to reproduce, republish, upload, post, transmit,
103
+ distribute or publicly display material from this Web site. Users agree not
104
+ to use the site for sale, trade or other commercial purposes. Users may not
105
+ use language that is threatening, abusive, vulgar, discourteous or criminal.
106
+ Users also may not post or transmit information or materials that would
107
+ violate rights of any third party or which contains a virus or other harmful
108
+ component. The Postal Service reserves the right to remove or edit any
109
+ messages or material submitted by users.
110
+
111
+ The author believes that the example usage given above does not violate
112
+ these terms, but sole responsibility for conforming to the terms of use
113
+ belongs to the user of this code, not the author.
114
+
115
+
116
+ = BUG REPORTS
117
+
118
+ When contacting the author with bug reports, please provide a test address that
119
+ exhibits the problem, and make sure it is OK to add that address to the test
120
+ suite.
121
+
122
+ Be sure to let me know if you don't want me to mention your name or email
123
+ address when I document the changes and contributions to the release. Typically
124
+ I put this information in the CHANGES file.
125
+
126
+ = History
127
+ $Id: zip_lookup.rb 2255 2006-08-07 05:39:57Z gregor $
128
+
129
+ = Author
130
+
131
+ Gregor N. Purdy, C<gregor@focusresearch.com>.
132
+
133
+ = Copyright
134
+
135
+ Copyright (C) 2006 Gregor N. Purdy. All rights reserved.
136
+ This program is free software; you can redistribute it and/or
137
+ modify it under the same terms as Ruby itself.
138
+
139
+ =end
140
+
141
+ #require 'mechanize'
142
+
143
+ module USPS
144
+
145
+ class ZipLookup
146
+ # @@VERSION = '1.0'
147
+ @@usps_host = 'zip4.usps.com'
148
+
149
+ @@start_path = '/zip4/welcome.jsp'
150
+ @@start_url = sprintf('http://%s%s', @@usps_host, @@start_path)
151
+
152
+ @@post_path = '/zip4/zcl_0_results.jsp'
153
+ @@post_url = sprintf('http://%s%s', @@usps_host, @@post_path)
154
+
155
+ # @@form_name = 'form1'
156
+ @@form_number = 0
157
+
158
+ attr_reader :user_agent, :verbose
159
+ attr_writer :verbose
160
+
161
+ def initialize
162
+ # @user_agent = WWW::Mechanize.new
163
+ @verbose = false
164
+ end
165
+
166
+ def std_addr(address)
167
+ return std_inner(address)
168
+ end
169
+
170
+ def std_addrs(addresses)
171
+ result = [ ]
172
+
173
+ addresses.each { |address|
174
+ temp = std_inner(address)
175
+
176
+ result.push(temp)
177
+ }
178
+
179
+ return result
180
+ end
181
+
182
+ def direct_get(addr)
183
+ query_string = addr.query_string
184
+
185
+ require 'net/http'
186
+
187
+ content = nil
188
+
189
+ # headers = { 'Referer' => @@start_url, 'Content-Type' => 'application/x-www-form-urlencoded' }
190
+ headers = { }
191
+
192
+ path = @@post_path + "?" + query_string
193
+
194
+ session = Net::HTTP.new(@@usps_host)
195
+ (response, content) = session.get(path, headers)
196
+
197
+ if @verbose
198
+ print "-" * 79, "\n"
199
+ printf "Direct HTTP GET (of http://%s%s) Body:\n", @@usps_host, path
200
+ print "HTTP Response:\n"
201
+ print content
202
+ end
203
+
204
+ return content
205
+ rescue WWW::Mechanize::ResponseCodeError => error
206
+ printf "Unhandled response: %s\n", error.response_code
207
+ raise
208
+ end
209
+
210
+ #
211
+ # std_inner()
212
+ #
213
+ # The inner portion of the process, so it can be shared by
214
+ # std_addr() and std_addrs().
215
+ #
216
+ #
217
+ def std_inner(addr)
218
+ if @verbose
219
+ print ' ', '_' * 77, ' ', "\n"
220
+ print '/', ' ' * 77, '\\', "\n"
221
+ addr.dump("Input")
222
+ print "\n"
223
+ end
224
+
225
+ content = direct_get(addr)
226
+
227
+ #
228
+ # Time to Parse:
229
+ #
230
+ # The results look like this:
231
+ #
232
+ # <td width="312" background="images/light_blue_bg2.gif" class="mainText">6216 EDDINGTON ST <br>LIBERTY TOWNSHIP&nbsp;OH&nbsp;45044-9761 <br>
233
+ #
234
+ # 1. We find <td header ...> ... </td> to find the data fields.
235
+ # 2. We strip out <font> and <a>
236
+ # 3. We replace &nbsp; with space
237
+ # 4. We strip out leading "...: "
238
+ # 5. We find <!--< ... />--> to get the field id
239
+ # 6. We standardize the field id (upper case, alpha only)
240
+ # 7. We standardize the value (trimming and whitespace coalescing)
241
+ #
242
+ # We end up with something like this:
243
+ #
244
+ # ADDRESSLINE: 6216 EDDINGTON ST
245
+ # CITYSTATEZIP: LIBERTY TOWNSHIP OH 45044-9761
246
+ # CARRIERROUTE: R007
247
+ # COUNTY: BUTLER
248
+ # DELIVERYPOINT: 16
249
+ # CHECKDIGIT: 3
250
+ #
251
+
252
+ matches =[ ]
253
+
254
+ content.gsub!(Regexp.new('[\cI\cJ\cM]'), '')
255
+ content.squeeze!(" ")
256
+ content.strip!
257
+
258
+ raw_matches = content.scan(%r{<td headers="\w+" height="34" valign="top" class="main" style="background:url\(images/table_gray\.gif\); padding:5px 10px;">(.*?)>Mailing Industry Information</a>}mi)
259
+
260
+ raw_matches.each { |raw_match|
261
+ if @verbose
262
+ print "-" * 79, "\n"
263
+ print "Raw match:\n"
264
+ printf("%s\n", raw_match[0])
265
+ end
266
+
267
+ match = parse_match(raw_match[0])
268
+
269
+ matches.push(match)
270
+ }
271
+
272
+ print('\\', '_' * 77, '/', "\n") if @verbose
273
+
274
+ return matches;
275
+ end # method std_inner
276
+
277
+ def parse_match(raw_match)
278
+ carrier_route = nil
279
+ county = nil
280
+ delivery_point = nil
281
+ check_digit = nil
282
+ lac_indicator = nil
283
+ elot_sequence = nil
284
+ elot_indicator = nil
285
+ record_type = nil
286
+ pmb_designator = nil
287
+ pmb_number = nil
288
+ default_address = nil
289
+ early_warning = nil
290
+ valid = nil
291
+
292
+ #
293
+ # Looking for some text like this:
294
+ #
295
+ # onClick="mailingIndustryPopup2('R007','BUTLER','16','3','','0179','A','S','','','','','Y');"
296
+ #
297
+
298
+ regex = %r{mailingIndustryPopup2\((.*?)\);}i
299
+ result = regex.match(raw_match)
300
+
301
+ if result != nil
302
+ args = result[1]
303
+
304
+ # Reformat to pipe-delimited
305
+ args.sub!(/^'/, '')
306
+ args.gsub!(/\s*'?\s*,\s*'?\s*/, '|')
307
+ args.sub!(/'$/, '')
308
+
309
+ args_array = args.split(/\|/)
310
+
311
+ carrier_route = (args_array[0] != nil && args_array[0] != '') ? args_array[0] : nil
312
+ county = (args_array[1] != nil && args_array[1] != '') ? args_array[1] : nil
313
+ delivery_point = (args_array[2] != nil && args_array[2] != '') ? args_array[2] : nil
314
+ check_digit = (args_array[3] != nil && args_array[3] != '') ? args_array[3] : nil
315
+ lac_indicator = (args_array[4] != nil && args_array[4] != '') ? args_array[4] : nil
316
+ elot_sequence = (args_array[5] != nil && args_array[5] != '') ? args_array[5] : nil
317
+ elot_indicator = (args_array[6] != nil && args_array[6] != '') ? args_array[6] : nil
318
+ record_type = (args_array[7] != nil && args_array[7] != '') ? args_array[7] : nil
319
+ pmb_designator = (args_array[8] != nil && args_array[8] != '') ? args_array[8] : nil
320
+ pmb_number = (args_array[9] != nil && args_array[9] != '') ? args_array[9] : nil
321
+ default_address = (args_array[10] != nil && args_array[10] != '') ? args_array[10] : nil
322
+ early_warning = (args_array[11] != nil && args_array[11] != '') ? args_array[11] : nil
323
+ valid = (args_array[12] != nil && args_array[12] != '') ? args_array[12] : nil
324
+ else
325
+ if @verbose
326
+ printf "WARNING: Could not find Mailing Industry info in '%s'!\n", raw_match
327
+ end
328
+ end
329
+
330
+ raw_match.gsub!(%r{</td>\s*<td.*?>}, ' ')
331
+ raw_match.gsub!(%r{</?font.*?>}, '')
332
+ raw_match.gsub!(%r{</?span.*?>}, '')
333
+ raw_match.gsub!(%r{</?a.*?>}, '')
334
+ raw_match.gsub!(%r{&nbsp;}, ' ')
335
+ raw_match.gsub!(%r{^.*?:\s*}, '')
336
+ raw_match.gsub!(%r{\s+}, ' ')
337
+ raw_match.gsub!(%r{<!--<(.*?)/>-->}, '')
338
+ raw_match.sub!(%r{<a.*$}, '')
339
+ raw_match.sub!(%r{<br\s*/?>\s*$}, '')
340
+
341
+ if @verbose
342
+ print "-" * 79, "\n"
343
+ print "Distilled match:\n"
344
+ printf "%s\n", raw_match
345
+ end
346
+
347
+ parts = raw_match.split( /\s*<br\s*\/?>\s*/)
348
+
349
+ firm = nil
350
+ address = nil
351
+ city_state_zip = nil
352
+
353
+ if parts.size == 2
354
+ (address, city_state_zip) = parts
355
+ elsif parts.size == 3
356
+ (firm, address, city_state_zip) = parts
357
+ else
358
+ # die "Parts = " . scalar(@parts) . "!";
359
+ end
360
+
361
+ next if city_state_zip == nil
362
+ next if !(city_state_zip =~ /^(.*)\s+(\w\w)\s+(\d{5}(-\d{4})?)/)
363
+
364
+ city = $1
365
+ state = $2
366
+ zip = $3
367
+
368
+ if @verbose
369
+ print("-" * 70, "\n");
370
+
371
+ printf "Firm: %s\n", firm if firm != nil
372
+
373
+ printf "Address: %s\n", address
374
+ printf "City: %s\n", city
375
+ printf "State: %s\n", state
376
+ printf "Zip: %s\n", zip
377
+
378
+ printf "Carrier Route: %s\n", carrier_route if carrier_route != nil
379
+ printf "County: %s\n", county if county != nil
380
+ printf "Delivery Point: %s\n", delivery_point if delivery_point != nil
381
+ printf "Check Digit: %s\n", check_digit if check_digit != nil
382
+ printf "LAC Indicator: %s\n", lac_indicator if lac_indicator != nil
383
+ printf "eLOT Sequence: %s\n", elot_sequence if elot_sequence != nil
384
+ printf "eLOT Indicator: %s\n", elot_indicator if elot_indicator != nil
385
+ printf "Record Type: %s\n", record_type if record_type != nil
386
+ printf "PMB Designator: %s\n", pmb_designator if pmb_designator != nil
387
+ printf "PMB Number: %s\n", pmb_number if pmb_number != nil
388
+ printf "Default Address: %s\n", default_address if default_address != nil
389
+ printf "Early Warning: %s\n", early_warning if early_warning != nil
390
+ printf "Valid: %s\n", valid if valid != nil
391
+
392
+ print "\n";
393
+ end
394
+
395
+ match = USPS::Address.new
396
+
397
+ match.delivery_address = address
398
+ match.city = city
399
+ match.state = state
400
+ match.zip_code = zip
401
+
402
+ match.firm = firm
403
+
404
+ match.carrier_route = carrier_route
405
+ match.county = county
406
+ match.delivery_point = delivery_point
407
+ match.check_digit = check_digit
408
+
409
+ match.lac_indicator = lac_indicator
410
+ match.elot_sequence = elot_sequence
411
+ match.elot_indicator = elot_indicator
412
+ match.record_type = record_type
413
+ match.pmb_designator = pmb_designator
414
+ match.pmb_number = pmb_number
415
+ match.default_address = default_address
416
+ match.early_warning = early_warning
417
+ match.valid = valid
418
+
419
+ return match
420
+ end # method parse_match
421
+
422
+ end # class ZipLookup
423
+
424
+ end # module USPS
@@ -0,0 +1,26 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require 'test/unit'
4
+ #require 'rubygems'
5
+ require 'USPS/address'
6
+ #require 'test_includes'
7
+
8
+ class AddressTest < Test::Unit::TestCase
9
+ # include TestMethods
10
+
11
+ def setup
12
+ end
13
+
14
+ def test_address
15
+ address = USPS::Address.new
16
+
17
+ address.delivery_address = '6216 Eddington'
18
+ address.city = 'Middletown'
19
+ address.zip_code = '45044'
20
+
21
+ assert_equal('6216 Eddington', address.delivery_address)
22
+ assert_equal('Middletown', address.city)
23
+ assert_equal('45044', address.zip_code)
24
+ end
25
+ end
26
+
@@ -0,0 +1,94 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+ #
3
+ # Copyright (C) 2006 Gregor N. Purdy. All rights reserved.
4
+ # This program is free software. It is subject to the same license as Ruby.
5
+ #
6
+ # [ $Id: tc_standardize.rb 2255 2006-08-07 05:39:57Z gregor $ ]
7
+ #
8
+
9
+ require 'test/unit'
10
+ require 'USPS/address'
11
+ require 'USPS/zip_lookup'
12
+
13
+ class StandardizeTest < Test::Unit::TestCase
14
+ def setup
15
+ @zlu = USPS::ZipLookup.new
16
+ if (ARGV.size >= 1) && (ARGV[0] == '-v') # ARGV is a global var, but doesn't use prefix '$'; GO FIGURE!
17
+ @zlu.verbose = true
18
+ end
19
+ end
20
+
21
+ def test_error
22
+ address = USPS::Address.new
23
+
24
+ address.delivery_address = 'bar'
25
+ address.city = 'splee'
26
+ address.state = 'OH'
27
+
28
+ result = @zlu.std_addr(address)
29
+ assert_equal([], result)
30
+ end
31
+
32
+ def test_simple_1
33
+ address = USPS::Address.new
34
+
35
+ address.delivery_address = '6216 Eddington Drive'
36
+ address.city = 'Liberty Township'
37
+ address.state = 'oh'
38
+
39
+ result = @zlu.std_addr(address)
40
+ assert_equal(1, result.size)
41
+
42
+ assert_equal('6216 EDDINGTON ST', result[0].delivery_address)
43
+ assert_equal('LIBERTY TOWNSHIP', result[0].city)
44
+ assert_equal('OH', result[0].state)
45
+ assert_equal('45044-9761', result[0].zip_code)
46
+ end
47
+
48
+ def test_apartment
49
+ address = USPS::Address.new
50
+
51
+ address.delivery_address = '3303 Pine Meadow DR SE #202'
52
+ address.city = 'Kentwood'
53
+ address.state = 'MI'
54
+ address.zip_code = '49512'
55
+
56
+ result = @zlu.std_addr(address)
57
+ assert_equal(1, result.size)
58
+
59
+ assert_equal('3303 PINE MEADOW DR SE APT 202', result[0].delivery_address)
60
+ assert_equal('KENTWOOD', result[0].city)
61
+ assert_equal('MI', result[0].state)
62
+ assert_equal('49512-8325', result[0].zip_code)
63
+ end
64
+
65
+ def test_simple_2
66
+ address = USPS::Address.new
67
+
68
+ address.delivery_address = '2701 DOUGLAS AVE'
69
+ address.city = 'DES MOINES'
70
+ address.state = 'IA'
71
+ address.zip_code = '50310'
72
+
73
+ result = @zlu.std_addr(address)
74
+ assert_equal(1, result.size)
75
+
76
+ assert_equal('2701 DOUGLAS AVE', result[0].delivery_address)
77
+ assert_equal('DES MOINES', result[0].city)
78
+ assert_equal('IA', result[0].state)
79
+ assert_equal('50310-5840', result[0].zip_code)
80
+ end
81
+
82
+ def test_multiple
83
+ address = USPS::Address.new
84
+
85
+ address.delivery_address = '1670 Broadway'
86
+ address.city = 'Denver'
87
+ address.state = 'CO'
88
+ address.zip_code = '80202'
89
+
90
+ result = @zlu.std_addr(address)
91
+ assert(result.size > 1)
92
+ end
93
+
94
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+ $:.unshift File.join(File.dirname(__FILE__), "..", "test")
3
+
4
+ require 'test/unit'
5
+
6
+ require 'tc_address'
7
+ require 'tc_standardize'
8
+
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: ziplookup
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2006-08-06 00:00:00 -07:00
8
+ summary: Classes for standardizing addresses via the USPS web site.
9
+ require_paths:
10
+ - lib
11
+ email: gregor@focusresearch.com
12
+ homepage:
13
+ rubyforge_project:
14
+ description: Classes for standardizing addresses via the USPS web site.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ signing_key:
28
+ cert_chain:
29
+ post_install_message:
30
+ authors:
31
+ - Gregor N. Purdy
32
+ files:
33
+ - ".project"
34
+ - bin/tryme.rb
35
+ - lib/USPS/address.rb
36
+ - lib/USPS/zip_lookup.rb
37
+ - Manifest.txt
38
+ - Rakefile
39
+ - test/tc_address.rb
40
+ - test/tc_standardize.rb
41
+ - test/ts_zip_lookup.rb
42
+ test_files: []
43
+ rdoc_options: []
44
+ extra_rdoc_files: []
45
+ executables:
46
+ - tryme.rb
47
+ extensions: []
48
+ requirements: []
49
+ dependencies: []