Skip to content

Commit

Permalink
Update version (#9)
Browse files Browse the repository at this point in the history
* Update argparser version from 1.1.0 to 1.3.0

* Update documentation

* Update version to 1.3.6

* Fix some errors in documentation

* Fix some small errors in documentation

* Refactor ui lib

* Refactor utils lib

* Refactor forecast lib

* Update argparser version to v1.3.5

* Update docs
  • Loading branch information
bialger authored Aug 28, 2024
1 parent 9c55fa0 commit 8eb1b92
Show file tree
Hide file tree
Showing 23 changed files with 137 additions and 166 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12)

project(
weather-forecast
VERSION 1.3.5
VERSION 1.3.6
DESCRIPTION "Console weather forecast app that uses OpenMeteo and Yandex Geocoder API"
LANGUAGES CXX
)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ cd %userprofile%\weather-forecast && .\weather-forecast.exe

## Использование

Программа weather-forecast - консольное приложение для просмотра погоды.
Программа weather-forecast консольное приложение для просмотра погоды.
Предусмотрен показ погоды для локаций, перечисленных в конфигурационном файле, на
текущий момент, а также на утро, день, вечер и ночь некоторого количества дней.
Программа в один момент времени отображает непосредственно прогноз на три дня, для
Expand All @@ -164,7 +164,7 @@ cd %userprofile%\weather-forecast && .\weather-forecast.exe

### Вызов

Программа может быть вызвана без аргументов - будут применены значения по умолчанию.
Программа может быть вызвана без аргументов будут применены значения по умолчанию.
Порядок аргументов не имеет значения.

#### Аргументы командной строки:
Expand Down Expand Up @@ -212,7 +212,7 @@ cd %userprofile%\weather-forecast && .\weather-forecast.exe
* `F5` или `r` - обновление данных.
* `+` - увеличение количества отображаемых дней на единицу, но не более 15.
* `-` - уменьшение количества отображаемых дней на единицу, но не менее 3.
При этом в том случае, если фокус направлен на последни день, происходит
При этом в том случае, если фокус направлен на последний день, происходит
смещение фокуса вверх.
* `w` или `ArrowUp` - смещение фокуса отображения вверх (меньшая дата) на единицу.
* `s` или `ArrowDown` - смещение фокуса отображения вверх (меньшая дата) на единицу.
Expand Down
6 changes: 3 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Документация проекта

Данный документ - сборник документации по проекту Weather Forecast. Здесь
будут все ссылки на документацию.
Данный документ сборник документации по проекту Weather Forecast.
Здесь будут все ссылки на документацию.

## Документация разработки

* [Проблема](dev/problem.md)
* [Требования](dev/requirements.md)
* [Архитектура](dev/architecture.md)
* [Модуль ArgParser, v1.1.0](https://github.com/bialger/ArgParser/blob/v1.1.0/lib/argparser/docs/README.md)
* [Модуль ArgParser, v1.3.5](https://github.com/bialger/ArgParser/blob/v1.3.5/lib/argparser/docs/README.md)
10 changes: 4 additions & 6 deletions docs/dev/architecture.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Архитектура продукта

В этом документе описывается архитектура продукта - парсера аргументов командной
В этом документе описывается архитектура продукта парсера аргументов командной
строки, разработанная на основании [требований](requirements.md).

## Системная архитектура

Продукт состоит из нескольких связанных подсистем. Несколько из них - внешние
библиотеки.
Продукт состоит из нескольких связанных подсистем.
Несколько из них — внешние библиотеки.

* Используется модуль UI для взаимодействия с пользовательским вводом любого рода и
вывода информации.
* Используется модуль [ArgParser](https://github.com/bialger/ArgParser/tree/v1.1.0) - подсистема
* Используется модуль [ArgParser](https://github.com/bialger/ArgParser/tree/v1.3.5) подсистема
для обработки аргументов командной строки.
* Используется модуль Forecast для выполнения и обработки запросов прогноза.
* Используется библиотека [C++ Requests](https://github.com/libcpr/cpr) для выполнения HTTP-запросов.
Expand Down Expand Up @@ -70,8 +70,6 @@ classDiagram
+string kProgramName$
+CompositeString kDefaultConfigPath$
+CompositeString kDefaultLogPath$
-string kIntervalDescription$
-string kDaysCountDescription$
-ostream& out_
-istream& in_
-ConditionalOutput error_output_
Expand Down
6 changes: 3 additions & 3 deletions docs/dev/requirements.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Требования к продукту

В этом документе описаны требования к продукту - приложению для показа прогноза
В этом документе описаны требования к продукту приложению для показа прогноза
погоды в консоли.

## Функциональные требования
Expand All @@ -15,14 +15,14 @@

### Требования к формату выходных данных

* Выходные данные - периодически меняющееся ASCII-изображение в терминале,
* Выходные данные периодически меняющееся ASCII-изображение в терминале,
отображающее прогноз погоды.

### Требования к функциональности продукта

* Приложение должно корректно отображать прогноз погоды для выбранного города.
* Приложение должно иметь визуально приятный интерфейс.
* Приложение должно иметь "оффлайн-режим" - при отсутствии Интернет-соединения
* Приложение должно иметь "оффлайн-режим" при отсутствии Интернет-соединения
программа не должна завершаться с ошибкой.
* Отображать прогноз погоды на несколько дней вперед (значение по умолчанию задается конфигом)
* Обновлять с некоторой частотой (задается конфигом)
Expand Down
2 changes: 1 addition & 1 deletion lib/argparser/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
include(FetchContent)
FetchContent_Declare(argparser GIT_REPOSITORY https://github.com/bialger/ArgParser GIT_TAG v1.1.0)
FetchContent_Declare(argparser GIT_REPOSITORY https://github.com/bialger/ArgParser GIT_TAG v1.3.5)
FetchContent_MakeAvailable(argparser)
17 changes: 9 additions & 8 deletions lib/forecast/Forecaster.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <regex>
#include <utility>

#include "Forecaster.hpp"

Expand All @@ -7,17 +8,17 @@
Forecaster::Forecaster(int32_t days_count,
int32_t location_index,
const std::vector<std::string>& locations,
const std::string& api_key,
std::string api_key,
const std::string& config_dir,
ConditionalOutput error_output,
ConditionalOutput log_output) : geocoder_cache_("geocoder", config_dir),
ConditionalOutput log_output) : locations_(locations),
days_count_(days_count),
location_index_(location_index),
locations_(locations),
api_key_(api_key),
api_key_(std::move(api_key)),
current_weather_("Now"),
geocoder_cache_("geocoder", config_dir),
error_output_(error_output),
log_output_(log_output),
current_weather_("Now") {
log_output_(log_output) {
forecast_ = std::vector<WeatherDay>(WeatherDay::kDaysInForecast);
}

Expand Down Expand Up @@ -236,7 +237,7 @@ int32_t Forecaster::ProcessPosition(const json& answer) {
WriteCurrentTime(log_output_);
log_output_ << "FORECASTER: Processing position\n";

int32_t result = geocoder_.SetCoordinates(answer);
const int32_t result = geocoder_.SetCoordinates(answer);

if (result != 0) {
DisplayError("Unknown error occurred while geocoding.\n", error_output_);
Expand All @@ -256,7 +257,7 @@ int32_t Forecaster::ProcessPosition(const json& answer) {

int32_t Forecaster::ProcessForecast(const json& answer) {
for (int32_t day_number = 0; day_number < WeatherDay::kDaysInForecast; ++day_number) {
bool result = forecast_[day_number].SetForecast(answer, day_number);
const bool result = forecast_[day_number].SetForecast(answer, day_number);

if (!result) {
geocoder_cache_.PutJsonToCache("error", answer);
Expand Down
2 changes: 1 addition & 1 deletion lib/forecast/Forecaster.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Forecaster {
Forecaster(int32_t days_count,
int32_t location_index,
const std::vector<std::string>& locations,
const std::string& api_key,
std::string api_key,
const std::string& config_dir,
ConditionalOutput error_output,
ConditionalOutput log_output);
Expand Down
2 changes: 1 addition & 1 deletion lib/forecast/Geocoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ int32_t Geocoder::SetCoordinates(const json& geocode) {
return 1;
}

std::vector<std::string> positions = Split(
const std::vector<std::string> positions = Split(
geocode["response"]["GeoObjectCollection"]["featureMember"][0]["GeoObject"]["Point"]["pos"].get<std::string>()
);

Expand Down
8 changes: 3 additions & 5 deletions lib/forecast/JsonCache.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#include <fstream>

#include "JsonCache.hpp"
#include "lib/utils/utils.hpp"
#include "lib/utils/utils.hpp"

const json JsonCache::kNotFound = "{}";

Expand All @@ -15,12 +13,12 @@ JsonCache::JsonCache(const std::string& cache_group, const std::string& common_c
}
}

void JsonCache::PutJsonToCache(const std::string& cache_name, const json& data) {
void JsonCache::PutJsonToCache(const std::string& cache_name, const json& data) const {
std::ofstream cache_file(GetCacheFilename(cache_name).c_str());
cache_file << data;
}

json JsonCache::GetJsonFromCache(const std::string& cache_name) {
json JsonCache::GetJsonFromCache(const std::string& cache_name) const {
if (!std::filesystem::is_regular_file(GetCacheFilename(cache_name))) {
return kNotFound;
}
Expand All @@ -30,6 +28,6 @@ json JsonCache::GetJsonFromCache(const std::string& cache_name) {
return data;
}

std::string JsonCache::GetCacheFilename(const std::string& cache_name) {
std::string JsonCache::GetCacheFilename(const std::string& cache_name) const {
return cache_dir_ + "/" + cache_name + ".json";
}
8 changes: 4 additions & 4 deletions lib/forecast/JsonCache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ class JsonCache {
static const json kNotFound;

JsonCache() = delete;
JsonCache(const std::string& cache_group, const std::string& cache_dir);
JsonCache(const std::string& cache_group, const std::string& common_cache_dir);

void PutJsonToCache(const std::string& cache_name, const json& data);
json GetJsonFromCache(const std::string& cache_name);
void PutJsonToCache(const std::string& cache_name, const json& data) const;
json GetJsonFromCache(const std::string& cache_name) const;

private:
std::string cache_group_;
std::string cache_dir_;

std::string GetCacheFilename(const std::string& cache_name);
std::string GetCacheFilename(const std::string& cache_name) const;
};

#endif //JSONCACHE_HPP_
8 changes: 4 additions & 4 deletions lib/forecast/WeatherDay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ WeatherTimeUnit WeatherDay::GetCurrentWeather(const json& forecast) {
return time_unit;
}

int32_t hour = std::stoi(current[kOpenMeteoNames.time].get<std::string>().substr(11, 2));
const int32_t hour = std::stoi(current[kOpenMeteoNames.time].get<std::string>().substr(11, 2));

if (hour < 0 || hour >= kHoursInDay) {
return time_unit;
Expand All @@ -89,11 +89,11 @@ bool WeatherDay::SetForecast(const json& forecast, int32_t day_number) {
}

date_ = daily_values_[kOpenMeteoNames.dates][day_number].get<std::string>();
double uv_index = daily_values_[kOpenMeteoNames.uv_index][day_number].get<double>();
const double uv_index = daily_values_[kOpenMeteoNames.uv_index][day_number].get<double>();

const size_t start_index = day_number * kHoursInDay;
const size_t end_index = start_index + kHoursInDay - 1;
const size_t kHoursInUnit = kHoursInDay / kUnitsInDay;
constexpr size_t kHoursInUnit = kHoursInDay / kUnitsInDay;

for (size_t unit_index = 0; unit_index < kUnitsInDay; ++unit_index) {
WeatherTimeUnit& unit = units_[unit_index];
Expand All @@ -110,7 +110,7 @@ bool WeatherDay::SetForecast(const json& forecast, int32_t day_number) {
double humidity_summa = 0;

for (size_t i = 0; i < kHoursInUnit; ++i) {
size_t element_index = start_index + unit_index * kHoursInUnit + i;
const size_t element_index = start_index + unit_index * kHoursInUnit + i;

if (element_index > end_index) {
return false;
Expand Down
12 changes: 7 additions & 5 deletions lib/forecast/WeatherTimeUnit.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "WeatherTimeUnit.hpp"

#include <utility>

const std::map<int32_t, std::string> WeatherTimeUnit::kWeatherCodeToString = {
{0, "Clear sky"},
{1, "Mainly clear"},
Expand Down Expand Up @@ -55,7 +57,7 @@ const std::map<std::string, std::string> WeatherTimeUnit::kChargeUnits = {
{kShownNames.humidity, "%"}
};

WeatherTimeUnit::WeatherTimeUnit(const std::string& name) : name_(name) {}
WeatherTimeUnit::WeatherTimeUnit(std::string name) : name_(std::move(name)) {}

std::map<std::string, std::string> WeatherTimeUnit::GetAllAsMap() const {
std::map<std::string, std::string> result;
Expand All @@ -71,13 +73,13 @@ std::map<std::string, std::string> WeatherTimeUnit::GetAllAsMap() const {
uv_level = "Very high";
}

std::string str_visibility = std::string(128, '\0');
auto str_visibility = std::string(128, '\0');
std::snprintf(str_visibility.data(), str_visibility.size(), "%.2f", visibility);
std::string str_pressure = std::string(128, '\0');
auto str_pressure = std::string(128, '\0');
std::snprintf(str_pressure.data(), str_pressure.size(), "%.1f", pressure);
std::string str_uv_index = std::string(128, '\0');
auto str_uv_index = std::string(128, '\0');
std::snprintf(str_uv_index.data(), str_uv_index.size(), "%.2f", uv_index);
std::string str_precipitation = std::string(128, '\0');
auto str_precipitation = std::string(128, '\0');
std::snprintf(str_precipitation.data(), str_precipitation.size(), "%.1f", precipitation);

result[kShownNames.weather_code] = kWeatherCodeToString.at(weather_type);
Expand Down
2 changes: 1 addition & 1 deletion lib/forecast/WeatherTimeUnit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class WeatherTimeUnit {
double uv_index{};
int32_t humidity{};

explicit WeatherTimeUnit(const std::string& name);
explicit WeatherTimeUnit(std::string name);

[[nodiscard]] std::map<std::string, std::string> GetAllAsMap() const;
[[nodiscard]] std::string GetName() const;
Expand Down
25 changes: 13 additions & 12 deletions lib/ui/ConfigParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "ConfigParser.hpp"

#include "lib/utils/utils.hpp"
#include "lib/forecast/Forecaster.hpp"

const std::string ConfigParser::kDefaultLocation = "First location in config";

Expand Down Expand Up @@ -32,9 +33,9 @@ bool ConfigParser::IsValidConfig(const std::string& str_config) {
return false;
}

json api_key_file = config["api_key_file"];
json locations = config["locations"];
json defaults = config["defaults"];
const json& api_key_file = config["api_key_file"];
const json& locations = config["locations"];
const json& defaults = config["defaults"];

if (!api_key_file.is_string() || !locations.is_array() || !defaults.is_object()) {
return false;
Expand All @@ -55,10 +56,10 @@ int32_t ConfigParser::ParseConfig() {
return 1;
}

json config = json::parse(str_config);
json api_key_file = config["api_key_file"];
json locations = config["locations"];
json defaults = config["defaults"];
const json config = json::parse(str_config);
const json& api_key_file = config["api_key_file"];
const json& locations = config["locations"];
const json& defaults = config["defaults"];

std::string api_key_path = config_dir_ + "/" + api_key_file.get<std::string>();

Expand All @@ -67,7 +68,7 @@ int32_t ConfigParser::ParseConfig() {
return 1;
}

int32_t result = SetApiKey(api_key_path);
const int32_t result = SetApiKey(api_key_path);

if (result != 0) {
DisplayError("Invalid API key!\n", error_output_);
Expand All @@ -86,7 +87,7 @@ int32_t ConfigParser::ParseConfig() {
days_count_ = defaults["days_count"].get<int32_t>();
}

size_t listed_locations_size = locations.size();
const size_t listed_locations_size = locations.size();
interval_ = std::clamp(interval_, kLowerLimitIntervalSize + 1, kUpperLimitIntervalSize - 1);
days_count_ = std::clamp(days_count_, Forecaster::kLowerLimitDaysCount + 1, Forecaster::kUpperLimitDaysCount - 1);
location_index_ = std::clamp(location_index_, 0, static_cast<int32_t>(listed_locations_size + locations_.size() - 1));
Expand All @@ -100,15 +101,15 @@ int32_t ConfigParser::ParseConfig() {

int32_t ConfigParser::SetApiKey(const std::string& api_key_path) {
std::ifstream api_key_file_(api_key_path);
std::string api_key = std::string((std::istreambuf_iterator<char>(api_key_file_)),
std::istreambuf_iterator<char>());
auto api_key = std::string((std::istreambuf_iterator<char>(api_key_file_)),
std::istreambuf_iterator<char>());

if (api_key.size() < 36) {
return 1;
}

api_key = api_key.substr(0, 36);
std::regex yandex_api_regex = std::regex(R"(^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$)");
const auto yandex_api_regex = std::regex(R"(^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$)");

if (!std::regex_match(api_key, yandex_api_regex)) {
return 1;
Expand Down
1 change: 0 additions & 1 deletion lib/ui/ConfigParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <vector>

#include "lib/utils/utils.hpp"
#include "lib/forecast/Forecaster.hpp"

#include <nlohmann/json.hpp>

Expand Down
Loading

0 comments on commit 8eb1b92

Please sign in to comment.