us_geo 1.0.3 → 2.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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/MIT_LICENSE.txt +21 -0
  4. data/README.md +77 -60
  5. data/UPDATING_TO_VERSION_2.md +172 -0
  6. data/VERSION +1 -0
  7. data/db/migrate/20190221054200_create_regions.rb +4 -2
  8. data/db/migrate/20190221054300_create_divisions.rb +4 -2
  9. data/db/migrate/20190221054400_create_states.rb +4 -2
  10. data/db/migrate/20190221054500_create_combined_statistical_areas.rb +4 -2
  11. data/db/migrate/20190221054600_create_core_based_statistical_areas.rb +4 -2
  12. data/db/migrate/20190221054650_create_metropolitan_divisions.rb +4 -2
  13. data/db/migrate/20190221054700_create_counties.rb +4 -3
  14. data/db/migrate/20190221054800_create_zctas.rb +4 -2
  15. data/db/migrate/20190221054900_create_zcta_counties.rb +4 -2
  16. data/db/migrate/20190221055000_create_urban_areas.rb +4 -2
  17. data/db/migrate/20190221055100_create_urban_area_counties.rb +4 -4
  18. data/db/migrate/20190221055200_create_zcta_urban_areas.rb +4 -4
  19. data/db/migrate/20190221060000_create_places.rb +4 -2
  20. data/db/migrate/20190221061000_create_place_counties.rb +4 -2
  21. data/db/migrate/20190221062000_create_zcta_places.rb +4 -4
  22. data/db/migrate/20190221063000_create_county_subdivisions.rb +4 -2
  23. data/db/migrate/20220722000000_allow_null_zcta_counties_demographics.rb +23 -0
  24. data/db/migrate/20220722000200_allow_null_zcta_places_demographics.rb +23 -0
  25. data/db/migrate/20230414000000_add_zcta_primary_place.rb +13 -0
  26. data/db/migrate/20230414000200_add_demographics_to_regions.rb +28 -0
  27. data/db/migrate/20230414000300_add_demographics_to_divisions.rb +28 -0
  28. data/db/migrate/20230414000400_add_demographics_to_states.rb +28 -0
  29. data/db/migrate/20230414000700_add_short_name_to_core_based_statistical_areas.rb +22 -0
  30. data/db/migrate/20230414000750_add_short_name_to_combined_statistical_areas.rb +22 -0
  31. data/db/migrate/20230414000800_create_zcta_mappings.rb +18 -0
  32. data/db/migrate/20230417000100_create_zcta_county_subdivisions.rb +22 -0
  33. data/db/migrate/20230417000200_add_unique_name_index_to_county_subdivisions.rb +26 -0
  34. data/db/migrate/20230417000250_add_zcta_primary_county_subdivision.rb +13 -0
  35. data/db/migrate/20230417000300_create_urban_area_county_subdivisions.rb +23 -0
  36. data/db/migrate/20230417000400_allow_null_urban_area_counties_demographics.rb +23 -0
  37. data/db/migrate/20230417000500_allow_null_zcta_urban_areas_demographics.rb +23 -0
  38. data/db/migrate/20230417000600_add_additional_time_zone_name_to_counties.rb +13 -0
  39. data/db/schema.rb +303 -0
  40. data/explorer_app/.gitattributes +7 -0
  41. data/explorer_app/.gitignore +34 -0
  42. data/explorer_app/Gemfile +38 -0
  43. data/explorer_app/Rakefile +6 -0
  44. data/explorer_app/app/assets/images/.keep +0 -0
  45. data/explorer_app/app/assets/stylesheets/application.css +1 -0
  46. data/explorer_app/app/controllers/application_controller.rb +64 -0
  47. data/explorer_app/app/controllers/combined_statistical_areas_controller.rb +12 -0
  48. data/explorer_app/app/controllers/concerns/.keep +0 -0
  49. data/explorer_app/app/controllers/core_based_statistical_areas_controller.rb +36 -0
  50. data/explorer_app/app/controllers/counties_controller.rb +22 -0
  51. data/explorer_app/app/controllers/county_subdivisions_controller.rb +23 -0
  52. data/explorer_app/app/controllers/divisions_controller.rb +27 -0
  53. data/explorer_app/app/controllers/home_controller.rb +6 -0
  54. data/explorer_app/app/controllers/metropolitan_divisions_controller.rb +27 -0
  55. data/explorer_app/app/controllers/places_controller.rb +23 -0
  56. data/explorer_app/app/controllers/regions_controller.rb +13 -0
  57. data/explorer_app/app/controllers/states_controller.rb +25 -0
  58. data/explorer_app/app/controllers/urban_areas_controller.rb +24 -0
  59. data/explorer_app/app/controllers/zctas_controller.rb +23 -0
  60. data/explorer_app/app/helpers/application_helper.rb +137 -0
  61. data/explorer_app/app/models/application_record.rb +3 -0
  62. data/explorer_app/app/models/concerns/.keep +0 -0
  63. data/explorer_app/app/views/combined_statistical_areas/_table.html.erb +18 -0
  64. data/explorer_app/app/views/combined_statistical_areas/index.html.erb +7 -0
  65. data/explorer_app/app/views/combined_statistical_areas/show.html.erb +52 -0
  66. data/explorer_app/app/views/core_based_statistical_areas/_table.html.erb +32 -0
  67. data/explorer_app/app/views/core_based_statistical_areas/index.html.erb +19 -0
  68. data/explorer_app/app/views/core_based_statistical_areas/show.html.erb +60 -0
  69. data/explorer_app/app/views/counties/_table.html.erb +64 -0
  70. data/explorer_app/app/views/counties/show.html.erb +96 -0
  71. data/explorer_app/app/views/county_subdivisions/_table.html.erb +48 -0
  72. data/explorer_app/app/views/county_subdivisions/show.html.erb +84 -0
  73. data/explorer_app/app/views/divisions/_table.html.erb +24 -0
  74. data/explorer_app/app/views/divisions/index.html.erb +3 -0
  75. data/explorer_app/app/views/divisions/show.html.erb +3 -0
  76. data/explorer_app/app/views/home/index.html.erb +23 -0
  77. data/explorer_app/app/views/layouts/application.html.erb +34 -0
  78. data/explorer_app/app/views/metropolitan_divisions/_table.html.erb +42 -0
  79. data/explorer_app/app/views/metropolitan_divisions/index.html.erb +8 -0
  80. data/explorer_app/app/views/metropolitan_divisions/show.html.erb +46 -0
  81. data/explorer_app/app/views/places/_table.html.erb +47 -0
  82. data/explorer_app/app/views/places/show.html.erb +92 -0
  83. data/explorer_app/app/views/regions/_table.html.erb +18 -0
  84. data/explorer_app/app/views/regions/index.html.erb +7 -0
  85. data/explorer_app/app/views/regions/show.html.erb +3 -0
  86. data/explorer_app/app/views/shared/_breadcrumbs.html.erb +13 -0
  87. data/explorer_app/app/views/shared/_demographics_cells.html.erb +5 -0
  88. data/explorer_app/app/views/shared/_demographics_headers.html.erb +5 -0
  89. data/explorer_app/app/views/states/_table.html.erb +31 -0
  90. data/explorer_app/app/views/states/index.html.erb +7 -0
  91. data/explorer_app/app/views/states/show.html.erb +54 -0
  92. data/explorer_app/app/views/urban_areas/_table.html.erb +45 -0
  93. data/explorer_app/app/views/urban_areas/index.html.erb +19 -0
  94. data/explorer_app/app/views/urban_areas/show.html.erb +68 -0
  95. data/explorer_app/app/views/zctas/_table.html.erb +60 -0
  96. data/explorer_app/app/views/zctas/show.html.erb +104 -0
  97. data/explorer_app/bin/bundle +109 -0
  98. data/explorer_app/bin/rails +4 -0
  99. data/explorer_app/bin/rake +4 -0
  100. data/explorer_app/bin/setup +33 -0
  101. data/explorer_app/config/application.rb +37 -0
  102. data/explorer_app/config/boot.rb +3 -0
  103. data/explorer_app/config/database.yml +13 -0
  104. data/explorer_app/config/environment.rb +5 -0
  105. data/explorer_app/config/environments/development.rb +59 -0
  106. data/explorer_app/config/initializers/filter_parameter_logging.rb +8 -0
  107. data/explorer_app/config/locales/en.yml +2 -0
  108. data/explorer_app/config/puma.rb +43 -0
  109. data/explorer_app/config/routes.rb +56 -0
  110. data/explorer_app/config.ru +6 -0
  111. data/explorer_app/db/seeds.rb +7 -0
  112. data/explorer_app/lib/assets/.keep +0 -0
  113. data/explorer_app/lib/tasks/.keep +0 -0
  114. data/explorer_app/log/.keep +0 -0
  115. data/explorer_app/public/404.html +67 -0
  116. data/explorer_app/public/422.html +67 -0
  117. data/explorer_app/public/500.html +66 -0
  118. data/explorer_app/public/apple-touch-icon-precomposed.png +0 -0
  119. data/explorer_app/public/apple-touch-icon.png +0 -0
  120. data/explorer_app/public/favicon.ico +0 -0
  121. data/explorer_app/public/robots.txt +1 -0
  122. data/explorer_app/tmp/.keep +0 -0
  123. data/explorer_app/tmp/pids/.keep +0 -0
  124. data/lib/tasks/us_geo/us_geo.rake +44 -3
  125. data/lib/us_geo/area.rb +44 -0
  126. data/lib/us_geo/base_record.rb +22 -16
  127. data/lib/us_geo/combined_statistical_area.rb +18 -8
  128. data/lib/us_geo/core_based_statistical_area.rb +24 -12
  129. data/lib/us_geo/county.rb +67 -16
  130. data/lib/us_geo/county_subdivision.rb +43 -7
  131. data/lib/us_geo/division.rb +17 -7
  132. data/lib/us_geo/metropolitan_area.rb +1 -5
  133. data/lib/us_geo/metropolitan_division.rb +17 -9
  134. data/lib/us_geo/micropolitan_area.rb +1 -5
  135. data/lib/us_geo/place.rb +61 -11
  136. data/lib/us_geo/place_county.rb +1 -4
  137. data/lib/us_geo/population.rb +26 -0
  138. data/lib/us_geo/region.rb +18 -8
  139. data/lib/us_geo/state.rb +32 -11
  140. data/lib/us_geo/urban_area.rb +46 -16
  141. data/lib/us_geo/urban_area_county.rb +4 -21
  142. data/lib/us_geo/urban_area_county_subdivision.rb +51 -0
  143. data/lib/us_geo/urban_cluster.rb +1 -5
  144. data/lib/us_geo/urbanized_area.rb +1 -5
  145. data/lib/us_geo/version.rb +1 -1
  146. data/lib/us_geo/zcta.rb +90 -13
  147. data/lib/us_geo/zcta_county.rb +5 -22
  148. data/lib/us_geo/zcta_county_subdivision.rb +51 -0
  149. data/lib/us_geo/zcta_mapping.rb +35 -0
  150. data/lib/us_geo/zcta_place.rb +5 -12
  151. data/lib/us_geo/zcta_urban_area.rb +3 -20
  152. data/lib/us_geo.rb +34 -31
  153. data/us_geo.gemspec +36 -0
  154. metadata +125 -129
  155. data/Gemfile +0 -5
  156. data/Gemfile.lock +0 -75
  157. data/Rakefile +0 -18
  158. data/db/migrate/20190221054490_create_designated_market_areas.rb +0 -16
  159. data/lib/us_geo/demographics.rb +0 -25
  160. data/lib/us_geo/designated_market_area.rb +0 -30
  161. data/spec/spec_helper.rb +0 -22
  162. data/spec/us_geo/base_record_spec.rb +0 -67
  163. data/spec/us_geo/combined_statistical_area_spec.rb +0 -33
  164. data/spec/us_geo/core_based_statistical_area_spec.rb +0 -56
  165. data/spec/us_geo/county_spec.rb +0 -131
  166. data/spec/us_geo/county_subdivision_spec.rb +0 -37
  167. data/spec/us_geo/demographics_spec.rb +0 -19
  168. data/spec/us_geo/designated_market_area_spec.rb +0 -29
  169. data/spec/us_geo/division_spec.rb +0 -37
  170. data/spec/us_geo/metropolitan_division_spec.rb +0 -41
  171. data/spec/us_geo/place_county_spec.rb +0 -39
  172. data/spec/us_geo/place_spec.rb +0 -71
  173. data/spec/us_geo/region_spec.rb +0 -36
  174. data/spec/us_geo/state_spec.rb +0 -70
  175. data/spec/us_geo/urban_area_county_spec.rb +0 -82
  176. data/spec/us_geo/urban_area_spec.rb +0 -98
  177. data/spec/us_geo/zcta_county_spec.rb +0 -82
  178. data/spec/us_geo/zcta_place_spec.rb +0 -82
  179. data/spec/us_geo/zcta_spec.rb +0 -99
  180. data/spec/us_geo/zcta_urban_area_spec.rb +0 -82
data/lib/us_geo/county.rb CHANGED
@@ -1,45 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # County or county equivalent. Counties are composed of zero or more ZCTA's and may
6
5
  # belong to a CBSA. The county's significance withing the CBSA is indicated by the
7
6
  # central flag which indicates if it is a central or outlying county.
8
7
  class County < BaseRecord
9
-
10
- include Demographics
8
+ include Population
9
+ include Area
11
10
 
12
11
  self.primary_key = "geoid"
13
12
 
14
- belongs_to :designated_market_area, foreign_key: :dma_code, optional: true, inverse_of: :counties
15
13
  belongs_to :core_based_statistical_area, foreign_key: :cbsa_geoid, optional: true, inverse_of: :counties
16
14
  belongs_to :metropolitan_division, foreign_key: :metropolitan_division_geoid, optional: true, inverse_of: :counties
17
15
  belongs_to :state, foreign_key: :state_code, inverse_of: :counties
18
16
 
19
- has_many :subdivisions, foreign_key: :county_geoid, inverse_of: :county, class_name: "USGeo::CountySubdivision"
17
+ has_many :subdivisions, -> { not_removed }, foreign_key: :county_geoid, inverse_of: :county, class_name: "USGeo::CountySubdivision"
20
18
 
21
- has_many :zcta_counties, foreign_key: :county_geoid, inverse_of: :county, dependent: :destroy
22
- has_many :zctas, through: :zcta_counties
19
+ has_many :zcta_counties, -> { not_removed }, foreign_key: :county_geoid, inverse_of: :county, dependent: :destroy
20
+ has_many :zctas, -> { not_removed }, through: :zcta_counties
23
21
 
24
22
  has_many :urban_area_counties, foreign_key: :county_geoid, inverse_of: :county, dependent: :destroy
25
23
  has_many :urban_areas, through: :urban_area_counties
26
24
 
27
- has_many :place_counties, foreign_key: :county_geoid, inverse_of: :county, dependent: :destroy
28
- has_many :places, through: :place_counties
25
+ has_many :place_counties, -> { not_removed }, foreign_key: :county_geoid, inverse_of: :county, dependent: :destroy
26
+ has_many :places, -> { not_removed }, through: :place_counties
29
27
 
30
28
  validates :geoid, length: {is: 5}
31
- validates :name, length: {maximum: 60}
32
- validates :short_name, length: {maximum: 30}
29
+ validates :name, presence: true, length: {maximum: 60}, uniqueness: {scope: :state_code}
30
+ validates :short_name, presence: true, length: {maximum: 30}, uniqueness: {scope: :state_code}
33
31
  validates :state_code, length: {is: 2}
34
32
  validates :fips_class_code, length: {is: 2}
35
33
  validates :metropolitan_division_geoid, length: {is: 5}, allow_nil: true
36
34
  validates :cbsa_geoid, length: {is: 5}, allow_nil: true
37
- validates :dma_code, length: {is: 3}, allow_nil: true
38
35
  validates :land_area, numericality: true, allow_nil: true
39
36
  validates :water_area, numericality: true, allow_nil: true
40
37
  validates :population, numericality: {only_integer: true}, allow_nil: true
41
38
  validates :housing_units, numericality: {only_integer: true}, allow_nil: true
42
39
 
40
+ # @!attribute geoid
41
+ # @return [String] 5-digit code for the county.
42
+
43
+ # @!attribute name
44
+ # @return [String] Name of the county.
45
+
46
+ # @!attribute short_name
47
+ # @return [String] Short name of the county.
48
+
49
+ # @!attribute state_code
50
+ # @return [String] 2-letter code for the state.
51
+
52
+ # @!attribute fips_class_code
53
+ # @return [String] 2-character FIPS class code.
54
+
55
+ # @!attribute time_zone_name
56
+ # @return [String] Time zone name.
57
+
58
+ # @!attribute time_zone_2_name
59
+ # @return [String] Time zone name.
60
+
61
+ # @!method central?
62
+ # @return [Boolean] True if the county is a central county in the CBSA.
63
+
64
+ # @!method combined_statistical_area
65
+ # @return [USGeo::CombinedStatisticalArea] Combined statistical area that the county belongs to.
66
+ delegate :combined_statistical_area, to: :core_based_statistical_area, allow_nil: true
67
+
43
68
  class << self
44
69
  def load!(uri = nil)
45
70
  location = data_uri(uri || "counties.csv")
@@ -53,14 +78,14 @@ module USGeo
53
78
  record.state_code = row["State"]
54
79
  record.cbsa_geoid = row["CBSA"]
55
80
  record.metropolitan_division_geoid = row["Metropolitan Division"]
56
- record.dma_code = row["DMA"]
57
81
  record.time_zone_name = row["Time Zone"]
82
+ record.time_zone_2_name = row["Time Zone 2"]
58
83
  record.fips_class_code = row["FIPS Class"]
59
84
  record.central = (row["Central"] == "T")
60
85
  record.population = row["Population"]
61
86
  record.housing_units = row["Housing Units"]
62
- record.land_area = area_meters_to_miles(row["Land Area"])
63
- record.water_area = area_meters_to_miles(row["Water Area"])
87
+ record.land_area = row["Land Area"]
88
+ record.water_area = row["Water Area"]
64
89
  record.lat = row["Latitude"]
65
90
  record.lng = row["Longitude"]
66
91
  end
@@ -69,6 +94,13 @@ module USGeo
69
94
  end
70
95
  end
71
96
 
97
+ # Full name of the county with the state.
98
+ #
99
+ # @return [String]
100
+ def full_name
101
+ "#{name}, #{state_code}"
102
+ end
103
+
72
104
  def state_fips
73
105
  geoid[0, 2]
74
106
  end
@@ -79,12 +111,31 @@ module USGeo
79
111
 
80
112
  # Return the CBSA only if it is a metropolitan area.
81
113
  def metropolitan_area
82
- core_based_statistical_area if core_based_statistical_area && core_based_statistical_area.metropolitan?
114
+ core_based_statistical_area if core_based_statistical_area&.metropolitan?
83
115
  end
84
116
 
117
+ # Return a single time zone for the county. If the county has two time zones,
118
+ # only one is returned.
119
+ #
120
+ # @return [ActiveSupport::TimeZone, nil]
85
121
  def time_zone
86
122
  ActiveSupport::TimeZone[time_zone_name] if time_zone_name
87
123
  end
88
124
 
125
+ # Get all time zones for the county.
126
+ #
127
+ # @return [Array<ActiveSupport::TimeZone>]
128
+ def time_zones
129
+ [time_zone_name, time_zone_2_name].compact.collect do |tz_name|
130
+ ActiveSupport::TimeZone[tz_name]
131
+ end.compact
132
+ end
133
+
134
+ # True if the county is an outlying county in the CBSA.
135
+ #
136
+ # @return [Boolean]
137
+ def outlying?
138
+ !central?
139
+ end
89
140
  end
90
141
  end
@@ -1,24 +1,58 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # County subdivision.
6
5
  class CountySubdivision < BaseRecord
7
-
8
- include Demographics
6
+ include Population
7
+ include Area
9
8
 
10
9
  self.primary_key = "geoid"
11
10
 
12
11
  belongs_to :county, foreign_key: :county_geoid, inverse_of: :subdivisions
13
12
 
13
+ has_many :zcta_county_subdivisions, -> { not_removed }, foreign_key: :county_subdivision_geoid, inverse_of: :county_subdivision, dependent: :destroy
14
+ has_many :zctas, -> { not_removed }, through: :zcta_county_subdivisions
15
+
16
+ has_many :urban_area_county_subdivisions, foreign_key: :county_subdivision_geoid, inverse_of: :county_subdivision, dependent: :destroy
17
+ has_many :urban_areas, through: :urban_area_county_subdivisions
18
+
14
19
  validates :geoid, length: {is: 10}
15
- validates :name, length: {maximum: 60}
20
+ validates :name, presence: true, length: {maximum: 60}, uniqueness: {scope: :county_geoid}
16
21
  validates :fips_class_code, length: {is: 2}
17
22
  validates :land_area, numericality: true, allow_nil: true
18
23
  validates :water_area, numericality: true, allow_nil: true
19
24
  validates :population, numericality: {only_integer: true}, allow_nil: true
20
25
  validates :housing_units, numericality: {only_integer: true}, allow_nil: true
21
26
 
27
+ # @!attribute geoid
28
+ # @return [String] 10-digit code for the subdivision.
29
+
30
+ # @!attribute name
31
+ # @return [String] Name of the subdivision.
32
+
33
+ # @!attribute fips_class_code
34
+ # @return [String] 2-character FIPS class code.
35
+
36
+ # @!method :core_based_statistical_area
37
+ # @return [CoreBasedStatisticalArea] Core-based statistical area the subdivision is in.
38
+ delegate :core_based_statistical_area, to: :county
39
+
40
+ # @!method :combined_statistical_area
41
+ # @return [CombinedStatisticalArea] Combined statistical area the subdivision is in.
42
+ delegate :combined_statistical_area, to: :county
43
+
44
+ # @!method :metropolitan_division
45
+ # @return [MetropolitanDivision] Metropolitan division the subdivision is in.
46
+ delegate :metropolitan_division, to: :county
47
+
48
+ # @!method :state
49
+ # @return [State] State the subdivision is in.
50
+ delegate :state, to: :county
51
+
52
+ # @!method :state_code
53
+ # @return [String] 2-character state code.
54
+ delegate :state_code, to: :county
55
+
22
56
  class << self
23
57
  def load!(uri = nil)
24
58
  location = data_uri(uri || "county_subdivisions.csv")
@@ -32,15 +66,17 @@ module USGeo
32
66
  record.fips_class_code = row["FIPS Class"]
33
67
  record.population = row["Population"]
34
68
  record.housing_units = row["Housing Units"]
35
- record.land_area = area_meters_to_miles(row["Land Area"])
36
- record.water_area = area_meters_to_miles(row["Water Area"])
69
+ record.land_area = row["Land Area"]
70
+ record.water_area = row["Water Area"]
37
71
  record.lat = row["Latitude"]
38
72
  record.lng = row["Longitude"]
73
+
74
+ duplicate = where.not(geoid: record.geoid).find_by(name: record.name, county_geoid: record.county_geoid)
75
+ duplicate&.update!(name: "#{record.name} (deleted)", status: BaseRecord::STATUS_REMOVED)
39
76
  end
40
77
  end
41
78
  end
42
79
  end
43
80
  end
44
-
45
81
  end
46
82
  end
@@ -1,29 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # U.S. regional division composed of states.
6
5
  class Division < BaseRecord
6
+ include Population
7
+ include Area
7
8
 
8
9
  belongs_to :region, inverse_of: :divisions
9
- has_many :states, inverse_of: :division
10
+ has_many :states, -> { not_removed }, inverse_of: :division
11
+
12
+ validates :name, presence: true, length: {maximum: 30}, uniqueness: true
13
+
14
+ # @!attribute id
15
+ # @return [Integer] ID of the division.
10
16
 
11
- validates :name, length: {maximum: 30}
17
+ # @!attribute name
18
+ # @return [String] Name of the division.
12
19
 
13
20
  class << self
14
21
  def load!(uri = nil)
15
22
  location = data_uri(uri || "divisions.csv")
16
-
23
+
17
24
  import! do
18
25
  load_data_file(location) do |row|
19
- load_record!(id: row["Division ID"]) do |record|
20
- record.name = row["Division Name"]
26
+ load_record!(id: row["ID"]) do |record|
27
+ record.name = row["Name"]
21
28
  record.region_id = row["Region ID"]
29
+ record.population = row["Population"]
30
+ record.housing_units = row["Housing Units"]
31
+ record.land_area = row["Land Area"]
32
+ record.water_area = row["Water Area"]
22
33
  end
23
34
  end
24
35
  end
25
36
  end
26
37
  end
27
-
28
38
  end
29
39
  end
@@ -1,18 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # Core based statistical area with a population greater then 50,000.
6
5
  class MetropolitanArea < CoreBasedStatisticalArea
7
-
8
6
  def metropolitan?
9
7
  true
10
8
  end
11
-
9
+
12
10
  def micropolitan?
13
11
  false
14
12
  end
15
-
16
13
  end
17
-
18
14
  end
@@ -1,23 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # Division of very large metropolitian areas into groups of approximately 2.5 million people.
6
5
  class MetropolitanDivision < BaseRecord
7
-
8
- include Demographics
6
+ include Population
7
+ include Area
9
8
 
10
9
  self.primary_key = "geoid"
11
10
 
12
- has_many :counties, foreign_key: :metropolitan_division_geoid, inverse_of: :metropolitan_division
11
+ has_many :counties, -> { not_removed }, foreign_key: :metropolitan_division_geoid, inverse_of: :metropolitan_division
13
12
  belongs_to :core_based_statistical_area, foreign_key: :cbsa_geoid, optional: true, inverse_of: :metropolitan_divisions
14
13
 
15
14
  validates :geoid, length: {is: 5}
16
- validates :name, length: {maximum: 60}
15
+ validates :name, presence: true, length: {maximum: 60}, uniqueness: true
17
16
  validates :land_area, numericality: true, presence: true
18
17
  validates :water_area, numericality: true, presence: true
19
18
  validates :population, numericality: {only_integer: true}, presence: true
20
- validates :housing_units, numericality: {only_integer: true}, presence: true
19
+ validates :housing_units, numericality: {only_integer: true}, presence: true
20
+
21
+ # @!attribute geoid
22
+ # @return [String] 5-digit code for the metropolitan division.
23
+
24
+ # @!attribute name
25
+ # @return [String] Name of the metropolitan division.
26
+
27
+ # @!method combined_statistical_area
28
+ # @return [CombinedStatisticalArea, nil] Combined statistical area that the metropolitan division is a part of.
29
+ delegate :combined_statistical_area, to: :core_based_statistical_area, allow_nil: true
21
30
 
22
31
  class << self
23
32
  def load!(uri = nil)
@@ -30,13 +39,12 @@ module USGeo
30
39
  record.cbsa_geoid = row["CBSA"]
31
40
  record.population = row["Population"]
32
41
  record.housing_units = row["Housing Units"]
33
- record.land_area = area_meters_to_miles(row["Land Area"])
34
- record.water_area = area_meters_to_miles(row["Water Area"])
42
+ record.land_area = row["Land Area"]
43
+ record.water_area = row["Water Area"]
35
44
  end
36
45
  end
37
46
  end
38
47
  end
39
48
  end
40
-
41
49
  end
42
50
  end
@@ -1,18 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # Core based statistical area with a population greater then 10,000 but less than 50,000.
6
5
  class MicropolitanArea < CoreBasedStatisticalArea
7
-
8
6
  def metropolitan?
9
7
  false
10
8
  end
11
-
9
+
12
10
  def micropolitan?
13
11
  true
14
12
  end
15
-
16
13
  end
17
-
18
14
  end
data/lib/us_geo/place.rb CHANGED
@@ -1,29 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # Division of very large metropolitian areas into groups of approximately 2.5 million people.
6
5
  class Place < BaseRecord
7
-
8
- include Demographics
6
+ include Population
7
+ include Area
9
8
 
10
9
  self.primary_key = "geoid"
11
10
 
12
- has_many :zcta_places, foreign_key: :place_geoid, inverse_of: :place, dependent: :destroy
13
- has_many :zctas, through: :zcta_places
11
+ # !@method zcta_places
12
+ # @return [ActiveRecord::Relation<ZctaPlace>] ZCTA to place mapping.
13
+ has_many :zcta_places, -> { not_removed }, foreign_key: :place_geoid, inverse_of: :place, dependent: :destroy
14
+
15
+ # !@method zctas
16
+ # @return [ActiveRecord::Relation<Zcta>] ZCTA's that overlap with this place.
17
+ has_many :zctas, -> { not_removed }, through: :zcta_places
14
18
 
15
- has_many :place_counties, foreign_key: :place_geoid, inverse_of: :place, dependent: :destroy
16
- has_many :counties, through: :place_counties
19
+ # !@method place_counties
20
+ # @return [ActiveRecord::Relation<PlaceCounty>] Place to county mapping.
21
+ has_many :place_counties, -> { not_removed }, foreign_key: :place_geoid, inverse_of: :place, dependent: :destroy
17
22
 
23
+ # !@method counties
24
+ # @return [ActiveRecord::Relation<County>] Counties that this place is a part of.
25
+ has_many :counties, -> { not_removed }, through: :place_counties
26
+
27
+ # !@method primary_county
28
+ # @return [County] County that contains most of the place.
18
29
  belongs_to :primary_county, foreign_key: :primary_county_geoid, class_name: "USGeo::County"
30
+
31
+ # !@method urban_area
32
+ # @return [UrbanArea] Urban area that the place is a part of.
19
33
  belongs_to :urban_area, foreign_key: :urban_area_geoid, optional: true, class_name: "USGeo::UrbanArea"
34
+
35
+ # !@method state
36
+ # @return [State] State that the place is in.
20
37
  belongs_to :state, foreign_key: :state_code, inverse_of: :places
21
38
 
22
39
  validates :geoid, length: {is: 7}
23
40
  validates :state_code, length: {is: 2}
24
41
  validates :primary_county_geoid, length: {is: 5}
25
42
  validates :urban_area_geoid, length: {is: 5}, allow_nil: true
26
- validates :name, length: {maximum: 60}
43
+ validates :name, presence: true, length: {maximum: 60}
27
44
  validates :short_name, length: {maximum: 30}
28
45
  validates :fips_class_code, length: {is: 2}
29
46
  validates :land_area, numericality: true, allow_nil: true
@@ -31,6 +48,40 @@ module USGeo
31
48
  validates :population, numericality: {only_integer: true}, allow_nil: true
32
49
  validates :housing_units, numericality: {only_integer: true}, allow_nil: true
33
50
 
51
+ # @!attribute geoid
52
+ # @return [String] 7-digit code for the place.
53
+
54
+ # @!attribute name
55
+ # @return [String] Name of the place.
56
+
57
+ # @!attribute short_name
58
+ # @return [String] Short name of the place.
59
+
60
+ # @!attribute state_code
61
+ # @return [String] 2-letter code for the state.
62
+
63
+ # @!attribute fips_class_code
64
+ # @return [String] 2-character FIPS class code.
65
+
66
+ # @!method combined_statistical_area
67
+ # @return [CombinedStatisticalArea, nil] Combined statistical area that the place is a part of.
68
+ delegate :combined_statistical_area, to: :primary_county, allow_nil: true
69
+
70
+ # @!method core_based_statistical_area
71
+ # @return [CoreBasedStatisticalArea, nil] Core-based statistical area that the place is a part of.
72
+ delegate :core_based_statistical_area, to: :primary_county, allow_nil: true
73
+
74
+ # @!method metropolitan_division
75
+ # @return [MetropolitanDivision, nil] Metropolitan division that the place is a part of.
76
+ delegate :metropolitan_division, to: :primary_county, allow_nil: true
77
+
78
+ # Full name of the place as short name plus the state.
79
+ #
80
+ # @return [String]
81
+ def full_name
82
+ "#{short_name}, #{state_code}"
83
+ end
84
+
34
85
  class << self
35
86
  def load!(uri = nil)
36
87
  location = data_uri(uri || "places.csv")
@@ -47,8 +98,8 @@ module USGeo
47
98
  record.fips_class_code = row["FIPS Class"]
48
99
  record.population = row["Population"]
49
100
  record.housing_units = row["Housing Units"]
50
- record.land_area = area_meters_to_miles(row["Land Area"])
51
- record.water_area = area_meters_to_miles(row["Water Area"])
101
+ record.land_area = row["Land Area"]
102
+ record.water_area = row["Water Area"]
52
103
  record.lat = row["Latitude"]
53
104
  record.lng = row["Longitude"]
54
105
  end
@@ -56,6 +107,5 @@ module USGeo
56
107
  end
57
108
  end
58
109
  end
59
-
60
110
  end
61
111
  end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
- # Mapping of urban areas to counties they overlap with.
4
+ # Mapping of places to counties they overlap with.
6
5
  class PlaceCounty < BaseRecord
7
-
8
6
  belongs_to :county, foreign_key: :county_geoid, inverse_of: :place_counties
9
7
  belongs_to :place, foreign_key: :place_geoid, inverse_of: :place_counties
10
8
 
@@ -23,6 +21,5 @@ module USGeo
23
21
  end
24
22
  end
25
23
  end
26
-
27
24
  end
28
25
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module USGeo
4
+ # This module is mixed into all models with a population and land area.
5
+ module Population
6
+ # @!attribute population
7
+ # @return [Integer, nil] Total population of the area.
8
+
9
+ # @!attribute housing_units
10
+ # @return [Integer, nil] Total housing units in the area.
11
+
12
+ # Population per square mile.
13
+ #
14
+ # @return [Float, nil]
15
+ def population_density
16
+ population.to_f / land_area if population && land_area.to_f > 0
17
+ end
18
+
19
+ # Population per square kilometer.
20
+ #
21
+ # @return [Float, nil]
22
+ def population_density_km
23
+ population.to_f / land_area_km if population && land_area.to_f > 0
24
+ end
25
+ end
26
+ end
data/lib/us_geo/region.rb CHANGED
@@ -1,28 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # U.S. region.
6
5
  class Region < BaseRecord
6
+ include Population
7
+ include Area
8
+
9
+ has_many :divisions, -> { not_removed }, inverse_of: :region
10
+ has_many :states, -> { not_removed }, inverse_of: :region
7
11
 
8
- has_many :divisions, inverse_of: :region
9
- has_many :states, inverse_of: :region
12
+ validates :name, presence: true, length: {maximum: 30}, uniqueness: true
10
13
 
11
- validates :name, length: {maximum: 30}
14
+ # @!attribute id
15
+ # @return [Integer] ID of the region.
16
+
17
+ # @!attribute name
18
+ # @return [String] Name of the region.
12
19
 
13
20
  class << self
14
21
  def load!(uri = nil)
15
- location = data_uri(uri || "divisions.csv")
22
+ location = data_uri(uri || "regions.csv")
16
23
 
17
24
  import! do
18
25
  load_data_file(location) do |row|
19
- load_record!(id: row["Region ID"]) do |record|
20
- record.name = row["Region Name"]
26
+ load_record!(id: row["ID"]) do |record|
27
+ record.name = row["Name"]
28
+ record.population = row["Population"]
29
+ record.housing_units = row["Housing Units"]
30
+ record.land_area = row["Land Area"]
31
+ record.water_area = row["Water Area"]
21
32
  end
22
33
  end
23
34
  end
24
35
  end
25
36
  end
26
-
27
37
  end
28
38
  end
data/lib/us_geo/state.rb CHANGED
@@ -1,31 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module USGeo
4
-
5
4
  # U.S. state or territory.
6
5
  class State < BaseRecord
6
+ include Population
7
+ include Area
7
8
 
8
9
  STATE_TYPE = "state"
9
10
  DISTRICT_TYPE = "district"
10
11
  TERRITORY_TYPE = "territory"
11
-
12
+
12
13
  self.primary_key = "code"
13
14
  self.inheritance_column = :_type_disabled
14
15
 
15
16
  belongs_to :region, optional: -> { territory? }, inverse_of: :states
16
17
  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
18
 
20
- validates :code, length: {is: 2}
19
+ has_many :counties, -> { not_removed }, foreign_key: :state_code, inverse_of: :state
20
+ has_many :places, -> { not_removed }, foreign_key: :state_code, inverse_of: :state
21
+
22
+ validates :code, length: {is: 2}, uniqueness: true
21
23
  validates :fips, length: {is: 2}
22
- validates :name, length: {maximum: 30}
24
+ validates :name, presence: true, length: {maximum: 30}, uniqueness: true
23
25
  validates :type, inclusion: [STATE_TYPE, DISTRICT_TYPE, TERRITORY_TYPE]
24
26
 
27
+ # @!attribute code
28
+ # @return [String] 2-letter postal code of the state.
29
+
30
+ # @!attribute name
31
+ # @return [String] Name of the state.
32
+
33
+ # @!attribute fips
34
+ # @return [String] 2-digit FIPS code of the state.
35
+
36
+ # @!attribute type
37
+ # @return [String] Type of the state or territory.
38
+
39
+ # @!method :region
40
+ # @return [Region] Region the state is in.
41
+ delegate :region, to: :division, allow_nil: true
42
+
25
43
  class << self
26
44
  def load!(uri = nil)
27
45
  location = data_uri(uri || "states.csv")
28
-
46
+
29
47
  import! do
30
48
  load_data_file(location) do |row|
31
49
  load_record!(code: row["Code"]) do |record|
@@ -34,23 +52,26 @@ module USGeo
34
52
  record.fips = row["FIPS"]
35
53
  record.region_id = row["Region ID"]
36
54
  record.division_id = row["Division ID"]
55
+ record.population = row["Population"]
56
+ record.housing_units = row["Housing Units"]
57
+ record.land_area = row["Land Area"]
58
+ record.water_area = row["Water Area"]
37
59
  end
38
60
  end
39
61
  end
40
62
  end
41
63
  end
42
-
64
+
43
65
  def state?
44
66
  type == STATE_TYPE
45
67
  end
46
-
68
+
47
69
  def territory?
48
70
  type == TERRITORY_TYPE
49
71
  end
50
-
72
+
51
73
  def district?
52
74
  type == DISTRICT_TYPE
53
75
  end
54
-
55
76
  end
56
77
  end