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.
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