us_geo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +5 -0
  3. data/Gemfile.lock +75 -0
  4. data/README.md +154 -0
  5. data/Rakefile +18 -0
  6. data/db/migrate/20190221054200_create_regions.rb +16 -0
  7. data/db/migrate/20190221054300_create_divisions.rb +17 -0
  8. data/db/migrate/20190221054400_create_states.rb +20 -0
  9. data/db/migrate/20190221054490_create_designated_market_areas.rb +16 -0
  10. data/db/migrate/20190221054500_create_combined_statistical_areas.rb +20 -0
  11. data/db/migrate/20190221054600_create_core_based_statistical_areas.rb +24 -0
  12. data/db/migrate/20190221054650_create_metropolitan_divisions.rb +21 -0
  13. data/db/migrate/20190221054700_create_counties.rb +34 -0
  14. data/db/migrate/20190221054800_create_zctas.rb +23 -0
  15. data/db/migrate/20190221054900_create_zcta_counties.rb +22 -0
  16. data/db/migrate/20190221055000_create_urban_areas.rb +25 -0
  17. data/db/migrate/20190221055100_create_urban_area_counties.rb +22 -0
  18. data/db/migrate/20190221055200_create_zcta_urban_areas.rb +22 -0
  19. data/db/migrate/20190221060000_create_places.rb +28 -0
  20. data/db/migrate/20190221061000_create_place_counties.rb +18 -0
  21. data/db/migrate/20190221062000_create_zcta_places.rb +22 -0
  22. data/db/migrate/20190221063000_create_county_subdivisions.rb +25 -0
  23. data/lib/tasks/us_geo/us_geo.rake +43 -0
  24. data/lib/us_geo/base_record.rb +104 -0
  25. data/lib/us_geo/combined_statistical_area.rb +40 -0
  26. data/lib/us_geo/core_based_statistical_area.rb +57 -0
  27. data/lib/us_geo/county.rb +89 -0
  28. data/lib/us_geo/county_subdivision.rb +46 -0
  29. data/lib/us_geo/demographics.rb +25 -0
  30. data/lib/us_geo/designated_market_area.rb +30 -0
  31. data/lib/us_geo/division.rb +29 -0
  32. data/lib/us_geo/engine.rb +6 -0
  33. data/lib/us_geo/metropolitan_area.rb +18 -0
  34. data/lib/us_geo/metropolitan_division.rb +42 -0
  35. data/lib/us_geo/micropolitan_area.rb +18 -0
  36. data/lib/us_geo/place.rb +61 -0
  37. data/lib/us_geo/place_county.rb +28 -0
  38. data/lib/us_geo/region.rb +28 -0
  39. data/lib/us_geo/state.rb +56 -0
  40. data/lib/us_geo/urban_area.rb +66 -0
  41. data/lib/us_geo/urban_area_county.rb +68 -0
  42. data/lib/us_geo/urban_cluster.rb +18 -0
  43. data/lib/us_geo/urbanized_area.rb +18 -0
  44. data/lib/us_geo/version.rb +5 -0
  45. data/lib/us_geo/zcta.rb +63 -0
  46. data/lib/us_geo/zcta_county.rb +68 -0
  47. data/lib/us_geo/zcta_place.rb +68 -0
  48. data/lib/us_geo/zcta_urban_area.rb +68 -0
  49. data/lib/us_geo.rb +53 -0
  50. data/spec/spec_helper.rb +22 -0
  51. data/spec/us_geo/base_record_spec.rb +67 -0
  52. data/spec/us_geo/combined_statistical_area_spec.rb +33 -0
  53. data/spec/us_geo/core_based_statistical_area_spec.rb +56 -0
  54. data/spec/us_geo/county_spec.rb +130 -0
  55. data/spec/us_geo/county_subdivision_spec.rb +37 -0
  56. data/spec/us_geo/demographics_spec.rb +19 -0
  57. data/spec/us_geo/designated_market_area_spec.rb +29 -0
  58. data/spec/us_geo/division_spec.rb +37 -0
  59. data/spec/us_geo/metropolitan_division_spec.rb +41 -0
  60. data/spec/us_geo/place_county_spec.rb +39 -0
  61. data/spec/us_geo/place_spec.rb +71 -0
  62. data/spec/us_geo/region_spec.rb +36 -0
  63. data/spec/us_geo/state_spec.rb +70 -0
  64. data/spec/us_geo/urban_area_county_spec.rb +82 -0
  65. data/spec/us_geo/urban_area_spec.rb +98 -0
  66. data/spec/us_geo/zcta_county_spec.rb +82 -0
  67. data/spec/us_geo/zcta_place_spec.rb +82 -0
  68. data/spec/us_geo/zcta_spec.rb +99 -0
  69. data/spec/us_geo/zcta_urban_area_spec.rb +82 -0
  70. metadata +229 -0
@@ -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
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USGeo
4
+
5
+ # Urban area with population < 50,000.
6
+ class UrbanCluster < UrbanArea
7
+
8
+ def urbanized?
9
+ false
10
+ end
11
+
12
+ def cluster?
13
+ true
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USGeo
4
+
5
+ # Urban area with population >= 50,000.
6
+ class UrbanizedArea < UrbanArea
7
+
8
+ def urbanized?
9
+ true
10
+ end
11
+
12
+ def cluster?
13
+ false
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USGeo
4
+ VERSION = "1.0.0"
5
+ end
@@ -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
@@ -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