weather_gem_kg 0.32.0 → 1.0.1
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 +4 -4
- data/.github/workflows/ci.yml +22 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +33 -0
- data/Gemfile +2 -3
- data/Gemfile.lock +38 -26
- data/README.md +108 -18
- data/lib/generators/templates/weather_gem_kg_initializer.rb +2 -2
- data/lib/generators/weather_gem_kg/install_generator.rb +3 -3
- data/lib/weather_gem_kg/client.rb +11 -0
- data/lib/weather_gem_kg/clients/open_meteo.rb +103 -0
- data/lib/weather_gem_kg/config.rb +16 -9
- data/lib/weather_gem_kg/errors.rb +8 -0
- data/lib/weather_gem_kg/forecast_day.rb +5 -0
- data/lib/weather_gem_kg/version.rb +3 -1
- data/lib/weather_gem_kg.rb +12 -8
- data/weather_gem_kg.gemspec +10 -14
- metadata +34 -21
- data/.travis.yml +0 -7
- data/lib/weather_gem_kg/clients/apixu.rb +0 -30
- data/lib/weather_gem_kg/clients/dark_sky.rb +0 -37
- data/lib/weather_gem_kg/generator.rb +0 -18
- data/weather_gem_kg-0.31.0.gem +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a95c4c55f26f7f75e7fe956bc5d91d0148849e3df4366d98b5a90ceb1cd45ca1
|
|
4
|
+
data.tar.gz: 7970245200fcfb56dfcaecefb6fbb33ab32f7266f626fda99bb3c69d5e4cbf1e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45d9ad7f35f0f21c345d8f12109b9cf177eed2b700236d8fad7b00e86d147c814b1cfd6b7c84d8ed9edac9a8adab9b0b93c85f27cc0eb56b36a1663c80ce7de0
|
|
7
|
+
data.tar.gz: 7432f57f7412c7f1c3b7370556941a3022821c9d1dce641bb7795eda1c38c29409d73390b1e27b5a7f5969d9189bdbe6d4070518ed28771a4efbac43c7308396
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Set up Ruby
|
|
16
|
+
uses: ruby/setup-ruby@v1
|
|
17
|
+
with:
|
|
18
|
+
ruby-version: .ruby-version
|
|
19
|
+
bundler-cache: true
|
|
20
|
+
|
|
21
|
+
- name: Run specs
|
|
22
|
+
run: bundle exec rake
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4.0.6
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.0] — 2026-07-21
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `WeatherGemKg.forecast(city:, days:, client:)` public API
|
|
10
|
+
- `WeatherGemKg::ForecastDay` (`date`, `max_temp`, `min_temp`, `condition`)
|
|
11
|
+
- `WeatherGemKg::Client` interface and `WeatherGemKg::Clients::OpenMeteo`
|
|
12
|
+
- Errors: `LocationNotFoundError`, `RequestError`, `InvalidArgumentError`
|
|
13
|
+
- GitHub Actions CI workflow
|
|
14
|
+
- `.ruby-version` pinned to Ruby 4.0.6
|
|
15
|
+
- Rails installer updated for key-free configuration
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Runtime dependency is `httparty` only (declared in the gemspec)
|
|
20
|
+
- Specs use WebMock stubs (no live HTTP in CI)
|
|
21
|
+
- `required_ruby_version` set to `>= 3.2`
|
|
22
|
+
|
|
23
|
+
### Removed
|
|
24
|
+
|
|
25
|
+
- Apixu and Dark Sky clients
|
|
26
|
+
- `WeatherGemKg::Generator` and `#generate_me`
|
|
27
|
+
- API key settings (`api_key_apixu`, `api_key_dark`)
|
|
28
|
+
- `geocoder` and `vcr` dependencies
|
|
29
|
+
- Travis CI configuration
|
|
30
|
+
|
|
31
|
+
## [0.32.0] — prior
|
|
32
|
+
|
|
33
|
+
Initial published line with Apixu and Dark Sky providers.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,45 +1,57 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
weather_gem_kg (0.
|
|
4
|
+
weather_gem_kg (1.0.1)
|
|
5
|
+
httparty (~> 0.24)
|
|
5
6
|
|
|
6
7
|
GEM
|
|
7
8
|
remote: https://rubygems.org/
|
|
8
9
|
specs:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
addressable (2.9.0)
|
|
11
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
12
|
+
bigdecimal (4.1.2)
|
|
13
|
+
crack (1.0.1)
|
|
14
|
+
bigdecimal
|
|
15
|
+
rexml
|
|
16
|
+
csv (3.3.5)
|
|
17
|
+
diff-lcs (1.6.2)
|
|
18
|
+
hashdiff (1.2.1)
|
|
19
|
+
httparty (0.24.2)
|
|
20
|
+
csv
|
|
21
|
+
mini_mime (>= 1.0.0)
|
|
13
22
|
multi_xml (>= 0.5.2)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
rake (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
rspec-
|
|
22
|
-
rspec-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
mini_mime (1.1.5)
|
|
24
|
+
multi_xml (0.9.1)
|
|
25
|
+
bigdecimal (>= 3.1, < 5)
|
|
26
|
+
public_suffix (7.0.5)
|
|
27
|
+
rake (13.4.2)
|
|
28
|
+
rexml (3.4.4)
|
|
29
|
+
rspec (3.13.2)
|
|
30
|
+
rspec-core (~> 3.13.0)
|
|
31
|
+
rspec-expectations (~> 3.13.0)
|
|
32
|
+
rspec-mocks (~> 3.13.0)
|
|
33
|
+
rspec-core (3.13.6)
|
|
34
|
+
rspec-support (~> 3.13.0)
|
|
35
|
+
rspec-expectations (3.13.5)
|
|
26
36
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
27
|
-
rspec-support (~> 3.
|
|
28
|
-
rspec-mocks (3.8
|
|
37
|
+
rspec-support (~> 3.13.0)
|
|
38
|
+
rspec-mocks (3.13.8)
|
|
29
39
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
30
|
-
rspec-support (~> 3.
|
|
31
|
-
rspec-support (3.
|
|
40
|
+
rspec-support (~> 3.13.0)
|
|
41
|
+
rspec-support (3.13.7)
|
|
42
|
+
webmock (3.26.2)
|
|
43
|
+
addressable (>= 2.8.0)
|
|
44
|
+
crack (>= 0.3.2)
|
|
45
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
32
46
|
|
|
33
47
|
PLATFORMS
|
|
34
48
|
ruby
|
|
35
49
|
|
|
36
50
|
DEPENDENCIES
|
|
37
|
-
|
|
38
|
-
geocoder
|
|
39
|
-
httparty
|
|
40
|
-
rake (~> 10.0)
|
|
51
|
+
rake (~> 13.0)
|
|
41
52
|
rspec (~> 3.0)
|
|
42
53
|
weather_gem_kg!
|
|
54
|
+
webmock (~> 3.0)
|
|
43
55
|
|
|
44
56
|
BUNDLED WITH
|
|
45
|
-
|
|
57
|
+
4.0.16
|
data/README.md
CHANGED
|
@@ -1,43 +1,133 @@
|
|
|
1
1
|
# WeatherGemKg
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Daily city weather forecasts for Ruby, powered by [Open-Meteo](https://open-meteo.com/).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- **No API key** required
|
|
6
|
+
- Returns structured `ForecastDay` objects (`date`, `max_temp`, `min_temp`, `condition`)
|
|
7
|
+
- Swappable client interface for custom providers
|
|
8
|
+
- Ruby **≥ 3.2**
|
|
6
9
|
|
|
7
10
|
## Installation
|
|
8
11
|
|
|
9
|
-
Add
|
|
12
|
+
Add to your Gemfile:
|
|
10
13
|
|
|
11
14
|
```ruby
|
|
12
|
-
gem
|
|
15
|
+
gem "weather_gem_kg", "~> 1.0"
|
|
13
16
|
```
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
Then:
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
```bash
|
|
21
|
+
bundle install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or install directly:
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
```bash
|
|
27
|
+
gem install weather_gem_kg
|
|
28
|
+
```
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
Pin `~> 1.0` if you previously used `0.x` — **1.0.0 is a breaking release**. See [CHANGELOG.md](CHANGELOG.md).
|
|
31
|
+
|
|
32
|
+
### Rails
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
rails generate weather_gem_kg:install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This creates `config/initializers/weather_gem_kg.rb`.
|
|
22
39
|
|
|
23
40
|
## Usage
|
|
24
41
|
|
|
25
|
-
|
|
42
|
+
```ruby
|
|
43
|
+
require "weather_gem_kg"
|
|
26
44
|
|
|
27
|
-
|
|
45
|
+
forecast = WeatherGemKg.forecast(city: "Bishkek", days: 3)
|
|
28
46
|
|
|
29
|
-
|
|
47
|
+
forecast.each do |day|
|
|
48
|
+
puts "#{day.date}: #{day.min_temp}–#{day.max_temp}°C, #{day.condition}"
|
|
49
|
+
end
|
|
50
|
+
# => 2026-07-21: 15.2–30.1°C, Clear sky
|
|
51
|
+
```
|
|
30
52
|
|
|
31
|
-
|
|
53
|
+
### `ForecastDay`
|
|
32
54
|
|
|
33
|
-
|
|
55
|
+
| Attribute | Type | Description |
|
|
56
|
+
|-------------|---------|--------------------------|
|
|
57
|
+
| `date` | String | ISO date (`YYYY-MM-DD`) |
|
|
58
|
+
| `max_temp` | Float | Daily high (°C) |
|
|
59
|
+
| `min_temp` | Float | Daily low (°C) |
|
|
60
|
+
| `condition` | String | Human-readable condition |
|
|
34
61
|
|
|
35
|
-
|
|
62
|
+
`days` must be between **1 and 16** (Open-Meteo limit). If omitted, `configuration.default_days` is used (default: `1`).
|
|
36
63
|
|
|
37
|
-
|
|
64
|
+
### Configuration
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
WeatherGemKg.configure do |config|
|
|
68
|
+
config.default_days = 3
|
|
69
|
+
# config.client = WeatherGemKg::Clients::OpenMeteo.new
|
|
70
|
+
end
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
No API keys are needed for the default Open-Meteo client.
|
|
74
|
+
|
|
75
|
+
### Errors
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
begin
|
|
79
|
+
WeatherGemKg.forecast(city: "Bishkek", days: 3)
|
|
80
|
+
rescue WeatherGemKg::LocationNotFoundError
|
|
81
|
+
# city could not be geocoded
|
|
82
|
+
rescue WeatherGemKg::RequestError
|
|
83
|
+
# HTTP / upstream failure
|
|
84
|
+
rescue WeatherGemKg::InvalidArgumentError
|
|
85
|
+
# blank city or days out of range
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
All errors inherit from `WeatherGemKg::Error`.
|
|
90
|
+
|
|
91
|
+
### Custom client
|
|
92
|
+
|
|
93
|
+
Any object that implements `#forecast(city:, days:)` and returns an `Array` of `ForecastDay` can be used:
|
|
38
94
|
|
|
39
|
-
|
|
95
|
+
```ruby
|
|
96
|
+
class MyClient < WeatherGemKg::Client
|
|
97
|
+
def forecast(city:, days:)
|
|
98
|
+
# ...
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
WeatherGemKg.forecast(city: "Bishkek", days: 1, client: MyClient.new)
|
|
103
|
+
# or
|
|
104
|
+
WeatherGemKg.configure { |c| c.client = MyClient.new }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Development
|
|
40
108
|
|
|
41
|
-
|
|
109
|
+
```bash
|
|
110
|
+
bundle install
|
|
111
|
+
bundle exec rake # run specs
|
|
112
|
+
bin/console # interactive console with the gem loaded
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Specs stub HTTP with WebMock — no network required for the test suite.
|
|
116
|
+
|
|
117
|
+
### Releasing to RubyGems
|
|
118
|
+
|
|
119
|
+
1. Bump `WeatherGemKg::VERSION` in `lib/weather_gem_kg/version.rb`
|
|
120
|
+
2. Update [CHANGELOG.md](CHANGELOG.md)
|
|
121
|
+
3. Commit all changes (the gemspec packs files via `git ls-files`)
|
|
122
|
+
4. Publish:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bundle exec rake release
|
|
126
|
+
# or
|
|
127
|
+
gem build weather_gem_kg.gemspec
|
|
128
|
+
gem push weather_gem_kg-X.Y.Z.gem
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
42
132
|
|
|
43
|
-
|
|
133
|
+
MIT — see [LICENSE.txt](LICENSE.txt).
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WeatherGemKg
|
|
2
4
|
module Generators
|
|
3
5
|
class InstallGenerator < Rails::Generators::Base
|
|
4
6
|
source_root File.expand_path("../../templates", __FILE__)
|
|
5
|
-
desc "Creates
|
|
7
|
+
desc "Creates WeatherGemKg initializer for your application"
|
|
6
8
|
|
|
7
9
|
def copy_initializer
|
|
8
10
|
template "weather_gem_kg_initializer.rb", "config/initializers/weather_gem_kg.rb"
|
|
9
|
-
|
|
10
|
-
puts "Install complete! Truly Outrageous!"
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WeatherGemKg
|
|
4
|
+
# Base contract for weather providers.
|
|
5
|
+
# Implementations must return an Array of ForecastDay.
|
|
6
|
+
class Client
|
|
7
|
+
def forecast(city:, days:)
|
|
8
|
+
raise NotImplementedError, "#{self.class}#forecast must be implemented"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "httparty"
|
|
4
|
+
require "weather_gem_kg/client"
|
|
5
|
+
require "weather_gem_kg/errors"
|
|
6
|
+
require "weather_gem_kg/forecast_day"
|
|
7
|
+
|
|
8
|
+
module WeatherGemKg
|
|
9
|
+
module Clients
|
|
10
|
+
class OpenMeteo < Client
|
|
11
|
+
GEOCODING_URL = "https://geocoding-api.open-meteo.com/v1/search"
|
|
12
|
+
FORECAST_URL = "https://api.open-meteo.com/v1/forecast"
|
|
13
|
+
|
|
14
|
+
WEATHER_CODES = {
|
|
15
|
+
0 => "Clear sky",
|
|
16
|
+
1 => "Mainly clear",
|
|
17
|
+
2 => "Partly cloudy",
|
|
18
|
+
3 => "Overcast",
|
|
19
|
+
45 => "Fog",
|
|
20
|
+
48 => "Depositing rime fog",
|
|
21
|
+
51 => "Light drizzle",
|
|
22
|
+
53 => "Moderate drizzle",
|
|
23
|
+
55 => "Dense drizzle",
|
|
24
|
+
56 => "Light freezing drizzle",
|
|
25
|
+
57 => "Dense freezing drizzle",
|
|
26
|
+
61 => "Slight rain",
|
|
27
|
+
63 => "Moderate rain",
|
|
28
|
+
65 => "Heavy rain",
|
|
29
|
+
66 => "Light freezing rain",
|
|
30
|
+
67 => "Heavy freezing rain",
|
|
31
|
+
71 => "Slight snow",
|
|
32
|
+
73 => "Moderate snow",
|
|
33
|
+
75 => "Heavy snow",
|
|
34
|
+
77 => "Snow grains",
|
|
35
|
+
80 => "Slight rain showers",
|
|
36
|
+
81 => "Moderate rain showers",
|
|
37
|
+
82 => "Violent rain showers",
|
|
38
|
+
85 => "Slight snow showers",
|
|
39
|
+
86 => "Heavy snow showers",
|
|
40
|
+
95 => "Thunderstorm",
|
|
41
|
+
96 => "Thunderstorm with slight hail",
|
|
42
|
+
99 => "Thunderstorm with heavy hail"
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
def forecast(city:, days:)
|
|
46
|
+
days = Integer(days)
|
|
47
|
+
raise InvalidArgumentError, "days must be between 1 and 16" unless days.between?(1, 16)
|
|
48
|
+
|
|
49
|
+
location = geocode(city)
|
|
50
|
+
payload = fetch_forecast(location.fetch(:latitude), location.fetch(:longitude), days)
|
|
51
|
+
parse_forecast(payload)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def geocode(city)
|
|
57
|
+
response = HTTParty.get(GEOCODING_URL, query: { name: city, count: 1 })
|
|
58
|
+
raise RequestError, "Geocoding failed (HTTP #{response.code})" unless response.success?
|
|
59
|
+
|
|
60
|
+
result = response.parsed_response&.dig("results", 0)
|
|
61
|
+
raise LocationNotFoundError, "No location found for #{city.inspect}" unless result
|
|
62
|
+
|
|
63
|
+
{
|
|
64
|
+
latitude: result.fetch("latitude"),
|
|
65
|
+
longitude: result.fetch("longitude")
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def fetch_forecast(latitude, longitude, days)
|
|
70
|
+
response = HTTParty.get(
|
|
71
|
+
FORECAST_URL,
|
|
72
|
+
query: {
|
|
73
|
+
latitude: latitude,
|
|
74
|
+
longitude: longitude,
|
|
75
|
+
daily: "weather_code,temperature_2m_max,temperature_2m_min",
|
|
76
|
+
forecast_days: days,
|
|
77
|
+
timezone: "auto"
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
raise RequestError, "Forecast request failed (HTTP #{response.code})" unless response.success?
|
|
81
|
+
|
|
82
|
+
response.parsed_response
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def parse_forecast(payload)
|
|
86
|
+
daily = payload.fetch("daily")
|
|
87
|
+
times = daily.fetch("time")
|
|
88
|
+
max_temps = daily.fetch("temperature_2m_max")
|
|
89
|
+
min_temps = daily.fetch("temperature_2m_min")
|
|
90
|
+
codes = daily.fetch("weather_code")
|
|
91
|
+
|
|
92
|
+
times.each_index.map do |index|
|
|
93
|
+
ForecastDay.new(
|
|
94
|
+
date: times[index],
|
|
95
|
+
max_temp: max_temps[index],
|
|
96
|
+
min_temp: min_temps[index],
|
|
97
|
+
condition: WEATHER_CODES.fetch(codes[index], "Unknown")
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -1,26 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WeatherGemKg
|
|
2
4
|
class << self
|
|
3
|
-
|
|
5
|
+
attr_writer :configuration
|
|
4
6
|
end
|
|
5
7
|
|
|
6
8
|
def self.configuration
|
|
7
|
-
@configuration ||=
|
|
9
|
+
@configuration ||= Configuration.new
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
def self.configure
|
|
11
13
|
yield(configuration) if block_given?
|
|
12
14
|
end
|
|
13
15
|
|
|
16
|
+
def self.reset_configuration!
|
|
17
|
+
@configuration = Configuration.new
|
|
18
|
+
end
|
|
19
|
+
|
|
14
20
|
class Configuration
|
|
15
|
-
|
|
21
|
+
attr_writer :client
|
|
22
|
+
attr_accessor :default_days
|
|
16
23
|
|
|
17
24
|
def initialize
|
|
18
|
-
@
|
|
19
|
-
@
|
|
25
|
+
@default_days = 1
|
|
26
|
+
@client = nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def client
|
|
30
|
+
@client ||= Clients::OpenMeteo.new
|
|
20
31
|
end
|
|
21
32
|
end
|
|
22
33
|
end
|
|
23
|
-
WeatherGemKg.configure do |c| # => MyGem
|
|
24
|
-
c.api_key_apixu = '6d79fff9ef764b8c85d61836190907' # => 1
|
|
25
|
-
c.api_key_dark = '0a06f48b71537e4e72554c3f8d39d234' # => "some string"
|
|
26
|
-
end # => "some string"
|
data/lib/weather_gem_kg.rb
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require "weather_gem_kg/version"
|
|
3
|
-
require "weather_gem_kg/
|
|
4
|
+
require "weather_gem_kg/errors"
|
|
5
|
+
require "weather_gem_kg/forecast_day"
|
|
6
|
+
require "weather_gem_kg/client"
|
|
4
7
|
require "weather_gem_kg/config"
|
|
8
|
+
require "weather_gem_kg/clients/open_meteo"
|
|
5
9
|
|
|
6
10
|
module WeatherGemKg
|
|
7
|
-
|
|
11
|
+
def self.forecast(city:, days: nil, client: nil)
|
|
12
|
+
raise InvalidArgumentError, "city is required" if city.nil? || city.to_s.strip.empty?
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# puts weather2.generate_me
|
|
14
|
+
days ||= configuration.default_days
|
|
15
|
+
(client || configuration.client).forecast(city: city, days: days)
|
|
16
|
+
end
|
|
17
|
+
end
|
data/weather_gem_kg.gemspec
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
lib = File.expand_path("lib", __dir__)
|
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
5
|
require "weather_gem_kg/version"
|
|
@@ -8,27 +10,21 @@ Gem::Specification.new do |spec|
|
|
|
8
10
|
spec.authors = ["Edilbek"]
|
|
9
11
|
spec.email = ["edil.talantbekov@gmail.com"]
|
|
10
12
|
|
|
11
|
-
spec.summary =
|
|
12
|
-
spec.description =
|
|
13
|
-
# spec.homepage = "Put your gem's website or public repo URL here."
|
|
13
|
+
spec.summary = "Daily weather forecasts via Open-Meteo"
|
|
14
|
+
spec.description = "A small Ruby gem that fetches daily city forecasts using the free Open-Meteo API."
|
|
14
15
|
spec.license = "MIT"
|
|
16
|
+
spec.required_ruby_version = ">= 3.2"
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
-
# spec.metadata["source_code_uri"] = "Put your gem's public repo URL here."
|
|
20
|
-
# spec.metadata["changelog_uri"] = "Put your gem's CHANGELOG.md URL here."
|
|
21
|
-
|
|
22
|
-
# Specify which files should be added to the gem when it is released.
|
|
23
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
24
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
18
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
|
25
19
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
26
20
|
end
|
|
27
21
|
spec.bindir = "exe"
|
|
28
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
29
23
|
spec.require_paths = ["lib"]
|
|
30
24
|
|
|
31
|
-
spec.
|
|
32
|
-
|
|
25
|
+
spec.add_dependency "httparty", "~> 0.24"
|
|
26
|
+
|
|
27
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
33
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
|
29
|
+
spec.add_development_dependency "webmock", "~> 3.0"
|
|
34
30
|
end
|
metadata
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: weather_gem_kg
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Edilbek
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: httparty
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
20
|
-
type: :
|
|
18
|
+
version: '0.24'
|
|
19
|
+
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '0.24'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: rake
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
30
29
|
requirements:
|
|
31
30
|
- - "~>"
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
32
|
+
version: '13.0'
|
|
34
33
|
type: :development
|
|
35
34
|
prerelease: false
|
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
36
|
requirements:
|
|
38
37
|
- - "~>"
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
39
|
+
version: '13.0'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
41
|
name: rspec
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,16 +51,33 @@ dependencies:
|
|
|
52
51
|
- - "~>"
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
53
|
version: '3.0'
|
|
55
|
-
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: webmock
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '3.0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '3.0'
|
|
68
|
+
description: A small Ruby gem that fetches daily city forecasts using the free Open-Meteo
|
|
69
|
+
API.
|
|
56
70
|
email:
|
|
57
71
|
- edil.talantbekov@gmail.com
|
|
58
72
|
executables: []
|
|
59
73
|
extensions: []
|
|
60
74
|
extra_rdoc_files: []
|
|
61
75
|
files:
|
|
76
|
+
- ".github/workflows/ci.yml"
|
|
62
77
|
- ".gitignore"
|
|
63
78
|
- ".rspec"
|
|
64
|
-
- ".
|
|
79
|
+
- ".ruby-version"
|
|
80
|
+
- CHANGELOG.md
|
|
65
81
|
- CODE_OF_CONDUCT.md
|
|
66
82
|
- Gemfile
|
|
67
83
|
- Gemfile.lock
|
|
@@ -73,18 +89,16 @@ files:
|
|
|
73
89
|
- lib/generators/templates/weather_gem_kg_initializer.rb
|
|
74
90
|
- lib/generators/weather_gem_kg/install_generator.rb
|
|
75
91
|
- lib/weather_gem_kg.rb
|
|
76
|
-
- lib/weather_gem_kg/
|
|
77
|
-
- lib/weather_gem_kg/clients/
|
|
92
|
+
- lib/weather_gem_kg/client.rb
|
|
93
|
+
- lib/weather_gem_kg/clients/open_meteo.rb
|
|
78
94
|
- lib/weather_gem_kg/config.rb
|
|
79
|
-
- lib/weather_gem_kg/
|
|
95
|
+
- lib/weather_gem_kg/errors.rb
|
|
96
|
+
- lib/weather_gem_kg/forecast_day.rb
|
|
80
97
|
- lib/weather_gem_kg/version.rb
|
|
81
|
-
- weather_gem_kg-0.31.0.gem
|
|
82
98
|
- weather_gem_kg.gemspec
|
|
83
|
-
homepage:
|
|
84
99
|
licenses:
|
|
85
100
|
- MIT
|
|
86
101
|
metadata: {}
|
|
87
|
-
post_install_message:
|
|
88
102
|
rdoc_options: []
|
|
89
103
|
require_paths:
|
|
90
104
|
- lib
|
|
@@ -92,15 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
92
106
|
requirements:
|
|
93
107
|
- - ">="
|
|
94
108
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: '
|
|
109
|
+
version: '3.2'
|
|
96
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
111
|
requirements:
|
|
98
112
|
- - ">="
|
|
99
113
|
- !ruby/object:Gem::Version
|
|
100
114
|
version: '0'
|
|
101
115
|
requirements: []
|
|
102
|
-
rubygems_version:
|
|
103
|
-
signing_key:
|
|
116
|
+
rubygems_version: 4.0.16
|
|
104
117
|
specification_version: 4
|
|
105
|
-
summary:
|
|
118
|
+
summary: Daily weather forecasts via Open-Meteo
|
|
106
119
|
test_files: []
|
data/.travis.yml
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
require_relative '../config'
|
|
2
|
-
|
|
3
|
-
module WeatherGemKg
|
|
4
|
-
module Clients
|
|
5
|
-
class Apixu
|
|
6
|
-
API_KEY = WeatherGemKg.configuration.api_key_apixu
|
|
7
|
-
|
|
8
|
-
def initialize
|
|
9
|
-
@base_url = "http://api.apixu.com/v1/forecast.json?key=#{API_KEY}"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def get_weather(city, days)
|
|
13
|
-
@data = get_weather_info(city, days)
|
|
14
|
-
@data.dig('forecast', 'forecastday').map do |f|
|
|
15
|
-
day = f.dig('day')
|
|
16
|
-
{
|
|
17
|
-
date: Time.at(f['date_epoch']).ctime.slice(0, 10),
|
|
18
|
-
max_temp: day['maxtemp_c'],
|
|
19
|
-
min_temp: day['mintemp_c'],
|
|
20
|
-
condition: day.dig('condition', 'text')
|
|
21
|
-
}
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def get_weather_info(city, days)
|
|
26
|
-
HTTParty.get("#{@base_url}&q=#{city}&days=#{days}")
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
require "geocoder"
|
|
2
|
-
require_relative '../config'
|
|
3
|
-
|
|
4
|
-
module WeatherGemKg
|
|
5
|
-
module Clients
|
|
6
|
-
class DarkSky
|
|
7
|
-
API_KEY = WeatherGemKg.configuration.api_key_dark
|
|
8
|
-
|
|
9
|
-
def initialize
|
|
10
|
-
@base_url = "https://api.darksky.net/forecast/#{API_KEY}"
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def get_weather(city, days)
|
|
14
|
-
@data = get_weather_info(city, days)
|
|
15
|
-
|
|
16
|
-
@data.dig("daily", "data")[0...days].map do |f|
|
|
17
|
-
{
|
|
18
|
-
date: Time.at(f['time']).ctime.slice(0, 10),
|
|
19
|
-
max_temp: ((f["temperatureHigh"] - 32) * 5 / 9).round(1),
|
|
20
|
-
min_temp: ((f["temperatureLow"] - 32) * 5 / 9).round(1),
|
|
21
|
-
condition: f["summary"]
|
|
22
|
-
}
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def get_weather_info(city, days)
|
|
27
|
-
coordinates = get_city_coordinates(city)
|
|
28
|
-
|
|
29
|
-
HTTParty.get("#{@base_url}/#{coordinates}")
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def get_city_coordinates(city)
|
|
33
|
-
Geocoder.search("#{city}").first.coordinates.map(&:inspect).join(',')
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require "weather_gem_kg/clients/apixu"
|
|
2
|
-
require "weather_gem_kg/clients/dark_sky"
|
|
3
|
-
|
|
4
|
-
module WeatherGemKg
|
|
5
|
-
class Generator
|
|
6
|
-
attr_reader :city, :day, :generator
|
|
7
|
-
|
|
8
|
-
def initialize(city, day, generator)
|
|
9
|
-
@city = city
|
|
10
|
-
@day = day
|
|
11
|
-
@generator = generator
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def generate_me
|
|
15
|
-
generator.get_weather(city, day)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
data/weather_gem_kg-0.31.0.gem
DELETED
|
Binary file
|