us_geo 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/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
|