open-meteo 0.1.0 → 0.3.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: 823b394116c34b4acad4f7a01f7e48aa70db6b1953f316cf65c5fe7bc10c22fd
4
- data.tar.gz: 472b5dd09142afea3e1f496654719150fa3d172a05ef6519d188d558e8f6e2d5
3
+ metadata.gz: f33676766f8b3c6bb0e373337e836eafe3cc8d7d4d2f0ee17a5cd397768592e8
4
+ data.tar.gz: 928328683daf2420bd23852cff7aa08ca71ffc637050dd2df5a77aa072729ac0
5
5
  SHA512:
6
- metadata.gz: c52a61be8ca120808d296925106c5d19c4486b6cf0835606a05484be01f4f25268af330baae510ce3dd0f6b240391673dca8e4bdcac5121742330c6a81b3c8e3
7
- data.tar.gz: 686bdb878b51779187d22b1262d479fedcff9f179761cfc4049754f7bd213d44ff19196f0ba5c4eb849de647722ab7694cda6f3c4190df491bef4e91776e3c1a
6
+ metadata.gz: 85d8aef77f27747a258b26e54eece4a092843bf7bb5f5b852c4d85246e56ae94bfeb902219edf78b3501fe266e741ed6d4e8a4bb8928c39ae00be8a56bfa9479
7
+ data.tar.gz: bcd21c77a39fdc3bd8f30b2ef8f003ec52d68725b5f664852086f995ad620ad2ae804eb5c6605874e29a7c5de986aacd54b498c35d4d0be90a9cd3c45790ab7d
@@ -3,9 +3,10 @@ module OpenMeteo
3
3
  ##
4
4
  # The configuration for the OpenMeteo::Client.
5
5
  class Config
6
- attr_reader :host, :logger
6
+ attr_reader :api_key, :host, :logger
7
7
 
8
- def initialize(host: nil, logger: nil)
8
+ def initialize(api_key: nil, host: nil, logger: nil)
9
+ @api_key = api_key || OpenMeteo.configuration.api_key
9
10
  @host = host || OpenMeteo.configuration.host
10
11
  @logger = logger || OpenMeteo.configuration.logger
11
12
  end
@@ -3,7 +3,7 @@ module OpenMeteo
3
3
  ##
4
4
  # The class that constructs the URLs for given endpoints.
5
5
  class UrlBuilder
6
- API_PATHS = { forecast: "v1/forecast" }.freeze
6
+ API_PATHS = { forecast: "v1/forecast", forecast_dwd_icon: "v1/dwd-icon" }.freeze
7
7
 
8
8
  attr_reader :api_config
9
9
 
@@ -1,4 +1,5 @@
1
1
  require "faraday"
2
+ require "faraday/retry"
2
3
 
3
4
  require_relative "client/config"
4
5
  require_relative "client/url_builder"
@@ -12,24 +13,23 @@ module OpenMeteo
12
13
  class Timeout < StandardError
13
14
  end
14
15
 
15
- attr_reader :api_config
16
+ # See https://github.com/lostisland/faraday-retry/tree/main#usage
17
+ RETRY_OPTIONS = { max: 3, interval: 0.05, interval_randomness: 0.5, backoff_factor: 3 }.freeze
16
18
 
17
- def initialize(
18
- api_config: OpenMeteo::Client::Config.new,
19
- url_builder: OpenMeteo::Client::UrlBuilder.new,
20
- agent: Faraday.new
21
- )
19
+ attr_reader :api_config, :agent
20
+
21
+ def initialize(api_config: OpenMeteo::Client::Config.new, url_builder: nil, agent: nil)
22
22
  @api_config = api_config
23
- @url_builder = url_builder
24
- @agent = agent
23
+ @url_builder = url_builder || UrlBuilder.new(api_config:)
24
+ @agent = agent || Faraday.new { |f| f.request :retry, RETRY_OPTIONS }
25
25
  end
26
26
 
27
27
  def get(endpoint_name, *endpoint_args, **get_params)
28
28
  endpoint = url_builder.build_url(endpoint_name, *endpoint_args)
29
29
 
30
- agent.get do |req|
31
- req.params = get_params
32
- req.url(endpoint)
30
+ agent.get do |request|
31
+ request.params = get_params.merge({ apikey: api_config.api_key }.compact)
32
+ request.url(endpoint)
33
33
  end
34
34
  rescue Faraday::ConnectionFailed => e
35
35
  raise ConnectionFailed, "Could not connect to OpenMeteo API: #{e.message}"
@@ -39,6 +39,6 @@ module OpenMeteo
39
39
 
40
40
  private
41
41
 
42
- attr_reader :agent, :url_builder
42
+ attr_reader :url_builder
43
43
  end
44
44
  end
@@ -27,5 +27,6 @@ module OpenMeteo
27
27
 
28
28
  add_setting :logger, -> { Logger.new($stdout) }
29
29
  add_setting :host, "api.open-meteo.com"
30
+ add_setting :api_key, -> { ENV.fetch("OPEN_METEO_API_KEY", nil) }
30
31
  end
31
32
  end
@@ -0,0 +1,35 @@
1
+ module OpenMeteo
2
+ module Entities
3
+ class Forecast
4
+ ##
5
+ # A forecast Entity for 15 minute data returned by OpenMeteo
6
+ class Minutely15
7
+ attr_reader :items, :units, :raw_json_hourly, :raw_json_hourly_units
8
+
9
+ def initialize(json_minutely_15, json_minutely_15_units)
10
+ @items = initialize_items(json_minutely_15)
11
+ @units =
12
+ json_minutely_15_units &&
13
+ OpenMeteo::Entities::Forecast::Units.new(json_minutely_15_units)
14
+
15
+ @raw_json_minutely_15 = json_minutely_15
16
+ @raw_json_minutely_15_units = json_minutely_15_units
17
+ end
18
+
19
+ private
20
+
21
+ def initialize_items(json_minutely_15)
22
+ json_minutely_15["time"]
23
+ .map do |element|
24
+ json_minutely_15
25
+ .keys
26
+ .each_with_object({}) do |attr, json_item|
27
+ json_item[attr] = json_minutely_15[attr][json_minutely_15["time"].index(element)]
28
+ end
29
+ end
30
+ .map { |json_item| OpenMeteo::Entities::Forecast::Item.new(json_item) }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,4 +1,5 @@
1
1
  require_relative "forecast/current"
2
+ require_relative "forecast/minutely_15"
2
3
  require_relative "forecast/hourly"
3
4
  require_relative "forecast/daily"
4
5
  require_relative "forecast/units"
@@ -9,29 +10,35 @@ module OpenMeteo
9
10
  #
10
11
  # A forecast Entity with data returned by OpenMeteo
11
12
  class Forecast
12
- attr_reader :attributes, :current, :hourly, :daily, :raw_json
13
+ attr_reader :attributes, :current, :minutely_15, :hourly, :daily, :raw_json
13
14
 
14
15
  def initialize(json_body)
15
16
  @raw_json = json_body
16
17
 
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"])
18
+ init_data_for(OpenMeteo::Entities::Forecast::Current)
19
+ init_data_for(OpenMeteo::Entities::Forecast::Minutely15)
20
+ init_data_for(OpenMeteo::Entities::Forecast::Hourly)
21
+ init_data_for(OpenMeteo::Entities::Forecast::Daily)
32
22
 
33
23
  @attributes = json_body.keys
34
24
  end
25
+
26
+ private
27
+
28
+ def init_data_for(klass)
29
+ name = name_for_klass(klass)
30
+
31
+ return if raw_json[name.to_s].nil?
32
+
33
+ instance_variable_set("@#{name}", klass.new(raw_json[name.to_s], raw_json["#{name}_units"]))
34
+ end
35
+
36
+ def name_for_klass(klass)
37
+ # Extract that last part of the class name, e.g. "Minutely15"
38
+ # from "OpenMeteo::Entities::Forecast::Minutely15"
39
+ # but as snake_case version e.g. "minutely_15"
40
+ klass.to_s.split("::").last.downcase.gsub(/(\d+)/, '_\1').to_sym
41
+ end
35
42
  end
36
43
  end
37
44
  end
@@ -9,6 +9,10 @@ module OpenMeteo
9
9
  :current,
10
10
  OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
11
11
  )
12
+ attribute(
13
+ :minutely_15,
14
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
15
+ )
12
16
  attribute(
13
17
  :hourly,
14
18
  OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
@@ -17,13 +21,17 @@ module OpenMeteo
17
21
  :daily,
18
22
  OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
19
23
  )
24
+ attribute(
25
+ :models,
26
+ OpenMeteo::Types::Strict::Array.of(OpenMeteo::Types::Strict::Symbol).default([].freeze),
27
+ )
20
28
 
21
29
  def to_get_params
22
30
  get_params = {}
23
31
 
24
- get_params[:current] = current.join(",") if current != []
25
- get_params[:hourly] = hourly.join(",") if hourly != []
26
- get_params[:daily] = daily.join(",") if daily != []
32
+ %i[current minutely_15 hourly daily models].each do |key|
33
+ get_params[key] = send(key).join(",") if send(key) != []
34
+ end
27
35
 
28
36
  get_params
29
37
  end
@@ -3,7 +3,7 @@ require_relative "forecast/variables"
3
3
 
4
4
  module OpenMeteo
5
5
  ##
6
- # Perform a forecase request to the OpenMeteo API.
6
+ # Perform a forecast request to the OpenMeteo API.
7
7
  #
8
8
  # See https://open-meteo.com/en/docs
9
9
  class Forecast
@@ -12,8 +12,9 @@ module OpenMeteo
12
12
  class WrongLocationType < StandardError
13
13
  end
14
14
 
15
- def initialize(client: OpenMeteo::Client.new)
15
+ def initialize(client: OpenMeteo::Client.new, response_wrapper: OpenMeteo::ResponseWrapper.new)
16
16
  @client = client
17
+ @response_wrapper = response_wrapper
17
18
  end
18
19
 
19
20
  def get(location:, variables:, model: :general)
@@ -35,6 +36,10 @@ module OpenMeteo
35
36
  # See https://open-meteo.com/en/docs
36
37
  endpoint: :forecast,
37
38
  },
39
+ dwd_icon: {
40
+ # See https://open-meteo.com/en/docs/dwd-api
41
+ endpoint: :forecast_dwd_icon,
42
+ },
38
43
  }.freeze
39
44
 
40
45
  def get_model_definition(model)
@@ -49,7 +54,9 @@ module OpenMeteo
49
54
 
50
55
  def get_forecast(endpoint, location, variables)
51
56
  get_params = { **location.to_get_params, **variables.to_get_params }
52
- client.get(endpoint, **get_params)
57
+ response = client.get(endpoint, **get_params)
58
+
59
+ @response_wrapper.wrap(response, entity: OpenMeteo::Entities::Forecast)
53
60
  end
54
61
  end
55
62
  end
@@ -1,3 +1,3 @@
1
1
  module OpenMeteo
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.3.0".freeze
3
3
  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.1.0
4
+ version: 0.3.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-08 00:00:00.000000000 Z
11
+ date: 2024-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-struct
@@ -70,6 +70,26 @@ dependencies:
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
72
  version: 2.0.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: faraday-retry
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '2.0'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.0.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 2.0.0
73
93
  description:
74
94
  email:
75
95
  - gundel.peter@gmail.com
@@ -89,6 +109,7 @@ files:
89
109
  - lib/open_meteo/entities/forecast/daily.rb
90
110
  - lib/open_meteo/entities/forecast/hourly.rb
91
111
  - lib/open_meteo/entities/forecast/item.rb
112
+ - lib/open_meteo/entities/forecast/minutely_15.rb
92
113
  - lib/open_meteo/entities/forecast/units.rb
93
114
  - lib/open_meteo/entities/location.rb
94
115
  - lib/open_meteo/errors.rb
@@ -117,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
138
  - !ruby/object:Gem::Version
118
139
  version: '0'
119
140
  requirements: []
120
- rubygems_version: 3.4.21
141
+ rubygems_version: 3.4.10
121
142
  signing_key:
122
143
  specification_version: 4
123
144
  summary: A client for OpenMeteo weather data