meteoservice 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format doc
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
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-11-21
4
+
5
+ - Initial release
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,11 @@
1
+ {
2
+ "69": "Санкт-Петербург",
3
+ "99": "Новосибирск",
4
+ "105": "Калининград",
5
+ "113": "Мурманск",
6
+ "4": "Архангельск",
7
+ "111": "Петропавловск-Камчатский",
8
+ "199": "Краснодар",
9
+ "37": "Москва",
10
+ "135": "Ростов-на-Дону"
11
+ }
@@ -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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meteoservice
4
+ VERSION = '0.1.0'
5
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ module Meteoservice
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ 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: []