meteoservice 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +54 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +21 -0
- data/README.md +101 -0
- data/Rakefile +22 -0
- data/lib/main.rb +17 -0
- data/lib/meteoservice/constants.rb +34 -0
- data/lib/meteoservice/data/towns.json +11 -0
- data/lib/meteoservice/error.rb +43 -0
- data/lib/meteoservice/meteo.rb +18 -0
- data/lib/meteoservice/nested_hash_value.rb +16 -0
- data/lib/meteoservice/parser_xml.rb +39 -0
- data/lib/meteoservice/predict.rb +65 -0
- data/lib/meteoservice/read_data.rb +75 -0
- data/lib/meteoservice/towns_data.rb +67 -0
- data/lib/meteoservice/version.rb +5 -0
- data/lib/meteoservice.rb +25 -0
- data/sig/meteoservice.rbs +4 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: eb3502dc35e5eec707fe5f4f4369933694c38c60eaa12e43062d0cab1aefb635
|
4
|
+
data.tar.gz: c7a53bdd74dd3b5567a4103354027cf0060fc00fdd2bcf9b00894b120723d28f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 885a7487c76588e0d8708f2444ecea1a335aa73fffd14214f67d4917e590d4d2eeacac09afab0238f4208e2155c56243c03437b14e6026a830f12e3d131077fa
|
7
|
+
data.tar.gz: 1ae0d8ab03f884d7f1ccab4579c1af1d0342f3464083123f012d4c18270256c19d3bd2ce18ff1d679ef27066a7231a6449f498569dd30123d1b23f34f0c63a97
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
3
|
+
- rubocop-rspec
|
4
|
+
|
5
|
+
AllCops:
|
6
|
+
NewCops: enable
|
7
|
+
TargetRubyVersion: 3.0.3
|
8
|
+
|
9
|
+
Style/StringLiteralsInInterpolation:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Layout/LineLength:
|
13
|
+
Max: 150
|
14
|
+
Exclude:
|
15
|
+
- spec/**/*.rb
|
16
|
+
|
17
|
+
Metrics/BlockLength:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/AbcSize:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/Documentation:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Metrics/MethodLength:
|
27
|
+
Max: 150
|
28
|
+
|
29
|
+
RSpec/MultipleExpectations:
|
30
|
+
Max: 10
|
31
|
+
|
32
|
+
RSpec/ExampleLength:
|
33
|
+
Max: 100
|
34
|
+
|
35
|
+
RSpec/FilePath:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
RSpec/NoExpectationExample:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Metrics/CyclomaticComplexity:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Metrics/PerceivedComplexity:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
LineEndStringConcatenationIndentation:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Style/FrozenStringLiteralComment:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
Style/StringLiterals:
|
54
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in meteoservice.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem 'rake', '~> 13.0'
|
9
|
+
|
10
|
+
group :test do
|
11
|
+
gem 'byebug'
|
12
|
+
gem 'codecov', '~> 0.4'
|
13
|
+
gem 'rspec', '~> 3.1'
|
14
|
+
gem 'rubocop', '~> 1.3'
|
15
|
+
gem 'rubocop-performance', '~> 1.1'
|
16
|
+
gem 'rubocop-rspec', '~> 2.1'
|
17
|
+
gem 'simplecov', '~> 0.21'
|
18
|
+
gem 'vcr', '~> 6.1'
|
19
|
+
gem 'webmock', '~> 3.1'
|
20
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
meteoservice (0.1.0)
|
5
|
+
faraday-encode_xml
|
6
|
+
faraday_middleware
|
7
|
+
multi_xml (~> 0.6)
|
8
|
+
uri
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
addressable (2.8.1)
|
14
|
+
public_suffix (>= 2.0.2, < 6.0)
|
15
|
+
ast (2.4.2)
|
16
|
+
builder (3.2.4)
|
17
|
+
byebug (11.1.3)
|
18
|
+
codecov (0.6.0)
|
19
|
+
simplecov (>= 0.15, < 0.22)
|
20
|
+
crack (0.4.5)
|
21
|
+
rexml
|
22
|
+
diff-lcs (1.5.0)
|
23
|
+
docile (1.4.0)
|
24
|
+
faraday (1.10.2)
|
25
|
+
faraday-em_http (~> 1.0)
|
26
|
+
faraday-em_synchrony (~> 1.0)
|
27
|
+
faraday-excon (~> 1.1)
|
28
|
+
faraday-httpclient (~> 1.0)
|
29
|
+
faraday-multipart (~> 1.0)
|
30
|
+
faraday-net_http (~> 1.0)
|
31
|
+
faraday-net_http_persistent (~> 1.0)
|
32
|
+
faraday-patron (~> 1.0)
|
33
|
+
faraday-rack (~> 1.0)
|
34
|
+
faraday-retry (~> 1.0)
|
35
|
+
ruby2_keywords (>= 0.0.4)
|
36
|
+
faraday-em_http (1.0.0)
|
37
|
+
faraday-em_synchrony (1.0.0)
|
38
|
+
faraday-encode_xml (0.2.0)
|
39
|
+
faraday (~> 1.0)
|
40
|
+
gyoku (~> 1.3)
|
41
|
+
faraday-excon (1.1.0)
|
42
|
+
faraday-httpclient (1.0.1)
|
43
|
+
faraday-multipart (1.0.4)
|
44
|
+
multipart-post (~> 2)
|
45
|
+
faraday-net_http (1.0.1)
|
46
|
+
faraday-net_http_persistent (1.2.0)
|
47
|
+
faraday-patron (1.0.0)
|
48
|
+
faraday-rack (1.0.0)
|
49
|
+
faraday-retry (1.0.3)
|
50
|
+
faraday_middleware (1.2.0)
|
51
|
+
faraday (~> 1.0)
|
52
|
+
gyoku (1.4.0)
|
53
|
+
builder (>= 2.1.2)
|
54
|
+
rexml (~> 3.0)
|
55
|
+
hashdiff (1.0.1)
|
56
|
+
json (2.6.2)
|
57
|
+
multi_xml (0.6.0)
|
58
|
+
multipart-post (2.2.3)
|
59
|
+
parallel (1.22.1)
|
60
|
+
parser (3.1.2.1)
|
61
|
+
ast (~> 2.4.1)
|
62
|
+
public_suffix (5.0.0)
|
63
|
+
rainbow (3.1.1)
|
64
|
+
rake (13.0.6)
|
65
|
+
regexp_parser (2.6.1)
|
66
|
+
rexml (3.2.5)
|
67
|
+
rspec (3.12.0)
|
68
|
+
rspec-core (~> 3.12.0)
|
69
|
+
rspec-expectations (~> 3.12.0)
|
70
|
+
rspec-mocks (~> 3.12.0)
|
71
|
+
rspec-core (3.12.0)
|
72
|
+
rspec-support (~> 3.12.0)
|
73
|
+
rspec-expectations (3.12.0)
|
74
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
75
|
+
rspec-support (~> 3.12.0)
|
76
|
+
rspec-mocks (3.12.0)
|
77
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
78
|
+
rspec-support (~> 3.12.0)
|
79
|
+
rspec-support (3.12.0)
|
80
|
+
rubocop (1.39.0)
|
81
|
+
json (~> 2.3)
|
82
|
+
parallel (~> 1.10)
|
83
|
+
parser (>= 3.1.2.1)
|
84
|
+
rainbow (>= 2.2.2, < 4.0)
|
85
|
+
regexp_parser (>= 1.8, < 3.0)
|
86
|
+
rexml (>= 3.2.5, < 4.0)
|
87
|
+
rubocop-ast (>= 1.23.0, < 2.0)
|
88
|
+
ruby-progressbar (~> 1.7)
|
89
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
90
|
+
rubocop-ast (1.23.0)
|
91
|
+
parser (>= 3.1.1.0)
|
92
|
+
rubocop-performance (1.15.1)
|
93
|
+
rubocop (>= 1.7.0, < 2.0)
|
94
|
+
rubocop-ast (>= 0.4.0)
|
95
|
+
rubocop-rspec (2.15.0)
|
96
|
+
rubocop (~> 1.33)
|
97
|
+
ruby-progressbar (1.11.0)
|
98
|
+
ruby2_keywords (0.0.5)
|
99
|
+
simplecov (0.21.2)
|
100
|
+
docile (~> 1.1)
|
101
|
+
simplecov-html (~> 0.11)
|
102
|
+
simplecov_json_formatter (~> 0.1)
|
103
|
+
simplecov-html (0.12.3)
|
104
|
+
simplecov_json_formatter (0.1.4)
|
105
|
+
unicode-display_width (2.3.0)
|
106
|
+
uri (0.11.0)
|
107
|
+
vcr (6.1.0)
|
108
|
+
webmock (3.18.1)
|
109
|
+
addressable (>= 2.8.0)
|
110
|
+
crack (>= 0.3.2)
|
111
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
112
|
+
|
113
|
+
PLATFORMS
|
114
|
+
x86_64-linux
|
115
|
+
|
116
|
+
DEPENDENCIES
|
117
|
+
byebug
|
118
|
+
codecov (~> 0.4)
|
119
|
+
meteoservice!
|
120
|
+
rake (~> 13.0)
|
121
|
+
rspec (~> 3.1)
|
122
|
+
rubocop (~> 1.3)
|
123
|
+
rubocop-performance (~> 1.1)
|
124
|
+
rubocop-rspec (~> 2.1)
|
125
|
+
simplecov (~> 0.21)
|
126
|
+
vcr (~> 6.1)
|
127
|
+
webmock (~> 3.1)
|
128
|
+
|
129
|
+
BUNDLED WITH
|
130
|
+
2.3.24
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Gleb V. Zhegilin
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# `meteoservice`
|
2
|
+
|
3
|
+
###### Язык написания - Ruby 3.0.3
|
4
|
+
|
5
|
+
## Описание:
|
6
|
+
> Программа показывает текущую погоду, используя свежие данные в XML-структуре от `Метеосервиса`.
|
7
|
+
> Пользователю предлагается указать, для какого города он хочет посмотреть прогноз.
|
8
|
+
> В библиотеке заведен словарик (`towns.json`) из 10 городов с уникальными индексами
|
9
|
+
> (см. <http://www.meteoservice.ru/content/export.html>). Вы можете продолжить заполнять его,
|
10
|
+
> используя консольную версию программы.
|
11
|
+
|
12
|
+
---
|
13
|
+
|
14
|
+
## Установка:
|
15
|
+
|
16
|
+
Добавьте
|
17
|
+
|
18
|
+
``` rb
|
19
|
+
gem 'meteoservice'
|
20
|
+
```
|
21
|
+
|
22
|
+
И сделайте
|
23
|
+
|
24
|
+
bundle
|
25
|
+
|
26
|
+
Или сделайте
|
27
|
+
|
28
|
+
gem install meteoservice
|
29
|
+
|
30
|
+
## Использование:
|
31
|
+
|
32
|
+
``` rb
|
33
|
+
require 'meteoservice'
|
34
|
+
|
35
|
+
Meteoservice.result
|
36
|
+
|
37
|
+
# Или, если не хотите использовать консоль для ввода данных
|
38
|
+
# укажите 'id' города в скобках:
|
39
|
+
|
40
|
+
Meteoservice.result('113')
|
41
|
+
```
|
42
|
+
|
43
|
+
## Пример (вариант с вводом 'id' в консоли):
|
44
|
+
|
45
|
+
```
|
46
|
+
Погоду для какого города Вы хотите узнать?
|
47
|
+
Введите уникальный индекс города и нажмите "enter". Если вашего города
|
48
|
+
нет в списке, перейдите по ссылке https://www.meteoservice.ru/content/export.html,
|
49
|
+
найдите интересуемый индекс и введите его ниже. Название города с индексом добавятся
|
50
|
+
в список автоматически:
|
51
|
+
|
52
|
+
1: ["4", "Архангельск"]
|
53
|
+
2: ["105", "Калининград"]
|
54
|
+
3: ["199", "Краснодар"]
|
55
|
+
4: ["37", "Москва"]
|
56
|
+
5: ["113", "Мурманск"]
|
57
|
+
6: ["99", "Новосибирск"]
|
58
|
+
7: ["111", "Петропавловск-Камчатский"]
|
59
|
+
8: ["135", "Ростов-на-Дону"]
|
60
|
+
9: ["69", "Санкт-Петербург"]
|
61
|
+
69
|
62
|
+
|
63
|
+
|
64
|
+
Санкт-Петербург
|
65
|
+
|
66
|
+
Относительная влажность воздуха: 67..69 %
|
67
|
+
Комфорт: -11..-11 °С
|
68
|
+
|
69
|
+
2022-11-22 в вторник утром
|
70
|
+
Температура: -6..-5 °С
|
71
|
+
Ветер: 2..3 м/с, юго-восточный
|
72
|
+
Атмосферное давление: 764..764 мм.рт.ст.
|
73
|
+
Облачность: облачно
|
74
|
+
Осадки:
|
75
|
+
Интенсивность осадков: возможен дождь/снег
|
76
|
+
Вероятность грозы: возможна гроза
|
77
|
+
Относительная влажность воздуха: 65..66 %
|
78
|
+
Комфорт: -11..-11 °С
|
79
|
+
|
80
|
+
2022-11-22 в вторник днём
|
81
|
+
Температура: -4..-3 °С
|
82
|
+
Ветер: 3..3 м/с, восточный
|
83
|
+
Атмосферное давление: 764..764 мм.рт.ст.
|
84
|
+
Облачность: облачно
|
85
|
+
Осадки:
|
86
|
+
Интенсивность осадков: возможен дождь/снег
|
87
|
+
Вероятность грозы: возможна гроза
|
88
|
+
Относительная влажность воздуха: 63..65 %
|
89
|
+
Комфорт: -9..-9 °С
|
90
|
+
|
91
|
+
2022-11-22 в вторник вечером
|
92
|
+
Температура: -3..-2 °С
|
93
|
+
Ветер: 3..4 м/с, восточный
|
94
|
+
Атмосферное давление: 763..764 мм.рт.ст.
|
95
|
+
Облачность: облачно
|
96
|
+
Осадки:
|
97
|
+
Интенсивность осадков: возможен дождь/снег
|
98
|
+
Вероятность грозы: возможна гроза
|
99
|
+
Относительная влажность воздуха: 60..62 %
|
100
|
+
Комфорт: -9..-9 °С
|
101
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler/setup'
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
rescue LoadError
|
9
|
+
puts 'although not required, bundler is recommened for running the tests'
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: :spec
|
13
|
+
|
14
|
+
require 'bundler/gem_tasks'
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
RSpec::Core::RakeTask.new(:spec)
|
17
|
+
|
18
|
+
require 'rubocop/rake_task'
|
19
|
+
RuboCop::RakeTask.new do |task|
|
20
|
+
task.requires << 'rubocop-performance'
|
21
|
+
task.requires << 'rubocop-rspec'
|
22
|
+
end
|
data/lib/main.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'byebug'
|
7
|
+
require 'faraday/encode_xml'
|
8
|
+
require 'faraday_middleware'
|
9
|
+
require 'multi_xml'
|
10
|
+
require_relative 'meteoservice/constants'
|
11
|
+
require_relative 'meteoservice/nested_hash_value'
|
12
|
+
require_relative 'meteoservice/parser_xml'
|
13
|
+
require_relative 'meteoservice/meteo'
|
14
|
+
require_relative 'meteoservice/towns_data'
|
15
|
+
require_relative 'meteoservice/read_data'
|
16
|
+
require_relative 'meteoservice/predict'
|
17
|
+
require_relative 'meteoservice/error'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoservice
|
4
|
+
module Constants
|
5
|
+
# Облачность
|
6
|
+
CLOUDINESS = %w[туман ясно малооблачно облачно пасмурно].freeze
|
7
|
+
|
8
|
+
# Осадки
|
9
|
+
PRECIPITATION = %w[смешанные дождь ливень снег гроза нет данных без осадков].freeze
|
10
|
+
|
11
|
+
# Интенсивность осадков, если они есть
|
12
|
+
RPOWER = ['возможен дождь/снег', 'дождь/снег'].freeze
|
13
|
+
|
14
|
+
# Вероятность грозы, если прогнозируется
|
15
|
+
SPOWER = ['возможна гроза', 'гроза'].freeze
|
16
|
+
|
17
|
+
# Ветер (направление)
|
18
|
+
WIND_DIRECTION = %w[северный северо-восточный восточный юго-восточный южный
|
19
|
+
юго-западный западный северо-западный].freeze
|
20
|
+
|
21
|
+
# Дни недели
|
22
|
+
DAYS_OF_WEEK = %w[понедельник вторник среда четверг пятница суббота воскресенье].freeze
|
23
|
+
|
24
|
+
# аттрибуты xml
|
25
|
+
KEYS_DATA = %w[year month day hour weekday].freeze
|
26
|
+
|
27
|
+
# Погодные явления
|
28
|
+
KEYS_PHENOMENA = %w[cloudiness precipitation rpower spower].freeze
|
29
|
+
|
30
|
+
KEYS_LIMIT = %w[min max].freeze
|
31
|
+
|
32
|
+
BASE_URL = 'https://xml.meteoservice.ru'
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoservice
|
4
|
+
class Error < StandardError
|
5
|
+
ClientError = Class.new(self)
|
6
|
+
ServerError = Class.new(self)
|
7
|
+
|
8
|
+
BadRequest = Class.new(ClientError)
|
9
|
+
Unauthorized = Class.new(ClientError)
|
10
|
+
NotAcceptable = Class.new(ClientError)
|
11
|
+
NotFound = Class.new(ClientError)
|
12
|
+
Conflict = Class.new(ClientError)
|
13
|
+
TooManyRequests = Class.new(ClientError)
|
14
|
+
Forbidden = Class.new(ClientError)
|
15
|
+
Locked = Class.new(ClientError)
|
16
|
+
MethodNotAllowed = Class.new(ClientError)
|
17
|
+
NotImplemented = Class.new(ServerError)
|
18
|
+
BadGateway = Class.new(ServerError)
|
19
|
+
ServiceUnavailable = Class.new(ServerError)
|
20
|
+
GatewayTimeout = Class.new(ServerError)
|
21
|
+
|
22
|
+
ERRORS = {
|
23
|
+
400 => Meteoservice::Error::BadRequest,
|
24
|
+
401 => Meteoservice::Error::Unauthorized,
|
25
|
+
403 => Meteoservice::Error::Forbidden,
|
26
|
+
404 => Meteoservice::Error::NotFound,
|
27
|
+
405 => Meteoservice::Error::MethodNotAllowed,
|
28
|
+
406 => Meteoservice::Error::NotAcceptable,
|
29
|
+
409 => Meteoservice::Error::Conflict,
|
30
|
+
423 => Meteoservice::Error::Locked,
|
31
|
+
429 => Meteoservice::Error::TooManyRequests,
|
32
|
+
500 => Meteoservice::Error::ServerError,
|
33
|
+
502 => Meteoservice::Error::BadGateway,
|
34
|
+
503 => Meteoservice::Error::ServiceUnavailable,
|
35
|
+
504 => Meteoservice::Error::GatewayTimeout
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
def self.from_response(body)
|
39
|
+
msg = body['detail'] || body['message'] || body
|
40
|
+
new msg.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoservice
|
4
|
+
class Meteo
|
5
|
+
attr_reader :data, :phenomena, :pressure, :temperature, :wind,
|
6
|
+
:relwet, :heat
|
7
|
+
|
8
|
+
def initialize(tags)
|
9
|
+
@data = tags[:data]
|
10
|
+
@phenomena = tags[:phenomena]
|
11
|
+
@pressure = tags[:pressure]
|
12
|
+
@temperature = tags[:temperature]
|
13
|
+
@wind = tags[:wind]
|
14
|
+
@relwet = tags[:relwet]
|
15
|
+
@heat = tags[:heat]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoservice
|
4
|
+
module NestedHashValue
|
5
|
+
def nested_hash_value(obj, key)
|
6
|
+
if obj.respond_to?(:key?) && obj.key?(key)
|
7
|
+
obj[key]
|
8
|
+
elsif obj.respond_to?(:each)
|
9
|
+
r = nil
|
10
|
+
|
11
|
+
obj.find { |*a| r = nested_hash_value(a.last, key) }
|
12
|
+
r
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoservice
|
4
|
+
module ParserXml
|
5
|
+
include Meteoservice::Constants
|
6
|
+
|
7
|
+
def connection(path)
|
8
|
+
connection = Faraday.new(url: BASE_URL) do |faraday|
|
9
|
+
faraday.request :xml, content_type: /\bxml$/
|
10
|
+
faraday.adapter Faraday.default_adapter
|
11
|
+
faraday.response :xml
|
12
|
+
end
|
13
|
+
|
14
|
+
response ||= connection.get(path)
|
15
|
+
rescue Faraday::Error => e
|
16
|
+
puts "Ошибка соединения с сервером: #{e.message}"
|
17
|
+
abort e.message
|
18
|
+
else
|
19
|
+
begin
|
20
|
+
body = response.body
|
21
|
+
rescue StandardError => e
|
22
|
+
puts e.class.name
|
23
|
+
abort e.message
|
24
|
+
else
|
25
|
+
respond_with_error(response.status, body) unless response.success?
|
26
|
+
body
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# code - это код состояния HTTP (504, 429, 404...)
|
33
|
+
def respond_with_error(code, body)
|
34
|
+
raise(Meteoservice::Error, body) unless Meteoservice::Error::ERRORS.key?(code)
|
35
|
+
|
36
|
+
raise Meteoservice::Error::ERRORS[code].from_response(body)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Meteoservice
|
2
|
+
class Predict
|
3
|
+
include Meteoservice::Constants
|
4
|
+
|
5
|
+
def initialize(forecasts)
|
6
|
+
@date = forecasts.data
|
7
|
+
@phenomena = forecasts.phenomena
|
8
|
+
@pressure = forecasts.pressure
|
9
|
+
@temperature = forecasts.temperature
|
10
|
+
@wind = forecasts.wind
|
11
|
+
@relwet = forecasts.relwet
|
12
|
+
@heat = forecasts.heat
|
13
|
+
end
|
14
|
+
|
15
|
+
# Какой день недели?
|
16
|
+
def day_week
|
17
|
+
firstday_wday = Date.new(@date[0], @date[1], @date[2]).wday
|
18
|
+
|
19
|
+
firstday_wday = 7 if firstday_wday.zero?
|
20
|
+
|
21
|
+
DAYS_OF_WEEK[firstday_wday - 1]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Вывод результата в терминал
|
25
|
+
def to_s
|
26
|
+
times_day = 'ночью' if Range.new(*[0, 5].map(&:to_i)).include? @date[3]
|
27
|
+
times_day = 'утром' if Range.new(*[6, 12].map(&:to_i)).include? @date[3]
|
28
|
+
times_day = 'днём' if Range.new(*[13, 17].map(&:to_i)).include? @date[3]
|
29
|
+
times_day = 'вечером' if Range.new(*[18, 23].map(&:to_i)).include? @date[3]
|
30
|
+
|
31
|
+
result = if today?
|
32
|
+
"Сегодня в #{day_week} #{times_day}\n"
|
33
|
+
else
|
34
|
+
"#{DateTime.new(@date[0], @date[1], @date[2], @date[3], 0, 0)
|
35
|
+
.strftime('%F')} в #{day_week} #{times_day}\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
result << "Температура: #{temperature_range_string} °С\n" \
|
39
|
+
"Ветер: #{@wind[0]}..#{@wind[1]} м/с, #{WIND_DIRECTION[@wind[2].to_i]}\n" \
|
40
|
+
"Атмосферное давление: #{@pressure[0]}..#{@pressure[1]} мм.рт.ст.\n" \
|
41
|
+
"Облачность: #{CLOUDINESS[@phenomena[0].to_i]}\n" \
|
42
|
+
"Осадки: #{PRECIPITATION[@phenomena[1].to_i]}\n" \
|
43
|
+
"Интенсивность осадков: #{RPOWER[@phenomena[2].to_i]}\n" \
|
44
|
+
"Вероятность грозы: #{SPOWER[@phenomena[3].to_i]}\n" \
|
45
|
+
"Относительная влажность воздуха: #{@relwet[0]}..#{@relwet[1]} %\n" \
|
46
|
+
"Комфорт: #{@heat[0]}..#{@heat[1]} °С"
|
47
|
+
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
# Добавим знак "+" к температуре, если она положительная
|
52
|
+
def temperature_range_string
|
53
|
+
result = ''
|
54
|
+
result << '+' if @temperature[0].positive?
|
55
|
+
result << "#{@temperature[0]}.."
|
56
|
+
result << '+' if @temperature[1].positive?
|
57
|
+
result << @temperature[1].to_s
|
58
|
+
result
|
59
|
+
end
|
60
|
+
|
61
|
+
def today?
|
62
|
+
@date == Date.today
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoservice
|
4
|
+
class ReadData
|
5
|
+
def self.from_array(doc)
|
6
|
+
include Meteoservice::Constants
|
7
|
+
|
8
|
+
forecasts = doc.map do |prediction|
|
9
|
+
predict_data = {}
|
10
|
+
|
11
|
+
# дата "год, месяц, день, час, день недели"
|
12
|
+
data = KEYS_DATA.map do |key|
|
13
|
+
prediction[key].to_i
|
14
|
+
end
|
15
|
+
|
16
|
+
predict_data[:data] = data
|
17
|
+
|
18
|
+
# атмосферные явления
|
19
|
+
phenomena = KEYS_PHENOMENA.map do |key|
|
20
|
+
prediction['PHENOMENA'][key].to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
predict_data[:phenomena] = phenomena
|
24
|
+
|
25
|
+
# атмосферное давление
|
26
|
+
pressure = KEYS_LIMIT.map do |key|
|
27
|
+
prediction['PRESSURE'][key].to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
predict_data[:pressure] = pressure
|
31
|
+
|
32
|
+
# температура
|
33
|
+
temperature = KEYS_LIMIT.map do |key|
|
34
|
+
prediction['TEMPERATURE'][key].to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
predict_data[:temperature] = temperature
|
38
|
+
|
39
|
+
# относительная влажность воздуха
|
40
|
+
relwet = KEYS_LIMIT.map do |key|
|
41
|
+
prediction['RELWET'][key].to_i
|
42
|
+
end
|
43
|
+
|
44
|
+
predict_data[:relwet] = relwet
|
45
|
+
|
46
|
+
# комфорт - температура воздуха по ощущению одетого по сезону
|
47
|
+
# человека, выходящего на улицу
|
48
|
+
heat = KEYS_LIMIT.map do |key|
|
49
|
+
prediction['HEAT'][key].to_i
|
50
|
+
end
|
51
|
+
|
52
|
+
predict_data[:heat] = heat
|
53
|
+
|
54
|
+
# приземный ветер
|
55
|
+
max_wind = prediction['WIND']['max']
|
56
|
+
min_wind = prediction['WIND']['min']
|
57
|
+
direction_wind = prediction['WIND']['direction']
|
58
|
+
|
59
|
+
predict_data[:wind] = [min_wind, max_wind, direction_wind]
|
60
|
+
|
61
|
+
Meteoservice::Meteo.new(predict_data)
|
62
|
+
end
|
63
|
+
|
64
|
+
new(forecasts)
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize(forecasts)
|
68
|
+
@forecasts = forecasts
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_a
|
72
|
+
@forecasts
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoservice
|
4
|
+
module TownsData
|
5
|
+
extend Meteoservice::NestedHashValue
|
6
|
+
extend Meteoservice::Constants
|
7
|
+
extend Meteoservice::ParserXml
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def process
|
11
|
+
catalogue = load
|
12
|
+
|
13
|
+
puts <<~TOWNS
|
14
|
+
\nПогоду для какого города Вы хотите узнать?
|
15
|
+
Введите уникальный индекс города и нажмите "enter". Если вашего города#{' '}
|
16
|
+
нет в списке, перейдите по ссылке https://www.meteoservice.ru/content/export.html,
|
17
|
+
найдите интересуемый индекс и введите его ниже. Название города с индексом добавятся
|
18
|
+
в список автоматически:\n
|
19
|
+
TOWNS
|
20
|
+
|
21
|
+
catalogue.sort_by { |_key, value| value }
|
22
|
+
.to_h.each_with_index { |name, index| puts "#{index + 1}: #{name}" }
|
23
|
+
|
24
|
+
city_index = gets.to_i
|
25
|
+
path = "/export/gismeteo/point/#{city_index}.xml"
|
26
|
+
if catalogue.key?('city_index')
|
27
|
+
data_taking(path, city_index)
|
28
|
+
else
|
29
|
+
data_taking(path, city_index, catalogue, conservation: true)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def auto_process(city_index)
|
34
|
+
path = "/export/gismeteo/point/#{city_index}.xml"
|
35
|
+
|
36
|
+
data_taking(path, city_index)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def load
|
42
|
+
data = nil
|
43
|
+
File.open("#{__dir__}/data/towns.json", encoding: 'utf-8') do |f|
|
44
|
+
data = JSON.parse(f.read)
|
45
|
+
end
|
46
|
+
|
47
|
+
data
|
48
|
+
end
|
49
|
+
|
50
|
+
def save(data, index, name)
|
51
|
+
File.open("#{__dir__}/data/towns.json", 'w+') do |f|
|
52
|
+
f.puts(JSON.pretty_generate(data.merge({ index.to_s => name.to_s })))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def data_taking(path, index, data = nil, conservation: false)
|
57
|
+
result = connection(path)
|
58
|
+
|
59
|
+
city_name = URI.decode_www_form_component(nested_hash_value(result, 'TOWN')['sname'])
|
60
|
+
|
61
|
+
save(data, index, city_name) if conservation
|
62
|
+
|
63
|
+
[nested_hash_value(result, 'FORECAST'), city_name]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/meteoservice.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'main'
|
4
|
+
|
5
|
+
# Main Meteoservice module
|
6
|
+
module Meteoservice
|
7
|
+
def self.result(city_index = nil)
|
8
|
+
doc = if city_index
|
9
|
+
Meteoservice::TownsData.auto_process(city_index.to_i)
|
10
|
+
else
|
11
|
+
Meteoservice::TownsData.process
|
12
|
+
end
|
13
|
+
|
14
|
+
puts "\e[H\e[2J"
|
15
|
+
|
16
|
+
weather = Meteoservice::ReadData.from_array(doc[0]).to_a
|
17
|
+
|
18
|
+
puts "#{doc[1]}\n\n"
|
19
|
+
|
20
|
+
weather.each_with_index do |_day, index|
|
21
|
+
puts Meteoservice::Predict.new(weather[index])
|
22
|
+
puts
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meteoservice
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gleb V. Zhegulin
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-11-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday-encode_xml
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday_middleware
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: multi_xml
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.6'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: uri
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: |-
|
70
|
+
The program shows the current weather using fresh data in an XML structure.
|
71
|
+
The user is prompted to indicate for which city he wants to see the forecast.
|
72
|
+
email:
|
73
|
+
- gleboceanborn@gmail.com
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files:
|
77
|
+
- README.md
|
78
|
+
files:
|
79
|
+
- ".rspec"
|
80
|
+
- ".rubocop.yml"
|
81
|
+
- CHANGELOG.md
|
82
|
+
- Gemfile
|
83
|
+
- Gemfile.lock
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- lib/main.rb
|
88
|
+
- lib/meteoservice.rb
|
89
|
+
- lib/meteoservice/constants.rb
|
90
|
+
- lib/meteoservice/data/towns.json
|
91
|
+
- lib/meteoservice/error.rb
|
92
|
+
- lib/meteoservice/meteo.rb
|
93
|
+
- lib/meteoservice/nested_hash_value.rb
|
94
|
+
- lib/meteoservice/parser_xml.rb
|
95
|
+
- lib/meteoservice/predict.rb
|
96
|
+
- lib/meteoservice/read_data.rb
|
97
|
+
- lib/meteoservice/towns_data.rb
|
98
|
+
- lib/meteoservice/version.rb
|
99
|
+
- sig/meteoservice.rbs
|
100
|
+
homepage: https://github.com/ProfessorNemo/meteoservice
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
metadata:
|
104
|
+
homepage_uri: https://github.com/ProfessorNemo/meteoservice
|
105
|
+
source_code_uri: https://github.com/ProfessorNemo/meteoservice
|
106
|
+
rubygems_mfa_required: 'true'
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 3.0.2
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubygems_version: 3.3.23
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: Weather forecast for the next day.
|
126
|
+
test_files: []
|