open-meteo 0.0.2 → 0.0.3

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