street_sweeper 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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1472 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -0
- data/LICENCE +21 -0
- data/README.md +70 -0
- data/Rakefile +6 -0
- data/lib/street_sweeper.rb +4 -0
- data/lib/street_sweeper/address.rb +103 -0
- data/lib/street_sweeper/base.rb +121 -0
- data/lib/street_sweeper/constants.rb +568 -0
- data/lib/street_sweeper/matchers.rb +173 -0
- data/lib/version.rb +3 -0
- data/spec/address_spec.rb +530 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/street_sweeper_spec.rb +637 -0
- data/street_sweeper.gemspec +26 -0
- metadata +106 -0
@@ -0,0 +1,173 @@
|
|
1
|
+
module StreetSweeper
|
2
|
+
module Matchers
|
3
|
+
class << self
|
4
|
+
attr_accessor(
|
5
|
+
:street_type_regexp,
|
6
|
+
:street_type_matches,
|
7
|
+
:number_regexp,
|
8
|
+
:fraction_regexp,
|
9
|
+
:state_regexp,
|
10
|
+
:city_and_state_regexp,
|
11
|
+
:direct_regexp,
|
12
|
+
:zip_regexp,
|
13
|
+
:corner_regexp,
|
14
|
+
:unit_regexp,
|
15
|
+
:street_regexp,
|
16
|
+
:po_street_regexp,
|
17
|
+
:place_regexp,
|
18
|
+
:address_regexp,
|
19
|
+
:po_address_regexp,
|
20
|
+
:informal_address_regexp,
|
21
|
+
:dircode_regexp,
|
22
|
+
:unit_prefix_numbered_regexp,
|
23
|
+
:unit_prefix_unnumbered_regexp,
|
24
|
+
:unit_regexp,
|
25
|
+
:sep_regexp,
|
26
|
+
:sep_avoid_unit_regexp,
|
27
|
+
:intersection_regexp
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
self.street_type_matches = {}
|
32
|
+
Constants::STREET_TYPES.each_pair do |type, abbrv|
|
33
|
+
street_type_matches[abbrv] = /\b (?: #{abbrv}|#{Regexp.quote(type)} ) \b/ix
|
34
|
+
end
|
35
|
+
|
36
|
+
self.street_type_regexp = Regexp.new(Constants::STREET_TYPES_LIST.keys.join('|'), Regexp::IGNORECASE)
|
37
|
+
self.fraction_regexp = /\d+\/\d+/
|
38
|
+
self.state_regexp = Regexp.new(
|
39
|
+
'\b' + Constants::STATE_CODES.flatten.map { |code| Regexp.quote(code) }.join('|') + '\b',
|
40
|
+
Regexp::IGNORECASE
|
41
|
+
)
|
42
|
+
self.direct_regexp = Regexp.new(
|
43
|
+
(Constants::DIRECTIONAL.keys +
|
44
|
+
Constants::DIRECTIONAL.values.sort do |a, b|
|
45
|
+
b.length <=> a.length
|
46
|
+
end.map do |c|
|
47
|
+
f = c.gsub(/(\w)/, '\1.')
|
48
|
+
[Regexp.quote(f), Regexp.quote(c)]
|
49
|
+
end
|
50
|
+
).join('|'),
|
51
|
+
Regexp::IGNORECASE
|
52
|
+
)
|
53
|
+
self.dircode_regexp = Regexp.new(Constants::DIRECTION_CODES.keys.join('|'), Regexp::IGNORECASE)
|
54
|
+
self.zip_regexp = /(?:(?<postal_code>\d{5})(?:-?(?<postal_code_ext>\d{4}))?)/
|
55
|
+
self.corner_regexp = /(?:\band\b|\bat\b|&|\@)/i
|
56
|
+
|
57
|
+
# we don't include letters in the number regex because we want to
|
58
|
+
# treat "42S" as "42 S" (42 South). For example,
|
59
|
+
# Utah and Wisconsin have a more elaborate system of block numbering
|
60
|
+
# http://en.wikipedia.org/wiki/House_number#Block_numbers
|
61
|
+
self.number_regexp = /(?<number>\d+-?\d*)(?=\D)/ix
|
62
|
+
|
63
|
+
# note that expressions like [^,]+ may scan more than you expect
|
64
|
+
self.street_regexp = /
|
65
|
+
(?:
|
66
|
+
# special case for addresses like 14168 W River Rd and 3301 N Park
|
67
|
+
# Blvd, where the street name matches one of the street types
|
68
|
+
(?:
|
69
|
+
(?<prefix> #{direct_regexp})\W+
|
70
|
+
(?<street> [^\d]+)\W+
|
71
|
+
(?<street_type> #{street_type_regexp})\b
|
72
|
+
)
|
73
|
+
|
|
74
|
+
# special case for addresses like 100 South Street
|
75
|
+
(?:(?<street> #{direct_regexp})\W+
|
76
|
+
(?<street_type> #{street_type_regexp})\b
|
77
|
+
)
|
78
|
+
|
|
79
|
+
(?:(?<prefix> #{direct_regexp})\W+)?
|
80
|
+
(?:
|
81
|
+
(?<street> [^,]*\d)
|
82
|
+
(?:[^\w,]* (?<suffix> #{direct_regexp})\b)
|
83
|
+
|
|
84
|
+
(?<street> [^,]+)
|
85
|
+
(?:[^\w,]+(?<street_type> #{street_type_regexp})\b)
|
86
|
+
(?:[^\w,]+(?<suffix> #{direct_regexp})\b)?
|
87
|
+
|
|
88
|
+
(?<street> [^,]+?)
|
89
|
+
(?:[^\w,]+(?<street_type> #{street_type_regexp})\b)?
|
90
|
+
(?:[^\w,]+(?<suffix> #{direct_regexp})\b)?
|
91
|
+
)
|
92
|
+
)
|
93
|
+
/ix
|
94
|
+
|
95
|
+
self.po_street_regexp = /^(?<street>p\.?o\.?\s?(?:box|\#)?\s\d\d*[-a-z]*)/ix
|
96
|
+
|
97
|
+
# http://pe.usps.com/text/pub28/pub28c2_003.htm
|
98
|
+
self.unit_prefix_numbered_regexp = /
|
99
|
+
(?<unit_prefix>
|
100
|
+
#{Constants::UNIT_ABBREVIATIONS_NUMBERED.keys.join("|")}
|
101
|
+
)(?![a-z])/ix
|
102
|
+
|
103
|
+
self.unit_prefix_unnumbered_regexp = /
|
104
|
+
(?<unit_prefix>
|
105
|
+
#{Constants::UNIT_ABBREVIATIONS_UNNUMBERED.keys.join("|")}
|
106
|
+
)\b/ix
|
107
|
+
|
108
|
+
self.unit_regexp = /
|
109
|
+
(?:
|
110
|
+
(?: (?:#{unit_prefix_numbered_regexp} \W*)
|
111
|
+
| (?<unit_prefix> \#)\W*
|
112
|
+
)
|
113
|
+
(?<unit> [\w-]+)
|
114
|
+
)
|
115
|
+
|
|
116
|
+
#{unit_prefix_unnumbered_regexp}
|
117
|
+
/ix
|
118
|
+
|
119
|
+
self.city_and_state_regexp = /
|
120
|
+
(?:
|
121
|
+
(?<city> [^\d,]+?)\W+
|
122
|
+
(?<state> #{state_regexp})
|
123
|
+
)
|
124
|
+
/ix
|
125
|
+
|
126
|
+
self.place_regexp = /
|
127
|
+
(?:#{city_and_state_regexp}\W*)? (?:#{zip_regexp})?
|
128
|
+
/ix
|
129
|
+
|
130
|
+
self.address_regexp = /
|
131
|
+
\A
|
132
|
+
[^\w\x23]* # skip non-word chars except # (eg unit)
|
133
|
+
#{number_regexp} \W*
|
134
|
+
(?:#{fraction_regexp}\W*)?
|
135
|
+
#{street_regexp}\W+
|
136
|
+
(?:#{unit_regexp}\W+)?
|
137
|
+
#{place_regexp}
|
138
|
+
\W* # require on non-word chars at end
|
139
|
+
\z # right up to end of string
|
140
|
+
/ix
|
141
|
+
|
142
|
+
self.po_address_regexp = /
|
143
|
+
\A
|
144
|
+
#{po_street_regexp} \W*
|
145
|
+
#{place_regexp}
|
146
|
+
\W* # require on non-word chars at end
|
147
|
+
\z # right up to end of string
|
148
|
+
/ix
|
149
|
+
|
150
|
+
self.sep_regexp = /(?:\W+|\Z)/
|
151
|
+
self.sep_avoid_unit_regexp = /(?:[^\#\w]+|\Z)/
|
152
|
+
|
153
|
+
self.informal_address_regexp = /
|
154
|
+
\A
|
155
|
+
\s* # skip leading whitespace
|
156
|
+
(?:#{unit_regexp} #{sep_regexp})?
|
157
|
+
(?:#{number_regexp})? \W*
|
158
|
+
(?:#{fraction_regexp} \W*)?
|
159
|
+
#{street_regexp} #{sep_avoid_unit_regexp}
|
160
|
+
(?:#{unit_regexp} #{sep_regexp})?
|
161
|
+
(?:#{place_regexp})?
|
162
|
+
# don't require match to reach end of string
|
163
|
+
/ix
|
164
|
+
|
165
|
+
self.intersection_regexp = /\A\W*
|
166
|
+
#{street_regexp}\W*?
|
167
|
+
\s+#{corner_regexp}\s+
|
168
|
+
#{street_regexp}\W+
|
169
|
+
#{place_regexp}
|
170
|
+
\W*\z
|
171
|
+
/ix
|
172
|
+
end
|
173
|
+
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1,530 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe StreetSweeper::Address do
|
6
|
+
NORMAL_ADDRESSES = {
|
7
|
+
'1005 Gravenstein Hwy 95472' => {
|
8
|
+
line1: '1005 Gravenstein Hwy',
|
9
|
+
line2: '95472',
|
10
|
+
street_address_1: '1005 Gravenstein Hwy',
|
11
|
+
street_address_2: '',
|
12
|
+
full_street_address: '1005 Gravenstein Hwy, 95472',
|
13
|
+
intersection?: false
|
14
|
+
},
|
15
|
+
'1005 Gravenstein Hwy, 95472' => {
|
16
|
+
line1: '1005 Gravenstein Hwy',
|
17
|
+
line2: '95472',
|
18
|
+
street_address_1: '1005 Gravenstein Hwy',
|
19
|
+
street_address_2: '',
|
20
|
+
full_street_address: '1005 Gravenstein Hwy, 95472',
|
21
|
+
intersection?: false
|
22
|
+
},
|
23
|
+
'1005 Gravenstein Hwy N, 95472' => {
|
24
|
+
line1: '1005 Gravenstein Hwy N',
|
25
|
+
line2: '95472',
|
26
|
+
street_address_1: '1005 Gravenstein Hwy N',
|
27
|
+
street_address_2: '',
|
28
|
+
full_street_address: '1005 Gravenstein Hwy N, 95472',
|
29
|
+
intersection?: false
|
30
|
+
},
|
31
|
+
'1005 Gravenstein Highway North, 95472' => {
|
32
|
+
line1: '1005 Gravenstein Hwy N',
|
33
|
+
line2: '95472',
|
34
|
+
street_address_1: '1005 Gravenstein Hwy N',
|
35
|
+
street_address_2: '',
|
36
|
+
full_street_address: '1005 Gravenstein Hwy N, 95472',
|
37
|
+
intersection?: false
|
38
|
+
},
|
39
|
+
'1005 N Gravenstein Highway, Sebastopol, CA' => {
|
40
|
+
line1: '1005 N Gravenstein Hwy',
|
41
|
+
line2: 'Sebastopol, CA',
|
42
|
+
street_address_1: '1005 N Gravenstein Hwy',
|
43
|
+
street_address_2: '',
|
44
|
+
full_street_address: '1005 N Gravenstein Hwy, Sebastopol, CA',
|
45
|
+
intersection?: false
|
46
|
+
},
|
47
|
+
'1005 N Gravenstein Highway, Suite 500, Sebastopol, CA' => {
|
48
|
+
line1: '1005 N Gravenstein Hwy Ste 500',
|
49
|
+
line2: 'Sebastopol, CA',
|
50
|
+
street_address_1: '1005 N Gravenstein Hwy',
|
51
|
+
street_address_2: 'Ste 500',
|
52
|
+
full_street_address: '1005 N Gravenstein Hwy Ste 500, Sebastopol, CA',
|
53
|
+
intersection?: false
|
54
|
+
},
|
55
|
+
'1005 N Gravenstein Hwy Suite 500 Sebastopol, CA' => {
|
56
|
+
line1: '1005 N Gravenstein Hwy Ste 500',
|
57
|
+
line2: 'Sebastopol, CA',
|
58
|
+
street_address_1: '1005 N Gravenstein Hwy',
|
59
|
+
street_address_2: 'Ste 500',
|
60
|
+
full_street_address: '1005 N Gravenstein Hwy Ste 500, Sebastopol, CA',
|
61
|
+
intersection?: false
|
62
|
+
},
|
63
|
+
'1005 N Gravenstein Highway, Sebastopol, CA, 95472' => {
|
64
|
+
line1: '1005 N Gravenstein Hwy',
|
65
|
+
line2: 'Sebastopol, CA 95472',
|
66
|
+
street_address_1: '1005 N Gravenstein Hwy',
|
67
|
+
street_address_2: '',
|
68
|
+
full_street_address: '1005 N Gravenstein Hwy, Sebastopol, CA 95472',
|
69
|
+
intersection?: false
|
70
|
+
},
|
71
|
+
'1005 N Gravenstein Highway Sebastopol CA 95472' => {
|
72
|
+
line1: '1005 N Gravenstein Hwy',
|
73
|
+
line2: 'Sebastopol, CA 95472',
|
74
|
+
street_address_1: '1005 N Gravenstein Hwy',
|
75
|
+
street_address_2: '',
|
76
|
+
full_street_address: '1005 N Gravenstein Hwy, Sebastopol, CA 95472',
|
77
|
+
intersection?: false
|
78
|
+
},
|
79
|
+
'1005 Gravenstein Hwy N Sebastopol CA' => {
|
80
|
+
line1: '1005 Gravenstein Hwy N',
|
81
|
+
line2: 'Sebastopol, CA',
|
82
|
+
street_address_1: '1005 Gravenstein Hwy N',
|
83
|
+
street_address_2: '',
|
84
|
+
full_street_address: '1005 Gravenstein Hwy N, Sebastopol, CA',
|
85
|
+
intersection?: false
|
86
|
+
},
|
87
|
+
'1005 Gravenstein Hwy N, Sebastopol CA' => {
|
88
|
+
line1: '1005 Gravenstein Hwy N',
|
89
|
+
line2: 'Sebastopol, CA',
|
90
|
+
street_address_1: '1005 Gravenstein Hwy N',
|
91
|
+
street_address_2: '',
|
92
|
+
full_street_address: '1005 Gravenstein Hwy N, Sebastopol, CA',
|
93
|
+
intersection?: false
|
94
|
+
},
|
95
|
+
'1005 Gravenstein Hwy, N Sebastopol CA' => {
|
96
|
+
line1: '1005 Gravenstein Hwy',
|
97
|
+
line2: 'North Sebastopol, CA',
|
98
|
+
street_address_1: '1005 Gravenstein Hwy',
|
99
|
+
street_address_2: '',
|
100
|
+
full_street_address: '1005 Gravenstein Hwy, North Sebastopol, CA',
|
101
|
+
intersection?: false
|
102
|
+
},
|
103
|
+
'1005 Gravenstein Hwy Sebastopol CA' => {
|
104
|
+
line1: '1005 Gravenstein Hwy',
|
105
|
+
line2: 'Sebastopol, CA',
|
106
|
+
street_address_1: '1005 Gravenstein Hwy',
|
107
|
+
street_address_2: '',
|
108
|
+
full_street_address: '1005 Gravenstein Hwy, Sebastopol, CA',
|
109
|
+
intersection?: false
|
110
|
+
},
|
111
|
+
'115 Broadway San Francisco CA' => {
|
112
|
+
line1: '115 Broadway',
|
113
|
+
line2: 'San Francisco, CA',
|
114
|
+
street_address_1: '115 Broadway',
|
115
|
+
street_address_2: '',
|
116
|
+
full_street_address: '115 Broadway, San Francisco, CA',
|
117
|
+
intersection?: false
|
118
|
+
},
|
119
|
+
'7800 Mill Station Rd, Sebastopol, CA 95472' => {
|
120
|
+
line1: '7800 Mill Station Rd',
|
121
|
+
line2: 'Sebastopol, CA 95472',
|
122
|
+
street_address_1: '7800 Mill Station Rd',
|
123
|
+
street_address_2: '',
|
124
|
+
full_street_address: '7800 Mill Station Rd, Sebastopol, CA 95472',
|
125
|
+
intersection?: false
|
126
|
+
},
|
127
|
+
'7800 Mill Station Rd Sebastopol CA 95472' => {
|
128
|
+
line1: '7800 Mill Station Rd',
|
129
|
+
line2: 'Sebastopol, CA 95472',
|
130
|
+
street_address_1: '7800 Mill Station Rd',
|
131
|
+
street_address_2: '',
|
132
|
+
full_street_address: '7800 Mill Station Rd, Sebastopol, CA 95472',
|
133
|
+
intersection?: false
|
134
|
+
},
|
135
|
+
'1005 State Highway 116 Sebastopol CA 95472' => {
|
136
|
+
line1: '1005 State Highway 116',
|
137
|
+
line2: 'Sebastopol, CA 95472',
|
138
|
+
street_address_1: '1005 State Highway 116',
|
139
|
+
street_address_2: '',
|
140
|
+
full_street_address: '1005 State Highway 116, Sebastopol, CA 95472',
|
141
|
+
intersection?: false
|
142
|
+
},
|
143
|
+
'1600 Pennsylvania Ave. NW Washington DC' => {
|
144
|
+
line1: '1600 Pennsylvania Ave NW',
|
145
|
+
line2: 'Washington, DC',
|
146
|
+
street_address_1: '1600 Pennsylvania Ave NW',
|
147
|
+
street_address_2: '',
|
148
|
+
full_street_address: '1600 Pennsylvania Ave NW, Washington, DC',
|
149
|
+
intersection?: false
|
150
|
+
},
|
151
|
+
'1600 Pennsylvania Avenue NW Washington DC' => {
|
152
|
+
line1: '1600 Pennsylvania Ave NW',
|
153
|
+
line2: 'Washington, DC',
|
154
|
+
street_address_1: '1600 Pennsylvania Ave NW',
|
155
|
+
street_address_2: '',
|
156
|
+
full_street_address: '1600 Pennsylvania Ave NW, Washington, DC',
|
157
|
+
intersection?: false
|
158
|
+
},
|
159
|
+
'48S 400E, Salt Lake City UT' => {
|
160
|
+
line1: '48 S 400 E',
|
161
|
+
line2: 'Salt Lake City, UT',
|
162
|
+
street_address_1: '48 S 400 E',
|
163
|
+
street_address_2: '',
|
164
|
+
full_street_address: '48 S 400 E, Salt Lake City, UT',
|
165
|
+
intersection?: false
|
166
|
+
},
|
167
|
+
'550 S 400 E #3206, Salt Lake City UT 84111' => {
|
168
|
+
line1: '550 S 400 E # 3206',
|
169
|
+
line2: 'Salt Lake City, UT 84111',
|
170
|
+
street_address_1: '550 S 400 E',
|
171
|
+
street_address_2: '# 3206',
|
172
|
+
full_street_address: '550 S 400 E # 3206, Salt Lake City, UT 84111',
|
173
|
+
intersection?: false
|
174
|
+
},
|
175
|
+
'6641 N 2200 W Apt D304 Park City, UT 84098' => {
|
176
|
+
line1: '6641 N 2200 W Apt D304',
|
177
|
+
line2: 'Park City, UT 84098',
|
178
|
+
street_address_1: '6641 N 2200 W',
|
179
|
+
street_address_2: 'Apt D304',
|
180
|
+
full_street_address: '6641 N 2200 W Apt D304, Park City, UT 84098',
|
181
|
+
intersection?: false
|
182
|
+
},
|
183
|
+
'100 South St, Philadelphia, PA' => {
|
184
|
+
line1: '100 South St',
|
185
|
+
line2: 'Philadelphia, PA',
|
186
|
+
street_address_1: '100 South St',
|
187
|
+
street_address_2: '',
|
188
|
+
full_street_address: '100 South St, Philadelphia, PA',
|
189
|
+
intersection?: false
|
190
|
+
},
|
191
|
+
'100 S.E. Washington Ave, Minneapolis, MN' => {
|
192
|
+
line1: '100 SE Washington Ave',
|
193
|
+
line2: 'Minneapolis, MN',
|
194
|
+
street_address_1: '100 SE Washington Ave',
|
195
|
+
street_address_2: '',
|
196
|
+
full_street_address: '100 SE Washington Ave, Minneapolis, MN',
|
197
|
+
intersection?: false
|
198
|
+
},
|
199
|
+
'3813 1/2 Some Road, Los Angeles, CA' => {
|
200
|
+
line1: '3813 Some Rd',
|
201
|
+
line2: 'Los Angeles, CA',
|
202
|
+
street_address_1: '3813 Some Rd',
|
203
|
+
street_address_2: '',
|
204
|
+
full_street_address: '3813 Some Rd, Los Angeles, CA',
|
205
|
+
intersection?: false
|
206
|
+
},
|
207
|
+
'1 First St, e San Jose CA' => {
|
208
|
+
line1: '1 1st St',
|
209
|
+
line2: 'East San Jose, CA',
|
210
|
+
street_address_1: '1 1st St',
|
211
|
+
street_address_2: '',
|
212
|
+
full_street_address: '1 1st St, East San Jose, CA',
|
213
|
+
intersection?: false
|
214
|
+
},
|
215
|
+
'lt42 99 Some Road, Some City LA' => {
|
216
|
+
line1: '99 Some Rd Lot 42',
|
217
|
+
line2: 'Some City, LA',
|
218
|
+
street_address_1: '99 Some Rd',
|
219
|
+
street_address_2: 'Lot 42',
|
220
|
+
full_street_address: '99 Some Rd Lot 42, Some City, LA',
|
221
|
+
intersection?: false
|
222
|
+
},
|
223
|
+
'36401 County Road 43, Eaton, CO 80615' => {
|
224
|
+
line1: '36401 County Road 43',
|
225
|
+
line2: 'Eaton, CO 80615',
|
226
|
+
street_address_1: '36401 County Road 43',
|
227
|
+
street_address_2: '',
|
228
|
+
full_street_address: '36401 County Road 43, Eaton, CO 80615',
|
229
|
+
intersection?: false
|
230
|
+
},
|
231
|
+
'1234 COUNTY HWY 60E, Town, CO 12345' => {
|
232
|
+
line1: '1234 County Hwy 60 E',
|
233
|
+
line2: 'Town, CO 12345',
|
234
|
+
street_address_1: '1234 County Hwy 60 E',
|
235
|
+
street_address_2: '',
|
236
|
+
full_street_address: '1234 County Hwy 60 E, Town, CO 12345',
|
237
|
+
intersection?: false
|
238
|
+
},
|
239
|
+
"'45 Quaker Ave, Ste 105'" => {
|
240
|
+
line1: '45 Quaker Ave Ste 105',
|
241
|
+
line2: '',
|
242
|
+
street_address_1: '45 Quaker Ave',
|
243
|
+
street_address_2: 'Ste 105',
|
244
|
+
full_street_address: '45 Quaker Ave Ste 105',
|
245
|
+
intersection?: false
|
246
|
+
},
|
247
|
+
'2730 S Veitch St Apt 207, Arlington, VA 22206' => {
|
248
|
+
line1: '2730 S Veitch St Apt 207',
|
249
|
+
line2: 'Arlington, VA 22206',
|
250
|
+
street_address_1: '2730 S Veitch St',
|
251
|
+
street_address_2: 'Apt 207',
|
252
|
+
full_street_address: '2730 S Veitch St Apt 207, Arlington, VA 22206',
|
253
|
+
intersection?: false
|
254
|
+
},
|
255
|
+
'2730 S Veitch St #207, Arlington, VA 22206' => {
|
256
|
+
line1: '2730 S Veitch St # 207',
|
257
|
+
line2: 'Arlington, VA 22206',
|
258
|
+
street_address_1: '2730 S Veitch St',
|
259
|
+
street_address_2: '# 207',
|
260
|
+
full_street_address: '2730 S Veitch St # 207, Arlington, VA 22206',
|
261
|
+
intersection?: false
|
262
|
+
},
|
263
|
+
'44 Canal Center Plaza Suite 500, Alexandria, VA 22314' => {
|
264
|
+
line1: '44 Canal Center Plz Ste 500',
|
265
|
+
line2: 'Alexandria, VA 22314',
|
266
|
+
street_address_1: '44 Canal Center Plz',
|
267
|
+
street_address_2: 'Ste 500',
|
268
|
+
full_street_address: '44 Canal Center Plz Ste 500, Alexandria, VA 22314',
|
269
|
+
intersection?: false
|
270
|
+
},
|
271
|
+
'One East 161st Street, Bronx, NY 10451' => {
|
272
|
+
line1: 'One East 161st St',
|
273
|
+
line2: 'Bronx, NY 10451',
|
274
|
+
street_address_1: 'One East 161st St',
|
275
|
+
street_address_2: '',
|
276
|
+
full_street_address: 'One East 161st St, Bronx, NY 10451',
|
277
|
+
intersection?: false
|
278
|
+
},
|
279
|
+
'One East 161st Street Suite 10, Bronx, NY 10451' => {
|
280
|
+
line1: 'One East 161st St Ste 10',
|
281
|
+
line2: 'Bronx, NY 10451',
|
282
|
+
street_address_1: 'One East 161st St',
|
283
|
+
street_address_2: 'Ste 10',
|
284
|
+
full_street_address: 'One East 161st St Ste 10, Bronx, NY 10451',
|
285
|
+
intersection?: false
|
286
|
+
},
|
287
|
+
'P.O. Box 280568 Queens Village, New York 11428' => {
|
288
|
+
line1: 'PO Box 280568',
|
289
|
+
line2: 'Queens Village, NY 11428',
|
290
|
+
street_address_1: 'PO Box 280568',
|
291
|
+
street_address_2: '',
|
292
|
+
full_street_address: 'PO Box 280568, Queens Village, NY 11428',
|
293
|
+
intersection?: false
|
294
|
+
},
|
295
|
+
'PO BOX 280568 Queens Village, New York 11428' => {
|
296
|
+
line1: 'PO Box 280568',
|
297
|
+
line2: 'Queens Village, NY 11428',
|
298
|
+
street_address_1: 'PO Box 280568',
|
299
|
+
street_address_2: '',
|
300
|
+
full_street_address: 'PO Box 280568, Queens Village, NY 11428',
|
301
|
+
intersection?: false
|
302
|
+
},
|
303
|
+
'PO 280568 Queens Village, New York 11428' => {
|
304
|
+
line1: 'PO 280568',
|
305
|
+
line2: 'Queens Village, NY 11428',
|
306
|
+
street_address_1: 'PO 280568',
|
307
|
+
street_address_2: '',
|
308
|
+
full_street_address: 'PO 280568, Queens Village, NY 11428',
|
309
|
+
intersection?: false
|
310
|
+
},
|
311
|
+
'Two Pennsylvania Plaza New York, NY 10121-0091' => {
|
312
|
+
line1: 'Two Pennsylvania Plz',
|
313
|
+
line2: 'New York, NY 10121-0091',
|
314
|
+
street_address_1: 'Two Pennsylvania Plz',
|
315
|
+
street_address_2: '',
|
316
|
+
full_street_address: 'Two Pennsylvania Plz, New York, NY 10121-0091',
|
317
|
+
intersection?: false
|
318
|
+
},
|
319
|
+
'1400 CONNECTICUT AVE NW, WASHINGTON, DC 20036' => {
|
320
|
+
line1: '1400 Connecticut Ave NW',
|
321
|
+
line2: 'Washington, DC 20036',
|
322
|
+
street_address_1: '1400 Connecticut Ave NW',
|
323
|
+
street_address_2: '',
|
324
|
+
full_street_address: '1400 Connecticut Ave NW, Washington, DC 20036',
|
325
|
+
intersection?: false
|
326
|
+
}
|
327
|
+
}.freeze
|
328
|
+
|
329
|
+
INTERSECTIONS = {
|
330
|
+
'Mission & Valencia San Francisco CA' => {
|
331
|
+
line1: 'Mission and Valencia',
|
332
|
+
line2: 'San Francisco, CA',
|
333
|
+
street_address_1: 'Mission and Valencia',
|
334
|
+
street_address_2: '',
|
335
|
+
full_street_address: 'Mission and Valencia, San Francisco, CA',
|
336
|
+
intersection?: true
|
337
|
+
},
|
338
|
+
'Mission & Valencia, San Francisco CA' => {
|
339
|
+
line1: 'Mission and Valencia',
|
340
|
+
line2: 'San Francisco, CA',
|
341
|
+
street_address_1: 'Mission and Valencia',
|
342
|
+
street_address_2: '',
|
343
|
+
full_street_address: 'Mission and Valencia, San Francisco, CA',
|
344
|
+
intersection?: true
|
345
|
+
},
|
346
|
+
'Mission St and Valencia St San Francisco CA' => {
|
347
|
+
line1: 'Mission St and Valencia St',
|
348
|
+
line2: 'San Francisco, CA',
|
349
|
+
street_address_1: 'Mission St and Valencia St',
|
350
|
+
street_address_2: '',
|
351
|
+
full_street_address: 'Mission St and Valencia St, San Francisco, CA',
|
352
|
+
intersection?: true
|
353
|
+
},
|
354
|
+
'Hollywood Blvd and Vine St Los Angeles, CA' => {
|
355
|
+
line1: 'Hollywood Blvd and Vine St',
|
356
|
+
line2: 'Los Angeles, CA',
|
357
|
+
street_address_1: 'Hollywood Blvd and Vine St',
|
358
|
+
street_address_2: '',
|
359
|
+
full_street_address: 'Hollywood Blvd and Vine St, Los Angeles, CA',
|
360
|
+
intersection?: true
|
361
|
+
},
|
362
|
+
'Mission St & Valencia St San Francisco CA' => {
|
363
|
+
line1: 'Mission St and Valencia St',
|
364
|
+
line2: 'San Francisco, CA',
|
365
|
+
street_address_1: 'Mission St and Valencia St',
|
366
|
+
street_address_2: '',
|
367
|
+
full_street_address: 'Mission St and Valencia St, San Francisco, CA',
|
368
|
+
intersection?: true
|
369
|
+
},
|
370
|
+
'Mission and Valencia Sts San Francisco CA' => {
|
371
|
+
line1: 'Mission St and Valencia St',
|
372
|
+
line2: 'San Francisco, CA',
|
373
|
+
street_address_1: 'Mission St and Valencia St',
|
374
|
+
street_address_2: '',
|
375
|
+
full_street_address: 'Mission St and Valencia St, San Francisco, CA',
|
376
|
+
intersection?: true
|
377
|
+
},
|
378
|
+
'Mission & Valencia Sts. San Francisco CA' => {
|
379
|
+
line1: 'Mission St and Valencia St',
|
380
|
+
line2: 'San Francisco, CA',
|
381
|
+
street_address_1: 'Mission St and Valencia St',
|
382
|
+
street_address_2: '',
|
383
|
+
full_street_address: 'Mission St and Valencia St, San Francisco, CA',
|
384
|
+
intersection?: true
|
385
|
+
},
|
386
|
+
'Mission & Valencia Streets San Francisco CA' => {
|
387
|
+
line1: 'Mission St and Valencia St',
|
388
|
+
line2: 'San Francisco, CA',
|
389
|
+
street_address_1: 'Mission St and Valencia St',
|
390
|
+
street_address_2: '',
|
391
|
+
full_street_address: 'Mission St and Valencia St, San Francisco, CA',
|
392
|
+
intersection?: true
|
393
|
+
},
|
394
|
+
'Mission Avenue and Valencia Street San Francisco CA' => {
|
395
|
+
line1: 'Mission Ave and Valencia St',
|
396
|
+
line2: 'San Francisco, CA',
|
397
|
+
street_address_1: 'Mission Ave and Valencia St',
|
398
|
+
street_address_2: '',
|
399
|
+
full_street_address: 'Mission Ave and Valencia St, San Francisco, CA',
|
400
|
+
intersection?: true
|
401
|
+
}
|
402
|
+
}.freeze
|
403
|
+
|
404
|
+
INFORMAL_ADDRESSES = {
|
405
|
+
'#42 233 S Wacker Dr 60606' => {
|
406
|
+
line1: '233 S Wacker Dr # 42',
|
407
|
+
line2: '60606',
|
408
|
+
street_address_1: '233 S Wacker Dr',
|
409
|
+
street_address_2: '# 42',
|
410
|
+
full_street_address: '233 S Wacker Dr # 42, 60606',
|
411
|
+
intersection?: false
|
412
|
+
},
|
413
|
+
'Apt. 42, 233 S Wacker Dr 60606' => {
|
414
|
+
line1: '233 S Wacker Dr Apt 42',
|
415
|
+
line2: '60606',
|
416
|
+
street_address_1: '233 S Wacker Dr',
|
417
|
+
street_address_2: 'Apt 42',
|
418
|
+
full_street_address: '233 S Wacker Dr Apt 42, 60606',
|
419
|
+
intersection?: false
|
420
|
+
},
|
421
|
+
'2730 S Veitch St #207' => {
|
422
|
+
line1: '2730 S Veitch St # 207',
|
423
|
+
line2: '',
|
424
|
+
street_address_1: '2730 S Veitch St',
|
425
|
+
street_address_2: '# 207',
|
426
|
+
full_street_address: '2730 S Veitch St # 207',
|
427
|
+
intersection?: false
|
428
|
+
},
|
429
|
+
'321 S. Washington' => {
|
430
|
+
line1: '321 S Washington',
|
431
|
+
line2: '',
|
432
|
+
street_address_1: '321 S Washington',
|
433
|
+
street_address_2: '',
|
434
|
+
full_street_address: '321 S Washington',
|
435
|
+
intersection?: false
|
436
|
+
},
|
437
|
+
'233 S Wacker Dr lobby 60606' => {
|
438
|
+
line1: '233 S Wacker Dr Lbby',
|
439
|
+
line2: '60606',
|
440
|
+
street_address_1: '233 S Wacker Dr',
|
441
|
+
street_address_2: 'Lbby',
|
442
|
+
full_street_address: '233 S Wacker Dr Lbby, 60606',
|
443
|
+
intersection?: false
|
444
|
+
}
|
445
|
+
}.freeze
|
446
|
+
|
447
|
+
METHODS = %w[line1 line2 street_address_1 street_address_2 full_street_address intersection?].freeze\
|
448
|
+
|
449
|
+
ADDRS = NORMAL_ADDRESSES.merge(INFORMAL_ADDRESSES)
|
450
|
+
ALL = ADDRS.merge(INTERSECTIONS)
|
451
|
+
|
452
|
+
ALL.each_pair do |address, expected|
|
453
|
+
context address.to_s do
|
454
|
+
METHODS.each do |method_name|
|
455
|
+
next if expected[method_name.to_sym].to_s == ''
|
456
|
+
it "#{method_name}: #{expected[method_name.to_sym]}" do
|
457
|
+
compare_expected_to_actual(expected, address, method_name)
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
describe '#full_postal_code' do
|
464
|
+
it 'without postal code' do
|
465
|
+
addr = StreetSweeper.parse('7800 Mill Station Rd Sebastopol CA')
|
466
|
+
expect(addr.full_postal_code).to be_nil
|
467
|
+
end
|
468
|
+
|
469
|
+
it 'with only the first five digits' do
|
470
|
+
addr = StreetSweeper.parse('7800 Mill Station Rd Sebastopol CA 95472')
|
471
|
+
expect(addr.full_postal_code).to eq('95472')
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'with valid zip plus 4 with dash' do
|
475
|
+
addr = StreetSweeper.parse('2730 S Veitch St, Arlington, VA 22206-3333')
|
476
|
+
expect(addr.full_postal_code).to eq('22206-3333')
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'with valid zip plus 4 without dash' do
|
480
|
+
addr = StreetSweeper.parse('2730 S Veitch St, Arlington, VA 222064444')
|
481
|
+
expect(addr.full_postal_code).to eq('22206-4444')
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
describe '#postal_code_ext' do
|
486
|
+
it 'without postal code' do
|
487
|
+
addr = StreetSweeper.parse('7800 Mill Station Rd Sebastopol CA')
|
488
|
+
expect(addr.full_postal_code).to be_nil
|
489
|
+
end
|
490
|
+
|
491
|
+
it 'with valid zip plus 4 with dash' do
|
492
|
+
addr = StreetSweeper.parse('2730 S Veitch St, Arlington, VA 22206-3333')
|
493
|
+
expect(addr.postal_code_ext).to eq('3333')
|
494
|
+
end
|
495
|
+
|
496
|
+
it 'with valid zip plus 4 without dash' do
|
497
|
+
addr = StreetSweeper.parse('2730 S Veitch St, Arlington, VA 222064444')
|
498
|
+
expect(addr.postal_code_ext).to eq('4444')
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
describe '#state_name' do
|
503
|
+
it 'with a vaild address' do
|
504
|
+
addr = StreetSweeper.parse('7800 Mill Station Rd Sebastopol CA 95472')
|
505
|
+
expect(addr.state_name).to eq('California')
|
506
|
+
end
|
507
|
+
|
508
|
+
it 'with an invaild address' do
|
509
|
+
addr = StreetSweeper.parse('7800 Mill Station Rd Sebastopol 95472')
|
510
|
+
expect(addr.state_name).to be_nil
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
describe '#state_fips' do
|
515
|
+
it 'with a vaild address' do
|
516
|
+
addr = StreetSweeper.parse('7800 Mill Station Rd Sebastopol CA 95472')
|
517
|
+
expect(addr.state_fips).to eq('06')
|
518
|
+
end
|
519
|
+
|
520
|
+
it 'with an invaild address' do
|
521
|
+
addr = StreetSweeper.parse('7800 Mill Station Rd Sebastopol 95472')
|
522
|
+
expect(addr.state_fips).to be_nil
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
def compare_expected_to_actual(expected, address, method_name)
|
527
|
+
addr = StreetSweeper.parse(address)
|
528
|
+
expect(addr.send(method_name)).to eq(expected[method_name.to_sym])
|
529
|
+
end
|
530
|
+
end
|