fips_lookup 0.3.0 → 0.4
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 +4 -4
- data/.rubocop.yml +1 -1
- data/Gemfile.lock +37 -30
- data/README.md +78 -140
- data/lib/data/subdivision/CT.csv +0 -4
- data/lib/data/subdivision/GU.csv +0 -1
- data/lib/data/subdivision/IL.csv +0 -2
- data/lib/data/subdivision/IN.csv +0 -2
- data/lib/data/subdivision/MA.csv +0 -6
- data/lib/data/subdivision/MI.csv +0 -40
- data/lib/data/subdivision/MN.csv +0 -3
- data/lib/data/subdivision/MP.csv +0 -4
- data/lib/data/subdivision/NH.csv +0 -1
- data/lib/data/subdivision/NJ.csv +0 -5
- data/lib/data/subdivision/NY.csv +0 -9
- data/lib/data/subdivision/OH.csv +0 -5
- data/lib/data/subdivision/PA.csv +0 -1
- data/lib/data/subdivision/PR.csv +0 -38
- data/lib/data/subdivision/RI.csv +0 -1
- data/lib/data/subdivision/VI.csv +0 -3
- data/lib/data/subdivision/WI.csv +0 -12
- data/lib/fips/county.rb +112 -0
- data/lib/fips/state.rb +67 -0
- data/lib/fips/subdivision.rb +163 -0
- data/lib/fips/version.rb +5 -0
- data/lib/fips.rb +68 -0
- data/sig/fips.rbs +50 -0
- metadata +38 -9
- data/lib/fips_lookup/county.rb +0 -65
- data/lib/fips_lookup/state.rb +0 -46
- data/lib/fips_lookup/subdivision.rb +0 -48
- data/lib/fips_lookup/version.rb +0 -5
- data/lib/fips_lookup.rb +0 -25
- data/sig/fips_lookup.rbs +0 -4
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "csv"
|
|
4
|
+
|
|
5
|
+
# FIPS::Subdivision
|
|
6
|
+
module FIPS
|
|
7
|
+
class Subdivision
|
|
8
|
+
class << self
|
|
9
|
+
def lookup(**params)
|
|
10
|
+
fips = params.fetch(:fips, nil)
|
|
11
|
+
state = params.fetch(:state, nil)
|
|
12
|
+
county = params.fetch(:county, nil)
|
|
13
|
+
subdivision = params.fetch(:subdivision, nil)
|
|
14
|
+
|
|
15
|
+
unless fips.nil? || (fips.is_a?(String) && fips.match?(/\A(?:\d{2}|\d{3}|\d{5}|\d{10})\z/))
|
|
16
|
+
raise ArgumentError, "FIPS input must be a 2, 3, 5, or 10 digit string"
|
|
17
|
+
end
|
|
18
|
+
raise ArgumentError, "State input must be a non-empty string" unless state.nil? || (state.is_a?(String) && !state.strip.empty?)
|
|
19
|
+
raise ArgumentError, "County input must be a non-empty string" unless county.nil? || (county.is_a?(String) && !county.strip.empty?)
|
|
20
|
+
unless subdivision.nil? || (subdivision.is_a?(String) && !subdivision.strip.empty?)
|
|
21
|
+
raise ArgumentError, "Subdivision input must be a non-empty string"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
state_abbr = determine_state_abbr(fips, state)
|
|
25
|
+
raise ArgumentError, "Could not determine state abbreviation from parameters provided: #{params.inspect}" if state_abbr.nil?
|
|
26
|
+
|
|
27
|
+
location = identify_with_fips(fips, state, county, subdivision, state_abbr)
|
|
28
|
+
return location unless location.nil?
|
|
29
|
+
|
|
30
|
+
return by_name(state_abbr, county, subdivision) if %i[state county subdivision].all? { |key| !params[key].nil? }
|
|
31
|
+
|
|
32
|
+
raise ArgumentError, "cannot determine subdivision: no valid parameters provided"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def all(state:, county: nil)
|
|
36
|
+
raise ArgumentError, "State input must be a non-empty string" unless state.is_a?(String) && !state.strip.empty?
|
|
37
|
+
raise ArgumentError, "County input must be a non-empty string" unless county.nil? || (county.is_a?(String) && !county.strip.empty?)
|
|
38
|
+
|
|
39
|
+
state_abbr = FIPS::State.lookup(state: state)[:abbr]
|
|
40
|
+
raise ArgumentError, "Could not determine state abbreviation from state: #{state}" if state_abbr.nil?
|
|
41
|
+
|
|
42
|
+
county_name = normalize_name(county)
|
|
43
|
+
records = CSV.read(file_path(state_abbr))
|
|
44
|
+
records.map do |row|
|
|
45
|
+
formatted_subdivision(row)
|
|
46
|
+
end.select { |record| county.nil? || normalize_name(record[:county_name]) == county_name }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def file_path(state_abbr)
|
|
50
|
+
File.expand_path("../data/subdivision/#{state_abbr.upcase}.csv", __dir__)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def determine_state_abbr(fips, state)
|
|
56
|
+
return FIPS::State.lookup(state: state)[:abbr] unless state.nil?
|
|
57
|
+
|
|
58
|
+
FIPS::State.fips_to_abbr(fips[0, 2]) unless fips.nil? || fips.length < 2
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def identify_with_fips(fips, state, county, subdivision, state_abbr = nil)
|
|
62
|
+
return nil if fips.nil?
|
|
63
|
+
|
|
64
|
+
case fips.length
|
|
65
|
+
when 2
|
|
66
|
+
return nil if county.nil? || subdivision.nil?
|
|
67
|
+
|
|
68
|
+
by_name(FIPS::State.fips_to_abbr(fips), county, subdivision)
|
|
69
|
+
when 3
|
|
70
|
+
return nil if state.nil? || subdivision.nil?
|
|
71
|
+
|
|
72
|
+
state_abbr = FIPS::State.lookup(state: state)[:abbr]
|
|
73
|
+
by_county_fips_and_sub_name(state_abbr, fips, subdivision)
|
|
74
|
+
when 5
|
|
75
|
+
unless subdivision.nil?
|
|
76
|
+
state_abbr = FIPS::State.fips_to_abbr(fips[0, 2])
|
|
77
|
+
return by_county_fips_and_sub_name(state_abbr, fips[2, 3], subdivision)
|
|
78
|
+
end
|
|
79
|
+
return nil if state.nil?
|
|
80
|
+
|
|
81
|
+
state_abbr = FIPS::State.lookup(state: state)[:abbr]
|
|
82
|
+
by_state_and_sub_fips(state_abbr, fips)
|
|
83
|
+
when 10
|
|
84
|
+
by_fips(fips)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def by_state_and_sub_fips(state_abbr, fips)
|
|
89
|
+
subdivision = state_index(state_abbr)[:by_subdivision_fips][fips]
|
|
90
|
+
return subdivision unless subdivision.nil?
|
|
91
|
+
|
|
92
|
+
raise FIPS::NotFoundError, "No subdivision found matching fips: #{fips}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def by_fips(fips)
|
|
96
|
+
state_abbr = FIPS::State.fips_to_abbr(fips[0, 2])
|
|
97
|
+
subdivision = state_index(state_abbr)[:by_full_fips][fips]
|
|
98
|
+
return subdivision unless subdivision.nil?
|
|
99
|
+
|
|
100
|
+
raise FIPS::NotFoundError, "No subdivision found matching fips: #{fips}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def by_name(state_abbr, county, subdivision)
|
|
104
|
+
key = [normalize_name(county), normalize_name(subdivision)]
|
|
105
|
+
match = state_index(state_abbr)[:by_county_and_name][key]
|
|
106
|
+
return match unless match.nil?
|
|
107
|
+
|
|
108
|
+
raise FIPS::NotFoundError, "No subdivision found matching: #{subdivision} in #{county}"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def by_county_fips_and_sub_name(state_abbr, county_fips, subdivision)
|
|
112
|
+
key = [county_fips, normalize_name(subdivision)]
|
|
113
|
+
match = state_index(state_abbr)[:by_county_fips_and_name][key]
|
|
114
|
+
return match unless match.nil?
|
|
115
|
+
|
|
116
|
+
nil
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def state_index(state_abbr)
|
|
120
|
+
indexes = subdivision_indexes
|
|
121
|
+
indexes[state_abbr] ||= build_state_index(state_abbr)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def subdivision_indexes
|
|
125
|
+
@subdivision_indexes ||= {}
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def build_state_index(state_abbr)
|
|
129
|
+
records = CSV.read(file_path(state_abbr)).map { |row| formatted_subdivision(row) }
|
|
130
|
+
{
|
|
131
|
+
records: records,
|
|
132
|
+
by_full_fips: records.to_h { |record| [record[:fips], record] },
|
|
133
|
+
by_subdivision_fips: records.each_with_object({}) do |record, index|
|
|
134
|
+
subdivision_fips = record[:fips][5, 5]
|
|
135
|
+
index[subdivision_fips] ||= record
|
|
136
|
+
end,
|
|
137
|
+
by_county_fips_and_name: records.to_h do |record|
|
|
138
|
+
[[record[:fips][2, 3], normalize_name(record[:name])], record]
|
|
139
|
+
end,
|
|
140
|
+
by_county_and_name: records.to_h do |record|
|
|
141
|
+
[[normalize_name(record[:county_name]), normalize_name(record[:name])], record]
|
|
142
|
+
end
|
|
143
|
+
}
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def normalize_name(name)
|
|
147
|
+
name.to_s.strip.downcase
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def formatted_subdivision(row)
|
|
151
|
+
{
|
|
152
|
+
state_abbr: row[0],
|
|
153
|
+
fips: row[1] + row[2] + row[4],
|
|
154
|
+
county_name: row[3],
|
|
155
|
+
gnis: row[5],
|
|
156
|
+
name: row[6],
|
|
157
|
+
class_code: row[7],
|
|
158
|
+
status: row[8]
|
|
159
|
+
}
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
data/lib/fips/version.rb
ADDED
data/lib/fips.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zeitwerk"
|
|
4
|
+
|
|
5
|
+
module FIPS
|
|
6
|
+
loader = Zeitwerk::Loader.for_gem
|
|
7
|
+
loader.inflector.inflect("fips" => "FIPS")
|
|
8
|
+
loader.setup
|
|
9
|
+
|
|
10
|
+
class NotFoundError < StandardError
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def lookup(**params)
|
|
15
|
+
fips = params.fetch(:fips, nil)
|
|
16
|
+
state = params.fetch(:state, nil)
|
|
17
|
+
county = params.fetch(:county, nil)
|
|
18
|
+
subdivision = params.fetch(:subdivision, nil)
|
|
19
|
+
return identify_by_fips(fips, state, county, subdivision) unless fips.nil?
|
|
20
|
+
|
|
21
|
+
return FIPS::State.lookup(state: state) if !state.nil? && county.nil? && subdivision.nil?
|
|
22
|
+
return FIPS::County.lookup(state: state, county: county) if !state.nil? && !county.nil? && subdivision.nil?
|
|
23
|
+
|
|
24
|
+
if !state.nil? && !county.nil? && !subdivision.nil?
|
|
25
|
+
return FIPS::Subdivision.lookup(state: state, county: county,
|
|
26
|
+
subdivision: subdivision)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
raise ArgumentError, "Insufficient parameters to identify a state, county, or subdivision: #{params.inspect}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def identify_by_fips(fips, state, county, subdivision)
|
|
35
|
+
raise ArgumentError, "FIPS input must be a string" unless fips.is_a?(String)
|
|
36
|
+
|
|
37
|
+
case fips.length
|
|
38
|
+
when 2
|
|
39
|
+
return FIPS::Subdivision.lookup(fips: fips, county: county, subdivision: subdivision) if !county.nil? && !subdivision.nil?
|
|
40
|
+
return FIPS::County.lookup(fips: fips, county: county) if !county.nil? && subdivision.nil?
|
|
41
|
+
unless county.nil? && subdivision.nil?
|
|
42
|
+
raise ArgumentError, "A 2-digit FIPS code requires both county and subdivision names for subdivision lookup"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
FIPS::State.lookup(fips: fips)
|
|
46
|
+
when 3
|
|
47
|
+
return FIPS::Subdivision.lookup(fips: fips, state: state, subdivision: subdivision) if !state.nil? && !subdivision.nil?
|
|
48
|
+
unless !state.nil? && county.nil? && subdivision.nil?
|
|
49
|
+
raise ArgumentError, "A 3-digit FIPS code requires a state for county lookup, or state and subdivision for subdivision lookup"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
FIPS::County.lookup(fips: fips, state: state)
|
|
53
|
+
when 5
|
|
54
|
+
return FIPS::Subdivision.lookup(fips: fips, subdivision: subdivision) unless subdivision.nil?
|
|
55
|
+
return FIPS::Subdivision.lookup(fips: fips, state: state) if !state.nil? && county.nil?
|
|
56
|
+
unless state.nil? && county.nil? && subdivision.nil?
|
|
57
|
+
raise ArgumentError, "A 5-digit FIPS code accepts either state for subdivision FIPS or subdivision name for county FIPS"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
FIPS::County.lookup(fips: fips)
|
|
61
|
+
when 10
|
|
62
|
+
FIPS::Subdivision.lookup(fips: fips)
|
|
63
|
+
else
|
|
64
|
+
raise ArgumentError, "FIPS code (#{fips}) must identify a state, county, or subdivision"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/sig/fips.rbs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module FIPS
|
|
2
|
+
VERSION: String
|
|
3
|
+
|
|
4
|
+
type state_record = {
|
|
5
|
+
fips: String,
|
|
6
|
+
abbr: String,
|
|
7
|
+
name: String,
|
|
8
|
+
ansi: String
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type county_record = {
|
|
12
|
+
state_abbr: String,
|
|
13
|
+
fips: String,
|
|
14
|
+
gnis: String,
|
|
15
|
+
name: String,
|
|
16
|
+
class_code: String,
|
|
17
|
+
status: String
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type subdivision_record = {
|
|
21
|
+
state_abbr: String,
|
|
22
|
+
fips: String,
|
|
23
|
+
county_name: String,
|
|
24
|
+
gnis: String,
|
|
25
|
+
name: String,
|
|
26
|
+
class_code: String,
|
|
27
|
+
status: String
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type lookup_record = state_record | county_record | subdivision_record
|
|
31
|
+
class NotFoundError < StandardError
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.lookup: (?fips: String?, ?state: String?, ?county: String?, ?subdivision: String?) -> lookup_record
|
|
35
|
+
|
|
36
|
+
class State
|
|
37
|
+
def self.lookup: (?fips: String?, ?state: String?) -> state_record
|
|
38
|
+
def self.all: () -> Array[state_record]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class County
|
|
42
|
+
def self.lookup: (?fips: String?, ?state: String?, ?county: String?) -> county_record
|
|
43
|
+
def self.all: (state: String state) -> Array[county_record]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class Subdivision
|
|
47
|
+
def self.lookup: (?fips: String?, ?state: String?, ?county: String?, ?subdivision: String?) -> subdivision_record
|
|
48
|
+
def self.all: (state: String state, ?county: String?) -> Array[subdivision_record]
|
|
49
|
+
end
|
|
50
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fips_lookup
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: '0.4'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Erik Barroso
|
|
@@ -23,6 +23,20 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '3.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: zeitwerk
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.8'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.8'
|
|
26
40
|
- !ruby/object:Gem::Dependency
|
|
27
41
|
name: irb
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -51,6 +65,20 @@ dependencies:
|
|
|
51
65
|
- - ">="
|
|
52
66
|
- !ruby/object:Gem::Version
|
|
53
67
|
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: benchmark
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0.2'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0.2'
|
|
54
82
|
- !ruby/object:Gem::Dependency
|
|
55
83
|
name: rake
|
|
56
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -222,16 +250,17 @@ files:
|
|
|
222
250
|
- lib/data/subdivision/WI.csv
|
|
223
251
|
- lib/data/subdivision/WV.csv
|
|
224
252
|
- lib/data/subdivision/WY.csv
|
|
225
|
-
- lib/
|
|
226
|
-
- lib/
|
|
227
|
-
- lib/
|
|
228
|
-
- lib/
|
|
229
|
-
- lib/
|
|
230
|
-
- sig/
|
|
253
|
+
- lib/fips.rb
|
|
254
|
+
- lib/fips/county.rb
|
|
255
|
+
- lib/fips/state.rb
|
|
256
|
+
- lib/fips/subdivision.rb
|
|
257
|
+
- lib/fips/version.rb
|
|
258
|
+
- sig/fips.rbs
|
|
231
259
|
homepage: https://github.com/3barroso/fips_lookup
|
|
232
260
|
licenses:
|
|
233
261
|
- MIT
|
|
234
|
-
metadata:
|
|
262
|
+
metadata:
|
|
263
|
+
rubygems_mfa_required: 'true'
|
|
235
264
|
rdoc_options: []
|
|
236
265
|
require_paths:
|
|
237
266
|
- lib
|
|
@@ -239,7 +268,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
239
268
|
requirements:
|
|
240
269
|
- - ">="
|
|
241
270
|
- !ruby/object:Gem::Version
|
|
242
|
-
version: '3.
|
|
271
|
+
version: '3.2'
|
|
243
272
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
244
273
|
requirements:
|
|
245
274
|
- - ">="
|
data/lib/fips_lookup/county.rb
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# County related section of FipsLookup module
|
|
4
|
-
module FipsLookup
|
|
5
|
-
class << self
|
|
6
|
-
def county(state_param:, county_param:, return_nil: false)
|
|
7
|
-
state_code = find_state_code(state_param: state_param, return_nil: return_nil)
|
|
8
|
-
return {} if state_code.nil?
|
|
9
|
-
|
|
10
|
-
lookup = [state_code, county_param.upcase]
|
|
11
|
-
@county_fips ||= {}
|
|
12
|
-
@county_fips[lookup] ||= county_lookup(state_code, county_param, return_nil)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def fips_county(fips:, return_nil: false)
|
|
16
|
-
unless fips.is_a?(String) && fips.length == 5
|
|
17
|
-
return_nil ? (return nil) : (raise StandardError, "FIPS input must be 5 digit string")
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
state_code = find_state_code(state_param: fips[0..1], return_nil: return_nil)
|
|
21
|
-
return nil if state_code.nil?
|
|
22
|
-
|
|
23
|
-
CSV.foreach(county_file(state_code: state_code)) do |county_row|
|
|
24
|
-
# state_code (AL), state fips (01), county fips (001), name (Augtauga County), county gnis(00161526), class code (H1), status (A)
|
|
25
|
-
return [county_row[3], state_code] if county_row[2] == fips[2..4]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
raise StandardError, "Could not find county with fips: #{fips[2..4]}, in: #{state_code}" unless return_nil
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def county_file(state_code:)
|
|
32
|
-
file_path = "#{File.expand_path("..", __dir__)}/data/county/#{state_code}.csv"
|
|
33
|
-
file_path if File.exist?(file_path)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
def county_lookup(state_code, county_param, return_nil)
|
|
39
|
-
upcase_param = county_param.upcase
|
|
40
|
-
CSV.foreach(county_file(state_code: state_code)) do |row|
|
|
41
|
-
return formatted_county(row) if match_county?(row, upcase_param)
|
|
42
|
-
|
|
43
|
-
# keep? Memoize as file is being read but match isn't found ~ loses lookup flexiblity in county param + increases performacne?
|
|
44
|
-
@county_fips[[row[0], row[3].upcase]] = formatted_county(row) unless @county_fips.key?([row[0], row[3].upcase])
|
|
45
|
-
end
|
|
46
|
-
return_nil ? (return {}) : (raise StandardError, "No county found matching: #{county_param}" unless return_nil)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def match_county?(row, param)
|
|
50
|
-
# row => state (AL), state fips (01), county fips (001), name (Augtauga County), county gnis (00161526), class code (H1), status (A)
|
|
51
|
-
row[3].upcase == param || row[4] == param || row[2] == param || "#{row[1]}#{row[2]}" == param
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def formatted_county(row)
|
|
55
|
-
{
|
|
56
|
-
state_code: row[0],
|
|
57
|
-
fips: (row[1] + row[2]),
|
|
58
|
-
gnis: row[4],
|
|
59
|
-
name: row[3],
|
|
60
|
-
class_code: row[5],
|
|
61
|
-
status: row[6]
|
|
62
|
-
}
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
data/lib/fips_lookup/state.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# State related section of FipsLookup module
|
|
4
|
-
module FipsLookup
|
|
5
|
-
class << self
|
|
6
|
-
def state(state_param:, return_nil: false)
|
|
7
|
-
@state_fips ||= {}
|
|
8
|
-
@state_fips[state_param] ||= state_lookup(state_param, return_nil)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def find_state_code(state_param:, return_nil: false)
|
|
12
|
-
return state_param.upcase if STATE_CODES.key?(state_param.upcase)
|
|
13
|
-
return STATE_CODES.key(state_param) if STATE_CODES.value?(state_param)
|
|
14
|
-
|
|
15
|
-
state(state_param: state_param, return_nil: return_nil)[:code]
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def state_file
|
|
19
|
-
"#{File.expand_path("..", __dir__)}/data/state.csv"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
def state_lookup(state_param, return_nil = false)
|
|
25
|
-
upstate_param = state_param.upcase
|
|
26
|
-
CSV.foreach(state_file) do |state_row|
|
|
27
|
-
return formatted_state(state_row) if state_match_row?(state_row, upstate_param)
|
|
28
|
-
end
|
|
29
|
-
return_nil ? (return {}) : (raise StandardError, "No state found matching: #{state_param}")
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def state_match_row?(row, param)
|
|
33
|
-
# row => state fips (01), state code (AL), state name (Alabama), ansi (01779775)
|
|
34
|
-
row[0] == param || row[1] == param || row[2].upcase == param || row[3] == param
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def formatted_state(row)
|
|
38
|
-
{
|
|
39
|
-
fips: row[0],
|
|
40
|
-
code: row[1],
|
|
41
|
-
name: row[2],
|
|
42
|
-
ansi: row[3]
|
|
43
|
-
}
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Subdivision related section of FIPS module
|
|
4
|
-
module FipsLookup
|
|
5
|
-
class << self
|
|
6
|
-
def subdivision(state_param:, subdivision_param:, return_nil: false)
|
|
7
|
-
state_code = find_state_code(state_param: state_param, return_nil: return_nil)
|
|
8
|
-
return {} if state_code.nil?
|
|
9
|
-
|
|
10
|
-
lookup = [state_code, subdivision_param.upcase]
|
|
11
|
-
@subdivision_fips ||= {}
|
|
12
|
-
@subdivision_fips[lookup] ||= subdivision_lookup(state_code, subdivision_param, return_nil)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def subdivision_file(state_code:)
|
|
16
|
-
file_path = "#{File.expand_path("..", __dir__)}/data/subdivision/#{state_code}.csv"
|
|
17
|
-
file_path if File.exist?(file_path)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def subdivision_lookup(state_code, subdivision_param, return_nil)
|
|
23
|
-
upcase_param = subdivision_param.upcase
|
|
24
|
-
CSV.foreach(subdivision_file(state_code: state_code)) do |subdivision_row|
|
|
25
|
-
return formatted_subdivision(subdivision_row) if match_subdivision?(subdivision_row, upcase_param)
|
|
26
|
-
end
|
|
27
|
-
return_nil ? (return {}) : (raise StandardError, "No subdivision found matching: #{subdivision_param}" unless return_nil)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def match_subdivision?(row, param)
|
|
31
|
-
# row => state_code (AL), state fips (01), county fips (001), county name (Augtauga County)
|
|
32
|
-
# row => subdivision name(Autaugaville CCD), class code (Z5), status (S)
|
|
33
|
-
row[6].upcase == param || row[4] == param || row[5] == param
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def formatted_subdivision(row)
|
|
37
|
-
{
|
|
38
|
-
state_code: row[0],
|
|
39
|
-
fips: row[1] + row[2] + row[4],
|
|
40
|
-
county_name: row[3],
|
|
41
|
-
gnis: row[5],
|
|
42
|
-
name: row[6],
|
|
43
|
-
class_code: row[7],
|
|
44
|
-
status: row[8]
|
|
45
|
-
}
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
data/lib/fips_lookup/version.rb
DELETED
data/lib/fips_lookup.rb
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "csv"
|
|
4
|
-
require_relative "fips_lookup/version"
|
|
5
|
-
require_relative "fips_lookup/subdivision"
|
|
6
|
-
require_relative "fips_lookup/county"
|
|
7
|
-
require_relative "fips_lookup/state"
|
|
8
|
-
|
|
9
|
-
# parent section of module defining constants, requiring relative worker methods
|
|
10
|
-
module FipsLookup
|
|
11
|
-
STATE_CODES = { "AL" => "01", "AK" => "02", "AZ" => "04", "AR" => "05", "CA" => "06", "CO" => "08",
|
|
12
|
-
"CT" => "09", "DE" => "10", "DC" => "11", "FL" => "12", "GA" => "13", "HI" => "15",
|
|
13
|
-
"ID" => "16", "IL" => "17", "IN" => "18", "IA" => "19", "KS" => "20", "KY" => "21",
|
|
14
|
-
"LA" => "22", "ME" => "23", "MD" => "24", "MA" => "25", "MI" => "26", "MN" => "27",
|
|
15
|
-
"MS" => "28", "MO" => "29", "MT" => "30", "NE" => "31", "NV" => "32", "NH" => "33",
|
|
16
|
-
"NJ" => "34", "NM" => "35", "NY" => "36", "NC" => "37", "ND" => "38", "OH" => "39",
|
|
17
|
-
"OK" => "40", "OR" => "41", "PA" => "42", "RI" => "44", "SC" => "45", "SD" => "46",
|
|
18
|
-
"TN" => "47", "TX" => "48", "UT" => "49", "VT" => "50", "VA" => "51", "WA" => "53",
|
|
19
|
-
"WV" => "54", "WI" => "55", "WY" => "56", "AS" => "60", "GU" => "66", "MP" => "69",
|
|
20
|
-
"PR" => "72", "UM" => "74", "VI" => "78" }.freeze
|
|
21
|
-
|
|
22
|
-
class << self
|
|
23
|
-
attr_accessor :county_fips, :state_fips, :subdivision_fips
|
|
24
|
-
end
|
|
25
|
-
end
|
data/sig/fips_lookup.rbs
DELETED