open-meteo 0.0.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1fd59fe55c171c4cefb24b80613933b28d10040fdff524490dcd9e6e2ed0514
4
- data.tar.gz: 8231a53ba4250c627db4c44eb513f6f0cf41631c3a5ba3c3934a20d0ee731562
3
+ metadata.gz: 823b394116c34b4acad4f7a01f7e48aa70db6b1953f316cf65c5fe7bc10c22fd
4
+ data.tar.gz: 472b5dd09142afea3e1f496654719150fa3d172a05ef6519d188d558e8f6e2d5
5
5
  SHA512:
6
- metadata.gz: ec997727575db6186329054eca41b3c60c6729571788d012c57a74ed7c0314308ee75e11dc201287cc396d6be570b1e38ef675dd67ebd79e41d3d5a645de7957
7
- data.tar.gz: 4055bd5d3d7d63c40f3cfa8eae6822f755d806c48b7e700e65ffd2de14bdd3761373318bba2699752c97db26621893cefb3ec1b34caa87d9151ca5c05b112d40
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
  ##
@@ -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,9 @@ 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 = OpenMeteo::Forecast::Variables.new(**variables)
24
25
 
25
- get_forecast(model_definition[:endpoint], location, variables)
26
+ get_forecast(model_definition[:endpoint], location, variables_object)
26
27
  end
27
28
 
28
29
  private
@@ -32,7 +33,6 @@ module OpenMeteo
32
33
  AVAILABLE_FORECAST_MODELS = {
33
34
  general: {
34
35
  # See https://open-meteo.com/en/docs
35
- variables_class: OpenMeteo::Forecast::Variables::General,
36
36
  endpoint: :forecast,
37
37
  },
38
38
  }.freeze
@@ -42,7 +42,7 @@ module OpenMeteo
42
42
  end
43
43
 
44
44
  def ensure_valid_location(location)
45
- raise "Not an OpenMeteo::Location" unless location.is_a? OpenMeteo::Location
45
+ raise WrongLocationType unless location.is_a? OpenMeteo::Entities::Location
46
46
 
47
47
  location.validate!
48
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
@@ -0,0 +1,13 @@
1
+ require "dry-types"
2
+ require "dry-struct"
3
+ require "dry-validation"
4
+
5
+ require_relative "entities/contracts/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.1.0".freeze
3
3
  end
data/lib/open_meteo.rb CHANGED
@@ -1,2 +1,37 @@
1
+ require "open_meteo/types"
2
+ require "open_meteo/configuration"
3
+ require "open_meteo/entities/location"
4
+ require "open_meteo/entities/forecast"
1
5
  require "open_meteo/forecast"
2
- require "open_meteo/location"
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,15 +1,55 @@
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.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
+ - !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
@@ -41,9 +81,21 @@ files:
41
81
  - lib/open_meteo/client.rb
42
82
  - lib/open_meteo/client/config.rb
43
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
44
95
  - lib/open_meteo/forecast.rb
45
- - lib/open_meteo/forecast/variables/general.rb
46
- - lib/open_meteo/location.rb
96
+ - lib/open_meteo/forecast/variables.rb
97
+ - lib/open_meteo/response_wrapper.rb
98
+ - lib/open_meteo/types.rb
47
99
  - lib/open_meteo/version.rb
48
100
  homepage: https://github.com/open-meteo-ruby/open-meteo-ruby
49
101
  licenses:
@@ -65,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
117
  - !ruby/object:Gem::Version
66
118
  version: '0'
67
119
  requirements: []
68
- rubygems_version: 3.3.7
120
+ rubygems_version: 3.4.21
69
121
  signing_key:
70
122
  specification_version: 4
71
123
  summary: A client for OpenMeteo weather data
@@ -1,34 +0,0 @@
1
- module OpenMeteo
2
- class Forecast
3
- module Variables
4
- ##
5
- # The Variables for a general request (meaning without a specific model) to the OpenMeteo API.
6
- #
7
- # 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
16
-
17
- def validate
18
- # FIXME: Placeholder for validation
19
- true
20
- end
21
-
22
- def to_get_params
23
- get_params = {}
24
-
25
- get_params[:current] = current.join(",") if current != []
26
- get_params[:hourly] = hourly.join(",") if hourly != []
27
- get_params[:daily] = daily.join(",") if daily != []
28
-
29
- get_params
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,21 +0,0 @@
1
- module OpenMeteo
2
- ##
3
- # 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
11
-
12
- def validate!
13
- # FIXME: Placeholder for validation
14
- true
15
- end
16
-
17
- def to_get_params
18
- { latitude:, longitude: }
19
- end
20
- end
21
- end