open-meteo 0.0.3 → 0.1.0

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: c4d1b8d00c232c9cd399effc4246167fc6bdcf848cbe77d6ca4c84fa177a0979
4
- data.tar.gz: 5e87b95a9ed8876b46bfce225fde195f2e43f5deb7b816e6271eacf76db54968
3
+ metadata.gz: 823b394116c34b4acad4f7a01f7e48aa70db6b1953f316cf65c5fe7bc10c22fd
4
+ data.tar.gz: 472b5dd09142afea3e1f496654719150fa3d172a05ef6519d188d558e8f6e2d5
5
5
  SHA512:
6
- metadata.gz: 36ac57fc2acb0062996b48c3736058e2d7b2e4ab29dd4eea3ea9857d768bbf4a14a50a5496d44c69a1b307daf8c5d38e600a3f6b4bc359cd6084eebc646a0eec
7
- data.tar.gz: a71d7e7e08144eb2dc61c850bb45e66bf1614031bddc8405c6babeb02a46572457d9796c6387b27fb43882355d514676c5eaa092e1dec97ab5f3e8c1dd6f5196
6
+ metadata.gz: c52a61be8ca120808d296925106c5d19c4486b6cf0835606a05484be01f4f25268af330baae510ce3dd0f6b240391673dca8e4bdcac5121742330c6a81b3c8e3
7
+ data.tar.gz: 686bdb878b51779187d22b1262d479fedcff9f179761cfc4049754f7bd213d44ff19196f0ba5c4eb849de647722ab7694cda6f3c4190df491bef4e91776e3c1a
@@ -3,10 +3,11 @@ module OpenMeteo
3
3
  ##
4
4
  # The configuration for the OpenMeteo::Client.
5
5
  class Config
6
- attr_reader :host
6
+ attr_reader :host, :logger
7
7
 
8
- def initialize(host: "api.open-meteo.com")
9
- @host = host
8
+ def initialize(host: nil, logger: nil)
9
+ @host = host || OpenMeteo.configuration.host
10
+ @logger = logger || OpenMeteo.configuration.logger
10
11
  end
11
12
 
12
13
  def url
@@ -0,0 +1,31 @@
1
+ module OpenMeteo
2
+ ##
3
+ # The global configuration of the OpenMeteo client.
4
+ #
5
+ # @see OpenMeteo.configure
6
+ class Configuration
7
+ def initialize
8
+ @config = {}
9
+ end
10
+
11
+ ##
12
+ # Create a getter and a setter for a setting.
13
+ #
14
+ # If the default value is a Proc, it will be called on initialize.
15
+ #
16
+ # @param name: Symbol
17
+ # @param default: Proc | Object
18
+ def self.add_setting(name, default)
19
+ define_method name do
20
+ @config[name] ||= default.is_a?(Proc) ? default.call : default
21
+ end
22
+
23
+ define_method "#{name}=" do |value|
24
+ @config[name] = value
25
+ end
26
+ end
27
+
28
+ add_setting :logger, -> { Logger.new($stdout) }
29
+ add_setting :host, "api.open-meteo.com"
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ module Contracts
4
+ ##
5
+ # Shared functionality for dry contracts.
6
+ class ApplicationContract < Dry::Validation::Contract
7
+ ##
8
+ # A validation error that can be raised on contract validation.
9
+ class ValidationError < StandardError
10
+ attr_reader :result, :errors
11
+
12
+ def initialize(result)
13
+ @errors = result.errors
14
+ first_error_key = result.errors.first.path.first
15
+ first_error_value = result[first_error_key]
16
+
17
+ super(
18
+ "Validation failed: :#{first_error_key} is #{first_error_value} but #{errors.first.text}",
19
+ )
20
+ end
21
+ end
22
+
23
+ def self.validate!(object)
24
+ result = new.call(object)
25
+ raise ValidationError, result unless result.errors.empty?
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ module Contracts
4
+ ##
5
+ # Validation contract for OpenMeteo::Entities::Location.
6
+ class LocationContract < OpenMeteo::Entities::Contracts::ApplicationContract
7
+ params do
8
+ required(:latitude).filled(:float)
9
+ required(:longitude).filled(:float)
10
+ end
11
+
12
+ rule(:latitude) { key.failure("must be within [-90;90]") if value < -90 || value > 90 }
13
+
14
+ rule(:longitude) { key.failure("must be within [-180;180]") if value < -180 || value > 180 }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ class Forecast
4
+ ##
5
+ # A forecast Entity for current data returned by OpenMeteo
6
+ class Current
7
+ attr_reader :item, :units, :raw_json_current, :raw_json_current_units
8
+
9
+ def initialize(json_current, json_current_units)
10
+ @item = json_current && OpenMeteo::Entities::Forecast::Item.new(json_current)
11
+ @units =
12
+ json_current_units && OpenMeteo::Entities::Forecast::Units.new(json_current_units)
13
+
14
+ @raw_json_current = json_current
15
+ @raw_json_current_units = json_current_units
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ class Forecast
4
+ ##
5
+ # A forecast Entity for daily data returned by OpenMeteo
6
+ class Daily
7
+ attr_reader :items, :units, :raw_json_daily, :raw_json_daily_units
8
+
9
+ def initialize(json_daily, json_daily_units)
10
+ @items = initialize_items(json_daily)
11
+ @units = json_daily_units && OpenMeteo::Entities::Forecast::Units.new(json_daily_units)
12
+
13
+ @raw_json_daily = json_daily
14
+ @raw_json_daily_units = json_daily_units
15
+ end
16
+
17
+ private
18
+
19
+ def initialize_items(json_daily)
20
+ json_daily["time"]
21
+ .map do |element|
22
+ json_daily
23
+ .keys
24
+ .each_with_object({}) do |attr, json_item|
25
+ json_item[attr] = json_daily[attr][json_daily["time"].index(element)]
26
+ end
27
+ end
28
+ .map { |json_item| OpenMeteo::Entities::Forecast::Item.new(json_item) }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ class Forecast
4
+ ##
5
+ # A forecast Entity for hourly data returned by OpenMeteo
6
+ class Hourly
7
+ attr_reader :items, :units, :raw_json_hourly, :raw_json_hourly_units
8
+
9
+ def initialize(json_hourly, json_hourly_units)
10
+ @items = initialize_items(json_hourly)
11
+ @units = json_hourly_units && OpenMeteo::Entities::Forecast::Units.new(json_hourly_units)
12
+
13
+ @raw_json_hourly = json_hourly
14
+ @raw_json_hourly_units = json_hourly_units
15
+ end
16
+
17
+ private
18
+
19
+ def initialize_items(json_hourly)
20
+ json_hourly["time"]
21
+ .map do |element|
22
+ json_hourly
23
+ .keys
24
+ .each_with_object({}) do |attr, json_item|
25
+ json_item[attr] = json_hourly[attr][json_hourly["time"].index(element)]
26
+ end
27
+ end
28
+ .map { |json_item| OpenMeteo::Entities::Forecast::Item.new(json_item) }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,81 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ class Forecast
4
+ ##
5
+ # A forecast entity for a data item returned by OpenMeteo
6
+ class Item
7
+ class UnknownWeatherCode < StandardError
8
+ end
9
+
10
+ ##
11
+ # The conversion map of weather_codes to a more descriptive symbol.
12
+ #
13
+ # See "WMO Weather interpretation codes (WW)" on
14
+ # https://open-meteo.com/en/docs
15
+ WMO_CODE_TO_SYMBOL_MAP = {
16
+ 0 => :clear_sky,
17
+ 1 => :mainly_clear,
18
+ 2 => :partly_cloudy,
19
+ 3 => :overcast,
20
+ 45 => :fog,
21
+ 48 => :depositing_rime_fog,
22
+ 51 => :drizzle_light,
23
+ 53 => :drizzle_moderate,
24
+ 55 => :drizzle_dense,
25
+ 56 => :freezing_drizzle_light,
26
+ 57 => :freezing_drizzle_dense,
27
+ 61 => :rain_slight,
28
+ 63 => :rain_moderate,
29
+ 65 => :rain_heavy,
30
+ 66 => :freezing_rain_slight,
31
+ 67 => :freezing_rain_heavy,
32
+ 71 => :snow_slight,
33
+ 73 => :snow_moderate,
34
+ 75 => :snow_heavy,
35
+ 77 => :snow_grains,
36
+ 80 => :rain_showers_slight,
37
+ 81 => :rain_showers_moderate,
38
+ 82 => :rain_showers_violent,
39
+ 85 => :snow_showers_slight,
40
+ 86 => :snow_showers_heavy,
41
+ 95 => :thunderstorm_slight_or_moderate,
42
+ 96 => :thunderstorm_with_slight_hail,
43
+ 99 => :thunderstorm_with_heavy_hail,
44
+ }.freeze
45
+
46
+ attr_reader :raw_json, :attributes, :time
47
+
48
+ def initialize(json_data)
49
+ @raw_json = json_data
50
+
51
+ @attributes = json_data.keys
52
+ @time = json_data["time"]
53
+ end
54
+
55
+ ##
56
+ # Provide a symbol for the weather_code.
57
+ #
58
+ # @see WMO_CODE_TO_SYMBOL_MAP
59
+ def weather_code_symbol
60
+ return if weather_code.nil?
61
+
62
+ WMO_CODE_TO_SYMBOL_MAP.fetch(weather_code) { raise UnknownWeatherCode, weather_code }
63
+ end
64
+
65
+ private
66
+
67
+ def method_missing(name, *args)
68
+ if raw_json.key?(name.to_s)
69
+ raw_json[name.to_s]
70
+ else
71
+ super
72
+ end
73
+ end
74
+
75
+ def respond_to_missing?(name, include_private = false)
76
+ raw_json.key?(name.to_s) || super
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,32 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ class Forecast
4
+ ##
5
+ # A forecast entity for data units returned by OpenMeteo
6
+ class Units
7
+ attr_reader :raw_json_units, :attributes, :time
8
+
9
+ def initialize(json_units)
10
+ @raw_json_units = json_units
11
+
12
+ @attributes = json_units.keys
13
+ @time = json_units["time"]
14
+ end
15
+
16
+ private
17
+
18
+ def method_missing(name, *args)
19
+ if raw_json_units.key?(name.to_s)
20
+ raw_json_units[name.to_s]
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def respond_to_missing?(name, include_private = false)
27
+ raw_json_units.key?(name.to_s) || super
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,37 @@
1
+ require_relative "forecast/current"
2
+ require_relative "forecast/hourly"
3
+ require_relative "forecast/daily"
4
+ require_relative "forecast/units"
5
+ require_relative "forecast/item"
6
+
7
+ module OpenMeteo
8
+ module Entities
9
+ #
10
+ # A forecast Entity with data returned by OpenMeteo
11
+ class Forecast
12
+ attr_reader :attributes, :current, :hourly, :daily, :raw_json
13
+
14
+ def initialize(json_body)
15
+ @raw_json = json_body
16
+
17
+ @current =
18
+ json_body["current"] &&
19
+ OpenMeteo::Entities::Forecast::Current.new(
20
+ json_body["current"],
21
+ json_body["current_units"],
22
+ )
23
+ @hourly =
24
+ json_body["hourly"] &&
25
+ OpenMeteo::Entities::Forecast::Hourly.new(
26
+ json_body["hourly"],
27
+ json_body["hourly_units"],
28
+ )
29
+ @daily =
30
+ json_body["daily"] &&
31
+ OpenMeteo::Entities::Forecast::Daily.new(json_body["daily"], json_body["daily_units"])
32
+
33
+ @attributes = json_body.keys
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,20 @@
1
+ require_relative "contracts/location_contract"
2
+
3
+ module OpenMeteo
4
+ module Entities
5
+ ##
6
+ # A location for a request to OpenMeteo.
7
+ class Location < Dry::Struct
8
+ attribute :latitude, OpenMeteo::Types::Coercible::Decimal
9
+ attribute :longitude, OpenMeteo::Types::Coercible::Decimal
10
+
11
+ def validate!
12
+ OpenMeteo::Entities::Contracts::LocationContract.validate!(to_hash)
13
+ end
14
+
15
+ def to_get_params
16
+ { latitude:, longitude: }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ module OpenMeteo
2
+ module Errors
3
+ class ResponseError < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,32 @@
1
+ module OpenMeteo
2
+ class Forecast
3
+ ##
4
+ # The Variables for a forecast request to the OpenMeteo API.
5
+ #
6
+ # See https://open-meteo.com/en/docs
7
+ class Variables < Dry::Struct
8
+ attribute(
9
+ :current,
10
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
11
+ )
12
+ attribute(
13
+ :hourly,
14
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
15
+ )
16
+ attribute(
17
+ :daily,
18
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
19
+ )
20
+
21
+ def to_get_params
22
+ get_params = {}
23
+
24
+ get_params[:current] = current.join(",") if current != []
25
+ get_params[:hourly] = hourly.join(",") if hourly != []
26
+ get_params[:daily] = daily.join(",") if daily != []
27
+
28
+ get_params
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  require_relative "client"
2
- require_relative "forecast/variables/general"
2
+ require_relative "forecast/variables"
3
3
 
4
4
  module OpenMeteo
5
5
  ##
@@ -21,8 +21,7 @@ module OpenMeteo
21
21
 
22
22
  model_definition = get_model_definition(model)
23
23
 
24
- variables_object = model_definition[:variables_class].new(**variables)
25
- variables_object.validate!
24
+ variables_object = OpenMeteo::Forecast::Variables.new(**variables)
26
25
 
27
26
  get_forecast(model_definition[:endpoint], location, variables_object)
28
27
  end
@@ -34,7 +33,6 @@ module OpenMeteo
34
33
  AVAILABLE_FORECAST_MODELS = {
35
34
  general: {
36
35
  # See https://open-meteo.com/en/docs
37
- variables_class: OpenMeteo::Forecast::Variables::General,
38
36
  endpoint: :forecast,
39
37
  },
40
38
  }.freeze
@@ -44,7 +42,7 @@ module OpenMeteo
44
42
  end
45
43
 
46
44
  def ensure_valid_location(location)
47
- raise WrongLocationType unless location.is_a? OpenMeteo::Location
45
+ raise WrongLocationType unless location.is_a? OpenMeteo::Entities::Location
48
46
 
49
47
  location.validate!
50
48
  end
@@ -0,0 +1,40 @@
1
+ module OpenMeteo
2
+ ##
3
+ # Wrap the JSON body response from the OpenMeteo request.
4
+ #
5
+ class ResponseWrapper
6
+ def initialize(config: OpenMeteo::Client::Config.new)
7
+ @config = config
8
+ end
9
+
10
+ def wrap(response, entity:)
11
+ raise OpenMeteo::Errors::ResponseError, "Empty body" if response.body.nil?
12
+
13
+ json_body = JSON.parse(response.body)
14
+ check_for_error(response, json_body)
15
+
16
+ entity.new(json_body)
17
+ rescue JSON::ParserError
18
+ raise OpenMeteo::Errors::ResponseError, "Unable to parse the response body: #{response.body}"
19
+ end
20
+
21
+ private
22
+
23
+ def check_for_error(response, json_body)
24
+ return if response.status == 200
25
+
26
+ error_messages = extract_error_messages(json_body)
27
+
28
+ @config.logger.debug(error_messages)
29
+
30
+ raise OpenMeteo::Errors::ResponseError, error_messages
31
+ end
32
+
33
+ def extract_error_messages(json_body)
34
+ error_value = json_body["error"]
35
+ return "" if error_value.nil? || error_value == false
36
+
37
+ json_body["reason"].to_s
38
+ end
39
+ end
40
+ end
@@ -2,7 +2,7 @@ require "dry-types"
2
2
  require "dry-struct"
3
3
  require "dry-validation"
4
4
 
5
- require_relative "application_contract"
5
+ require_relative "entities/contracts/application_contract"
6
6
 
7
7
  module OpenMeteo
8
8
  ##
@@ -1,3 +1,3 @@
1
1
  module OpenMeteo
2
- VERSION = "0.0.3".freeze
2
+ VERSION = "0.1.0".freeze
3
3
  end
data/lib/open_meteo.rb CHANGED
@@ -1,3 +1,37 @@
1
1
  require "open_meteo/types"
2
- require "open_meteo/location"
2
+ require "open_meteo/configuration"
3
+ require "open_meteo/entities/location"
4
+ require "open_meteo/entities/forecast"
3
5
  require "open_meteo/forecast"
6
+ require "open_meteo/response_wrapper"
7
+ require "open_meteo/errors"
8
+
9
+ ##
10
+ # The OpenMeteo client.
11
+ module OpenMeteo
12
+ # Returns the global `OpenMeteo::Configuration` object. While
13
+ # you _can_ use this method to access the configuration, the more common
14
+ # convention is to use `OpenMeteo.configure``
15
+ #
16
+ # @example
17
+ # OpenMeteo.configuration.logger = Logger.new($stdout)
18
+ # @see OpenMeteo.configure
19
+ # @see OpenMeteo::Configuration
20
+ def self.configuration
21
+ @configuration ||= OpenMeteo::Configuration.new
22
+ end
23
+
24
+ # Yields the global configuration to a block.
25
+ # @yield [Configuration] global configuration
26
+ #
27
+ # @example
28
+ # OpenMeteo.configure do |config|
29
+ # config.logger Logger.new($stdout)
30
+ # end
31
+ # @see OpenMeteo::Configuration
32
+ def self.configure
33
+ raise ArgumentError, "Please provide a block to configure" unless block_given?
34
+
35
+ yield configuration
36
+ end
37
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: open-meteo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Morgenstern
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-03 00:00:00.000000000 Z
11
+ date: 2023-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-struct
@@ -78,15 +78,23 @@ extensions: []
78
78
  extra_rdoc_files: []
79
79
  files:
80
80
  - lib/open_meteo.rb
81
- - lib/open_meteo/application_contract.rb
82
81
  - lib/open_meteo/client.rb
83
82
  - lib/open_meteo/client/config.rb
84
83
  - lib/open_meteo/client/url_builder.rb
84
+ - lib/open_meteo/configuration.rb
85
+ - lib/open_meteo/entities/contracts/application_contract.rb
86
+ - lib/open_meteo/entities/contracts/location_contract.rb
87
+ - lib/open_meteo/entities/forecast.rb
88
+ - lib/open_meteo/entities/forecast/current.rb
89
+ - lib/open_meteo/entities/forecast/daily.rb
90
+ - lib/open_meteo/entities/forecast/hourly.rb
91
+ - lib/open_meteo/entities/forecast/item.rb
92
+ - lib/open_meteo/entities/forecast/units.rb
93
+ - lib/open_meteo/entities/location.rb
94
+ - lib/open_meteo/errors.rb
85
95
  - lib/open_meteo/forecast.rb
86
- - lib/open_meteo/forecast/variables/general.rb
87
- - lib/open_meteo/forecast/variables/general_contract.rb
88
- - lib/open_meteo/location.rb
89
- - lib/open_meteo/location_contract.rb
96
+ - lib/open_meteo/forecast/variables.rb
97
+ - lib/open_meteo/response_wrapper.rb
90
98
  - lib/open_meteo/types.rb
91
99
  - lib/open_meteo/version.rb
92
100
  homepage: https://github.com/open-meteo-ruby/open-meteo-ruby
@@ -109,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
117
  - !ruby/object:Gem::Version
110
118
  version: '0'
111
119
  requirements: []
112
- rubygems_version: 3.3.26
120
+ rubygems_version: 3.4.21
113
121
  signing_key:
114
122
  specification_version: 4
115
123
  summary: A client for OpenMeteo weather data
@@ -1,26 +0,0 @@
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,40 +0,0 @@
1
- require_relative "general_contract"
2
-
3
- module OpenMeteo
4
- class Forecast
5
- module Variables
6
- ##
7
- # The Variables for a general request (meaning without a specific model) to the OpenMeteo API.
8
- #
9
- # See https://open-meteo.com/en/docs
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
- )
23
-
24
- def validate!
25
- GeneralContract.validate!(to_hash)
26
- end
27
-
28
- def to_get_params
29
- get_params = {}
30
-
31
- get_params[:current] = current.join(",") if current != []
32
- get_params[:hourly] = hourly.join(",") if hourly != []
33
- get_params[:daily] = daily.join(",") if daily != []
34
-
35
- get_params
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,286 +0,0 @@
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
@@ -1,18 +0,0 @@
1
- require_relative "location_contract"
2
-
3
- module OpenMeteo
4
- ##
5
- # A location for a request to OpenMeteo.
6
- class Location < Dry::Struct
7
- attribute :latitude, OpenMeteo::Types::Strict::Float
8
- attribute :longitude, OpenMeteo::Types::Strict::Float
9
-
10
- def validate!
11
- LocationContract.validate!(to_hash)
12
- end
13
-
14
- def to_get_params
15
- { latitude:, longitude: }
16
- end
17
- end
18
- end
@@ -1,14 +0,0 @@
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