open-weather-ruby-client 0.1.0 → 0.2.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -1
  3. data/README.md +78 -9
  4. data/lib/open-weather-ruby-client.rb +1 -3
  5. data/lib/open_weather/client.rb +1 -0
  6. data/lib/open_weather/connection.rb +19 -17
  7. data/lib/open_weather/endpoints.rb +1 -0
  8. data/lib/open_weather/endpoints/current.rb +4 -4
  9. data/lib/open_weather/endpoints/one_call.rb +15 -0
  10. data/lib/open_weather/models.rb +3 -1
  11. data/lib/open_weather/models/city.rb +3 -0
  12. data/lib/open_weather/models/city/weather.rb +38 -0
  13. data/lib/open_weather/models/list.rb +7 -1
  14. data/lib/open_weather/models/main.rb +4 -4
  15. data/lib/open_weather/models/mixins.rb +4 -0
  16. data/lib/open_weather/models/mixins/speed.rb +45 -0
  17. data/lib/open_weather/models/mixins/temp.rb +64 -0
  18. data/lib/open_weather/models/model.rb +13 -0
  19. data/lib/open_weather/models/one_call.rb +9 -0
  20. data/lib/open_weather/models/one_call/current_weather.rb +35 -0
  21. data/lib/open_weather/models/one_call/daily_weather.rb +34 -0
  22. data/lib/open_weather/models/one_call/feels_like.rb +14 -0
  23. data/lib/open_weather/models/one_call/hourly_weather.rb +32 -0
  24. data/lib/open_weather/models/one_call/minutely_weather.rb +12 -0
  25. data/lib/open_weather/models/one_call/temp.rb +16 -0
  26. data/lib/open_weather/models/one_call/weather.rb +26 -0
  27. data/lib/open_weather/models/sys.rb +1 -0
  28. data/lib/open_weather/models/weather.rb +1 -0
  29. data/lib/open_weather/models/wind.rb +1 -1
  30. data/lib/open_weather/raise_error.rb +2 -2
  31. data/lib/open_weather/version.rb +1 -1
  32. metadata +19 -6
  33. data/lib/open_weather/models/city_weather.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 317dd6924aee3127f7a350a47ad0d4873db645af7d307d07a2f7f5102a058c03
4
- data.tar.gz: cd4a8bd78a0170ada43260fd0897ba388c54ddff5f9233ea79477c292affd5e4
3
+ metadata.gz: 1d3916328b6401b21690d359dab0aa1f893282b9456f7d9960fcb8a3024fc625
4
+ data.tar.gz: 66657fdd5b0cbad2889b5467cdf9e009b4b8e32cd997c0d86c7ddbf19b14e644
5
5
  SHA512:
6
- metadata.gz: df44462ca143dcd462d45ba7cb2cfc38ba1c951a705709e4b4b59d80b1b1d78057fff3cfa8aedc2d9f9c26fce1cf2b9c4a5c66178ed939055c0b4afca5083c15
7
- data.tar.gz: 256c0bac00841ba60a5ce65e10e3b66103c8756e5c619bf93479b74660d092e22973b6e8e07eaac4cdd370be243eb6382ea7f33829fd2db9d65bbe675b61d736
6
+ metadata.gz: 75c4b1f7baafa1a3a61d5b8ba3223a8ac3eeabc2a6a1ccec506e8f718608088b1289487e562a3061d74ba517c09de8bcd4150e3cbad381e893fb9db1b71976ee
7
+ data.tar.gz: 6e769293fc354dd3af19780e4cba5a92a0730d2ded3db7976f44d25e8518b49b58bd62bfd7e033ab2ca2d7194db01df03e91a834a67b55824443f45465a9b59e
@@ -1,3 +1,12 @@
1
- ### 0.1.0 (5/1/2020)
1
+ ### 0.2.0 (2020/05/17)
2
+
3
+ * [#14](https://github.com/dblock/open-weather-ruby-client/pull/14): Added support for One Call API - [@dblock](https://github.com/dblock).
4
+ * [#16](https://github.com/dblock/open-weather-ruby-client/pull/16): Added support for temperature and wind speed conversion - [@dblock](https://github.com/dblock).
5
+ * [#16](https://github.com/dblock/open-weather-ruby-client/pull/16): Added `weather#icon_url` returning a parsed `URI` - [@dblock](https://github.com/dblock).
6
+ * [#15](https://github.com/dblock/open-weather-ruby-client/pull/15): Renamed `CityWeather` to `OpenWeather::Models::City::Weather` - [@dblock](https://github.com/dblock).
7
+ * [#12](https://github.com/dblock/open-weather-ruby-client/pull/12): Cache `Faraday::Connection` for persistent adapters - [@dblock](https://github.com/dblock).
8
+ * [#13](https://github.com/dblock/open-weather-ruby-client/pull/13): Require Faraday >= 1.0 - [@dblock](https://github.com/dblock).
9
+
10
+ ### 0.1.0 (2020/05/01)
2
11
 
3
12
  * Initial public release - [@dblock](https://github.com/dblock).
data/README.md CHANGED
@@ -4,9 +4,9 @@ OpenWeather Ruby Client
4
4
  [![Gem Version](https://badge.fury.io/rb/open-weather-ruby-client.svg)](https://badge.fury.io/rb/open-weather-ruby-client)
5
5
  [![Build Status](https://travis-ci.org/dblock/open-weather-ruby-client.svg?branch=master)](https://travis-ci.org/dblock/open-weather-ruby-client)
6
6
 
7
- A Ruby client for the [OpenWeather API v3](https://openweathermap.org/api).
7
+ A Ruby client for the [OpenWeather API v2.5](https://openweathermap.org/api).
8
8
 
9
- Unlike other clients, including [open-weather](https://github.com/coderhs/ruby_open_weather_map), provides a rich first class interface to OpenWeather models, implements more consistent error handling, and is built with thorough test coverage using actual OpenWeather data.
9
+ Unlike other clients, including [open-weather](https://github.com/coderhs/ruby_open_weather_map), provides a rich first class interface to OpenWeather models, structured timestamps, built-in metrics conversion for temperature and wind speed, offers more consistent error handling, and is implemented with thorough test coverage using actual OpenWeather data.
10
10
 
11
11
  ## Table of Contents
12
12
 
@@ -17,8 +17,13 @@ Unlike other clients, including [open-weather](https://github.com/coderhs/ruby_o
17
17
  - [Cities Within a Rectangle Zone](#cities-within-a-rectangle-zone)
18
18
  - [Cities Within a Circle](#cities-within-a-circle)
19
19
  - [Multiple Cities by Id](#multiple-cities-by-id)
20
+ - [One Call](#one-call)
21
+ - [Current and Forecast Weather](#current-and-forecast-weather)
22
+ - [Historical Weather](#historical-weather)
20
23
  - [Configuration](#configuration)
21
24
  - [Units](#units)
25
+ - [Converting Temperature](#converting-temperature)
26
+ - [Converting Wind Speed](#converting-wind-speed)
22
27
  - [Language](#language)
23
28
  - [Errors](#errors)
24
29
  - [Resources](#resources)
@@ -50,21 +55,24 @@ client = OpenWeather::Client.new(
50
55
  Returns [current weather](https://openweathermap.org/current).
51
56
 
52
57
  ```ruby
53
- data = client.current_weather(city: 'London') # => OpenWeather::Models::CityWeather
58
+ data = client.current_weather(city: 'London') # => OpenWeather::Models::City::Weather
54
59
 
55
60
  data.name # => 'London'
61
+ data.dt # => Time
56
62
  data.main.feels_like # => 277.73
57
63
  data.main.humidity # => 81
58
64
  data.main.pressure # => 1005
59
65
  data.main.temp # => 282.57
60
- data.main.temp_max # => 283.15
66
+ data.main.temp_max # => 283.15, degrees Kelvin
67
+ data.main.temp_max_c # => 10, degrees Celcius
68
+ data.main.temp_max_f # => 50.0, degrees Farenheit
61
69
  data.main.temp_min # => 281.48
62
70
  ```
63
71
 
64
72
  Returns the current weather in metric units and Russian metadata.
65
73
 
66
74
  ```ruby
67
- data = client.current_weather(city: 'Moscow', units: 'metric', lang: 'ru') # => OpenWeather::Models::CityWeather
75
+ data = client.current_weather(city: 'Moscow', units: 'metric', lang: 'ru') # => OpenWeather::Models::City::Weather
68
76
 
69
77
  data.name # => 'Москва'
70
78
  data.main.temp # => 12
@@ -98,10 +106,12 @@ client.current_zip(10018, 'US') # => weather in New York, 10018
98
106
  client.current_weather(zip: 10018, country: 'US') # => weather in New York, 10018
99
107
  ```
100
108
 
101
- See [OpenWeather::Models::CityWeather](lib/open_weather/models/data.rb) for all available properties.
109
+ See [OpenWeather::Models::City::Weather](lib/open_weather/models/city/weather.rb) and related [OpenWeather::Models](lib/open_weather/models) for all available properties.
102
110
 
103
111
  ### Current Weather for Several Cities
104
112
 
113
+ Collection APIs return [OpenWeather::Models::List](lib/open_weather/models/list.rb), which includes multiple instances of [OpenWeather::Models::City::Weather](lib/open_weather/models/city/weather.rb).
114
+
105
115
  #### Cities Within a Rectangle Zone
106
116
 
107
117
  ```ruby
@@ -147,6 +157,42 @@ data.first.name # 'Moscow'
147
157
  data.main.temp # => 285.15
148
158
  ```
149
159
 
160
+ ### One Call
161
+
162
+ [One Call API](https://openweathermap.org/api/one-call-api) provides current weather, minute forecast for 1 hour, hourly forecast for 48 hours, daily forecast for 7 days, and historical weather data for 5 previous days for any geographical coordinate.
163
+
164
+ See [OpenWeather::Models::OneCall](lib/open_weather/models/one_call) for all available models and properties.
165
+
166
+ #### Current and Forecast Weather
167
+
168
+ ```ruby
169
+ data = client.one_call(lat: 33.441792, lon: -94.037689) # => OpenWeather::Models::OneCall::Weather
170
+ data.lat # => 33.44
171
+ data.lon # => -94.04
172
+ data.timezone # => 'America/Chicago'
173
+ data.current # => OpenWeather::Models::OneCall::CurrentWeather
174
+ data.minutely # => Array[OpenWeather::Models::OneCall::MinutelyWeather]
175
+ data.hourly # => Array[OpenWeather::Models::OneCall::HourlyWeather]
176
+ data.daily # => Array[OpenWeather::Models::OneCall::DailyWeather]
177
+ ```
178
+
179
+ Exclude minutely and hourly data.
180
+
181
+ ```ruby
182
+ client.one_call(lat: 33.441792, lon: -94.037689, exclude: ['minutely', 'hourly'])
183
+ ```
184
+
185
+ #### Historical Weather
186
+
187
+ ```ruby
188
+ data = client.one_call(lat: 33.441792, lon: -94.037689, dt: Time.now - 24 * 60 * 60) # => OpenWeather::Models::OneCall::Weather
189
+ data.lat # => 33.44
190
+ data.lon # => -94.04
191
+ data.timezone # => 'America/Chicago'
192
+ data.current # => OpenWeather::Models::OneCall::CurrentWeather
193
+ data.hourly # => Array[OpenWeather::Models::OneCall::HourlyWeather]
194
+ ```
195
+
150
196
  ## Configuration
151
197
 
152
198
  You can configure client options, globally.
@@ -181,7 +227,7 @@ The OpenWeather API returns responses in `standard`, `metric`, and `imperial` un
181
227
  ```ruby
182
228
  data = client.weather(id: 2643743, units: 'metric')
183
229
  data.name # => 'London'
184
- data.main.temp # => 12 (degrees Celsius)
230
+ data.main.temp # => 12, degrees Celcius
185
231
  ```
186
232
 
187
233
  ```ruby
@@ -191,7 +237,30 @@ end
191
237
 
192
238
  data = client.weather(id: 2643743)
193
239
  data.name # => 'London'
194
- data.main.temp # => 12 (degrees Celsius)
240
+ data.main.temp # => 12, degrees Celcius
241
+ ```
242
+
243
+ #### Converting Temperature
244
+
245
+ APIs that return temperature support conversion between default, metric and imperial units, regardless of what units were requested. The following example requests current weather in metric units in Moscow. Use `_k` for Kelvin, `_c` for Celcius and `_f` for Farenheit.
246
+
247
+ ```ruby
248
+ data = client.current_weather(city: 'Moscow', units: 'metric') # => OpenWeather::Models::City::Weather
249
+
250
+ data.main.temp_max # => 12, degrees Celcius, metric as requested
251
+ data.main.temp_max_c # => 12, degrees Celcius
252
+ data.main.temp_max_k # => 285.15, degrees Kelvin
253
+ data.main.temp_max_f # => 53.6, degrees Farenheit
254
+ ```
255
+
256
+ #### Converting Wind Speed
257
+
258
+ Use `_mps` for wind speed in meters-per-second, and `_mph` for miles-per-second.
259
+
260
+ ```ruby
261
+ data.wind.speed # => 3, in meters per second, metric as requested
262
+ data.main.speed_mph # => 6.71, miles per hour
263
+ data.main.speed_mps # 3, meters per second
195
264
  ```
196
265
 
197
266
  ### Language
@@ -214,7 +283,7 @@ data.name # => 'Лондон'
214
283
 
215
284
  ## Errors
216
285
 
217
- All errors that return HTTP codes 400-600 result in either `Faraday::Error::ResourceNotFound`, `Faraday::Error::ConnectionFailed` or [OpenWeather::Errors::Fault](lib/open_weather/errors/fault.rb) exceptions.
286
+ All errors that return HTTP codes 400-600 result in either `Faraday::ResourceNotFound`, `Faraday::ConnectionFailed` or [OpenWeather::Errors::Fault](lib/open_weather/errors/fault.rb) exceptions.
218
287
 
219
288
  ## Resources
220
289
 
@@ -16,13 +16,11 @@ require_relative 'open_weather/logger'
16
16
 
17
17
  require_relative 'open_weather/errors/fault'
18
18
 
19
- require_relative 'open_weather/models/model'
20
-
19
+ require_relative 'open_weather/models'
21
20
  require_relative 'open_weather/raise_error'
22
21
  require_relative 'open_weather/connection'
23
22
  require_relative 'open_weather/request'
24
23
  require_relative 'open_weather/config'
25
24
  require_relative 'open_weather/errors'
26
- require_relative 'open_weather/models'
27
25
  require_relative 'open_weather/endpoints'
28
26
  require_relative 'open_weather/client'
@@ -5,6 +5,7 @@ module OpenWeather
5
5
  include Connection
6
6
  include Request
7
7
  include Endpoints::Current
8
+ include Endpoints::OneCall
8
9
 
9
10
  attr_accessor(*Config::ATTRIBUTES)
10
11
 
@@ -9,26 +9,28 @@ module OpenWeather
9
9
  end
10
10
 
11
11
  def connection
12
- options = {
13
- headers: headers.merge('Accept' => 'application/json; charset=utf-8')
14
- }
12
+ @connection ||= begin
13
+ options = {
14
+ headers: headers.merge('Accept' => 'application/json; charset=utf-8')
15
+ }
15
16
 
16
- options[:headers]['User-Agent'] = user_agent if user_agent
17
- options[:proxy] = proxy if proxy
18
- options[:ssl] = { ca_path: ca_path, ca_file: ca_file } if ca_path || ca_file
17
+ options[:headers]['User-Agent'] = user_agent if user_agent
18
+ options[:proxy] = proxy if proxy
19
+ options[:ssl] = { ca_path: ca_path, ca_file: ca_file } if ca_path || ca_file
19
20
 
20
- request_options = {}
21
- request_options[:timeout] = timeout if timeout
22
- request_options[:open_timeout] = open_timeout if open_timeout
23
- options[:request] = request_options if request_options.any?
21
+ request_options = {}
22
+ request_options[:timeout] = timeout if timeout
23
+ request_options[:open_timeout] = open_timeout if open_timeout
24
+ options[:request] = request_options if request_options.any?
24
25
 
25
- ::Faraday::Connection.new(endpoint, options) do |connection|
26
- connection.use ::Faraday::Request::Multipart
27
- connection.use ::Faraday::Request::UrlEncoded
28
- connection.use ::OpenWeather::Response::RaiseError
29
- connection.use ::FaradayMiddleware::ParseJson, content_type: /\bjson$/
30
- connection.response :logger, logger if logger
31
- connection.adapter ::Faraday.default_adapter
26
+ ::Faraday::Connection.new(endpoint, options) do |connection|
27
+ connection.use ::Faraday::Request::Multipart
28
+ connection.use ::Faraday::Request::UrlEncoded
29
+ connection.use ::OpenWeather::Response::RaiseError
30
+ connection.use ::FaradayMiddleware::ParseJson, content_type: /\bjson$/
31
+ connection.response :logger, logger if logger
32
+ connection.adapter ::Faraday.default_adapter
33
+ end
32
34
  end
33
35
  end
34
36
  end
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'endpoints/current'
4
+ require_relative 'endpoints/one_call'
@@ -38,7 +38,7 @@ module OpenWeather
38
38
  options.delete(:country)
39
39
  ].compact.join(',')
40
40
  end
41
- OpenWeather::Models::CityWeather.new(get('weather', options))
41
+ OpenWeather::Models::City::Weather.new(get('weather', options), options)
42
42
  end
43
43
 
44
44
  def current_cities_geo_box(*args)
@@ -51,7 +51,7 @@ module OpenWeather
51
51
  options.delete(:lat_top),
52
52
  options.delete(:zoom)
53
53
  ].join(',')
54
- OpenWeather::Models::List.new(get('box/city', options))
54
+ OpenWeather::Models::List.new(get('box/city', options), options)
55
55
  end
56
56
 
57
57
  def current_cities_geo_circle(*args)
@@ -63,7 +63,7 @@ module OpenWeather
63
63
  options[:cnt] = args.shift || 1
64
64
  end
65
65
 
66
- OpenWeather::Models::List.new(get('find', options))
66
+ OpenWeather::Models::List.new(get('find', options), options)
67
67
  end
68
68
 
69
69
  def current_cities_id(*args)
@@ -71,7 +71,7 @@ module OpenWeather
71
71
  options[:id] = args.join(',') if args.any?
72
72
  options[:id] = options.delete(:ids) if options.key?(:ids)
73
73
  options[:id] = options[:id].join(',') if options[:id].is_a?(Array)
74
- OpenWeather::Models::List.new(get('group', options))
74
+ OpenWeather::Models::List.new(get('group', options), options)
75
75
  end
76
76
  end
77
77
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Endpoints
5
+ module OneCall
6
+ def one_call(lat, lon = nil, options = {})
7
+ options = lat.is_a?(Hash) ? options.merge(lat) : options.merge(lat: lat, lon: lon)
8
+ options[:exclude] = options[:exclude].join(',') if options[:exclude].is_a?(Array)
9
+ options[:dt] = options[:dt].to_i if options[:dt].is_a?(Time)
10
+ path = options.key?(:dt) ? 'onecall/timemachine' : 'onecall'
11
+ OpenWeather::Models::OneCall::Weather.new(get(path, options), options)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'models/mixins'
3
4
  require_relative 'models/model'
4
5
  require_relative 'models/clouds'
5
6
  require_relative 'models/coord'
6
- require_relative 'models/city_weather'
7
7
  require_relative 'models/main'
8
8
  require_relative 'models/sys'
9
9
  require_relative 'models/weather'
@@ -11,3 +11,5 @@ require_relative 'models/wind'
11
11
  require_relative 'models/rain'
12
12
  require_relative 'models/snow'
13
13
  require_relative 'models/list'
14
+ require_relative 'models/city'
15
+ require_relative 'models/one_call'
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'city/weather'
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module City
6
+ class Weather < Model
7
+ property 'coord'
8
+ property 'weather'
9
+ property 'base' # internal parameter
10
+ property 'main'
11
+ property 'visibility'
12
+ property 'wind'
13
+ property 'clouds'
14
+ property 'rain'
15
+ property 'snow'
16
+ property 'dt', transform_with: ->(v) { Time.at(v).utc } # time of data calculation, UTC
17
+ property 'sys'
18
+ property 'id' # city id
19
+ property 'timezone' # shift in seconds from UTC
20
+ property 'name' # city name
21
+ property 'cod' # internal parameter
22
+
23
+ def initialize(args = nil, options = {})
24
+ super args, options
25
+
26
+ self.coord = OpenWeather::Models::Coord.new(coord, options) if coord
27
+ self.weather = weather.map { |i| OpenWeather::Models::Weather.new(i, options) } if weather
28
+ self.main = OpenWeather::Models::Main.new(main, options) if main
29
+ self.wind = OpenWeather::Models::Wind.new(wind, options) if wind
30
+ self.clouds = OpenWeather::Models::Clouds.new(clouds, options) if clouds
31
+ self.rain = OpenWeather::Models::Rain.new(rain, options) if rain
32
+ self.snow = OpenWeather::Models::Snow.new(snow, options) if snow
33
+ self.sys = OpenWeather::Models::Sys.new(sys, options) if sys
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -8,9 +8,15 @@ module OpenWeather
8
8
  property 'cod'
9
9
  property 'calctime'
10
10
  property 'cnt', from: 'count'
11
- property 'list', transform_with: ->(v) { v.map { |i| OpenWeather::Models::CityWeather.new(i) } }
11
+ property 'list'
12
12
  property 'message'
13
13
 
14
+ def initialize(args = nil, options = {})
15
+ super args, options
16
+
17
+ self.list = list.map { |i| OpenWeather::Models::City::Weather.new(i, options) } if list
18
+ end
19
+
14
20
  def each(&block)
15
21
  list.each(&block)
16
22
  end
@@ -3,12 +3,12 @@
3
3
  module OpenWeather
4
4
  module Models
5
5
  class Main < Model
6
- property 'temp' # temperature in requested unit
6
+ temperature_property 'temp' # temperature in requested unit
7
7
  property 'pressure' # atmospheric pressure on the sea_level or grnd_level when unavailable, hPa
8
8
  property 'humidity' # humidity in %
9
- property 'feels_like' # temperature, accounting for the human perception of weather, in requested unit
10
- property 'temp_min' # minimal currently observed temperature
11
- property 'temp_max' # maximal currently observed temperature
9
+ temperature_property 'feels_like' # temperature, accounting for the human perception of weather, in requested unit
10
+ temperature_property 'temp_min' # minimal currently observed temperature
11
+ temperature_property 'temp_max' # maximal currently observed temperature
12
12
  property 'sea_level' # atmospheric pressure on the sea level, hPa
13
13
  property 'grnd_level' # atmospheric pressure on the ground level, hPa
14
14
  end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mixins/temp'
4
+ require_relative 'mixins/speed'
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module Mixins
6
+ module Speed
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def speed_property(field)
11
+ property field
12
+
13
+ define_method "#{field}_mps" do
14
+ to_meters_per_sec(send(field))
15
+ end
16
+
17
+ define_method "#{field}_mph" do
18
+ to_miles_per_hour(send(field))
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def to_meters_per_sec(value)
26
+ case units
27
+ when :imperial
28
+ (value.to_f / 2.23694).round(2)
29
+ else
30
+ value
31
+ end
32
+ end
33
+
34
+ def to_miles_per_hour(value)
35
+ case units
36
+ when :metric
37
+ (value * 2.23694).round(2)
38
+ else
39
+ value
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module Mixins
6
+ module Temp
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def temperature_property(field)
11
+ property field
12
+
13
+ define_method "#{field}_k" do
14
+ to_kelvin(send(field))
15
+ end
16
+
17
+ define_method "#{field}_c" do
18
+ to_celcius(send(field))
19
+ end
20
+
21
+ define_method "#{field}_f" do
22
+ to_farenheit(send(field))
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def to_kelvin(value)
30
+ case units
31
+ when :metric
32
+ (value.to_f + 273.15).round(2)
33
+ when :imperial
34
+ ((value.to_f - 32) * 5 / 9 + 273.15).round(2)
35
+ else
36
+ value
37
+ end
38
+ end
39
+
40
+ def to_celcius(value)
41
+ case units
42
+ when :metric
43
+ value
44
+ when :imperial
45
+ ((value.to_f - 32) * 5 / 9).round(2)
46
+ else
47
+ (value.to_f - 273.15).round(2)
48
+ end
49
+ end
50
+
51
+ def to_farenheit(value)
52
+ case units
53
+ when :metric
54
+ ((value.to_f * 9 / 5) + 32).round(2)
55
+ when :imperial
56
+ value
57
+ else
58
+ ((value.to_f - 273.15) * 9 / 5 + 32).round(2)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -4,6 +4,19 @@ module OpenWeather
4
4
  module Models
5
5
  class Model < Hashie::Trash
6
6
  include Hashie::Extensions::IgnoreUndeclared
7
+ include OpenWeather::Models::Mixins::Temp
8
+ include OpenWeather::Models::Mixins::Speed
9
+
10
+ attr_reader :options
11
+
12
+ def initialize(args = nil, options = {})
13
+ super args
14
+ @options = { units: OpenWeather.config.units }.merge(options || {})
15
+ end
16
+
17
+ def units
18
+ options && options[:units]&.to_sym
19
+ end
7
20
  end
8
21
  end
9
22
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'one_call/temp'
4
+ require_relative 'one_call/feels_like'
5
+ require_relative 'one_call/current_weather'
6
+ require_relative 'one_call/daily_weather'
7
+ require_relative 'one_call/hourly_weather'
8
+ require_relative 'one_call/minutely_weather'
9
+ require_relative 'one_call/weather'
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module OneCall
6
+ class CurrentWeather < Model
7
+ property 'dt', transform_with: ->(v) { Time.at(v).utc } # time of the forecasted data UTC
8
+ property 'sunrise', transform_with: ->(v) { Time.at(v).utc } # sunrise time, UTC
9
+ property 'sunset', transform_with: ->(v) { Time.at(v).utc } # sunset time, UTC
10
+ temperature_property 'temp' # temperature
11
+ temperature_property 'feels_like' # temperature, accounts for the human perception of weather
12
+ property 'pressure' # atmospheric pressure on the sea level, hPa
13
+ property 'humidity' # humidity, %
14
+ temperature_property 'dew_point' # atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form
15
+ property 'clouds' # cloudiness, %
16
+ property 'uvi' # UV index
17
+ property 'visibility' # average visibility, meters
18
+ speed_property 'wind_speed' # wind speed
19
+ speed_property 'wind_gust' # wind gust
20
+ property 'wind_deg' # wind direction, degrees (meteorological)
21
+ property 'rain'
22
+ property 'snow'
23
+ property 'weather'
24
+
25
+ def initialize(args = nil, options = {})
26
+ super args, options
27
+
28
+ self.rain = OpenWeather::Models::Rain.new(rain, options) if rain
29
+ self.snow = OpenWeather::Models::Snow.new(snow, options) if snow
30
+ self.weather = weather.map { |i| OpenWeather::Models::Weather.new(i, options) } if weather
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module OneCall
6
+ class DailyWeather < Model
7
+ property 'dt', transform_with: ->(v) { Time.at(v).utc } # time of the forecasted data UTC
8
+ property 'sunrise', transform_with: ->(v) { Time.at(v).utc } # sunrise time, UTC
9
+ property 'sunset', transform_with: ->(v) { Time.at(v).utc } # sunset time, UTC
10
+ property 'temp'
11
+ property 'feels_like'
12
+ property 'pressure' # atmospheric pressure on the sea level, hPa
13
+ property 'humidity' # humidity, %
14
+ temperature_property 'dew_point' # atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form
15
+ speed_property 'wind_speed' # wind speed
16
+ speed_property 'wind_gust' # wind gust
17
+ property 'wind_deg' # wind direction, degrees (meteorological)
18
+ property 'clouds' # cloudiness, %
19
+ property 'uvi' # UV index
20
+ property 'rain' # precipitation volume, mm
21
+ property 'snow' # snow volume, mm
22
+ property 'weather'
23
+
24
+ def initialize(args = nil, options = {})
25
+ super args, options
26
+
27
+ self.temp = OpenWeather::Models::OneCall::Temp.new(temp, options) if temp
28
+ self.feels_like = OpenWeather::Models::OneCall::FeelsLike.new(feels_like, options) if feels_like
29
+ self.weather = weather.map { |i| OpenWeather::Models::Weather.new(i, options) } if weather
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module OneCall
6
+ class FeelsLike < Model
7
+ temperature_property 'morn'
8
+ temperature_property 'day'
9
+ temperature_property 'eve'
10
+ temperature_property 'night'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module OneCall
6
+ class HourlyWeather < Model
7
+ property 'dt', transform_with: ->(v) { Time.at(v).utc } # Time of the forecasted data UTC
8
+ temperature_property 'temp'
9
+ temperature_property 'feels_like'
10
+ property 'pressure' # atmospheric pressure on the sea level, hPa
11
+ property 'humidity' # humidity, %
12
+ temperature_property 'dew_point' # atmospheric temperature (varying according to pressure and humidity) below which water droplets begin to condense and dew can form
13
+ property 'clouds' # cloudiness, %
14
+ property 'visibility' # average visibility, meters
15
+ speed_property 'wind_speed' # wind speed.
16
+ speed_property 'wind_gust' # wind gust.
17
+ property 'wind_deg' # wind direction, degrees (meteorological)
18
+ property 'rain'
19
+ property 'snow'
20
+ property 'weather'
21
+
22
+ def initialize(args = nil, options = {})
23
+ super args, options
24
+
25
+ self.rain = OpenWeather::Models::Rain.new(rain, options) if rain
26
+ self.snow = OpenWeather::Models::Snow.new(snow, options) if snow
27
+ self.weather = weather.map { |i| OpenWeather::Models::Weather.new(i, options) } if weather
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module OneCall
6
+ class MinutelyWeather < Model
7
+ property 'dt', transform_with: ->(v) { Time.at(v).utc } # time of the forecasted data UTC
8
+ property 'precipitation'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module OneCall
6
+ class Temp < Model
7
+ temperature_property 'morn'
8
+ temperature_property 'day'
9
+ temperature_property 'eve'
10
+ temperature_property 'night'
11
+ temperature_property 'min'
12
+ temperature_property 'max'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenWeather
4
+ module Models
5
+ module OneCall
6
+ class Weather < Model
7
+ property 'lat' # geographical coordinates of the location (latitude)
8
+ property 'lon' # geographical coordinates of the location (longitude)
9
+ property 'timezone' # timezone name for the requested location
10
+ property 'current' # current weather
11
+ property 'minutely' # minute forecast weather
12
+ property 'hourly' # hourly forecast weather
13
+ property 'daily' # daily forecast weather
14
+
15
+ def initialize(args = nil, options = {})
16
+ super args, options
17
+
18
+ self.current = OpenWeather::Models::OneCall::CurrentWeather.new(current, options) if current
19
+ self.minutely = minutely.map { |i| OpenWeather::Models::OneCall::MinutelyWeather.new(i, options) } if minutely
20
+ self.hourly = hourly.map { |i| OpenWeather::Models::OneCall::HourlyWeather.new(i, options) } if hourly
21
+ self.daily = daily.map { |i| OpenWeather::Models::OneCall::DailyWeather.new(i, options) } if daily
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -3,6 +3,7 @@
3
3
  module OpenWeather
4
4
  module Models
5
5
  class Sys < Model
6
+ property 'timezone' # shift in seconds from UTC
6
7
  property 'type' # internal parameter
7
8
  property 'id' # internal parameter
8
9
  property 'message' # internal parameter
@@ -6,6 +6,7 @@ module OpenWeather
6
6
  property 'id' # weather condition id
7
7
  property 'main' # group of weather parameters (Rain, Snow, Extreme, etc.)
8
8
  property 'description' # weather condition within the group, in your language
9
+ property 'icon_uri', from: 'icon', transform_with: ->(v) { URI.parse("http://openweathermap.org/img/wn/#{v}@2x.png") }
9
10
  property 'icon' # weather icon id
10
11
  end
11
12
  end
@@ -3,7 +3,7 @@
3
3
  module OpenWeather
4
4
  module Models
5
5
  class Wind < Model
6
- property 'speed' # wind speed in meter/sec or miles/hour
6
+ speed_property 'speed' # wind speed in meter/sec or miles/hour
7
7
  property 'deg' # wind direction in degrees (meteorological)
8
8
  end
9
9
  end
@@ -6,10 +6,10 @@ module OpenWeather
6
6
  def on_complete(env)
7
7
  case env[:status]
8
8
  when 404
9
- raise Faraday::Error::ResourceNotFound, response_values(env)
9
+ raise Faraday::ResourceNotFound, response_values(env)
10
10
  when 407
11
11
  # mimic the behavior that we get with proxy requests with HTTPS
12
- raise Faraday::Error::ConnectionFailed, %(407 "Proxy Authentication Required ")
12
+ raise Faraday::ConnectionFailed, %(407 "Proxy Authentication Required ")
13
13
  when (400...600).freeze
14
14
  raise OpenWeather::Errors::Fault, response_values(env)
15
15
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenWeather
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: open-weather-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Doubrovkine
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-01 00:00:00.000000000 Z
11
+ date: 2020-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0.9'
33
+ version: 1.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0.9'
40
+ version: 1.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: faraday_middleware
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -81,16 +81,29 @@ files:
81
81
  - lib/open_weather/connection.rb
82
82
  - lib/open_weather/endpoints.rb
83
83
  - lib/open_weather/endpoints/current.rb
84
+ - lib/open_weather/endpoints/one_call.rb
84
85
  - lib/open_weather/errors.rb
85
86
  - lib/open_weather/errors/fault.rb
86
87
  - lib/open_weather/logger.rb
87
88
  - lib/open_weather/models.rb
88
- - lib/open_weather/models/city_weather.rb
89
+ - lib/open_weather/models/city.rb
90
+ - lib/open_weather/models/city/weather.rb
89
91
  - lib/open_weather/models/clouds.rb
90
92
  - lib/open_weather/models/coord.rb
91
93
  - lib/open_weather/models/list.rb
92
94
  - lib/open_weather/models/main.rb
95
+ - lib/open_weather/models/mixins.rb
96
+ - lib/open_weather/models/mixins/speed.rb
97
+ - lib/open_weather/models/mixins/temp.rb
93
98
  - lib/open_weather/models/model.rb
99
+ - lib/open_weather/models/one_call.rb
100
+ - lib/open_weather/models/one_call/current_weather.rb
101
+ - lib/open_weather/models/one_call/daily_weather.rb
102
+ - lib/open_weather/models/one_call/feels_like.rb
103
+ - lib/open_weather/models/one_call/hourly_weather.rb
104
+ - lib/open_weather/models/one_call/minutely_weather.rb
105
+ - lib/open_weather/models/one_call/temp.rb
106
+ - lib/open_weather/models/one_call/weather.rb
94
107
  - lib/open_weather/models/rain.rb
95
108
  - lib/open_weather/models/snow.rb
96
109
  - lib/open_weather/models/sys.rb
@@ -118,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
131
  - !ruby/object:Gem::Version
119
132
  version: 1.3.6
120
133
  requirements: []
121
- rubygems_version: 3.0.3
134
+ rubygems_version: 3.1.3
122
135
  signing_key:
123
136
  specification_version: 4
124
137
  summary: OpenWeather API Ruby client.
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenWeather
4
- module Models
5
- class CityWeather < Model
6
- property 'coord', transform_with: ->(v) { OpenWeather::Models::Coord.new(v) }
7
- property 'weather', transform_with: ->(v) { v.map { |i| OpenWeather::Models::Weather.new(i) } }
8
- property 'base' # internal parameter
9
- property 'main', transform_with: ->(v) { OpenWeather::Models::Main.new(v) }
10
- property 'visibility'
11
- property 'wind', transform_with: ->(v) { OpenWeather::Models::Wind.new(v) }
12
- property 'clouds', transform_with: ->(v) { OpenWeather::Models::Clouds.new(v) }
13
- property 'rain', transform_with: ->(v) { OpenWeather::Models::Rain.new(v) }
14
- property 'snow', transform_with: ->(v) { OpenWeather::Models::Snow.new(v) }
15
- property 'dt', transform_with: ->(v) { Time.at(v).utc } # time of data calculation, UTC
16
- property 'sys', transform_with: ->(v) { OpenWeather::Models::Sys.new(v) }
17
- property 'id' # city id
18
- property 'timezone' # shift in seconds from UTC
19
- property 'name' # city name
20
- property 'cod' # internal parameter
21
- end
22
- end
23
- end