diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94ba2eb..6cdd326 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12)
project(
weather-forecast
- VERSION 1.3
+ VERSION 1.3.5
DESCRIPTION "Console weather forecast app that uses OpenMeteo and Yandex Geocoder API"
LANGUAGES CXX
)
diff --git a/README.md b/README.md
index 0fa5f79..7b4d72c 100644
--- a/README.md
+++ b/README.md
@@ -1,45 +1,222 @@
-# Лабораторная работа 7
+# Программа weather-forecast
+
+Данная программа предоставляет прогноз погоды в терминале с удобным текстовым интерфейсом.
+Она была написана как лабораторная работа в курсе "Программирование на C++" в программе ITMO SE.
+С заданием можно ознакомиться [здесь](./TASK.md).
Документация проекта находится [в соответствующей папке](./docs/README.md).
-Прогноз погоды. Внешние библиотеки.
+Этот документ описывает сборку из исходного кода и использование программы
+weather-forecast.
+
+## Зависимости
+
+Для успешной компиляции требует установленного `Git`, `CMake` и компилятора C++,
+поддерживающего стандарт C++20.
+Также потребуется ключ от [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/).
+
+> Если Вам не хочется получать ключ, можно воспользоваться архивом кэша:
+> [cache.zip](https://github.com/bialger/weather-forecast/releases/download/v1.2.0/cache.zip).
+> После распаковки поместите в каталог /.config, а затем начните установку.
+>
+> Используйте вместо API-ключа `00000000-0000-0000-0000-000000000000`.
+
+## Как собрать
+
+> **Важно!**
+> Для ОС Windows успешная сборка и компиляция возможна **только** при
+> установленном компиляторе `MinGW`.
+
+В данном документе описана исключительно процедура сборки главного исполняемого
+файла.
+> Процесс сборки тестов описан не будет, его можно восстановить из
+[CI/CD скрипта](/.github/workflows/ci_tests.yml).
+
+### Автоматическая сборка и установка
+
+Сделайте исполняемым и запустите [shell-script установки](/install.sh), затем следуйте
+инструкциям.
+> **Важно!**
+> Для ОС Windows автоматизированная сборка гарантирована только
+> при запуске в Git Bash.
+
+```shell
+chmod +x ./install.sh && ./install.sh
+```
+
+### Ручная сборка
+
+* Сначала, если Вы этого не сделали, клонируйте проект и перейдите в его каталог:
+
+```shell
+git clone https://github.com/bialger/weather-forecast.git && cd weather-forecast
+```
+
+#### Linux и MacOs
+
+* Создайте Release-кеш CMake:
+
+```shell
+cmake -S . -B ~/CMakeBuilds/weather-forecast -DCMAKE_BUILD_TYPE=Release
+```
+
+* Соберите проект из этого кеша:
+
+```shell
+cmake --build ~/CMakeBuilds/weather-forecast --target weather-forecast
+```
+
+* Введите ключ от [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/) и
+ запишите его в соответсвующий файл:
+
+```shell
+read -r API_KEY && echo "$API_KEY" > "./.config/yandex_api_key.apikey"
+```
+
+* Скопируйте в конфигурационный каталог файлы конфигурации:
+
+```shell
+cp -r ./.config ~/.config/weather-forecast
+```
+
+* Создайте символьную ссылку на исполняемый файл (`~/weather-forecast.run`):
+
+```shell
+ln -s ~/CMakeBuilds/weather-forecast/bin/weather-forecast ~/weather-forecast.run
+```
+
+* Запустите программу:
+
+```shell
+~/weather-forecast.run
+```
+
+#### Windows (`cmd.exe`)
-## Задача
+* Создайте Release-кеш CMake:
-Реализовать консольное приложение, отображающие прогноз погоды для выбранного списка городов, используя сторонние библиотеки.
+```shell
+cmake -S . -B "%userprofile%\CMakeBuilds\weather-forecast" -DCMAKE_BUILD_TYPE=Release
+```
-## Источник данных
+* Соберите проект из этого кеша:
-- [Open-Meteo](https://open-meteo.com/en/docs#latitude=59.94&longitude=30.31&hourly=temperature_2m&forecast_days=16) для прогноза
-- [Api-Ninjas](https://api-ninjas.com/api/city) для определения координат по названию города
+```shell
+cmake --build "%userprofile%\CMakeBuilds\weather-forecast" --target weather-forecast
+```
-## Функциональные требования
+* Введите ключ от [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/) и
+ запишите его в соответсвующий файл:
- - Отображать прогноз погоды на несколько дней вперед (значение по умолчанию задается конфигом)
- - Обновлять с некоторой частотой (задается конфигом)
- - Переключаться между городами с помощью клавиш "n", "p"
- - Заканчивать работу программы по Esc
- - Увеличивать\уменьшать количество дней прогноза по нажатие клавиш "+", "-"
+```shell
+SET /P API_KEY="Enter your Yandex Geocoder API key: " && echo %API_KEY% > ".config\yandex_api_key.apikey"
+```
-Список городов, частота обновления, количество дней прогноза должны быть определены в конфиге(например в формате ini, json, xml)
+* Скопируйте в конфигурационный каталог файлы конфигурации:
-## Отображение
+```shell
+xcopy /si .config "%userprofile%\.config\weather-forecast"
+```
-В качестве образца для визуализации предлагается взять следующий:
+* Скопируйте исполняемый файл и библиотеки в каталог `%userprofile%\weather-forecast` для быстрого доступа
-![image](assets/interface.png) Скриншот взят с https://wttr.in
+```shell
+mkdir "%userprofile%\weather-forecast"
+copy "%userprofile%\CMakeBuilds\weather-forecast\weather-forecast.exe" "%userprofile%\weather-forecast\weather-forecast.exe"
+copy "%userprofile%\CMakeBuilds\weather-forecast\libcpr.dll" "%userprofile%\weather-forecast\libcpr.dll"
+copy "%userprofile%\CMakeBuilds\weather-forecast\libcurl.dll" "%userprofile%\weather-forecast\libcurl.dll"
+```
-## Реализация
+* Создайте символьную ссылку на исполняемый файл (`%userprofile%\weather-forecast\weather-forecast.exe`):
-В данной лабораторной работе вам не запрещено использовать другие библиотеки.
+```shell
+mklink "%userprofile%\weather-forecast.exe" "%userprofile%\weather-forecast\weather-forecast.exe"
+```
-В качестве библиотеки для [HTTP-запросов](https://en.wikipedia.org/wiki/HTTP) требуется воспользоваться [C++ Requests](https://github.com/libcpr/cpr)
+> Для Windows запуск такой ссылки из командной строки или иного эмулятора терминала
+> полноценно невозможен, только из Проводника.
+* Запустите программу:
-В данной работе, при взаимодействии с внешними сервисами, может возникать достаточно большое количество коллизий и краевых случаев. Внимательно, подумайте об этом! Ваша программа должна корректно работать и "не падать"
+```shell
+cd %userprofile%\weather-forecast && .\weather-forecast.exe
+```
-## Deadline
+## Использование
-1. 20.02.24 0.85
-2. 27.02.24 0.65
-3. 05.03.24 0.5
+Программа weather-forecast - консольное приложение для просмотра погоды.
+Предусмотрен показ погоды для локаций, перечисленных в конфигурационном файле, на
+текущий момент, а также на утро, день, вечер и ночь некоторого количества дней.
+Программа в один момент времени отображает непосредственно прогноз на три дня, для
+просмотра прочих следует использовать навигации.
+В случае отсутствия Интернет-соединения программа запустится, однако не будет отображать
+актуальную информацию.
+Для получения актуальных данных возобновите подключение и обновите данные в программе.
+
+> Поскольку программа использует
+[Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/), для работы
+> требуется валидный API-ключ.
+> Бесплатная версия поддерживает 1000 запросов в сутки.
+
+### Пример интерфейса
+
+![image](/assets/weather_forecast_1.png)
+
+### Вызов
+
+Программа может быть вызвана без аргументов - будут применены значения по умолчанию.
+Порядок аргументов не имеет значения.
+
+#### Аргументы командной строки:
+
+* `-l` или `--location` - строка с названием первой локации, для которой будет
+ предоставлен прогноз погоды.
+ Если аргумент не указан, первая локация получается из конфигурационного файла.
+* `-c` или `--config` - строка с именем файла конфигурации в формате JSON.
+ Значения по умолчанию получают из
+ [файла конфигурации по умолчанию](/.config/default_config.json).
+ Документ должен содержать строковое поле `api_key_file` с относительным путем к
+ файлу, содержащему ключ к
+ [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/); поле `locations`,
+ содержащее список локаций (строк, содержащие адрес или название города на
+ английском языке) для показа погоды; поле `defaults`, содержащее следующие
+ значения параметров по умолчанию:
+ * `interval` - как аргумент `--interval`.
+ * `days_count` - как аргумент `--days-count`
+ * `location_index` - целое неотрицательное число, являющееся индексом локации
+ по умолчанию из списка `locations`.
+ Строго меньше количества локаций.
+* `-L` или `--log-file` - строка с именем файла для записи логов.
+ Имя файла должно быть валидным, в частности, не являться именем каталога.
+ Если параметр не указан, логи выводятся в стандартный поток вывода.
+* `-d` или `--days-count` - целое положительное число, определяющее количество дней
+ прогноза, отображаемых при запуске программы.
+ Не может превышать 15.
+ Если аргумент не указан, частота обновления получается из конфигурационного файла.
+* `-i` или `--interval` - целое положительное число, определяющее частоту
+ обновлений в часах.
+ Не может превышать 48.
+ Если аргумент не указан, частота обновления получается из конфигурационного файла.
+* `-v` или `--verbose` - флаг, при истинности которого происходит вывод логов работы
+ программы.
+* `-h` или `--help` - флаг, при истинности которого вместо выполнения программы
+ происходит вывод справки и завершение работы.
+
+### Использование
+
+Навигация в программе происходит с помощью нажатий клавиш.
+
+#### Список управляющих клавиш
+
+* `Esc` или `q` - выход из программы.
+* `F5` или `r` - обновление данных.
+* `+` - увеличение количества отображаемых дней на единицу, но не более 15.
+* `-` - уменьшение количества отображаемых дней на единицу, но не менее 3.
+ При этом в том случае, если фокус направлен на последни день, происходит
+ смещение фокуса вверх.
+* `w` или `ArrowUp` - смещение фокуса отображения вверх (меньшая дата) на единицу.
+* `s` или `ArrowDown` - смещение фокуса отображения вверх (меньшая дата) на единицу.
+* `n`, `d` или `ArrowRight` - переход к следующей локации из списка.
+ При достижении конца списка следующим считается первый элемент.
+* `p`, `a` или `ArrowLeft` - переход к предыдущей локации из списка.
+ При достижении начала списка предыдущим считается последний элемент.
diff --git a/TASK.md b/TASK.md
new file mode 100644
index 0000000..aea0dd0
--- /dev/null
+++ b/TASK.md
@@ -0,0 +1,43 @@
+# Лабораторная работа 7
+
+Прогноз погоды. Внешние библиотеки.
+
+## Задача
+
+Реализовать консольное приложение, отображающие прогноз погоды для выбранного списка городов, используя сторонние библиотеки.
+
+## Источник данных
+
+- [Open-Meteo](https://open-meteo.com/en/docs#latitude=59.94&longitude=30.31&hourly=temperature_2m&forecast_days=16) для прогноза
+- [Api-Ninjas](https://api-ninjas.com/api/city) для определения координат по названию города
+
+## Функциональные требования
+
+- Отображать прогноз погоды на несколько дней вперед (значение по умолчанию задается конфигом)
+- Обновлять с некоторой частотой (задается конфигом)
+- Переключаться между городами с помощью клавиш "n", "p"
+- Заканчивать работу программы по Esc
+- Увеличивать\уменьшать количество дней прогноза по нажатие клавиш "+", "-"
+
+Список городов, частота обновления, количество дней прогноза должны быть определены в конфиге(например в формате ini, json, xml)
+
+## Отображение
+
+В качестве образца для визуализации предлагается взять следующий:
+
+![image](assets/interface.png) Скриншот взят с https://wttr.in
+
+## Реализация
+
+В данной лабораторной работе вам не запрещено использовать другие библиотеки.
+
+В качестве библиотеки для [HTTP-запросов](https://en.wikipedia.org/wiki/HTTP) требуется воспользоваться [C++ Requests](https://github.com/libcpr/cpr)
+
+
+В данной работе, при взаимодействии с внешними сервисами, может возникать достаточно большое количество коллизий и краевых случаев. Внимательно, подумайте об этом! Ваша программа должна корректно работать и "не падать"
+
+## Deadline
+
+1. 20.02.24 0.85
+2. 27.02.24 0.65
+3. 05.03.24 0.5
diff --git a/docs/README.md b/docs/README.md
index f4190a3..f581a4e 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -8,8 +8,4 @@
* [Проблема](dev/problem.md)
* [Требования](dev/requirements.md)
* [Архитектура](dev/architecture.md)
-
-## Итоговая документация
-
-* [Модуль ArgParser](../lib/argparser/docs/README.md)
-* [Мануал weather-forecast](WeatherForecast.md)
+* [Модуль ArgParser, v1.1.0](https://github.com/bialger/ArgParser/blob/v1.1.0/lib/argparser/docs/README.md)
diff --git a/docs/WeatherForecast.md b/docs/WeatherForecast.md
deleted file mode 100644
index 827a0d6..0000000
--- a/docs/WeatherForecast.md
+++ /dev/null
@@ -1,212 +0,0 @@
-# Документация программы weather-forecast
-
-Этот документ описывает сборку из исходного кода и использование программы
-weather-forecast.
-
-## Зависимости
-
-Для успешной компиляции требует установленного `Git`, `CMake` и компилятора C++,
-поддерживающего стандарт C++20.
-Также потребуется ключ от [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/).
-
-> Если Вам не хочется получать ключ, можно воспользоваться архивом кэша:
-> [cache.zip](https://github.com/bialger/weather-forecast/releases/download/v1.2.0/cache.zip).
-> После распаковки поместите в каталог `./.config`, а затем начните установку.
-> Используйте вместо API-ключа `00000000-0000-0000-0000-000000000000`.
-
-## Как собрать
-
-> **Важно!**
-> Для ОС Windows успешная сборка и компиляция возможна **только** при
-> установленном компиляторе `MinGW`.
-
-В данном документе описана исключительно процедура сборки главного исполняемого
-файла.
-> Процесс сборки тестов описан не будет, его можно восстановить из
-[CI/CD скрипта](../.github/workflows/ci_tests.yml).
-
-### Автоматическая сборка и установка
-
-Сделайте исполняемым и запустите [shell-script установки](../install.sh), затем следуйте
-инструкциям.
-> **Важно!**
-> Для ОС Windows автоматизированная сборка гарантирована только
-> при запуске в Git Bash.
-
-```shell
-chmod +x ./install.sh && ./install.sh
-```
-
-### Ручная сборка
-
-* Сначала, если Вы этого не сделали, клонируйте проект и перейдите в его каталог:
-
-```shell
-git clone https://github.com/bialger/weather-forecast.git && cd weather-forecast
-```
-
-#### Linux и MacOs
-
-* Создайте Release-кеш CMake:
-
-```shell
-cmake -S . -B ~/CMakeBuilds/weather-forecast -DCMAKE_BUILD_TYPE=Release
-```
-
-* Соберите проект из этого кеша:
-
-```shell
-cmake --build ~/CMakeBuilds/weather-forecast --target weather-forecast
-```
-
-* Введите ключ от [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/) и
- запишите его в соответсвующий файл:
-
-```shell
-read -r API_KEY && echo "$API_KEY" > "./.config/yandex_api_key.apikey"
-```
-
-* Скопируйте в конфигурационный каталог файлы конфигурации:
-
-```shell
-cp -r ./.config ~/.config/weather-forecast
-```
-
-* Создайте символьную ссылку на исполняемый файл (`~/weather-forecast.run`):
-
-```shell
-ln -s ~/CMakeBuilds/weather-forecast/bin/weather-forecast ~/weather-forecast.run
-```
-
-* Запустите программу:
-
-```shell
-~/weather-forecast.run
-```
-
-#### Windows (`cmd.exe`)
-
-* Создайте Release-кеш CMake:
-
-```shell
-cmake -S . -B "%userprofile%\CMakeBuilds\weather-forecast" -DCMAKE_BUILD_TYPE=Release
-```
-
-* Соберите проект из этого кеша:
-
-```shell
-cmake --build "%userprofile%\CMakeBuilds\weather-forecast" --target weather-forecast
-```
-
-* Введите ключ от [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/) и
- запишите его в соответсвующий файл:
-
-```shell
-SET /P API_KEY="Enter your Yandex Geocoder API key: " && echo %API_KEY% > ".config\yandex_api_key.apikey"
-```
-
-* Скопируйте в конфигурационный каталог файлы конфигурации:
-
-```shell
-xcopy /si .config "%userprofile%\.config\weather-forecast"
-```
-
-* Скопируйте исполняемый файл и библиотеки в каталог `%userprofile%\weather-forecast` для быстрого доступа
-
-```shell
-mkdir "%userprofile%\weather-forecast"
-copy "%userprofile%\CMakeBuilds\weather-forecast\weather-forecast.exe" "%userprofile%\weather-forecast\weather-forecast.exe"
-copy "%userprofile%\CMakeBuilds\weather-forecast\libcpr.dll" "%userprofile%\weather-forecast\libcpr.dll"
-copy "%userprofile%\CMakeBuilds\weather-forecast\libcurl.dll" "%userprofile%\weather-forecast\libcurl.dll"
-```
-
-* Создайте символьную ссылку на исполняемый файл (`%userprofile%\weather-forecast\weather-forecast.exe`):
-
-```shell
-mklink "%userprofile%\weather-forecast.exe" "%userprofile%\weather-forecast\weather-forecast.exe"
-```
-
-> Для Windows запуск такой ссылки из командной строки или иного эмулятора терминала
-> полноценно невозможен, только из Проводника.
-
-* Запустите программу:
-
-```shell
-cd %userprofile%\weather-forecast && .\weather-forecast.exe
-```
-
-## Использование
-
-Программа weather-forecast - консольное приложение для просмотра погоды.
-Предусмотрен показ погоды для локаций, перечисленных в конфигурационном файле, на
-текущий момент, а также на утро, день, вечер и ночь некоторого количества дней.
-Программа в один момент времени отображает непосредственно прогноз на три дня, для
-просмотра прочих следует использовать навигации. В случае отсутствия
-Интернет-соединения программа запустится, однако не будет отображать актуальную
-информацию. Для получения актуальных данных возобновите подключение и обновите
-данные в программе.
-
-> Поскольку программа использует
-[Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/), для работы
-> требуется валидный API-ключ.
-> Бесплатная версия поддерживает 1000 запросов в сутки.
-
-### Пример интерфейса
-
-![image](../assets/weather_forecast_1.png)
-
-### Вызов
-
-Программа может быть вызвана без аргументов - будут применены значения по умолчанию.
-Порядок аргументов не имеет значения.
-
-#### Аргументы командной строки:
-
-* `-l` или `--location` - строка с названием первой локации, для которой будет
- предоставлен прогноз погоды. Если аргумент не указан, первая локация получается
- из конфигурационного файла.
-* `-c` или `--config` - строка с именем файла конфигурации в формате JSON.
- Значения по умолчанию получают из
- [файла конфигурации по умолчанию](../.config/default_config.json).
- Документ должен содержать строковое поле `api_key_file` с относительным путем к
- файлу, содержащему ключ к
- [Yandex Geocoder API](https://yandex.ru/dev/geocode/doc/ru/); поле `locations`,
- содержащее список локаций (строк, содержащие адрес или название города на
- английском языке) для показа погоды; поле `defaults`, содержащее следующие
- значения параметров по умолчанию:
- * `interval` - как аргумент `--interval`.
- * `days_count` - как аргумент `--days-count`
- * `location_index` - целое неотрицательное число, являющееся индексом локации
- по умолчанию из списка `locations`. Строго меньше количества локаций.
-* `-L` или `--log-file` - строка с именем файла для записи логов. Имя файла должно
- быть валидным, в частности, не являться именем каталога. Если параметр не указан,
- логи выводятся в стандартный поток вывода.
-* `-d` или `--days-count` - целое положительное число, определяющее количество дней
- прогноза, отображаемых при запуске программы. Не может превышать 15. Если аргумент
- не указан, частота обновления получается из конфигурационного файла.
-* `-i` или `--interval` - целое положительное число, определяющее частоту
- обновлений в часах. Не может превышать 48. Если аргумент не указан, частота
- обновления получается из конфигурационного файла.
-* `-v` или `--verbose` - флаг, при истинности которого происходит вывод логов работы
- программы.
-* `-h` или `--help` - флаг, при истинности которого вместо выполнения программы
- происходит вывод справки и завершение работы.
-
-### Использование
-
-Навигация в программе происходит с помощью нажатий клавиш.
-
-#### Список управляющих клавиш
-
-* `Esc` или `q` - выход из программы.
-* `F5` или `r` - обновление данных.
-* `+` - увеличение количества отображаемых дней на единицу, но не более 15.
-* `-` - уменьшение количества отображаемых дней на единицу, но не менее 3.
- При этом в том случае, если фокус направлен на последни день, происходит
- смещение фокуса вверх.
-* `w` или `ArrowUp` - смещение фокуса отображения вверх (меньшая дата) на единицу.
-* `s` или `ArrowDown` - смещение фокуса отображения вверх (меньшая дата) на единицу.
-* `n`, `d` или `ArrowRight` - переход к следующей локации из списка. При достижении
- конца списка следующим считается первый элемент.
-* `p`, `a` или `ArrowLeft` - переход к предыдущей локации из списка. При достижении
- начала списка следующим считается последний элемент.
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index 5953ce7..9a2c5a8 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -10,7 +10,7 @@
* Используется модуль UI для взаимодействия с пользовательским вводом любого рода и
вывода информации.
-* Используется модуль [ArgParser](../../lib/argparser/docs/README.md) - подсистема
+* Используется модуль [ArgParser](https://github.com/bialger/ArgParser/tree/v1.1.0) - подсистема
для обработки аргументов командной строки.
* Используется модуль Forecast для выполнения и обработки запросов прогноза.
* Используется библиотека [C++ Requests](https://github.com/libcpr/cpr) для выполнения HTTP-запросов.
@@ -26,13 +26,11 @@
title: Project system diagram
---
flowchart LR
- subgraph Independent systems
+ subgraph Third-party libraries
nodeArgParser([ArgParser])
- subgraph Third-party libraries
- nodeCPR([C++ Requests])
- nodeJSON([JSON])
- nodeFTXUI([FTXUI])
- end
+ nodeCPR([C++ Requests])
+ nodeJSON([JSON])
+ nodeFTXUI([FTXUI])
end
nodeForecast([Forecast])
nodeUI([UI])
@@ -325,165 +323,3 @@ Internet-запроса.
Этот класс является абстракцией для представления погоды за наименьший временной
промежуток: время суток. Должен иметь публичные поля для всех характеристик и метод,
универсально возвращающий их всех.
-
-### Архитектура подсистемы "ArgParser"
-
-Эта подсистема представляет собой набор классов и связей между ними, которые выполняют
-непосредственно парсинг аргументов командной строки, передаваемых в подсистему. Все
-классы находятся в пространстве имён ArgumentParser.
-
-#### UML-диаграмма
-
-```mermaid
----
-title: Diagram of the module ArgParser
----
-%%{
- init: {
- 'theme': 'base',
- 'classDiagram': { 'curve': 'linear' },
- }
-}%%
-classDiagram
- direction TB
- note for ArgParser "Has pseudonym functions for AddArgument and GetValue for each argument type"
- class ArgParser {
- -const char[] name_;
- -vector~ArgumentBuilder*~ argument_builders_;
- -vector~Argument*~ arguments_;
- -vector~string~ allowed_typenames_;
- -vector~string~ allowed_typenames_for_help_;
- -map~string, map~ string, size_t~~ arguments_by_type_;
- -map~char, string~ short_to_long_names_;
- -size_t help_index_;
- +Parse(vector~string~ args, ConditionalOutput error_output=()) bool
- +Parse(int argc, char[][] argv, ConditionalOutput error_output=()) bool
- +Help() bool
- +HelpDescription() string
- +AddHelp(char short_name, const char[] long_name, const char[] description="") ConcreteArgumentBuilder~bool~ &
- +AddHelp(const char[] long_name, const char[] description="") ConcreteArgumentBuilder~bool~ &
- +AddArgument~T~(char short_name, const char[] long_name, const char[] description="") ConcreteArgumentBuilder~T~ &
- +AddArgument~T~(const char[] long_name, const char[] description="") ConcreteArgumentBuilder~T~ &
- +GetValue~T~(const char[] long_name, size_t index=0) T
- -Parse_(vector~string~ args, ConditionalOutput error_output) bool
- -GetLongKeys(string current_argument) vector~string~
- -ParsePositionalArguments(vector~string~ argv, const vector~size_t~ & used_positions) void
- -HandleErrors(ConditionalOutput error_output) bool
- -RefreshArguments() void
- -AddArgument_~T~(char short_name, const char[] long_name, const char[] description) ConcreteArgumentBuilder~T~ &
- -GetValue_~T~(const char* long_name, size_t index) T
- }
- class Argument {
- <>
- +ValidateArgument(vector~string~ argv, size_t position)* vector~size_t~
- +CheckLimit()* bool
- +GetValueStatus()* ArgumentParsingStatus
- +GetType()* string
- +GetInfo()* ArgumentInformation
- +GetUsedValues()* size_t
- +ClearStored()* void
- #ObtainValue(vector~string~ argv, string& value_string, vector~size_t~ & used_values, size_t position)* size_t
- }
- class ArgumentBuilder {
- <>
- +GetInfo()* ArgumentInformation
- +GetDefaultValue()* string
- +build()* Argument*
- }
- class ConcreteArgument~T~ {
- -ArgumentInformation info_
- -ArgumentParsingStatus value_status_
- -size_t value_counter_
- -T value_
- -T default_value_
- -T* stored_value_
- -vector~T~* stored_values_
- +GetValue(size_t index) T
- +ValidateArgument(vector~string~ argv, size_t position) vector~size_t~
- +CheckLimit() bool
- +GetValueStatus() ArgumentParsingStatus
- +GetType() string
- +GetInfo() ArgumentInformation
- +GetUsedValues() size_t
- +ClearStored() void
- #ObtainValue(vector~string~ argv, string& value_string, vector~size_t~ & used_values, size_t position) size_t
- }
- class ConcreteArgumentBuilder~T~ {
- -ArgumentInformation info_;
- -T default_value_;
- -T* stored_value_;
- -vector~T~* stored_values_;
- -bool was_created_temp_vector_;
- +MultiValue(size_t min=0) ConcreteArgumentBuilder &
- +Positional() ConcreteArgumentBuilder&
- +StoreValue(T& value) ConcreteArgumentBuilder&
- +StoreValues(vector~T~ & values) ConcreteArgumentBuilder&
- +Default(T value) ConcreteArgumentBuilder&
- +AddValidate(function~bool(string&)~ validate) ConcreteArgumentBuilder&
- +AddIsGood(function~bool(string&)~ is_good) ConcreteArgumentBuilder&
- +GetInfo() ArgumentInformation
- +GetDefaultValue() string
- +build() Argument*`
- }
- class ArgumentInformation {
- +char short_key = kBadChar
- +const char[] long_key = ""
- +const char[] description = ""
- +string type
- +size_t minimum_values = 0
- +bool is_multi_value = false
- +bool is_positional = false
- +bool has_store_values = false
- +bool has_store_value = false
- +bool has_default = false
- +function~bool(string&)~ validate = &AlwaysTrue
- ++function~bool(string&)~ is_good = &AlwaysTrue
- }
- class ArgumentParsingStatus {
- <>
- NoArgument
- InvalidArgument
- InsufficientArguments
- Success
- }
-
- ArgParser *-- Argument
- ArgParser *-- ArgumentBuilder
- ArgParser <.. ConcreteArgument
- ArgParser <.. ConcreteArgumentBuilder
- Argument <|.. ConcreteArgument
- ArgumentBuilder <.. Argument
- ArgumentBuilder <|.. ConcreteArgumentBuilder
- ConcreteArgument *-- ArgumentInformation
- ConcreteArgument *-- ArgumentParsingStatus
- ConcreteArgumentBuilder <.. ConcreteArgument
- ConcreteArgumentBuilder *-- ArgumentInformation
-```
-
-#### Класс ArgParser
-
-Этот класс является основным классом модуля, именно с ним обычно взаимодействует
-пользователь. Он должен предоставлять следующие возможности: добавление обрабатываемого
-аргумента (любого из указанных) с указанным ключом, парсинг набора аргументов командной
-строки, а также функция добавления аргумента. Кроме того, должен иметь функцию
-составления справки и обрабатывать ошибки в синтаксисе аргументов командной строки,
-и, в некоторых случаях, выводить их.
-
-#### Класс ArgumentBuilder
-
-Этот класс реализует паттерн проектирования "Builder": ссылки на объекты наследников
-этого класса должна возвращать функция добавления аргумента из ArgParser, к нему
-должен обращаться пользователь, добавляя информацию об аргументе. Должен
-реализовывать функции добавления любой информации про аргумент, представленные в
-[тестах](../../tests/argparser_unit_tests.cpp) и функцию построения. Ему должен
-наследовать шаблонизированный класс конкретного Builder, который будет реализовывать
-вышеуказанный функционал для каждого из типов аргумента.
-
-#### Класс Argument
-
-Этот класс является родительским классом для всех классов аргументов. Должен иметь
-функции возврата статуса парсинга и возврата информации об аргументе, а также функцию
-получения значения аргумента из аргументов командной строки. Необходимая информация,
-не изменяемая в процессе парсинга, должна храниться в виде экземпляра структуры.
-На данный момент планируется аргументы всех базовых значащих типов (кроме 8-битных
-чисел), StringArgument и ComplexArgument (строка с валидацией и чтением пробелов).
diff --git a/lib/argparser/ArgParser.cpp b/lib/argparser/ArgParser.cpp
deleted file mode 100644
index e2a0c51..0000000
--- a/lib/argparser/ArgParser.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-#include
-
-#include "ArgParser.hpp"
-
-ArgumentParser::ArgParser::ArgParser(const char* name) {
- name_ = name;
- allowed_typenames_ =
- {typeid(std::string).name(), typeid(CompositeString).name(), typeid(int16_t).name(), typeid(int32_t).name(),
- typeid(int64_t).name(), typeid(uint16_t).name(), typeid(uint32_t).name(), typeid(uint64_t).name(),
- typeid(float).name(), typeid(double).name(), typeid(long double).name(), typeid(bool).name(),
- typeid(char).name()};
- allowed_typenames_for_help_ =
- {"string", "CompositeString", "short", "int", "long long", "unsigned short", "unsigned int", "unsigned long long",
- "float", "double", "long double", "bool", "char"};
- argument_builders_ = {};
- arguments_ = {};
- arguments_by_type_ = {};
- short_to_long_names_ = {};
-
- for (const std::string& type_name : allowed_typenames_) {
- arguments_by_type_[type_name] = {};
- }
-
- help_index_ = std::string::npos;
-}
-
-ArgumentParser::ArgParser::~ArgParser() {
- for (ArgumentBuilder*& argument_builder : argument_builders_) {
- delete argument_builder;
- }
-
- for (Argument*& argument : arguments_) {
- delete argument;
- }
-}
-
-bool ArgumentParser::ArgParser::Parse(const std::vector& args, ConditionalOutput error_output) {
- return Parse_(args, error_output);
-}
-
-bool ArgumentParser::ArgParser::Parse(int argc, char** argv, ConditionalOutput error_output) {
- std::vector args = std::vector(argv, argv + argc);
-
- return Parse_(args, error_output);
-}
-
-bool ArgumentParser::ArgParser::Help() {
- if (help_index_ == std::string::npos) {
- return false;
- }
-
- return GetValue(arguments_[help_index_]->GetInfo().long_key);
-}
-
-std::string ArgumentParser::ArgParser::HelpDescription() {
- if (help_index_ == std::string::npos) {
- return {};
- }
-
- std::string help = name_;
- help += "\n";
- help += argument_builders_[help_index_]->GetInfo().description;
- help += "\n\nOPTIONS:\n";
-
- for (size_t i = 0; i < allowed_typenames_.size(); ++i) {
- std::string type_name = allowed_typenames_[i];
- std::string output_type_name = allowed_typenames_for_help_[i];
-
- for (const auto& iterator : arguments_by_type_[type_name]) {
- if (iterator.second == help_index_) {
- continue;
- }
-
- ArgumentBuilder* argument = argument_builders_[iterator.second];
- ArgumentInformation current_info = argument->GetInfo();
- help += current_info.short_key == kBadChar ? " " : std::string("-") + current_info.short_key + ", ";
- help += std::string("--") + current_info.long_key;
-
- if (type_name != typeid(bool).name()) {
- help += "=<" + output_type_name + ">";
- }
-
- help += ": ";
- help += current_info.description;
-
- if (current_info.is_multi_value ||
- current_info.is_positional ||
- (current_info.has_default && type_name == typeid(bool).name() && argument->GetDefaultValue() != "0") ||
- (current_info.has_default && type_name != typeid(bool).name()) ||
- (current_info.minimum_values != 0 && current_info.is_multi_value)) {
- help += " [";
- if (current_info.is_multi_value) {
- help += "repeated, ";
- }
-
- if (current_info.is_positional) {
- help += "positional, ";
- }
-
- if (current_info.has_default) {
- help += "default = ";
-
- if (type_name == typeid(bool).name()) {
- help += (argument->GetDefaultValue() == "0") ? "false" : "true";
- } else {
- help += argument->GetDefaultValue();
- }
-
- help += ", ";
- }
-
- if (current_info.minimum_values != 0) {
- help += "min args = " + std::to_string(current_info.minimum_values) + ", ";
- }
-
- help = help.substr(0, help.size() - 2);
- help += "]";
- }
-
- help += "\n";
- }
- }
-
- help += "\n";
- ArgumentBuilder* argument = argument_builders_[help_index_];
- ArgumentInformation current_info = argument->GetInfo();
- help += current_info.short_key == kBadChar ? " " : std::string("-") + current_info.short_key + ", ";
- help += std::string("--") + current_info.long_key + ": " + "Display this help and exit";
- help += "\n";
-
- return help;
-}
-
-ArgumentParser::ConcreteArgumentBuilder& ArgumentParser::ArgParser::AddHelp(char short_name,
- const char* long_name,
- const char* description) {
- ConcreteArgumentBuilder* help_argument_ = &AddArgument(short_name, long_name, description);
- help_index_ = argument_builders_.size() - 1;
- return *help_argument_;
-}
-
-ArgumentParser::ConcreteArgumentBuilder& ArgumentParser::ArgParser::AddHelp(const char* long_name,
- const char* description) {
- return AddHelp(kBadChar, long_name, description);
-}
-
-bool ArgumentParser::ArgParser::Parse_(const std::vector& args, ConditionalOutput error_output) {
- RefreshArguments();
- std::vector used_positions = {0};
- std::vector argv = args;
-
- for (std::string& arg : argv) {
- if (arg[0] == '\'' || arg[0] == '"') {
- arg = arg.substr(1);
- }
-
- if (arg.back() == '\'' || arg.back() == '"') {
- arg = arg.substr(0, arg.size() - 1);
- }
- }
-
- argv.emplace_back("--");
-
- for (size_t position = 1; position < argv.size() && argv[position] != "--"; ++position) {
- if (argv[position][0] == '-') {
- if (argv[position].size() == 1) {
- return false;
- }
-
- std::vector long_keys = GetLongKeys(argv[position]);
-
- if (long_keys.empty()) {
- DisplayError("Used nonexistent argument: " + argv[position] + "\n", error_output);
- return false;
- }
-
- for (const std::string& long_key : long_keys) {
- bool was_found = false;
-
- for (const std::string& type_name : allowed_typenames_) {
- std::map* t_arguments = &arguments_by_type_.at(type_name);
-
- if (t_arguments->find(long_key) != t_arguments->end()) {
- was_found = true;
- std::vector current_used_positions =
- arguments_[t_arguments->at(long_key)]->ValidateArgument(argv, position);
- position = (current_used_positions.empty()) ? position : current_used_positions.back();
- used_positions.insert(std::end(used_positions), std::begin(current_used_positions),
- std::end(current_used_positions));
- }
-
- if (was_found) {
- break;
- }
- }
-
- if (!was_found) {
- DisplayError("Used nonexistent argument: " + argv[position] + "\n", error_output);
- return false;
- }
- }
- }
- }
-
- ParsePositionalArguments(argv, used_positions);
-
- return HandleErrors(error_output);
-}
-
-std::vector ArgumentParser::ArgParser::GetLongKeys(const std::string& current_argument) {
- std::vector long_keys = {current_argument.substr(2)};
-
- if (long_keys[0].find('=') != std::string::npos) {
- long_keys[0] = long_keys[0].substr(0, long_keys[0].find('='));
- }
-
- if (current_argument[1] != '-') {
- long_keys.clear();
-
- for (size_t current_key_index = 1;
- current_key_index < current_argument.size() &&
- short_to_long_names_.find(current_argument[current_key_index]) != short_to_long_names_.end();
- ++current_key_index) {
- long_keys.push_back(short_to_long_names_.at(current_argument[current_key_index]));
- }
- }
-
- return long_keys;
-}
-
-void ArgumentParser::ArgParser::ParsePositionalArguments(const std::vector& argv,
- const std::vector& used_positions) {
- std::vector positional_args = {};
- std::vector positional_indices = {};
-
- for (size_t i = 0; i < arguments_.size(); ++i) {
- if (arguments_[i]->GetInfo().is_positional) {
- positional_indices.push_back(i);
- }
- }
-
- for (size_t i = 0; i < argv.size(); ++i) {
- if (std::find(std::begin(used_positions), std::end(used_positions), i) ==
- std::end(used_positions)) {
- positional_args.push_back(argv[i]);
- }
- }
-
- for (size_t position = 0, argument_index = 0;
- position < positional_args.size() &&
- argument_index < positional_indices.size() &&
- positional_args[position] != "--";
- ++position, ++argument_index) {
- std::vector current_used_positions =
- arguments_[positional_indices[argument_index]]->ValidateArgument(positional_args, position);
- position = (current_used_positions.empty()) ? position : current_used_positions.back();
- }
-}
-
-void ArgumentParser::ArgParser::RefreshArguments() {
- for (Argument* argument : arguments_) {
- argument->ClearStored();
- delete argument;
- }
-
- arguments_.clear();
-
- for (ArgumentBuilder* argument_builder : argument_builders_) {
- arguments_.push_back(argument_builder->build());
- }
-}
-
-bool ArgumentParser::ArgParser::HandleErrors(ConditionalOutput error_output) {
- std::string error_string;
- bool is_correct = true;
-
- if (help_index_ != std::string::npos && Help()) {
- return true;
- }
-
- for (const auto& argument : arguments_) {
- if (!argument->CheckLimit()) {
- error_string += "Not enough values were passed to argument --";
- error_string += argument->GetInfo().long_key;
- error_string += ".\n";
- is_correct = false;
- }
-
- if (argument->GetValueStatus() == ArgumentParsingStatus::kInvalidArgument) {
- error_string += "An incorrect value was passed to the --";
- error_string += argument->GetInfo().long_key;
- error_string += " argument.\n";
- is_correct = false;
- }
- }
-
- DisplayError(error_string, error_output);
-
- return is_correct;
-}
diff --git a/lib/argparser/ArgParser.hpp b/lib/argparser/ArgParser.hpp
deleted file mode 100644
index b718e98..0000000
--- a/lib/argparser/ArgParser.hpp
+++ /dev/null
@@ -1,141 +0,0 @@
-#ifndef ARGPARSER_HPP_
-#define ARGPARSER_HPP_
-
-#define ALIAS_TEMPLATE_FUNCTION(highLevelF, lowLevelF) \
-template \
-inline auto highLevelF(Args&&... args) -> decltype(lowLevelF(std::forward(args)...)) \
-{ \
- return lowLevelF(std::forward(args)...); \
-}
-
-#include
-#include
-#include