us_street 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 007d55a2a54e1d6e42573edb3f5dfab5515ff1b0
4
+ data.tar.gz: fb7aae9671e5168511a4de1708f6f6bb0068e3fc
5
+ SHA512:
6
+ metadata.gz: a27b13fc431432e3fabb57a88e160f7340d53c00361cf60bb67c80d3a5d49e0ba8f2ff3cbf930f0a2f89b2d0b3657bbef5e5befa705585b941ed0efaa7366594
7
+ data.tar.gz: 1ec41605f2e513dfce2d05158b141bda74baef754051e13fba1baaf6498397df5a75afc938e6c31f1f70d0994761f90e9ab24d0e7c7cc6c41de71846a7a50ec1
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
16
+
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in us_street.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
7
+ gem 'pry'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Opendoor Labs
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # UsStreet
2
+
3
+ Parses and normalizes the street part of an address for US streets into it's parts.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'us_street'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install us_street
21
+
22
+ ## Usage
23
+
24
+ Can make sense of most streets
25
+
26
+ street = UsStreet.parse('123 north Fake street south 2034 #12')
27
+
28
+ # component accessors
29
+ street.street_number == '123'
30
+ street.dir_prefix == 'N'
31
+ street.street_name == 'Fake'
32
+ street.street_suffix == 'St'
33
+ street.dir_suffix == 'S'
34
+ street.road_number == '2034'
35
+ street.unit == '12'
36
+
37
+ street.street == 'N Fake St S 2034'
38
+ street.full_street == '123 N Fake St S 2034'
39
+ street.display == '123 N Fake St S 2034 #12'
40
+
41
+ It also works on simple streets
42
+
43
+ street = UsStreet.parse('12 st')
44
+ street.full_street = '12th St'
45
+
46
+ street = UsStreet.parse('123 north 12 st')
47
+ street.full_street == '123 N 12th St'
48
+
49
+ street = UsStreet.parse('123 something road')
50
+ street.full_street == '123 Something Rd'
51
+
52
+ ## Contributing
53
+
54
+ 1. Fork it ( https://github.com/[my-github-username]/us_street/fork )
55
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
56
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
57
+ 4. Push to the branch (`git push origin my-new-feature`)
58
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,550 @@
1
+ ---
2
+ alley: aly
3
+ allee: aly
4
+ aly: aly
5
+ ally: aly
6
+ anex: anx
7
+ anx: anx
8
+ annex: anx
9
+ annx: anx
10
+ arcade: arc
11
+ arc: arc
12
+ avenue: ave
13
+ av: ave
14
+ ave: ave
15
+ aven: ave
16
+ avenu: ave
17
+ avn: ave
18
+ avnue: ave
19
+ bayou: byu
20
+ bayoo: byu
21
+ byu: byu
22
+ beach: bch
23
+ bch: bch
24
+ bend: bnd
25
+ bnd: bnd
26
+ bluff: blf
27
+ blf: blf
28
+ bluf: blf
29
+ bluffs: blfs
30
+ blfs: blfs
31
+ bottom: btm
32
+ bot: btm
33
+ btm: btm
34
+ bottm: btm
35
+ boulevard: blvd
36
+ blvd: blvd
37
+ boul: blvd
38
+ boulv: blvd
39
+ branch: br
40
+ br: br
41
+ brnch: br
42
+ bridge: brg
43
+ brdge: brg
44
+ brg: brg
45
+ brook: brk
46
+ brk: brk
47
+ brooks: brks
48
+ brks: brks
49
+ burg: bg
50
+ bg: bg
51
+ burgs: bgs
52
+ bgs: bgs
53
+ bypass: byp
54
+ byp: byp
55
+ bypa: byp
56
+ bypas: byp
57
+ byps: byp
58
+ camp: cp
59
+ cp: cp
60
+ cmp: cp
61
+ canyon: cyn
62
+ canyn: cyn
63
+ cyn: cyn
64
+ cnyn: cyn
65
+ cape: cpe
66
+ cpe: cpe
67
+ causeway: cswy
68
+ cswy: cswy
69
+ causwa: cswy
70
+ center: ctr
71
+ cen: ctr
72
+ ctr: ctr
73
+ cent: ctr
74
+ centr: ctr
75
+ centre: ctr
76
+ cnter: ctr
77
+ cntr: ctr
78
+ centers: ctrs
79
+ ctrs: ctrs
80
+ circle: cir
81
+ cir: cir
82
+ circ: cir
83
+ circl: cir
84
+ crcl: cir
85
+ crcle: cir
86
+ circles: cirs
87
+ cirs: cirs
88
+ cliff: clf
89
+ clf: clf
90
+ cliffs: clfs
91
+ clfs: clfs
92
+ club: clb
93
+ clb: clb
94
+ common: cmn
95
+ cmn: cmn
96
+ commons: cmns
97
+ cmns: cmns
98
+ corner: cor
99
+ cor: cor
100
+ corners: cors
101
+ cors: cors
102
+ course: crse
103
+ crse: crse
104
+ court: ct
105
+ ct: ct
106
+ courts: cts
107
+ cts: cts
108
+ cove: cv
109
+ cv: cv
110
+ coves: cvs
111
+ cvs: cvs
112
+ creek: crk
113
+ crk: crk
114
+ crescent: cres
115
+ cres: cres
116
+ crsent: cres
117
+ crsnt: cres
118
+ crest: crst
119
+ crst: crst
120
+ crossing: xing
121
+ xing: xing
122
+ crssng: xing
123
+ crossroad: xrd
124
+ xrd: xrd
125
+ crossroads: xrds
126
+ xrds: xrds
127
+ curve: curv
128
+ curv: curv
129
+ dale: dl
130
+ dl: dl
131
+ dam: dm
132
+ dm: dm
133
+ divide: dv
134
+ div: dv
135
+ dv: dv
136
+ dvd: dv
137
+ drive: dr
138
+ dr: dr
139
+ driv: dr
140
+ drv: dr
141
+ drives: drs
142
+ drs: drs
143
+ estate: est
144
+ est: est
145
+ estates: ests
146
+ ests: ests
147
+ expressway: expy
148
+ exp: expy
149
+ expy: expy
150
+ expr: expy
151
+ express: expy
152
+ expw: expy
153
+ extension: ext
154
+ ext: ext
155
+ extn: ext
156
+ extnsn: ext
157
+ extensions: exts
158
+ exts: exts
159
+ fall: fall
160
+ falls: fls
161
+ fls: fls
162
+ ferry: fry
163
+ fry: fry
164
+ frry: fry
165
+ field: fld
166
+ fld: fld
167
+ fields: flds
168
+ flds: flds
169
+ flat: flt
170
+ flt: flt
171
+ flats: flts
172
+ flts: flts
173
+ ford: frd
174
+ frd: frd
175
+ fords: frds
176
+ frds: frds
177
+ forest: frst
178
+ frst: frst
179
+ forests: frst
180
+ forge: frg
181
+ forg: frg
182
+ frg: frg
183
+ forges: frgs
184
+ frgs: frgs
185
+ fork: frk
186
+ frk: frk
187
+ forks: frks
188
+ frks: frks
189
+ fort: ft
190
+ ft: ft
191
+ frt: ft
192
+ freeway: fwy
193
+ fwy: fwy
194
+ freewy: fwy
195
+ frway: fwy
196
+ frwy: fwy
197
+ garden: gdn
198
+ gdn: gdn
199
+ gardn: gdn
200
+ grden: gdn
201
+ grdn: gdn
202
+ gardens: gdns
203
+ gdns: gdns
204
+ grdns: gdns
205
+ gateway: gtwy
206
+ gtwy: gtwy
207
+ gatewy: gtwy
208
+ gatway: gtwy
209
+ gtway: gtwy
210
+ glen: gln
211
+ gln: gln
212
+ glens: glns
213
+ glns: glns
214
+ green: grn
215
+ grn: grn
216
+ greens: grns
217
+ grns: grns
218
+ grove: grv
219
+ grov: grv
220
+ grv: grv
221
+ groves: grvs
222
+ grvs: grvs
223
+ harbor: hbr
224
+ harb: hbr
225
+ hbr: hbr
226
+ harbr: hbr
227
+ hrbor: hbr
228
+ harbors: hbrs
229
+ hbrs: hbrs
230
+ haven: hvn
231
+ hvn: hvn
232
+ heights: hts
233
+ ht: hts
234
+ hts: hts
235
+ highway: hwy
236
+ hwy: hwy
237
+ highwy: hwy
238
+ hiway: hwy
239
+ hiwy: hwy
240
+ hway: hwy
241
+ hill: hl
242
+ hl: hl
243
+ hills: hls
244
+ hls: hls
245
+ hollow: holw
246
+ hllw: holw
247
+ holw: holw
248
+ hollows: holw
249
+ holws: holw
250
+ inlet: inlt
251
+ inlt: inlt
252
+ island: is
253
+ is: is
254
+ islnd: is
255
+ islands: iss
256
+ iss: iss
257
+ islnds: iss
258
+ isle: isle
259
+ isles: isle
260
+ junction: jct
261
+ jct: jct
262
+ jction: jct
263
+ jctn: jct
264
+ junctn: jct
265
+ juncton: jct
266
+ junctions: jcts
267
+ jctns: jcts
268
+ jcts: jcts
269
+ key: ky
270
+ ky: ky
271
+ keys: kys
272
+ kys: kys
273
+ knoll: knl
274
+ knl: knl
275
+ knol: knl
276
+ knolls: knls
277
+ knls: knls
278
+ lake: lk
279
+ lk: lk
280
+ lakes: lks
281
+ lks: lks
282
+ land: land
283
+ landing: lndg
284
+ lndg: lndg
285
+ lndng: lndg
286
+ lane: ln
287
+ ln: ln
288
+ light: lgt
289
+ lgt: lgt
290
+ lights: lgts
291
+ lgts: lgts
292
+ loaf: lf
293
+ lf: lf
294
+ lock: lck
295
+ lck: lck
296
+ locks: lcks
297
+ lcks: lcks
298
+ lodge: ldg
299
+ ldg: ldg
300
+ ldge: ldg
301
+ lodg: ldg
302
+ loop: loop
303
+ loops: loop
304
+ mall: mall
305
+ manor: mnr
306
+ mnr: mnr
307
+ manors: mnrs
308
+ mnrs: mnrs
309
+ meadow: mdw
310
+ mdw: mdws
311
+ meadows: mdws
312
+ mdws: mdws
313
+ medows: mdws
314
+ mews: mews
315
+ mill: ml
316
+ ml: ml
317
+ mills: mls
318
+ mls: mls
319
+ mission: msn
320
+ missn: msn
321
+ msn: msn
322
+ mssn: msn
323
+ motorway: mtwy
324
+ mtwy: mtwy
325
+ mount: mt
326
+ mnt: mt
327
+ mt: mt
328
+ mountain: mtn
329
+ mntain: mtn
330
+ mtn: mtn
331
+ mntn: mtn
332
+ mountin: mtn
333
+ mtin: mtn
334
+ mountains: mtns
335
+ mntns: mtns
336
+ mtns: mtns
337
+ neck: nck
338
+ nck: nck
339
+ orchard: orch
340
+ orch: orch
341
+ orchrd: orch
342
+ oval: oval
343
+ ovl: oval
344
+ overpass: opas
345
+ opas: opas
346
+ park: park
347
+ prk: park
348
+ parks: park
349
+ parkway: pkwy
350
+ pkwy: pkwy
351
+ parkwy: pkwy
352
+ pkway: pkwy
353
+ pky: pkwy
354
+ parkways: pkwy
355
+ pkwys: pkwy
356
+ pass: pass
357
+ passage: psge
358
+ psge: psge
359
+ path: path
360
+ paths: path
361
+ pike: pike
362
+ pikes: pike
363
+ pine: pne
364
+ pne: pne
365
+ pines: pnes
366
+ pnes: pnes
367
+ place: pl
368
+ pl: pl
369
+ plain: pln
370
+ pln: pln
371
+ plains: plns
372
+ plns: plns
373
+ plaza: plz
374
+ plz: plz
375
+ plza: plz
376
+ point: pt
377
+ pt: pt
378
+ points: pts
379
+ pts: pts
380
+ port: prt
381
+ prt: prt
382
+ ports: prts
383
+ prts: prts
384
+ prairie: pr
385
+ pr: pr
386
+ prr: pr
387
+ radial: radl
388
+ rad: radl
389
+ radl: radl
390
+ radiel: radl
391
+ ramp: ramp
392
+ ranch: rnch
393
+ rnch: rnch
394
+ ranches: rnch
395
+ rnchs: rnch
396
+ rapid: rpd
397
+ rpd: rpd
398
+ rapids: rpds
399
+ rpds: rpds
400
+ rest: rst
401
+ rst: rst
402
+ ridge: rdg
403
+ rdg: rdg
404
+ rdge: rdg
405
+ ridges: rdgs
406
+ rdgs: rdgs
407
+ river: riv
408
+ riv: riv
409
+ rvr: riv
410
+ rivr: riv
411
+ road: rd
412
+ rd: rd
413
+ roads: rds
414
+ rds: rds
415
+ route: rte
416
+ rte: rte
417
+ row: row
418
+ rue: rue
419
+ run: run
420
+ shoal: shl
421
+ shl: shl
422
+ shoals: shls
423
+ shls: shls
424
+ shore: shr
425
+ shoar: shr
426
+ shr: shr
427
+ shores: shrs
428
+ shoars: shrs
429
+ shrs: shrs
430
+ skyway: skwy
431
+ skwy: skwy
432
+ spring: spg
433
+ spg: spg
434
+ spng: spg
435
+ sprng: spg
436
+ springs: spgs
437
+ spgs: spgs
438
+ spngs: spgs
439
+ sprngs: spgs
440
+ spur: spur
441
+ spurs: spur
442
+ square: sq
443
+ sq: sq
444
+ sqr: sq
445
+ sqre: sq
446
+ squ: sq
447
+ squares: sqs
448
+ sqrs: sqs
449
+ sqs: sqs
450
+ station: sta
451
+ sta: sta
452
+ statn: sta
453
+ stn: sta
454
+ stravenue: stra
455
+ stra: stra
456
+ strav: stra
457
+ straven: stra
458
+ stravn: stra
459
+ strvn: stra
460
+ strvnue: stra
461
+ stream: strm
462
+ strm: strm
463
+ streme: strm
464
+ street: st
465
+ st: st
466
+ strt: st
467
+ str: st
468
+ streets: sts
469
+ sts: sts
470
+ summit: smt
471
+ smt: smt
472
+ sumit: smt
473
+ sumitt: smt
474
+ terrace: ter
475
+ ter: ter
476
+ terr: ter
477
+ throughway: trwy
478
+ trwy: trwy
479
+ trace: trce
480
+ trce: trce
481
+ traces: trce
482
+ track: trak
483
+ trak: trak
484
+ tracks: trak
485
+ trk: trak
486
+ trks: trak
487
+ trafficway: trfy
488
+ trfy: trfy
489
+ trail: trl
490
+ trl: trl
491
+ trails: trl
492
+ trls: trl
493
+ trailer: trlr
494
+ trlr: trlr
495
+ trlrs: trlr
496
+ tunnel: tunl
497
+ tunel: tunl
498
+ tunl: tunl
499
+ tunls: tunl
500
+ tunnels: tunl
501
+ tunnl: tunl
502
+ turnpike: tpke
503
+ trnpk: tpke
504
+ tpke: tpke
505
+ turnpk: tpke
506
+ underpass: upas
507
+ upas: upas
508
+ union: un
509
+ un: un
510
+ unions: uns
511
+ uns: uns
512
+ valley: vly
513
+ vly: vly
514
+ vally: vly
515
+ vlly: vly
516
+ valleys: vlys
517
+ vlys: vlys
518
+ viaduct: via
519
+ vdct: via
520
+ via: via
521
+ viadct: via
522
+ view: vw
523
+ vw: vw
524
+ views: vws
525
+ vws: vws
526
+ village: vlg
527
+ vill: vlg
528
+ vlg: vlg
529
+ villag: vlg
530
+ villg: vlg
531
+ villiage: vlg
532
+ villages: vlgs
533
+ vlgs: vlgs
534
+ ville: vl
535
+ vl: vl
536
+ vista: vis
537
+ vis: vis
538
+ vist: vis
539
+ vst: vis
540
+ vsta: vis
541
+ walk: walk
542
+ walks: walk
543
+ wall: wall
544
+ way: way
545
+ wy: way
546
+ ways: ways
547
+ well: wl
548
+ wl: wl
549
+ wells: wls
550
+ wls: wls
@@ -0,0 +1,3 @@
1
+ class UsStreet
2
+ VERSION = "0.1.0"
3
+ end
data/lib/us_street.rb ADDED
@@ -0,0 +1,172 @@
1
+ require "us_street/version"
2
+ require 'yaml'
3
+ require 'active_support/core_ext/object/blank'
4
+ require 'active_support/core_ext/hash/indifferent_access'
5
+ require 'active_support/core_ext/object/try'
6
+ require 'active_support/inflector/inflections'
7
+ require 'active_support/core_ext/integer/inflections'
8
+
9
+ class UsStreet
10
+ COMPONENTS = [:unit, :street_number, :dir_prefix, :street_name, :street_suffix, :dir_suffix, :road_number].freeze
11
+
12
+ f = File.expand_path('data/street_suffix_mapping.yml', __dir__)
13
+ ROAD_SUFFIXES = YAML.load(File.read(f))
14
+
15
+ DIRECTIONAL_MAPPINGS = {
16
+ "n" => "n",
17
+ "e" => "e",
18
+ "s" => "s",
19
+ "w" => "w",
20
+ "north" => "n",
21
+ "east" => "e",
22
+ "south" => "s",
23
+ "west" => "w",
24
+ "nth" => "n",
25
+ "sth" => "s",
26
+ "ne" => "ne",
27
+ "nw" => "nw",
28
+ "se" => "se",
29
+ "sw" => "sw",
30
+ "northeast" => "ne",
31
+ "northwest" => "nw",
32
+ "southeast" => "se",
33
+ "southwest" => "sw",
34
+ }
35
+
36
+ def self.components; COMPONENTS; end
37
+
38
+ def self.clean(str)
39
+ str.to_s.gsub(/([\.,:;]|\(.*?\))/, '').gsub(/#\d+$/, '').gsub(/\s+/, ' ').strip.downcase.presence
40
+ end
41
+
42
+ def self.clean_hash(hash)
43
+ hash.each_with_object({}.with_indifferent_access) { |(k,v),hsh| hsh[k] = clean(v) }
44
+ end
45
+
46
+ # Define methods for each of the components
47
+ components.each do |f|
48
+ define_method(f) { @components[f] }
49
+ end
50
+
51
+ attr_reader :components
52
+
53
+ # @param {String} street_number - The street number
54
+ # @param {String} street_name - The name of the street including all the 'ixes
55
+ # @param {Hash} components - The components of the street
56
+ def initialize(components = {})
57
+ @components = components
58
+ end
59
+
60
+ def street
61
+ @street ||= UsStreet.trim(dir_prefix, street_name, street_suffix, dir_suffix, road_number)
62
+ end
63
+
64
+ def full_street
65
+ @full_street ||= UsStreet.trim(street_number, street)
66
+ end
67
+
68
+ def display
69
+ @display ||= unit.present? ? UsStreet.trim(full_street, "##{unit}") : full_street
70
+ end
71
+
72
+ def attributes
73
+ @attributes ||= @components.merge(street: street, full_street: full_street, display: display)
74
+ end
75
+
76
+ def self.parse(full_street, overrides = {})
77
+ original_full_street = full_street.to_s
78
+ full_street = clean(full_street.to_s).to_s # the cleaner removes unit numbers :(
79
+ overrides = clean_hash(overrides)
80
+
81
+ parts = full_street.split(' ')
82
+ sidx, eidx = 0, parts.length - 1
83
+ unit_number = dir_suffix = dir_prefix = street_suffix = street_number = road_number = nil
84
+
85
+ # start at the end and chomp
86
+
87
+ # We could have a unit number last. Format '#\d+' but it's removed by the cleaners so match the original
88
+ if match = original_full_street.match(/#(\d+)$/)
89
+ unit_number = match[1]
90
+ end
91
+
92
+ # we may be on a numbered road. Like a country road.
93
+ if parts[eidx] =~ /^\d+$/
94
+ road_number = parts[eidx]
95
+ eidx -= 1
96
+ end
97
+
98
+ # We may have a directional suffix, and or a street suffix
99
+ eidx -= 1 if dir_suffix = direction_mapping(parts[eidx])
100
+ eidx -= 1 if street_suffix = road_mapping(parts[eidx])
101
+
102
+ # if our current spread is 0 then someone may have put in 12 st for 12th Street. We want to end it here if that's true.
103
+ if eidx - sidx > 0
104
+ # lets look at the start of the string
105
+
106
+ # is there a street number?
107
+ if parts[sidx] =~ /^\d+$/
108
+ street_number = parts[sidx]
109
+ sidx += 1
110
+ end
111
+
112
+ # is there a directional prefix?
113
+ sidx += 1 if dir_prefix = direction_mapping(parts[sidx])
114
+ end
115
+
116
+ # fix weirdo street names and make them consistent
117
+ parts[sidx] = "St" if parts[sidx] =~ /^((st\.?)|(saint))$/i # catch "Saint John Street"
118
+ parts[sidx] = "Dr" if parts[sidx] =~ /^((dr\.?)|(doctor))$/i # catch "Dr. Oz Road"
119
+
120
+ # Time to build up the output, prefer what was passed in
121
+ # Note: We needed to decompose the street because the street may have had the components put into it
122
+ # by some unsavoury operators :'(
123
+ out = {
124
+ unit: overrides[:unit].presence || unit_number,
125
+ dir_prefix: direction_mapping(overrides[:dir_prefix]).presence || dir_prefix,
126
+ street_name: overrides[:street_name].presence || parts[sidx..eidx].join(' '),
127
+ street_suffix: road_mapping(overrides[:street_suffix]).presence || street_suffix,
128
+ dir_suffix: direction_mapping(overrides[:dir_suffix]).presence || dir_suffix,
129
+ street_number: overrides[:street_number].presence || street_number,
130
+ road_number: overrides[:road_number].presence || road_number
131
+ }
132
+
133
+ # we may have country or co for a country road.
134
+ out[:street_name] = 'co' if out[:street_name] == 'country'
135
+
136
+ # perform one last mapping to be sure that we've got the correct 'ixes.
137
+ out[:dir_prefix] = out[:dir_prefix].try(:upcase)
138
+ out[:dir_suffix] = out[:dir_suffix].try(:upcase)
139
+ out[:street_suffix] = road_mapping(out[:street_suffix]).try(:titleize)
140
+ out[:street_name] = out[:street_name].try(:titleize)
141
+
142
+ out[:street_name] = out[:street_name].to_i.ordinalize if out[:street_name].present? && out[:street_name] =~ /^\d+$/
143
+
144
+ new out
145
+ end
146
+
147
+ def self.from_attrs(street_number, dir_prefix, street_name, street_suffix, dir_suffix)
148
+ return parse(
149
+ street_name,
150
+ street_number: street_number,
151
+ dir_prefix: dir_prefix,
152
+ street_suffix: street_suffix,
153
+ dir_suffix: dir_suffix
154
+ )
155
+ end
156
+
157
+ def self.direction_mapping(direction)
158
+ DIRECTIONAL_MAPPINGS[direction.to_s.downcase] && DIRECTIONAL_MAPPINGS[direction.to_s.downcase].upcase
159
+ end
160
+
161
+ def self.road_mapping(suffix)
162
+ ROAD_SUFFIXES[suffix.to_s.downcase] && ROAD_SUFFIXES[suffix.to_s.downcase].upcase
163
+ end
164
+
165
+ def self.trim(*address_components)
166
+ address_components.compact.join(' ').gsub(/\s+/, ' ').strip
167
+ end
168
+
169
+ def ==(other)
170
+ other.respond_to?(:full_street) && self.full_street == other.full_street
171
+ end
172
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift File.expand_path('../lib', __dir__)
2
+
3
+ require 'us_street'
4
+ require 'pry'
5
+
6
+ RSpec.configure do |config|
7
+ config.order = "random"
8
+ end
@@ -0,0 +1,208 @@
1
+ require 'spec_helper'
2
+
3
+ describe UsStreet do
4
+ describe ".from_attrs" do
5
+ it "builds a normalized street address" do
6
+ us_street = UsStreet.from_attrs(11421, "W", "LAURELWOOD", "Lane", nil)
7
+ expect(us_street.full_street).to eq("11421 W Laurelwood Ln")
8
+ end
9
+
10
+ it "removes unknown directions" do
11
+ us_street = UsStreet.from_attrs(11421, "WFS", "LAURELWOOD", "Lane", nil)
12
+ expect(us_street.full_street).to eq("11421 Laurelwood Ln")
13
+ end
14
+
15
+ it "simplifies known directions" do
16
+ us_street = UsStreet.from_attrs(11421, "NorthWesT", "LAURELWOOD", "Lane", "SE")
17
+ expect(us_street.full_street).to eq("11421 NW Laurelwood Ln SE")
18
+ end
19
+
20
+ it "checks for Saint & Doctor such-n'-such streets" do
21
+ us_street = UsStreet.from_attrs(11421, nil, "ST. JOHN", "Road", nil)
22
+ expect(us_street.full_street).to eq("11421 St John Rd")
23
+ us_street = UsStreet.from_attrs(11421, nil, "saInT John", "Road", nil)
24
+ expect(us_street.full_street).to eq("11421 St John Rd")
25
+
26
+ us_street = UsStreet.from_attrs(11421, nil, "DR JOHN", "Road", nil)
27
+ expect(us_street.full_street).to eq("11421 Dr John Rd")
28
+ us_street = UsStreet.from_attrs(11421, nil, "Doctor John", "Road", nil)
29
+ expect(us_street.full_street).to eq("11421 Dr John Rd")
30
+ end
31
+
32
+ it "removes stuff in parens" do
33
+ us_street = UsStreet.from_attrs(11421, "WFS", "LAURELWOOD (NOT HERE)", "Lane", nil)
34
+ expect(us_street.full_street).to eq("11421 Laurelwood Ln")
35
+ end
36
+
37
+ it "strips off unrequired characters" do
38
+ us_street = UsStreet.from_attrs(123, nil, "N. main, -southy", nil, nil)
39
+ expect(us_street.full_street).to eq("123 N Main Southy")
40
+ end
41
+
42
+ it "strips off spaces" do
43
+ us_street = UsStreet.from_attrs(" 123", nil, "N. main, -southy ", nil, nil)
44
+ expect(us_street.full_street).to eq("123 N Main Southy")
45
+ end
46
+
47
+ context 'with weird data' do
48
+ it 'checks for double entry of directional prefix' do
49
+ us_street = UsStreet.from_attrs(" 123", 'North', "N 12th St", nil, nil)
50
+ expect(us_street.full_street).to eq('123 N 12th St')
51
+ end
52
+
53
+ it 'checks for double entry of street suffix' do
54
+ us_street = UsStreet.from_attrs(" 123", nil, "N 12th St", 'Street', nil)
55
+ expect(us_street.full_street).to eq('123 N 12th St')
56
+ end
57
+
58
+ it 'checks for double entry of directional suffix' do
59
+ us_street = UsStreet.from_attrs(" 123", nil, "12th Street West", 'st', 'W')
60
+ expect(us_street.full_street).to eq('123 12th St W')
61
+ end
62
+
63
+ it 'handles all the suffixen and prefixen' do
64
+ us_street = UsStreet.from_attrs(" 123", 'S', "South 12th St East", 'Street', 'E')
65
+ expect(us_street.full_street).to eq('123 S 12th St E')
66
+ end
67
+
68
+ it 'reads the directional prefix from the street when not passed in' do
69
+ us_street = UsStreet.from_attrs(" 123", nil, 'southwest 12th St', nil, nil)
70
+ expect(us_street.full_street).to eq('123 SW 12th St')
71
+ end
72
+
73
+ it 'reads the street suffix from the street when not passed in' do
74
+ us_street = UsStreet.from_attrs(" 123", nil, "12th Street", nil, nil)
75
+ expect(us_street.full_street).to eq('123 12th St')
76
+ end
77
+
78
+ it 'reads the directional suffix from the street when not passed in' do
79
+ us_street = UsStreet.from_attrs(" 123", nil, "12th North", 'Street', nil)
80
+ expect(us_street.full_street).to eq('123 12th St N')
81
+ end
82
+
83
+ it 'prefers what is passed in' do
84
+ us_street = UsStreet.from_attrs(" 123", 'S', "North 12th St WEST", 'Street', 'E')
85
+ expect(us_street.full_street).to eq('123 S 12th St E')
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '.parse' do
91
+ it "builds a normalized street address" do
92
+ us_street = UsStreet.parse("11421 W LAURELWOOD Lane")
93
+ expect(us_street.full_street).to eq("11421 W Laurelwood Ln")
94
+ end
95
+
96
+ it "removes unknown directions" do
97
+ us_street = UsStreet.parse("11421 LAURELWOOD Lane", dir_prefix: 'WFS')
98
+ expect(us_street.full_street).to eq("11421 Laurelwood Ln")
99
+ end
100
+
101
+ it "simplifies known directions" do
102
+ us_street = UsStreet.parse("11421 NorthWesT LAURELWOOD Lane SE")
103
+ expect(us_street.full_street).to eq("11421 NW Laurelwood Ln SE")
104
+ end
105
+
106
+ it "checks for Saint & Doctor such-n'-such streets" do
107
+ us_street = UsStreet.parse("11421 ST. JOHN Road")
108
+ expect(us_street.full_street).to eq("11421 St John Rd")
109
+ us_street = UsStreet.parse("11421 saInT John Road")
110
+ expect(us_street.full_street).to eq("11421 St John Rd")
111
+
112
+ us_street = UsStreet.parse("11421 DR JOHN Road")
113
+ expect(us_street.full_street).to eq("11421 Dr John Rd")
114
+ us_street = UsStreet.parse("11421 Doctor John Road")
115
+ expect(us_street.full_street).to eq("11421 Dr John Rd")
116
+ end
117
+
118
+ it "removes stuff in parens" do
119
+ us_street = UsStreet.parse("11421 LAURELWOOD (NOT HERE) Lane")
120
+ expect(us_street.full_street).to eq("11421 Laurelwood Ln")
121
+ end
122
+
123
+ it "strips off unrequired characters" do
124
+ us_street = UsStreet.parse("123 N. main, -southy")
125
+ expect(us_street.full_street).to eq("123 N Main Southy")
126
+ end
127
+
128
+ it "strips off spaces" do
129
+ us_street = UsStreet.parse(" 123 N main southy ")
130
+ expect(us_street.full_street).to eq("123 N Main Southy")
131
+ end
132
+
133
+ it 'prefers an explicit dir_prefix' do
134
+ us_street = UsStreet.parse("123 S main southy", dir_prefix: "n")
135
+ expect(us_street.dir_prefix).to eq('N')
136
+ expect(us_street.full_street).to eq("123 N Main Southy")
137
+ end
138
+
139
+ it 'prefers an explicit dir_suffix' do
140
+ us_street = UsStreet.parse("123 main southy W", dir_suffix: "n")
141
+ expect(us_street.dir_suffix).to eq('N')
142
+ expect(us_street.full_street).to eq("123 Main Southy N")
143
+ end
144
+
145
+ it 'prefers an explicit street_suffix' do
146
+ us_street = UsStreet.parse("123 main southy road", street_suffix: "st")
147
+ expect(us_street.street_suffix).to eq('St')
148
+ expect(us_street.full_street).to eq("123 Main Southy St")
149
+ end
150
+
151
+ it 'handles unit numbers' do
152
+ us_street = UsStreet.parse('123 123rd st #15')
153
+ expect(us_street.unit).to eq('15')
154
+ expect(us_street.full_street).to eq('123 123rd St')
155
+ expect(us_street.display).to eq('123 123rd St #15')
156
+ end
157
+
158
+ it 'handles 123rd st without ordinals or street number' do
159
+ us_street = UsStreet.parse('123 st')
160
+ expect(us_street.street_number).to eq(nil)
161
+ expect(us_street.street_name).to eq('123rd')
162
+ expect(us_street.full_street).to eq('123rd St')
163
+ end
164
+
165
+ it 'handles non ordinalized street names' do
166
+ us_street = UsStreet.parse('13 1 st #14')
167
+ expect(us_street.street_number).to eq('13')
168
+ expect(us_street.unit).to eq('14')
169
+ expect(us_street.street_name).to eq('1st')
170
+ expect(us_street.full_street).to eq('13 1st St')
171
+ expect(us_street.display).to eq('13 1st St #14')
172
+ end
173
+
174
+ it 'handles overrides with string keys' do
175
+ us_street = UsStreet.parse('123 Fake st', "unit" => 12)
176
+ expect(us_street.unit).to eq('12')
177
+ end
178
+
179
+ it 'handles country roads' do
180
+ street1 = UsStreet.parse('1455 Indian Rte 9500')
181
+ street2 = UsStreet.parse('1455 Country Road 2085')
182
+
183
+ expect(street1.full_street).to eq('1455 Indian Rte 9500')
184
+ expect(street1.street_number).to eq('1455')
185
+ expect(street1.street_name).to eq('Indian')
186
+ expect(street1.road_number).to eq('9500')
187
+ expect(street1.street_suffix).to eq('Rte')
188
+ expect(street1.unit).to be_nil
189
+
190
+ expect(street2.full_street).to eq('1455 Co Rd 2085')
191
+ expect(street2.street_number).to eq('1455')
192
+ expect(street2.street_name).to eq('Co')
193
+ expect(street2.road_number).to eq('2085')
194
+ expect(street2.street_suffix).to eq('Rd')
195
+ expect(street2.unit).to be_nil
196
+ end
197
+
198
+ it 'handles country roads with units' do
199
+ street = UsStreet.parse('1455 Country Road 2085 #12')
200
+ expect(street.full_street).to eq('1455 Co Rd 2085')
201
+ expect(street.street_number).to eq('1455')
202
+ expect(street.street_name).to eq('Co')
203
+ expect(street.road_number).to eq('2085')
204
+ expect(street.street_suffix).to eq('Rd')
205
+ expect(street.unit).to eq('12')
206
+ end
207
+ end
208
+ end
data/us_street.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'us_street/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "us_street"
8
+ spec.version = UsStreet::VERSION
9
+ spec.authors = ["Daniel Neighman"]
10
+ spec.email = ["has.sox@gmail.com"]
11
+ spec.summary = %q{Normalizes Us Streets}
12
+ spec.description = %q{Normalizes Us Streets}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'activesupport', '>=3.0'
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: us_street
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Neighman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: Normalizes Us Streets
56
+ email:
57
+ - has.sox@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/data/street_suffix_mapping.yml
68
+ - lib/us_street.rb
69
+ - lib/us_street/version.rb
70
+ - spec/spec_helper.rb
71
+ - spec/us_street_spec.rb
72
+ - us_street.gemspec
73
+ homepage: ''
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.2.2
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Normalizes Us Streets
97
+ test_files:
98
+ - spec/spec_helper.rb
99
+ - spec/us_street_spec.rb
100
+ has_rdoc: