open-meteo 0.0.2 → 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: 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