weather_gov 0.1.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/.github/dependabot.yml +8 -0
- data/.github/workflows/rspec.yml +23 -0
- data/.github/workflows/rubocop.yml +23 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +29 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/weather_gov.rb +13 -0
- data/lib/weather_gov/address.rb +27 -0
- data/lib/weather_gov/alert.rb +45 -0
- data/lib/weather_gov/alert_collection.rb +28 -0
- data/lib/weather_gov/api.rb +93 -0
- data/lib/weather_gov/client.rb +115 -0
- data/lib/weather_gov/feature.rb +40 -0
- data/lib/weather_gov/feature_collection.rb +20 -0
- data/lib/weather_gov/forecast.rb +27 -0
- data/lib/weather_gov/forecast_period.rb +63 -0
- data/lib/weather_gov/gridpoint.rb +75 -0
- data/lib/weather_gov/identifier.rb +47 -0
- data/lib/weather_gov/identifier/alert.rb +13 -0
- data/lib/weather_gov/identifier/county_zone.rb +13 -0
- data/lib/weather_gov/identifier/fire_zone.rb +13 -0
- data/lib/weather_gov/identifier/forecast_zone.rb +13 -0
- data/lib/weather_gov/identifier/gridpoint.rb +29 -0
- data/lib/weather_gov/identifier/office.rb +13 -0
- data/lib/weather_gov/identifier/point.rb +21 -0
- data/lib/weather_gov/identifier/problem.rb +13 -0
- data/lib/weather_gov/identifier/station.rb +13 -0
- data/lib/weather_gov/observation_station.rb +27 -0
- data/lib/weather_gov/observation_station_collection.rb +20 -0
- data/lib/weather_gov/office.rb +68 -0
- data/lib/weather_gov/point.rb +81 -0
- data/lib/weather_gov/product.rb +29 -0
- data/lib/weather_gov/product_list.rb +17 -0
- data/lib/weather_gov/relative_location.rb +23 -0
- data/lib/weather_gov/valid_duration_value.rb +26 -0
- data/lib/weather_gov/valid_time.rb +48 -0
- data/lib/weather_gov/version.rb +5 -0
- data/lib/weather_gov/zone.rb +33 -0
- data/weather_gov.gemspec +39 -0
- metadata +190 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/identifier"
|
4
|
+
|
5
|
+
module WeatherGov
|
6
|
+
class Identifier
|
7
|
+
class Gridpoint < Identifier
|
8
|
+
def self.base_uri
|
9
|
+
URI.join(super, "/gridpoints/").to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def office_id
|
13
|
+
@office_id ||= id.split("/")[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
def grid_id
|
17
|
+
@grid_id ||= id.split("/")[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def grid_x
|
21
|
+
@grid_x ||= grid_id.split(",")[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def grid_y
|
25
|
+
@grid_y ||= grid_id.split(",")[1]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/identifier"
|
4
|
+
|
5
|
+
module WeatherGov
|
6
|
+
class Identifier
|
7
|
+
class Point < Identifier
|
8
|
+
def self.base_uri
|
9
|
+
URI.join(super, "/points/").to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def lat
|
13
|
+
@lat ||= id.split(",")[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
def lon
|
17
|
+
@lon ||= id.split(",")[1]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/feature"
|
4
|
+
|
5
|
+
module WeatherGov
|
6
|
+
class ObservationStation < Feature
|
7
|
+
def forecast_zone
|
8
|
+
@forecast_zone ||= Identifier::ForecastZone.new(properties.fetch("forecast"))
|
9
|
+
end
|
10
|
+
|
11
|
+
def fire_weather_zone
|
12
|
+
@fire_weather_zone ||= Identifier::FireZone.new(properties.fetch("fireWeatherZone"))
|
13
|
+
end
|
14
|
+
|
15
|
+
def station_identifier
|
16
|
+
properties.fetch("stationIdentifier")
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
properties.fetch("name")
|
21
|
+
end
|
22
|
+
|
23
|
+
def elevation
|
24
|
+
properties.fetch("elevation")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/feature_collection"
|
4
|
+
require "weather_gov/observation_station"
|
5
|
+
|
6
|
+
module WeatherGov
|
7
|
+
class ObservationStationCollection < FeatureCollection
|
8
|
+
def self.feature_class
|
9
|
+
ObservationStation
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_time
|
13
|
+
@update_time ||= Time.parse(data.fetch("updated"))
|
14
|
+
end
|
15
|
+
|
16
|
+
def observation_stations
|
17
|
+
data.fetch("observationStations")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/feature"
|
4
|
+
require "weather_gov/address"
|
5
|
+
|
6
|
+
module WeatherGov
|
7
|
+
class Office < Feature
|
8
|
+
def name
|
9
|
+
data.fetch("name")
|
10
|
+
end
|
11
|
+
|
12
|
+
def address
|
13
|
+
@address ||= Address.new(data.fetch("address"))
|
14
|
+
end
|
15
|
+
|
16
|
+
def telephone
|
17
|
+
data.fetch("telephone")
|
18
|
+
end
|
19
|
+
|
20
|
+
def fax
|
21
|
+
data.fetch("faxNumber")
|
22
|
+
end
|
23
|
+
|
24
|
+
def email
|
25
|
+
data.fetch("email")
|
26
|
+
end
|
27
|
+
|
28
|
+
def nws_region
|
29
|
+
data.fetch("nwsRegion")
|
30
|
+
end
|
31
|
+
|
32
|
+
def parent_organization
|
33
|
+
data.fetch("parentOrganization")
|
34
|
+
end
|
35
|
+
|
36
|
+
def responsible_counties
|
37
|
+
data.fetch("responsibleCounties", [])
|
38
|
+
end
|
39
|
+
|
40
|
+
def responsible_county_ids
|
41
|
+
data.fetch("responsibleCounties", []).map { |uri| Identifier::CountyZone.new(uri).id }
|
42
|
+
end
|
43
|
+
|
44
|
+
def responsible_forecast_zones
|
45
|
+
data.fetch("responsibleForecastZones", [])
|
46
|
+
end
|
47
|
+
|
48
|
+
def responsible_forecast_zone_ids
|
49
|
+
data.fetch("responsibleForecastZones", []).map { |uri| Identifier::ForecastZone.new(uri).id }
|
50
|
+
end
|
51
|
+
|
52
|
+
def responsible_fire_zones
|
53
|
+
data.fetch("responsibleFireZones", [])
|
54
|
+
end
|
55
|
+
|
56
|
+
def responsible_fire_zone_ids
|
57
|
+
data.fetch("responsibleFireZones", []).map { |uri| Identifier::FireZone.new(uri).id }
|
58
|
+
end
|
59
|
+
|
60
|
+
def approved_observation_stations
|
61
|
+
data.fetch("approvedObservationStations", []).map { |uri| client.station(uri: uri, value: uri) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def approved_observation_station_ids
|
65
|
+
data.fetch("approvedObservationStations", []).map { |uri| Identifier::Station.new(uri).id }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/feature"
|
4
|
+
require "weather_gov/relative_location"
|
5
|
+
|
6
|
+
module WeatherGov
|
7
|
+
class Point < Feature
|
8
|
+
def forecast_office_identifier
|
9
|
+
@forecast_office_identifier ||= Identifier::Office.new(properties.fetch("forecastOffice"))
|
10
|
+
end
|
11
|
+
|
12
|
+
def forecast_office
|
13
|
+
@forecast_office ||= client.office(uri: forecast_office_identifier.uri)
|
14
|
+
end
|
15
|
+
|
16
|
+
def forecast_zone_identifier
|
17
|
+
@forecast_zone_identifier ||= Identifier::ForecastZone.new(properties.fetch("forecastZone"))
|
18
|
+
end
|
19
|
+
|
20
|
+
def forecast_zone
|
21
|
+
@forecast_zone ||= client.zone(uri: forecast_zone_identifier.uri)
|
22
|
+
end
|
23
|
+
|
24
|
+
def county_zone_identifier
|
25
|
+
@county_zone_identifier ||= Identifier::CountyZone.new(properties.fetch("county"))
|
26
|
+
end
|
27
|
+
|
28
|
+
def county_zone
|
29
|
+
@county_zone ||= client.zone(uri: county_zone_identifier.uri)
|
30
|
+
end
|
31
|
+
|
32
|
+
def fire_zone_identifier
|
33
|
+
@fire_zone_identifier ||= Identifier::FireZone.new(properties.fetch("fireWeatherZone"))
|
34
|
+
end
|
35
|
+
|
36
|
+
def fire_zone
|
37
|
+
@fire_zone ||= client.zone(uri: fire_zone_identifier.uri)
|
38
|
+
end
|
39
|
+
|
40
|
+
def forecast_grid_data
|
41
|
+
@forecast_grid_data ||= Identifier::Gridpoint.new(properties.fetch("forecastGridData"))
|
42
|
+
end
|
43
|
+
|
44
|
+
def relative_location
|
45
|
+
@relative_location ||= RelativeLocation.new(client: client, data: properties.fetch("relativeLocation"))
|
46
|
+
end
|
47
|
+
|
48
|
+
def radar_station
|
49
|
+
properties.fetch("radarStation")
|
50
|
+
end
|
51
|
+
|
52
|
+
def observation_stations
|
53
|
+
@observation_stations ||= client.stations(uri: properties.fetch("observationStations"))
|
54
|
+
end
|
55
|
+
|
56
|
+
def alerts_active
|
57
|
+
@alerts_active ||= client.alerts_active(zone: forecast_zone_identifier.id)
|
58
|
+
end
|
59
|
+
|
60
|
+
def gridpoint
|
61
|
+
@gridpoint ||= client.gridpoint(uri: properties.fetch("forecastGridData"))
|
62
|
+
end
|
63
|
+
|
64
|
+
def forecast
|
65
|
+
@forecast ||= client.forecast(uri: properties.fetch("forecast"))
|
66
|
+
end
|
67
|
+
|
68
|
+
def forecast_hourly
|
69
|
+
@forecast_hourly ||= client.forecast(uri: properties.fetch("forecastHourly"))
|
70
|
+
end
|
71
|
+
|
72
|
+
def products(type)
|
73
|
+
@products ||= {}
|
74
|
+
@products[type] ||= client.products(type: type, location: forecast_office_identifier.id)
|
75
|
+
end
|
76
|
+
|
77
|
+
def product(type)
|
78
|
+
products(type).first.product
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WeatherGov
|
4
|
+
class Product < Feature
|
5
|
+
def issuing_office
|
6
|
+
data.fetch("issuingOffice")
|
7
|
+
end
|
8
|
+
|
9
|
+
def issuance_time
|
10
|
+
Time.parse(data.fetch("issuanceTime"))
|
11
|
+
end
|
12
|
+
|
13
|
+
def code
|
14
|
+
data.fetch("productCode")
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
data.fetch("productName")
|
19
|
+
end
|
20
|
+
|
21
|
+
def text
|
22
|
+
data.fetch("productText")
|
23
|
+
end
|
24
|
+
|
25
|
+
def product
|
26
|
+
client.product(id: id) if id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/feature"
|
4
|
+
require "weather_gov/product"
|
5
|
+
require "forwardable"
|
6
|
+
|
7
|
+
module WeatherGov
|
8
|
+
class ProductList < Feature
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def items
|
12
|
+
@items ||= data.fetch("@graph").map { |item| Product.new(client: client, data: item) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def_delegators :items, :[], :size, :each, :first, :last, :map
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/feature"
|
4
|
+
|
5
|
+
module WeatherGov
|
6
|
+
class RelativeLocation < Feature
|
7
|
+
def city
|
8
|
+
properties.fetch("city")
|
9
|
+
end
|
10
|
+
|
11
|
+
def state
|
12
|
+
properties.fetch("state")
|
13
|
+
end
|
14
|
+
|
15
|
+
def distance
|
16
|
+
properties.fetch("distance")
|
17
|
+
end
|
18
|
+
|
19
|
+
def bearing
|
20
|
+
properties.fetch("bearing")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "weather_gov/valid_time"
|
4
|
+
|
5
|
+
module WeatherGov
|
6
|
+
class ValidDurationValue
|
7
|
+
attr_reader :data, :unit
|
8
|
+
|
9
|
+
def initialize(data:, unit: nil)
|
10
|
+
@data = data
|
11
|
+
@unit = unit
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid_time
|
15
|
+
@valid_time ||= ValidTime.new(data.fetch("validTime"))
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid?
|
19
|
+
valid_time.valid?
|
20
|
+
end
|
21
|
+
|
22
|
+
def value
|
23
|
+
@value ||= data.fetch("value")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/time"
|
4
|
+
require "active_support/duration"
|
5
|
+
|
6
|
+
module WeatherGov
|
7
|
+
class ValidTime
|
8
|
+
def self.parse(valid_time_string)
|
9
|
+
ValidTime.new(valid_time_string)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(valid_time_string)
|
13
|
+
@valid_time_string = valid_time_string
|
14
|
+
end
|
15
|
+
|
16
|
+
def fields
|
17
|
+
@fields ||= @valid_time_string.split("/")
|
18
|
+
end
|
19
|
+
|
20
|
+
def start_time
|
21
|
+
@start_time ||= Time.parse(fields.first)
|
22
|
+
end
|
23
|
+
|
24
|
+
def duration
|
25
|
+
@duration ||= ActiveSupport::Duration.parse(fields.last)
|
26
|
+
end
|
27
|
+
|
28
|
+
def end_time
|
29
|
+
start_time + duration
|
30
|
+
end
|
31
|
+
|
32
|
+
def range
|
33
|
+
start_time...end_time
|
34
|
+
end
|
35
|
+
|
36
|
+
def valid?(time = Time.now)
|
37
|
+
range.include?(time)
|
38
|
+
end
|
39
|
+
|
40
|
+
def elapsed(time = Time.now)
|
41
|
+
ActiveSupport::Duration.build(time - start_time)
|
42
|
+
end
|
43
|
+
|
44
|
+
def remaining(time = Time.now)
|
45
|
+
ActiveSupport::Duration.build(end_time - time)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|