us_geo 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +75 -0
- data/README.md +154 -0
- data/Rakefile +18 -0
- data/db/migrate/20190221054200_create_regions.rb +16 -0
- data/db/migrate/20190221054300_create_divisions.rb +17 -0
- data/db/migrate/20190221054400_create_states.rb +20 -0
- data/db/migrate/20190221054490_create_designated_market_areas.rb +16 -0
- data/db/migrate/20190221054500_create_combined_statistical_areas.rb +20 -0
- data/db/migrate/20190221054600_create_core_based_statistical_areas.rb +24 -0
- data/db/migrate/20190221054650_create_metropolitan_divisions.rb +21 -0
- data/db/migrate/20190221054700_create_counties.rb +34 -0
- data/db/migrate/20190221054800_create_zctas.rb +23 -0
- data/db/migrate/20190221054900_create_zcta_counties.rb +22 -0
- data/db/migrate/20190221055000_create_urban_areas.rb +25 -0
- data/db/migrate/20190221055100_create_urban_area_counties.rb +22 -0
- data/db/migrate/20190221055200_create_zcta_urban_areas.rb +22 -0
- data/db/migrate/20190221060000_create_places.rb +28 -0
- data/db/migrate/20190221061000_create_place_counties.rb +18 -0
- data/db/migrate/20190221062000_create_zcta_places.rb +22 -0
- data/db/migrate/20190221063000_create_county_subdivisions.rb +25 -0
- data/lib/tasks/us_geo/us_geo.rake +43 -0
- data/lib/us_geo/base_record.rb +104 -0
- data/lib/us_geo/combined_statistical_area.rb +40 -0
- data/lib/us_geo/core_based_statistical_area.rb +57 -0
- data/lib/us_geo/county.rb +89 -0
- data/lib/us_geo/county_subdivision.rb +46 -0
- data/lib/us_geo/demographics.rb +25 -0
- data/lib/us_geo/designated_market_area.rb +30 -0
- data/lib/us_geo/division.rb +29 -0
- data/lib/us_geo/engine.rb +6 -0
- data/lib/us_geo/metropolitan_area.rb +18 -0
- data/lib/us_geo/metropolitan_division.rb +42 -0
- data/lib/us_geo/micropolitan_area.rb +18 -0
- data/lib/us_geo/place.rb +61 -0
- data/lib/us_geo/place_county.rb +28 -0
- data/lib/us_geo/region.rb +28 -0
- data/lib/us_geo/state.rb +56 -0
- data/lib/us_geo/urban_area.rb +66 -0
- data/lib/us_geo/urban_area_county.rb +68 -0
- data/lib/us_geo/urban_cluster.rb +18 -0
- data/lib/us_geo/urbanized_area.rb +18 -0
- data/lib/us_geo/version.rb +5 -0
- data/lib/us_geo/zcta.rb +63 -0
- data/lib/us_geo/zcta_county.rb +68 -0
- data/lib/us_geo/zcta_place.rb +68 -0
- data/lib/us_geo/zcta_urban_area.rb +68 -0
- data/lib/us_geo.rb +53 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/us_geo/base_record_spec.rb +67 -0
- data/spec/us_geo/combined_statistical_area_spec.rb +33 -0
- data/spec/us_geo/core_based_statistical_area_spec.rb +56 -0
- data/spec/us_geo/county_spec.rb +130 -0
- data/spec/us_geo/county_subdivision_spec.rb +37 -0
- data/spec/us_geo/demographics_spec.rb +19 -0
- data/spec/us_geo/designated_market_area_spec.rb +29 -0
- data/spec/us_geo/division_spec.rb +37 -0
- data/spec/us_geo/metropolitan_division_spec.rb +41 -0
- data/spec/us_geo/place_county_spec.rb +39 -0
- data/spec/us_geo/place_spec.rb +71 -0
- data/spec/us_geo/region_spec.rb +36 -0
- data/spec/us_geo/state_spec.rb +70 -0
- data/spec/us_geo/urban_area_county_spec.rb +82 -0
- data/spec/us_geo/urban_area_spec.rb +98 -0
- data/spec/us_geo/zcta_county_spec.rb +82 -0
- data/spec/us_geo/zcta_place_spec.rb +82 -0
- data/spec/us_geo/zcta_spec.rb +99 -0
- data/spec/us_geo/zcta_urban_area_spec.rb +82 -0
- metadata +229 -0
data/lib/us_geo/state.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module USGeo
|
4
|
+
|
5
|
+
# U.S. state or territory.
|
6
|
+
class State < BaseRecord
|
7
|
+
|
8
|
+
STATE_TYPE = "state"
|
9
|
+
DISTRICT_TYPE = "district"
|
10
|
+
TERRITORY_TYPE = "territory"
|
11
|
+
|
12
|
+
self.primary_key = "code"
|
13
|
+
self.inheritance_column = :_type_disabled
|
14
|
+
|
15
|
+
belongs_to :region, optional: -> { territory? }, inverse_of: :states
|
16
|
+
belongs_to :division, optional: -> { territory? }, inverse_of: :states
|
17
|
+
has_many :counties, foreign_key: :state_code, inverse_of: :state
|
18
|
+
has_many :places, foreign_key: :state_code, inverse_of: :state
|
19
|
+
|
20
|
+
validates :code, length: {is: 2}
|
21
|
+
validates :fips, length: {is: 2}
|
22
|
+
validates :name, length: {maximum: 30}
|
23
|
+
validates :type, inclusion: [STATE_TYPE, DISTRICT_TYPE, TERRITORY_TYPE]
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def load!(uri = nil)
|
27
|
+
location = data_uri(uri || "states.csv")
|
28
|
+
|
29
|
+
import! do
|
30
|
+
load_data_file(location) do |row|
|
31
|
+
load_record!(code: row["Code"]) do |record|
|
32
|
+
record.name = row["Name"]
|
33
|
+
record.type = row["Type"]
|
34
|
+
record.fips = row["FIPS"]
|
35
|
+
record.region_id = row["Region ID"]
|
36
|
+
record.division_id = row["Division ID"]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def state?
|
44
|
+
type == STATE_TYPE
|
45
|
+
end
|
46
|
+
|
47
|
+
def territory?
|
48
|
+
type == TERRITORY_TYPE
|
49
|
+
end
|
50
|
+
|
51
|
+
def district?
|
52
|
+
type == DISTRICT_TYPE
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module USGeo
|
4
|
+
|
5
|
+
# Urban areas are split into either urbanized areas (population > 50,000) or urban cluster (population < 50,000).
|
6
|
+
class UrbanArea < BaseRecord
|
7
|
+
|
8
|
+
include Demographics
|
9
|
+
|
10
|
+
self.primary_key = "geoid"
|
11
|
+
self.store_full_sti_class = false
|
12
|
+
|
13
|
+
has_many :urban_area_counties, foreign_key: :urban_area_geoid, inverse_of: :urban_area, dependent: :destroy
|
14
|
+
has_many :counties, through: :urban_area_counties
|
15
|
+
belongs_to :primary_county, foreign_key: :primary_county_geoid, class_name: "USGeo::County"
|
16
|
+
|
17
|
+
has_many :zcta_urban_areas, foreign_key: :urban_area_geoid, inverse_of: :urban_area, dependent: :destroy
|
18
|
+
has_many :zctas, through: :zcta_urban_areas
|
19
|
+
|
20
|
+
validates :geoid, length: {is: 5}
|
21
|
+
validates :primary_county_geoid, length: {is: 5}
|
22
|
+
validates :name, length: {maximum: 90}
|
23
|
+
validates :short_name, length: {maximum: 60}
|
24
|
+
validates :land_area, numericality: true, presence: true
|
25
|
+
validates :water_area, numericality: true, presence: true
|
26
|
+
validates :population, numericality: {only_integer: true}, presence: true
|
27
|
+
validates :housing_units, numericality: {only_integer: true}, presence: true
|
28
|
+
|
29
|
+
delegate :core_based_statistical_area, :designated_market_area, :state, :state_code, :time_zone, to: :primary_county, allow_nil: true
|
30
|
+
|
31
|
+
before_save do
|
32
|
+
self.short_name = name.sub(" Urbanized Area", "").sub(" Urban Cluster", "") if name
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def load!(uri = nil)
|
37
|
+
location = data_uri(uri || "urban_areas.csv")
|
38
|
+
|
39
|
+
import! do
|
40
|
+
load_data_file(location) do |row|
|
41
|
+
load_record!(geoid: row["GEOID"]) do |record|
|
42
|
+
record.type = (row["Population"].to_i >= 50_000 ? "UrbanizedArea" : "UrbanCluster")
|
43
|
+
record.name = row["Name"]
|
44
|
+
record.primary_county_geoid = row["Primary County"]
|
45
|
+
record.population = row["Population"]
|
46
|
+
record.housing_units = row["Housing Units"]
|
47
|
+
record.land_area = area_meters_to_miles(row["Land Area"])
|
48
|
+
record.water_area = area_meters_to_miles(row["Water Area"])
|
49
|
+
record.lat = row["Latitude"]
|
50
|
+
record.lng = row["Longitude"]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def urbanized?
|
58
|
+
raise NotImplementedError
|
59
|
+
end
|
60
|
+
|
61
|
+
def cluster?
|
62
|
+
raise NotImplementedError
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module USGeo
|
4
|
+
|
5
|
+
# Mapping of urban areas to counties they overlap with.
|
6
|
+
class UrbanAreaCounty < BaseRecord
|
7
|
+
|
8
|
+
include Demographics
|
9
|
+
|
10
|
+
belongs_to :county, foreign_key: :county_geoid, inverse_of: :urban_area_counties
|
11
|
+
belongs_to :urban_area, foreign_key: :urban_area_geoid, inverse_of: :urban_area_counties
|
12
|
+
|
13
|
+
validates :county_geoid, length: {is: 5}
|
14
|
+
validates :urban_area_geoid, length: {is: 5}
|
15
|
+
validates :land_area, numericality: true, presence: true
|
16
|
+
validates :water_area, numericality: true, presence: true
|
17
|
+
validates :population, numericality: {only_integer: true}, presence: true
|
18
|
+
validates :housing_units, numericality: {only_integer: true}, presence: true
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def load!(uri = nil)
|
22
|
+
location = data_uri(uri || "urban_area_counties.csv")
|
23
|
+
|
24
|
+
import! do
|
25
|
+
load_data_file(location) do |row|
|
26
|
+
load_record!(urban_area_geoid: row["Urban Area GEOID"], county_geoid: row["County GEOID"]) do |record|
|
27
|
+
record.population = row["Population"]
|
28
|
+
record.housing_units = row["Housing Units"]
|
29
|
+
record.land_area = area_meters_to_miles(row["Land Area"])
|
30
|
+
record.water_area = area_meters_to_miles(row["Water Area"])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Percentage of the urban area population.
|
38
|
+
def percent_urban_area_population
|
39
|
+
population.to_f / urban_area.population.to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
# Percentage of the urban area land area.
|
43
|
+
def percent_urban_area_land_area
|
44
|
+
land_area / urban_area.land_area
|
45
|
+
end
|
46
|
+
|
47
|
+
# Percentage of the urban area total area.
|
48
|
+
def percent_urban_area_total_area
|
49
|
+
total_area / urban_area.total_area
|
50
|
+
end
|
51
|
+
|
52
|
+
# Percentage of the county population.
|
53
|
+
def percent_county_population
|
54
|
+
population.to_f / county.population.to_f
|
55
|
+
end
|
56
|
+
|
57
|
+
# Percentage of the county land area.
|
58
|
+
def percent_county_land_area
|
59
|
+
land_area / county.land_area
|
60
|
+
end
|
61
|
+
|
62
|
+
# Percentage of the county total area.
|
63
|
+
def percent_county_total_area
|
64
|
+
total_area / county.total_area
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/lib/us_geo/zcta.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module USGeo
|
4
|
+
|
5
|
+
# ZIP code tabulation area. These roughly map to U.S. Postal service ZIP codes, but
|
6
|
+
# are designed for geographic and demographic purposes instead of mail routing. In particular
|
7
|
+
# certain optimizations that the Postal Service makes to optimize mail routing are
|
8
|
+
# omitted or smoothed over (i.e. ZIP codes mapping to a single building, one-off enclaves, etc.)
|
9
|
+
#
|
10
|
+
# ZCTA's can span counties, but the one with the majority of the residents is identified
|
11
|
+
# as the primary county for when a single county is required.
|
12
|
+
#
|
13
|
+
# ZCTA's can span urbanized area, but the one with the majority of the residents is identified
|
14
|
+
# as the primary urbanized area for when a single area is required.
|
15
|
+
class Zcta < BaseRecord
|
16
|
+
|
17
|
+
include Demographics
|
18
|
+
|
19
|
+
self.table_name = "us_geo_zctas"
|
20
|
+
self.primary_key = "zipcode"
|
21
|
+
|
22
|
+
has_many :zcta_counties, foreign_key: :zipcode, inverse_of: :zcta, dependent: :destroy
|
23
|
+
has_many :counties, through: :zcta_counties
|
24
|
+
belongs_to :primary_county, foreign_key: :primary_county_geoid, class_name: "USGeo::County"
|
25
|
+
|
26
|
+
has_many :zcta_urban_areas, foreign_key: :zipcode, inverse_of: :zcta, dependent: :destroy
|
27
|
+
has_many :urban_areas, through: :zcta_urban_areas
|
28
|
+
belongs_to :primary_urban_area, foreign_key: :primary_urban_area_geoid, class_name: "USGeo::UrbanArea"
|
29
|
+
|
30
|
+
has_many :zcta_places, foreign_key: :zipcode, inverse_of: :zcta, dependent: :destroy
|
31
|
+
has_many :places, through: :zcta_places
|
32
|
+
|
33
|
+
validates :zipcode, length: {is: 5}
|
34
|
+
validates :land_area, numericality: true, presence: true
|
35
|
+
validates :water_area, numericality: true, presence: true
|
36
|
+
validates :population, numericality: {only_integer: true}, presence: true
|
37
|
+
validates :housing_units, numericality: {only_integer: true}, presence: true
|
38
|
+
|
39
|
+
delegate :core_based_statistical_area, :designated_market_area, :state, :state_code, :time_zone, to: :primary_county, allow_nil: true
|
40
|
+
|
41
|
+
class << self
|
42
|
+
def load!(uri = nil)
|
43
|
+
location = data_uri(uri || "zctas.csv")
|
44
|
+
|
45
|
+
import! do
|
46
|
+
load_data_file(location) do |row|
|
47
|
+
load_record!(zipcode: row["ZCTA5"]) do |record|
|
48
|
+
record.primary_county_geoid = row["Primary County"]
|
49
|
+
record.primary_urban_area_geoid = row["Primary Urban Area"]
|
50
|
+
record.population = row["Population"]
|
51
|
+
record.housing_units = row["Housing Units"]
|
52
|
+
record.land_area = area_meters_to_miles(row["Land Area"])
|
53
|
+
record.water_area = area_meters_to_miles(row["Water Area"])
|
54
|
+
record.lat = row["Latitude"]
|
55
|
+
record.lng = row["Longitude"]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module USGeo
|
4
|
+
|
5
|
+
# Mapping of ZCTA's to counties they overlap with.
|
6
|
+
class ZctaCounty < BaseRecord
|
7
|
+
|
8
|
+
include Demographics
|
9
|
+
|
10
|
+
belongs_to :zcta, foreign_key: :zipcode, inverse_of: :zcta_counties
|
11
|
+
belongs_to :county, foreign_key: :county_geoid, inverse_of: :zcta_counties
|
12
|
+
|
13
|
+
validates :zipcode, length: {is: 5}
|
14
|
+
validates :county_geoid, length: {is: 5}
|
15
|
+
validates :land_area, numericality: true, presence: true
|
16
|
+
validates :water_area, numericality: true, presence: true
|
17
|
+
validates :population, numericality: {only_integer: true}, presence: true
|
18
|
+
validates :housing_units, numericality: {only_integer: true}, presence: true
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def load!(uri = nil)
|
22
|
+
location = data_uri(uri || "zcta_counties.csv")
|
23
|
+
|
24
|
+
import! do
|
25
|
+
load_data_file(location) do |row|
|
26
|
+
load_record!(zipcode: row["ZCTA5"], county_geoid: row["GEOID"]) do |record|
|
27
|
+
record.population = row["Population"]
|
28
|
+
record.housing_units = row["Housing Units"]
|
29
|
+
record.land_area = area_meters_to_miles(row["Land Area"])
|
30
|
+
record.water_area = area_meters_to_miles(row["Water Area"])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Percentage of the ZCTA population.
|
38
|
+
def percent_zcta_population
|
39
|
+
population.to_f / zcta.population.to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
# Percentage of the ZCTA land area.
|
43
|
+
def percent_zcta_land_area
|
44
|
+
land_area / zcta.land_area
|
45
|
+
end
|
46
|
+
|
47
|
+
# Percentage of the ZCTA total area.
|
48
|
+
def percent_zcta_total_area
|
49
|
+
total_area / zcta.total_area
|
50
|
+
end
|
51
|
+
|
52
|
+
# Percentage of the county population.
|
53
|
+
def percent_county_population
|
54
|
+
population.to_f / county.population.to_f
|
55
|
+
end
|
56
|
+
|
57
|
+
# Percentage of the county land area.
|
58
|
+
def percent_county_land_area
|
59
|
+
land_area / county.land_area
|
60
|
+
end
|
61
|
+
|
62
|
+
# Percentage of the county total area.
|
63
|
+
def percent_county_total_area
|
64
|
+
total_area / county.total_area
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module USGeo
|
4
|
+
|
5
|
+
# Mapping of ZCTA's to urban areas they overlap with.
|
6
|
+
class ZctaPlace < BaseRecord
|
7
|
+
|
8
|
+
include Demographics
|
9
|
+
|
10
|
+
belongs_to :zcta, foreign_key: :zipcode, inverse_of: :zcta_places
|
11
|
+
belongs_to :place, foreign_key: :place_geoid, inverse_of: :zcta_places
|
12
|
+
|
13
|
+
validates :zipcode, length: {is: 5}
|
14
|
+
validates :place_geoid, length: {is: 7}
|
15
|
+
validates :land_area, numericality: true, presence: true
|
16
|
+
validates :water_area, numericality: true, presence: true
|
17
|
+
validates :population, numericality: {only_integer: true}, presence: true
|
18
|
+
validates :housing_units, numericality: {only_integer: true}, presence: true
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def load!(uri = nil)
|
22
|
+
location = data_uri(uri || "zcta_places.csv")
|
23
|
+
|
24
|
+
import! do
|
25
|
+
load_data_file(location) do |row|
|
26
|
+
load_record!(zipcode: row["ZCTA5"], place_geoid: row["Place GEOID"]) do |record|
|
27
|
+
record.population = row["Population"]
|
28
|
+
record.housing_units = row["Housing Units"]
|
29
|
+
record.land_area = area_meters_to_miles(row["Land Area"])
|
30
|
+
record.water_area = area_meters_to_miles(row["Water Area"])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Percentage of the ZCTA population.
|
38
|
+
def percent_zcta_population
|
39
|
+
population.to_f / zcta.population.to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
# Percentage of the ZCTA land area.
|
43
|
+
def percent_zcta_land_area
|
44
|
+
land_area / zcta.land_area
|
45
|
+
end
|
46
|
+
|
47
|
+
# Percentage of the ZCTA total area.
|
48
|
+
def percent_zcta_total_area
|
49
|
+
total_area / zcta.total_area
|
50
|
+
end
|
51
|
+
|
52
|
+
# Percentage of the place population.
|
53
|
+
def percent_place_population
|
54
|
+
population.to_f / place.population.to_f
|
55
|
+
end
|
56
|
+
|
57
|
+
# Percentage of the place land area.
|
58
|
+
def percent_place_land_area
|
59
|
+
land_area / place.land_area
|
60
|
+
end
|
61
|
+
|
62
|
+
# Percentage of the place total area..
|
63
|
+
def percent_place_total_area
|
64
|
+
total_area / place.total_area
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module USGeo
|
4
|
+
|
5
|
+
# Mapping of ZCTA's to urban areas they overlap with.
|
6
|
+
class ZctaUrbanArea < BaseRecord
|
7
|
+
|
8
|
+
include Demographics
|
9
|
+
|
10
|
+
belongs_to :zcta, foreign_key: :zipcode, inverse_of: :zcta_urban_areas
|
11
|
+
belongs_to :urban_area, foreign_key: :urban_area_geoid, inverse_of: :zcta_urban_areas
|
12
|
+
|
13
|
+
validates :zipcode, length: {is: 5}
|
14
|
+
validates :urban_area_geoid, length: {is: 5}
|
15
|
+
validates :land_area, numericality: true, presence: true
|
16
|
+
validates :water_area, numericality: true, presence: true
|
17
|
+
validates :population, numericality: {only_integer: true}, presence: true
|
18
|
+
validates :housing_units, numericality: {only_integer: true}, presence: true
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def load!(uri = nil)
|
22
|
+
location = data_uri(uri || "zcta_urban_areas.csv")
|
23
|
+
|
24
|
+
import! do
|
25
|
+
load_data_file(location) do |row|
|
26
|
+
load_record!(zipcode: row["ZCTA5"], urban_area_geoid: row["Urban Area GEOID"]) do |record|
|
27
|
+
record.population = row["Population"]
|
28
|
+
record.housing_units = row["Housing Units"]
|
29
|
+
record.land_area = area_meters_to_miles(row["Land Area"])
|
30
|
+
record.water_area = area_meters_to_miles(row["Water Area"])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Percentage of the ZCTA population.
|
38
|
+
def percent_zcta_population
|
39
|
+
population.to_f / zcta.population.to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
# Percentage of the ZCTA land area.
|
43
|
+
def percent_zcta_land_area
|
44
|
+
land_area / zcta.land_area
|
45
|
+
end
|
46
|
+
|
47
|
+
# Percentage of the ZCTA total area.
|
48
|
+
def percent_zcta_total_area
|
49
|
+
total_area / zcta.total_area
|
50
|
+
end
|
51
|
+
|
52
|
+
# Percentage of the urban area population.
|
53
|
+
def percent_urban_area_population
|
54
|
+
population.to_f / urban_area.population.to_f
|
55
|
+
end
|
56
|
+
|
57
|
+
# Percentage of the urban area land area.
|
58
|
+
def percent_urban_area_land_area
|
59
|
+
land_area / urban_area.land_area
|
60
|
+
end
|
61
|
+
|
62
|
+
# Percentage of the urban area total area.
|
63
|
+
def percent_urban_area_total_area
|
64
|
+
total_area / urban_area.total_area
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/lib/us_geo.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record"
|
4
|
+
|
5
|
+
require_relative 'us_geo/version'
|
6
|
+
require_relative 'us_geo/demographics'
|
7
|
+
require_relative 'us_geo/base_record'
|
8
|
+
require_relative 'us_geo/region'
|
9
|
+
require_relative 'us_geo/division'
|
10
|
+
require_relative 'us_geo/state'
|
11
|
+
require_relative 'us_geo/designated_market_area'
|
12
|
+
require_relative 'us_geo/combined_statistical_area'
|
13
|
+
require_relative 'us_geo/core_based_statistical_area'
|
14
|
+
require_relative 'us_geo/metropolitan_area'
|
15
|
+
require_relative 'us_geo/micropolitan_area'
|
16
|
+
require_relative 'us_geo/metropolitan_division'
|
17
|
+
require_relative 'us_geo/county'
|
18
|
+
require_relative 'us_geo/county_subdivision'
|
19
|
+
require_relative 'us_geo/urban_area'
|
20
|
+
require_relative 'us_geo/urbanized_area'
|
21
|
+
require_relative 'us_geo/urban_cluster'
|
22
|
+
require_relative 'us_geo/urban_area_county'
|
23
|
+
require_relative 'us_geo/place'
|
24
|
+
require_relative 'us_geo/place_county'
|
25
|
+
require_relative 'us_geo/zcta'
|
26
|
+
require_relative 'us_geo/zcta_urban_area'
|
27
|
+
require_relative 'us_geo/zcta_county'
|
28
|
+
require_relative 'us_geo/zcta_place'
|
29
|
+
|
30
|
+
require_relative 'us_geo/engine' if defined?(::Rails::Engine)
|
31
|
+
|
32
|
+
module USGeo
|
33
|
+
|
34
|
+
BASE_DATA_URI = "https://raw.githubusercontent.com/bdurand/us_geo/master/data/dist"
|
35
|
+
|
36
|
+
class << self
|
37
|
+
# The root URI as a string of where to find the data files. This can be a URL
|
38
|
+
# or a file system path. The default is to load the data from files hosted with
|
39
|
+
# the project code on GitHub.
|
40
|
+
def base_data_uri
|
41
|
+
if defined?(@base_data_uri) && @base_data_uri
|
42
|
+
@base_data_uri
|
43
|
+
else
|
44
|
+
BASE_DATA_URI
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def base_data_uri=(value)
|
49
|
+
@base_data_uri = (value.nil? ? nil : value.to_s)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require_relative "../lib/us_geo"
|
3
|
+
|
4
|
+
require "active_record"
|
5
|
+
require "webmock/rspec"
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
# Enable flags like --only-failures and --next-failure
|
9
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
10
|
+
|
11
|
+
config.expect_with :rspec do |c|
|
12
|
+
c.syntax = :expect
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ActiveRecord::Base.establish_connection("adapter" => "sqlite3", "database" => ":memory:")
|
17
|
+
|
18
|
+
Dir.glob(File.expand_path("../db/migrate/*.rb", __dir__)).each do |path|
|
19
|
+
require(path)
|
20
|
+
class_name = File.basename(path).sub(/\.rb/, '').split('_', 2).last.camelcase
|
21
|
+
class_name.constantize.migrate(:up)
|
22
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe USGeo::BaseRecord do
|
4
|
+
|
5
|
+
describe "status" do
|
6
|
+
it "should be marked as imported" do
|
7
|
+
record = USGeo::County.new(status: 1)
|
8
|
+
expect(record.imported?).to eq true
|
9
|
+
expect(record.removed?).to eq false
|
10
|
+
expect(record.manual?).to eq false
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be marked as removed" do
|
14
|
+
record = USGeo::County.new(status: -1)
|
15
|
+
expect(record.imported?).to eq false
|
16
|
+
expect(record.removed?).to eq true
|
17
|
+
expect(record.manual?).to eq false
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should be marked as manual" do
|
21
|
+
record = USGeo::County.new(status: 0)
|
22
|
+
expect(record.imported?).to eq false
|
23
|
+
expect(record.removed?).to eq false
|
24
|
+
expect(record.manual?).to eq true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "load!" do
|
29
|
+
after { USGeo::Region.delete_all }
|
30
|
+
|
31
|
+
it "should mark previously imported records as removed" do
|
32
|
+
data = File.read(File.expand_path("../../data/dist/divisions.csv", __dir__))
|
33
|
+
stub_request(:get, "#{USGeo.base_data_uri}/divisions.csv").to_return(body: data, headers: {"Content-Type": "text/csv; charset=UTF-8"})
|
34
|
+
|
35
|
+
midwest = USGeo::Region.new
|
36
|
+
midwest.id = 2
|
37
|
+
midwest.name = "Northwest Territory"
|
38
|
+
midwest.status = USGeo::Region::STATUS_MANUAL
|
39
|
+
midwest.save!
|
40
|
+
|
41
|
+
other = USGeo::Region.new
|
42
|
+
other.id = 90
|
43
|
+
other.name = "Other"
|
44
|
+
other.status = USGeo::Region::STATUS_IMPORTED
|
45
|
+
other.save!
|
46
|
+
|
47
|
+
manual = USGeo::Region.new
|
48
|
+
manual.id = 80
|
49
|
+
manual.name = "Manual"
|
50
|
+
manual.status = USGeo::Region::STATUS_MANUAL
|
51
|
+
manual.save!
|
52
|
+
|
53
|
+
sleep(1)
|
54
|
+
USGeo::Region.load!
|
55
|
+
|
56
|
+
midwest.reload
|
57
|
+
other.reload
|
58
|
+
manual.reload
|
59
|
+
|
60
|
+
expect(midwest.status).to eq USGeo::Region::STATUS_IMPORTED
|
61
|
+
expect(midwest.name).to eq "Midwest"
|
62
|
+
expect(other.status).to eq USGeo::Region::STATUS_REMOVED
|
63
|
+
expect(manual.status).to eq USGeo::Region::STATUS_MANUAL
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe USGeo::CombinedStatisticalArea do
|
4
|
+
|
5
|
+
describe "associations" do
|
6
|
+
it "should have core_based_statistical_areas" do
|
7
|
+
csa = USGeo::CombinedStatisticalArea.new
|
8
|
+
csa.geoid = "001"
|
9
|
+
expect{ csa.core_based_statistical_areas }.to_not raise_error
|
10
|
+
expect(csa.core_based_statistical_areas.build).to be_a(USGeo::CoreBasedStatisticalArea)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "load" do
|
15
|
+
after { USGeo::CombinedStatisticalArea.delete_all }
|
16
|
+
|
17
|
+
it "should load the fixture data" do
|
18
|
+
data = File.read(File.expand_path("../../data/dist/combined_statistical_areas.csv", __dir__))
|
19
|
+
stub_request(:get, "#{USGeo.base_data_uri}/combined_statistical_areas.csv").to_return(body: data, headers: {"Content-Type": "text/csv; charset=UTF-8"})
|
20
|
+
USGeo::CombinedStatisticalArea.load!
|
21
|
+
expect(USGeo::CombinedStatisticalArea.imported.count).to be > 150
|
22
|
+
expect(USGeo::CombinedStatisticalArea.removed.count).to eq 0
|
23
|
+
|
24
|
+
chicagoland = USGeo::CombinedStatisticalArea.find("176")
|
25
|
+
expect(chicagoland.name).to eq "Chicago-Naperville, IL-IN-WI"
|
26
|
+
expect(chicagoland.population).to be > 8_000_000
|
27
|
+
expect(chicagoland.housing_units).to be > 3_000_000
|
28
|
+
expect(chicagoland.land_area.round).to eq 10636
|
29
|
+
expect(chicagoland.water_area.round).to eq 2431
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|