open-meteo 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1fd59fe55c171c4cefb24b80613933b28d10040fdff524490dcd9e6e2ed0514
4
- data.tar.gz: 8231a53ba4250c627db4c44eb513f6f0cf41631c3a5ba3c3934a20d0ee731562
3
+ metadata.gz: c4d1b8d00c232c9cd399effc4246167fc6bdcf848cbe77d6ca4c84fa177a0979
4
+ data.tar.gz: 5e87b95a9ed8876b46bfce225fde195f2e43f5deb7b816e6271eacf76db54968
5
5
  SHA512:
6
- metadata.gz: ec997727575db6186329054eca41b3c60c6729571788d012c57a74ed7c0314308ee75e11dc201287cc396d6be570b1e38ef675dd67ebd79e41d3d5a645de7957
7
- data.tar.gz: 4055bd5d3d7d63c40f3cfa8eae6822f755d806c48b7e700e65ffd2de14bdd3761373318bba2699752c97db26621893cefb3ec1b34caa87d9151ca5c05b112d40
6
+ metadata.gz: 36ac57fc2acb0062996b48c3736058e2d7b2e4ab29dd4eea3ea9857d768bbf4a14a50a5496d44c69a1b307daf8c5d38e600a3f6b4bc359cd6084eebc646a0eec
7
+ data.tar.gz: a71d7e7e08144eb2dc61c850bb45e66bf1614031bddc8405c6babeb02a46572457d9796c6387b27fb43882355d514676c5eaa092e1dec97ab5f3e8c1dd6f5196
@@ -0,0 +1,26 @@
1
+ module OpenMeteo
2
+ ##
3
+ # Shared functionality for dry contracts.
4
+ class ApplicationContract < Dry::Validation::Contract
5
+ ##
6
+ # A validation error that can be raised on contract validation.
7
+ class ValidationError < StandardError
8
+ attr_reader :result, :errors
9
+
10
+ def initialize(result)
11
+ @errors = result.errors
12
+ first_error_key = result.errors.first.path.first
13
+ first_error_value = result[first_error_key]
14
+
15
+ super(
16
+ "Validation failed: :#{first_error_key} is #{first_error_value} but #{errors.first.text}",
17
+ )
18
+ end
19
+ end
20
+
21
+ def self.validate!(object)
22
+ result = new.call(object)
23
+ raise ValidationError, result unless result.errors.empty?
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,5 @@
1
+ require_relative "general_contract"
2
+
1
3
  module OpenMeteo
2
4
  class Forecast
3
5
  module Variables
@@ -5,18 +7,22 @@ module OpenMeteo
5
7
  # The Variables for a general request (meaning without a specific model) to the OpenMeteo API.
6
8
  #
7
9
  # See https://open-meteo.com/en/docs
8
- class General
9
- attr_reader :current, :hourly, :daily
10
-
11
- def initialize(current:, hourly:, daily:)
12
- @current = current
13
- @hourly = hourly
14
- @daily = daily
15
- end
10
+ class General < Dry::Struct
11
+ attribute(
12
+ :current,
13
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
14
+ )
15
+ attribute(
16
+ :hourly,
17
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
18
+ )
19
+ attribute(
20
+ :daily,
21
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
22
+ )
16
23
 
17
- def validate
18
- # FIXME: Placeholder for validation
19
- true
24
+ def validate!
25
+ GeneralContract.validate!(to_hash)
20
26
  end
21
27
 
22
28
  def to_get_params
@@ -0,0 +1,286 @@
1
+ module OpenMeteo
2
+ class Forecast
3
+ module Variables
4
+ ##
5
+ # Validation contract for OpenMeteo::Forecast::Variables::General.
6
+ #
7
+ # See https://open-meteo.com/en/docs
8
+ class GeneralContract < OpenMeteo::ApplicationContract # rubocop:disable Metrics/ClassLength
9
+ params do
10
+ required(:current).array(:symbol)
11
+ required(:hourly).array(:symbol)
12
+ required(:daily).array(:symbol)
13
+ end
14
+
15
+ CURRENT_VARIABALES = %i[
16
+ apparent_temperature
17
+ cloudcover
18
+ is_day
19
+ precipitation
20
+ pressure_msl
21
+ rain
22
+ relativehumidity_2m
23
+ showers
24
+ snowfall
25
+ surface_pressure
26
+ temperature_2m
27
+ weathercode
28
+ winddirection_10m
29
+ windgusts_10m
30
+ windspeed_10m
31
+ ].freeze
32
+
33
+ HOURLY_VARIABLES_BASE = %i[
34
+ apparent_temperature
35
+ cloudcover
36
+ cloudcover_high
37
+ cloudcover_low
38
+ cloudcover_mid
39
+ dewpoint_2m
40
+ et0_fao_evapotranspiration
41
+ evapotranspiration
42
+ precipitation
43
+ precipitation_probability
44
+ pressure_msl
45
+ rain
46
+ relativehumidity_2m
47
+ showers
48
+ snow_depth
49
+ snowfall
50
+ soil_moisture_0_to_1cm
51
+ soil_moisture_1_to_3cm
52
+ soil_moisture_27_to_81cm
53
+ soil_moisture_3_to_9cm
54
+ soil_moisture_9_to_27cm
55
+ soil_temperature_0cm
56
+ soil_temperature_18cm
57
+ soil_temperature_54cm
58
+ soil_temperature_6cm
59
+ surface_pressure
60
+ temperature_120m
61
+ temperature_180m
62
+ temperature_2m
63
+ temperature_80m
64
+ vapor_pressure_deficit
65
+ visibility
66
+ weathercode
67
+ winddirection_10m
68
+ winddirection_120m
69
+ winddirection_180m
70
+ winddirection_80m
71
+ windgusts_10m
72
+ windspeed_10m
73
+ windspeed_120m
74
+ windspeed_180m
75
+ windspeed_80m
76
+ ].freeze
77
+
78
+ HOURLY_VARIABLES_ADDITIONAL = %i[
79
+ uv_index
80
+ uv_index_clear_sky
81
+ is_day
82
+ cape
83
+ freezinglevel_height
84
+ ].freeze
85
+
86
+ HOURLY_VARIABLES_SOLAR_RADIATION = %i[
87
+ shortwave_radiation
88
+ direct_radiation
89
+ diffuse_radiation
90
+ direct_normal_irradiance
91
+ terrestrial_radiation
92
+ shortwave_radiation_instant
93
+ direct_radiation_instant
94
+ diffuse_radiation_instant
95
+ direct_normal_irradiance_instant
96
+ terrestrial_radiation_instant
97
+ ].freeze
98
+
99
+ HOURLY_VARIABLES_PRESSURE_LEVEL_TEMPERATURE = %i[
100
+ temperature_1000hPa
101
+ temperature_975hPa
102
+ temperature_950hPa
103
+ temperature_925hPa
104
+ temperature_900hPa
105
+ temperature_850hPa
106
+ temperature_800hPa
107
+ temperature_700hPa
108
+ temperature_600hPa
109
+ temperature_500hPa
110
+ temperature_400hPa
111
+ temperature_300hPa
112
+ temperature_250hPa
113
+ temperature_200hPa
114
+ temperature_150hPa
115
+ temperature_100hPa
116
+ temperature_70hPa
117
+ temperature_50hPa
118
+ temperature_30hPa
119
+ ].freeze
120
+
121
+ HOURLY_VARIABLES_PRESSURE_LEVEL_RELATIVE_HUMIDITY = %i[
122
+ relativehumidity_1000hPa
123
+ relativehumidity_975hPa
124
+ relativehumidity_950hPa
125
+ relativehumidity_925hPa
126
+ relativehumidity_900hPa
127
+ relativehumidity_850hPa
128
+ relativehumidity_800hPa
129
+ relativehumidity_700hPa
130
+ relativehumidity_600hPa
131
+ relativehumidity_500hPa
132
+ relativehumidity_400hPa
133
+ relativehumidity_300hPa
134
+ relativehumidity_250hPa
135
+ relativehumidity_200hPa
136
+ relativehumidity_150hPa
137
+ relativehumidity_100hPa
138
+ relativehumidity_70hPa
139
+ relativehumidity_50hPa
140
+ relativehumidity_30hPa
141
+ ].freeze
142
+
143
+ HOURLY_VARIABLES_PRESSURE_LEVEL_CLOUDCOVER = %i[
144
+ cloudcover_1000hPa
145
+ cloudcover_975hPa
146
+ cloudcover_950hPa
147
+ cloudcover_925hPa
148
+ cloudcover_900hPa
149
+ cloudcover_850hPa
150
+ cloudcover_800hPa
151
+ cloudcover_700hPa
152
+ cloudcover_600hPa
153
+ cloudcover_500hPa
154
+ cloudcover_400hPa
155
+ cloudcover_300hPa
156
+ cloudcover_250hPa
157
+ cloudcover_200hPa
158
+ cloudcover_150hPa
159
+ cloudcover_100hPa
160
+ cloudcover_70hPa
161
+ cloudcover_50hPa
162
+ cloudcover_30hPa
163
+ ].freeze
164
+
165
+ HOURLY_VARIABLES_PRESSURE_LEVEL_WIND_SPEED = %i[
166
+ windspeed_1000hPa
167
+ windspeed_975hPa
168
+ windspeed_950hPa
169
+ windspeed_925hPa
170
+ windspeed_900hPa
171
+ windspeed_850hPa
172
+ windspeed_800hPa
173
+ windspeed_700hPa
174
+ windspeed_600hPa
175
+ windspeed_500hPa
176
+ windspeed_400hPa
177
+ windspeed_300hPa
178
+ windspeed_250hPa
179
+ windspeed_200hPa
180
+ windspeed_150hPa
181
+ windspeed_100hPa
182
+ windspeed_70hPa
183
+ windspeed_50hPa
184
+ windspeed_30hPa
185
+ ].freeze
186
+
187
+ HOURLY_VARIABLES_PRESSURE_LEVEL_WIND_DIRECTION = %i[
188
+ winddirection_1000hPa
189
+ winddirection_975hPa
190
+ winddirection_950hPa
191
+ winddirection_925hPa
192
+ winddirection_900hPa
193
+ winddirection_850hPa
194
+ winddirection_800hPa
195
+ winddirection_700hPa
196
+ winddirection_600hPa
197
+ winddirection_500hPa
198
+ winddirection_400hPa
199
+ winddirection_300hPa
200
+ winddirection_250hPa
201
+ winddirection_200hPa
202
+ winddirection_150hPa
203
+ winddirection_100hPa
204
+ winddirection_70hPa
205
+ winddirection_50hPa
206
+ winddirection_30hPa
207
+ ].freeze
208
+
209
+ HOURLY_VARIABLES_PRESSURE_LEVEL_GEOPOTENTIAL_HEIGHT = %i[
210
+ geopotential_height_1000hPa
211
+ geopotential_height_975hPa
212
+ geopotential_height_950hPa
213
+ geopotential_height_925hPa
214
+ geopotential_height_900hPa
215
+ geopotential_height_850hPa
216
+ geopotential_height_800hPa
217
+ geopotential_height_700hPa
218
+ geopotential_height_600hPa
219
+ geopotential_height_500hPa
220
+ geopotential_height_400hPa
221
+ geopotential_height_300hPa
222
+ geopotential_height_250hPa
223
+ geopotential_height_200hPa
224
+ geopotential_height_150hPa
225
+ geopotential_height_100hPa
226
+ geopotential_height_70hPa
227
+ geopotential_height_50hPa
228
+ geopotential_height_30hPa
229
+ ].freeze
230
+
231
+ HOURLY_VARIABLES = [
232
+ *HOURLY_VARIABLES_BASE,
233
+ *HOURLY_VARIABLES_ADDITIONAL,
234
+ *HOURLY_VARIABLES_SOLAR_RADIATION,
235
+ *HOURLY_VARIABLES_PRESSURE_LEVEL_TEMPERATURE,
236
+ *HOURLY_VARIABLES_PRESSURE_LEVEL_RELATIVE_HUMIDITY,
237
+ *HOURLY_VARIABLES_PRESSURE_LEVEL_CLOUDCOVER,
238
+ *HOURLY_VARIABLES_PRESSURE_LEVEL_WIND_SPEED,
239
+ *HOURLY_VARIABLES_PRESSURE_LEVEL_WIND_DIRECTION,
240
+ *HOURLY_VARIABLES_PRESSURE_LEVEL_GEOPOTENTIAL_HEIGHT,
241
+ ].freeze
242
+
243
+ DAILY_VARIABLES = %i[
244
+ apparent_temperature_max
245
+ apparent_temperature_min
246
+ et0_fao_evapotranspiration
247
+ precipitation_hours
248
+ precipitation_probability_max
249
+ precipitation_sum
250
+ rain_sum
251
+ shortwave_radiation_sum
252
+ showers_sum
253
+ snowfall_sum
254
+ sunrise
255
+ sunset
256
+ temperature_2m_max
257
+ temperature_2m_min
258
+ uv_index_clear_sky_max
259
+ uv_index_max
260
+ weathercode
261
+ winddirection_10m_dominant
262
+ windgusts_10m_max
263
+ windspeed_10m_max
264
+ ].freeze
265
+
266
+ rule(:current).each do
267
+ unless CURRENT_VARIABALES.include?(value)
268
+ key.failure("must be one of #{CURRENT_VARIABALES.join(", ")}")
269
+ end
270
+ end
271
+
272
+ rule(:hourly).each do
273
+ unless HOURLY_VARIABLES.include?(value)
274
+ key.failure("must be one of #{HOURLY_VARIABLES.join(", ")}")
275
+ end
276
+ end
277
+
278
+ rule(:daily).each do
279
+ unless DAILY_VARIABLES.include?(value)
280
+ key.failure("must be one of #{DAILY_VARIABLES.join(", ")}")
281
+ end
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
@@ -9,6 +9,8 @@ module OpenMeteo
9
9
  class Forecast
10
10
  class ForecastModelNotImplemented < StandardError
11
11
  end
12
+ class WrongLocationType < StandardError
13
+ end
12
14
 
13
15
  def initialize(client: OpenMeteo::Client.new)
14
16
  @client = client
@@ -19,10 +21,10 @@ module OpenMeteo
19
21
 
20
22
  model_definition = get_model_definition(model)
21
23
 
22
- variables = model_definition[:variables_class].new(**variables)
23
- variables.validate
24
+ variables_object = model_definition[:variables_class].new(**variables)
25
+ variables_object.validate!
24
26
 
25
- get_forecast(model_definition[:endpoint], location, variables)
27
+ get_forecast(model_definition[:endpoint], location, variables_object)
26
28
  end
27
29
 
28
30
  private
@@ -42,7 +44,7 @@ module OpenMeteo
42
44
  end
43
45
 
44
46
  def ensure_valid_location(location)
45
- raise "Not an OpenMeteo::Location" unless location.is_a? OpenMeteo::Location
47
+ raise WrongLocationType unless location.is_a? OpenMeteo::Location
46
48
 
47
49
  location.validate!
48
50
  end
@@ -1,17 +1,14 @@
1
+ require_relative "location_contract"
2
+
1
3
  module OpenMeteo
2
4
  ##
3
5
  # A location for a request to OpenMeteo.
4
- class Location
5
- attr_reader :latitude, :longitude
6
-
7
- def initialize(longitude:, latitude:)
8
- @longitude = longitude
9
- @latitude = latitude
10
- end
6
+ class Location < Dry::Struct
7
+ attribute :latitude, OpenMeteo::Types::Strict::Float
8
+ attribute :longitude, OpenMeteo::Types::Strict::Float
11
9
 
12
10
  def validate!
13
- # FIXME: Placeholder for validation
14
- true
11
+ LocationContract.validate!(to_hash)
15
12
  end
16
13
 
17
14
  def to_get_params
@@ -0,0 +1,14 @@
1
+ module OpenMeteo
2
+ ##
3
+ # Validation contract for OpenMeteo::Location.
4
+ class LocationContract < OpenMeteo::ApplicationContract
5
+ params do
6
+ required(:latitude).filled(:float)
7
+ required(:longitude).filled(:float)
8
+ end
9
+
10
+ rule(:latitude) { key.failure("must be within [-90;90]") if value < -90 || value > 90 }
11
+
12
+ rule(:longitude) { key.failure("must be within [-180;180]") if value < -180 || value > 180 }
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ require "dry-types"
2
+ require "dry-struct"
3
+ require "dry-validation"
4
+
5
+ require_relative "application_contract"
6
+
7
+ module OpenMeteo
8
+ ##
9
+ # The types from the dry-types gem.
10
+ module Types
11
+ include Dry.Types()
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module OpenMeteo
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.3".freeze
3
3
  end
data/lib/open_meteo.rb CHANGED
@@ -1,2 +1,3 @@
1
- require "open_meteo/forecast"
1
+ require "open_meteo/types"
2
2
  require "open_meteo/location"
3
+ require "open_meteo/forecast"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: open-meteo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Morgenstern
@@ -10,6 +10,46 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2023-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-struct
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: dry-validation
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.0.0
13
53
  - !ruby/object:Gem::Dependency
14
54
  name: faraday
15
55
  requirement: !ruby/object:Gem::Requirement
@@ -38,12 +78,16 @@ extensions: []
38
78
  extra_rdoc_files: []
39
79
  files:
40
80
  - lib/open_meteo.rb
81
+ - lib/open_meteo/application_contract.rb
41
82
  - lib/open_meteo/client.rb
42
83
  - lib/open_meteo/client/config.rb
43
84
  - lib/open_meteo/client/url_builder.rb
44
85
  - lib/open_meteo/forecast.rb
45
86
  - lib/open_meteo/forecast/variables/general.rb
87
+ - lib/open_meteo/forecast/variables/general_contract.rb
46
88
  - lib/open_meteo/location.rb
89
+ - lib/open_meteo/location_contract.rb
90
+ - lib/open_meteo/types.rb
47
91
  - lib/open_meteo/version.rb
48
92
  homepage: https://github.com/open-meteo-ruby/open-meteo-ruby
49
93
  licenses:
@@ -65,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
109
  - !ruby/object:Gem::Version
66
110
  version: '0'
67
111
  requirements: []
68
- rubygems_version: 3.3.7
112
+ rubygems_version: 3.3.26
69
113
  signing_key:
70
114
  specification_version: 4
71
115
  summary: A client for OpenMeteo weather data