ziplookup 1.0.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.
@@ -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: []