From ed93d4f048d5822f48960f9f503ad3bbebcffa6a Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 12 Aug 2024 13:34:10 +0300 Subject: [PATCH 1/4] Massive update: now use ArgParser from GitHub --- CMakeLists.txt | 2 +- lib/argparser/ArgParser.cpp | 300 -------------- lib/argparser/ArgParser.hpp | 141 ------- lib/argparser/Argument.hpp | 67 --- lib/argparser/ArgumentBuilder.hpp | 18 - lib/argparser/CMakeLists.txt | 16 +- lib/argparser/ConcreteArgument.hpp | 155 ------- lib/argparser/ConcreteArgument.inl | 385 ------------------ lib/argparser/ConcreteArgumentBuilder.hpp | 114 ------ lib/argparser/basic/BasicFunctions.cpp | 109 ----- lib/argparser/basic/BasicFunctions.hpp | 58 --- lib/argparser/basic/CMakeLists.txt | 5 - lib/argparser/basic/ConditionalOutput.hpp | 21 - lib/ui/TextUserInterface.cpp | 2 +- lib/ui/TextUserInterface.hpp | 3 +- tests/ArgParserUnitTestSuite.hpp | 2 +- tests/WeatherForecastIntegrationTestSuite.cpp | 2 +- tests/argparser_unit_tests.cpp | 4 +- 18 files changed, 11 insertions(+), 1393 deletions(-) delete mode 100644 lib/argparser/ArgParser.cpp delete mode 100644 lib/argparser/ArgParser.hpp delete mode 100644 lib/argparser/Argument.hpp delete mode 100644 lib/argparser/ArgumentBuilder.hpp delete mode 100644 lib/argparser/ConcreteArgument.hpp delete mode 100644 lib/argparser/ConcreteArgument.inl delete mode 100644 lib/argparser/ConcreteArgumentBuilder.hpp delete mode 100644 lib/argparser/basic/BasicFunctions.cpp delete mode 100644 lib/argparser/basic/BasicFunctions.hpp delete mode 100644 lib/argparser/basic/CMakeLists.txt delete mode 100644 lib/argparser/basic/ConditionalOutput.hpp 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/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 - -#include "ConcreteArgumentBuilder.hpp" -#include "ConcreteArgument.hpp" -#include "lib/argparser/basic/BasicFunctions.hpp" - -namespace ArgumentParser { - -class ArgParser { - public: - explicit ArgParser(const char* name = ""); - ArgParser(const ArgParser& other) = delete; - ArgParser& operator=(const ArgParser& other) = delete; - ~ArgParser(); - - bool Parse(const std::vector& args, ConditionalOutput error_output = {}); - bool Parse(int argc, char** argv, ConditionalOutput error_output = {}); - - bool Help(); - std::string HelpDescription(); - - ConcreteArgumentBuilder& AddHelp(char short_name, const char* long_name, const char* description = ""); - ConcreteArgumentBuilder& AddHelp(const char* long_name, const char* description); - - template - ConcreteArgumentBuilder& AddArgument(char short_name, const char* long_name, const char* description = ""); - - template - ConcreteArgumentBuilder& AddArgument(const char* long_name, const char* description = ""); - - template - T GetValue(const char* long_name, size_t index = 0); - - ALIAS_TEMPLATE_FUNCTION(AddShortArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddIntArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddLongLongArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddUnsignedShortArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddUnsignedIntArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddUnsignedLongLongArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddFloatArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddDoubleArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddLongDoubleArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddFlag, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddCharArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddStringArgument, AddArgument); - ALIAS_TEMPLATE_FUNCTION(AddCompositeArgument, AddArgument); - - ALIAS_TEMPLATE_FUNCTION(GetShortValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetIntValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetLongLongValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetUnsignedShortValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetUnsignedIntValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetUnsignedLongLongValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetFloatValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetDoubleValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetLongDoubleValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetFlag, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetChar, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetStringValue, GetValue); - ALIAS_TEMPLATE_FUNCTION(GetCompositeValue, GetValue); - - private: - const char* name_; - std::vector argument_builders_; - std::vector arguments_; - std::vector allowed_typenames_; - std::vector allowed_typenames_for_help_; - std::map> arguments_by_type_; - std::map short_to_long_names_; - size_t help_index_; - - bool Parse_(const std::vector& args, ConditionalOutput error_output); - - std::vector GetLongKeys(const std::string& current_argument); - - void ParsePositionalArguments(const std::vector& argv, const std::vector& used_positions); - - bool HandleErrors(ConditionalOutput error_output); - - void RefreshArguments(); - - template - ConcreteArgumentBuilder& AddArgument_(char short_name, const char* long_name, const char* description); - - template - T GetValue_(const char* long_name, size_t index); -}; - -template -ConcreteArgumentBuilder& ArgParser::AddArgument(char short_name, const char* long_name, const char* description) { - return AddArgument_(short_name, long_name, description); -} - -template -ConcreteArgumentBuilder& ArgParser::AddArgument(const char* long_name, const char* description) { - return AddArgument_(kBadChar, long_name, description); -} - -template -T ArgParser::GetValue(const char* long_name, size_t index) { - return GetValue_(long_name, index); -} - -template -ConcreteArgumentBuilder& ArgParser::AddArgument_(char short_name, const char* long_name, const char* description) { - std::map* t_arguments = &arguments_by_type_.at(typeid(T).name()); - - if (short_name != kBadChar) { - short_to_long_names_[short_name] = long_name; - } - - (*t_arguments)[long_name] = argument_builders_.size(); - ConcreteArgumentBuilder* argument_builder = new ConcreteArgumentBuilder(short_name, long_name, description); - argument_builders_.push_back(argument_builder); - - return *argument_builder; -} - -template -T ArgParser::GetValue_(const char* long_name, size_t index) { - std::map* t_arguments = &arguments_by_type_.at(typeid(T).name()); - size_t argument_index = t_arguments->at(long_name); - ConcreteArgument* argument = static_cast*>(arguments_.at(argument_index)); - return argument->GetValue(index); -} - -} // namespace ArgumentParser - -#endif // ARGPARSER_HPP_ diff --git a/lib/argparser/Argument.hpp b/lib/argparser/Argument.hpp deleted file mode 100644 index bd28a8d..0000000 --- a/lib/argparser/Argument.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef ARGUMENT_H_ -#define ARGUMENT_H_ - -#include -#include -#include - -#include "lib/argparser/basic/BasicFunctions.hpp" - -class CompositeString : public std::string { - private: - using base = std::string; - public: - using base::base; - using base::operator=; - using base::operator+=; - using base::operator[]; -}; - -namespace ArgumentParser { - -constexpr char kBadChar = '\x15'; - -enum class ArgumentParsingStatus { - kNoArgument, - kInvalidArgument, - kInsufficientArguments, - kSuccess -}; - -/** \n This structure represents a single information. - * Contains all required parameters for all argument types. */ - -struct ArgumentInformation { - char short_key = kBadChar; - const char* long_key = ""; - const char* description = ""; - std::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; - std::function validate = [](std::string& value_string) -> bool { return true; }; - std::function is_good = [](std::string& value_string) -> bool { return true; }; -}; - -class Argument { - public: - virtual ~Argument() = default; - virtual std::vector ValidateArgument(const std::vector& argv, size_t position) = 0; - virtual bool CheckLimit() = 0; - [[nodiscard]] virtual ArgumentParsingStatus GetValueStatus() const = 0; - [[nodiscard]] virtual const std::string& GetType() const = 0; - [[nodiscard]] virtual const ArgumentInformation& GetInfo() const = 0; - [[nodiscard]] virtual size_t GetUsedValues() const = 0; - virtual void ClearStored() = 0; - - protected: - virtual size_t ObtainValue(const std::vector& argv, std::string& value_string, - std::vector& used_values, size_t position) = 0; -}; - -} // namespace ArgumentParser - -#endif //ARGUMENT_H_ diff --git a/lib/argparser/ArgumentBuilder.hpp b/lib/argparser/ArgumentBuilder.hpp deleted file mode 100644 index 8173944..0000000 --- a/lib/argparser/ArgumentBuilder.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ARGUMENTBUILDER_HPP_ -#define ARGUMENTBUILDER_HPP_ - -#include "Argument.hpp" - -namespace ArgumentParser { - -class ArgumentBuilder { - public: - virtual ~ArgumentBuilder() = default; - [[nodiscard]] virtual const ArgumentInformation& GetInfo() const = 0; - [[nodiscard]] virtual std::string GetDefaultValue() const = 0; - virtual Argument* build() = 0; -}; - -} // namespace ArgumentParser - -#endif //ARGUMENTBUILDER_HPP_ diff --git a/lib/argparser/CMakeLists.txt b/lib/argparser/CMakeLists.txt index 88668b8..a56b413 100644 --- a/lib/argparser/CMakeLists.txt +++ b/lib/argparser/CMakeLists.txt @@ -1,13 +1,3 @@ -add_library(argparser STATIC ArgParser.cpp - ArgParser.hpp - ArgumentBuilder.hpp - Argument.hpp - ConcreteArgumentBuilder.hpp - ConcreteArgument.hpp -) - -add_subdirectory(basic) - -target_link_libraries(argparser PRIVATE argparser_basic) - -target_include_directories(argparser PUBLIC ${PROJECT_SOURCE_DIR}) +include(FetchContent) +FetchContent_Declare(argparser GIT_REPOSITORY https://github.com/bialger/ArgParser GIT_TAG v1.1.0) +FetchContent_MakeAvailable(argparser) diff --git a/lib/argparser/ConcreteArgument.hpp b/lib/argparser/ConcreteArgument.hpp deleted file mode 100644 index 50685af..0000000 --- a/lib/argparser/ConcreteArgument.hpp +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef CONCRETEARGUMENT_HPP_ -#define CONCRETEARGUMENT_HPP_ - -#include - -#include "Argument.hpp" - -namespace ArgumentParser { - -template -class ConcreteArgument : public Argument { - public: - ConcreteArgument() = delete; - ConcreteArgument(const ArgumentInformation& info, T default_value, T* stored_value, std::vector* stored_values); - [[nodiscard]] T GetValue(size_t index) const; - std::vector ValidateArgument(const std::vector& argv, size_t position) override; - bool CheckLimit() override; - [[nodiscard]] ArgumentParsingStatus GetValueStatus() const override; - [[nodiscard]] const std::string& GetType() const override; - [[nodiscard]] const ArgumentInformation& GetInfo() const override; - [[nodiscard]] size_t GetUsedValues() const override; - void ClearStored() override; - protected: - inline size_t ObtainValue(const std::vector& argv, std::string& value_string, - std::vector& used_values, size_t position) override; - - private: - ArgumentInformation info_; - ArgumentParsingStatus value_status_; - size_t value_counter_; - T value_; - T default_value_; - T* stored_value_; - std::vector* stored_values_; -}; - -template -ConcreteArgument::ConcreteArgument(const ArgumentInformation& info, - T default_value, - T* stored_value, - std::vector* stored_values) { - info_ = info; - value_ = default_value; - value_counter_ = 0; - value_status_ = ArgumentParsingStatus::kNoArgument; - default_value_ = default_value; - stored_value_ = stored_value; - stored_values_ = stored_values; -} - -template -T ConcreteArgument::GetValue(size_t index) const { - if (!info_.has_store_values) { - return value_; - } - - return stored_values_->at(index); -} - -template -ArgumentParsingStatus ConcreteArgument::GetValueStatus() const { - return value_status_; -} - -template -const std::string& ConcreteArgument::GetType() const { - return info_.type; -} - -template -const ArgumentInformation& ConcreteArgument::GetInfo() const { - return info_; -} - -template -size_t ConcreteArgument::GetUsedValues() const { - return value_counter_; -} - -template -bool ConcreteArgument::CheckLimit() { - if (value_counter_ < info_.minimum_values) { - value_status_ = ArgumentParsingStatus::kInsufficientArguments; - return false; - } - - if (value_status_ == ArgumentParsingStatus::kInsufficientArguments) { - value_status_ = ArgumentParsingStatus::kSuccess; - } - - return true; -} - -template -void ConcreteArgument::ClearStored() { - stored_values_->clear(); - value_counter_ = 0; - - if (stored_value_ != nullptr) { - *stored_value_ = default_value_; - } -} - -template -std::vector ConcreteArgument::ValidateArgument(const std::vector& argv, - size_t position) { - std::vector used_positions; - if (stored_values_->empty()) { - value_status_ = ArgumentParsingStatus::kSuccess; - } - - while (used_positions.empty() || info_.is_multi_value) { - std::string value_string = argv[position]; - used_positions.push_back(position); - - if (argv[position][0] == '-') { - size_t equals_index = argv[position].find('='); - - if (equals_index != std::string::npos) { - value_string = argv[position].substr(equals_index + 1); - } else if (std::is_same::value) { - value_string = "true"; - } else { - ++position; - used_positions.push_back(position); - value_string = argv[position]; - } - } - - position = ObtainValue(argv, value_string, used_positions, position); - - ++position; - ++value_counter_; - - stored_values_->push_back(value_); - - if (position >= argv.size() || argv[position][0] == '-') { - break; - } - } - - CheckLimit(); - - if (info_.has_store_value) { - *stored_value_ = value_; - } - - return used_positions; -} - -#include "ConcreteArgument.inl" - -} - -#endif //CONCRETEARGUMENT_HPP_ diff --git a/lib/argparser/ConcreteArgument.inl b/lib/argparser/ConcreteArgument.inl deleted file mode 100644 index 89f165c..0000000 --- a/lib/argparser/ConcreteArgument.inl +++ /dev/null @@ -1,385 +0,0 @@ -#include "ConcreteArgument.hpp" - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - int64_t pre_value = std::strtoll(value_string.c_str(), &end, 0); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = static_cast(pre_value); - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - int64_t pre_value = std::strtoll(value_string.c_str(), &end, 0); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = static_cast(pre_value); - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - int64_t pre_value = std::strtoll(value_string.c_str(), &end, 0); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = pre_value; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - uint64_t pre_value = std::strtoull(value_string.c_str(), &end, 0); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = static_cast(pre_value); - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - uint64_t pre_value = std::strtoull(value_string.c_str(), &end, 0); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = static_cast(pre_value); - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - uint64_t pre_value = std::strtoull(value_string.c_str(), &end, 0); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = pre_value; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - float pre_value = std::strtof(value_string.c_str(), &end); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = pre_value; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - double pre_value = std::strtod(value_string.c_str(), &end); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = pre_value; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - int32_t save_errno = errno; - errno = 0; - char* end; - long double pre_value = std::strtold(value_string.c_str(), &end); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE) || !info_.is_good(value_string)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = pre_value; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - if (value_string == "0" || value_string == "false") { - value_ = false; - } else if (value_string == "1" || value_string == "true") { - value_ = true; - } else { - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - if (value_string[0] != '\\') { - if (value_string.size() == 1 && info_.is_good(value_string)) { - value_ = value_string[0]; - } else { - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } - - return position; - } - - switch (value_string[1]) { - case 'b': { - value_ = '\b'; - break; - } - case 'f': { - value_ = '\f'; - break; - } - case 'n': { - value_ = '\n'; - break; - } - case 'r': { - value_ = '\r'; - break; - } - case 't': { - value_ = '\t'; - break; - } - case '"': { - value_ = '\"'; - break; - } - case '\'': { - value_ = '\''; - break; - } - case '0': { - value_ = '\0'; - break; - } - case '\\': { - value_ = '\\'; - break; - } - case 'v': { - value_ = '\v'; - break; - } - case 'a': { - value_ = '\a'; - break; - } - case '?': { - value_ = '\?'; - break; - } - case 'x': { - value_string[0] = '0'; - int32_t save_errno = errno; - errno = 0; - char* end; - int64_t pre_value = std::strtoll(value_string.c_str(), &end, 16); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = static_cast(pre_value); - } - - break; - } - default: { - if (value_string[1] >= '0' && value_string[1] <= '9') { - value_string[0] = '0'; - int32_t save_errno = errno; - errno = 0; - char* end; - int64_t pre_value = std::strtoll(value_string.c_str(), &end, 8); - - if (end == value_string.c_str() || *end != '\0' || - ((pre_value <= std::numeric_limits::min() || pre_value >= std::numeric_limits::max()) && - errno == ERANGE)) { - errno = save_errno; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } else { - value_ = static_cast(pre_value); - } - } else { - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } - - break; - } - } - - if (!info_.is_good(value_string)) { - value_ = default_value_; - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - if (info_.is_good(value_string)) { - value_ = value_string; - } else { - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } - - return position; -} - -template<> -inline size_t ArgumentParser::ConcreteArgument::ObtainValue(const std::vector& argv, - std::string& value_string, - std::vector& used_values, - size_t position) { - if (!info_.validate(value_string)) { - value_status_ = ArgumentParsingStatus::kInvalidArgument; - return position; - } - - size_t current = position + (info_.is_good(value_string) ? 0 : 1); - - while (current < argv.size() && argv[current][0] != '-' && - value_status_ != ArgumentParsingStatus::kInvalidArgument && - value_string.size() < 256 && - !info_.is_good(value_string)) { - value_string += " "; - value_string += argv[current]; - - if (!info_.validate(value_string)) { - value_status_ = ArgumentParsingStatus::kInvalidArgument; - break; - } - - ++current; - } - - if (info_.validate(value_string) && info_.is_good(value_string)) { - value_ = value_string; - position = current; - size_t start_position = used_values.back(); - - for (size_t i = start_position; i <= current; ++i) { - used_values.push_back(i); - } - } else { - value_status_ = ArgumentParsingStatus::kInvalidArgument; - } - - return position; -} diff --git a/lib/argparser/ConcreteArgumentBuilder.hpp b/lib/argparser/ConcreteArgumentBuilder.hpp deleted file mode 100644 index 2393ace..0000000 --- a/lib/argparser/ConcreteArgumentBuilder.hpp +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef CONCRETEARGUMENTBUILDER_HPP_ -#define CONCRETEARGUMENTBUILDER_HPP_ - -#include - -#include "ArgumentBuilder.hpp" -#include "ConcreteArgument.hpp" - -namespace ArgumentParser { - -template -class ConcreteArgumentBuilder : public ArgumentBuilder { - public: - ConcreteArgumentBuilder() = delete; - - ConcreteArgumentBuilder(char short_name, const char* long_name, const char* description) { - info_ = ArgumentInformation(); - info_.short_key = short_name; - info_.long_key = long_name; - info_.description = description; - info_.type = typeid(T).name(); - default_value_ = T(); - stored_value_ = nullptr; - stored_values_ = nullptr; - was_created_temp_vector_ = false; - } - - ConcreteArgumentBuilder(const ConcreteArgumentBuilder& other) = delete; - - ConcreteArgumentBuilder& operator=(const ConcreteArgumentBuilder& other) = delete; - - ~ConcreteArgumentBuilder() override { - if (was_created_temp_vector_) { - delete stored_values_; - } - } - - ConcreteArgumentBuilder& MultiValue(size_t min = 0) { - info_.is_multi_value = true; - info_.minimum_values = min; - return *this; - } - - ConcreteArgumentBuilder& Positional() { - info_.is_positional = true; - return *this; - } - - ConcreteArgumentBuilder& StoreValue(T& value) { - info_.has_store_value = true; - stored_value_ = &value; - return *this; - } - - ConcreteArgumentBuilder& StoreValues(std::vector& values) { - info_.has_store_values = true; - stored_values_ = &values; - return *this; - } - - ConcreteArgumentBuilder& Default(T value) { - info_.has_default = true; - default_value_ = value; - return *this; - } - - ConcreteArgumentBuilder& AddValidate(const std::function& validate) { - info_.validate = validate; - return *this; - } - - ConcreteArgumentBuilder& AddIsGood(const std::function& is_good) { - info_.is_good = is_good; - return *this; - } - - Argument* build() override { - if (std::is_same::value && !info_.has_default) { - info_.has_default = true; - } - - if (info_.minimum_values == 0 && !info_.has_default && !info_.is_multi_value) { - info_.minimum_values = 1; - } - - if (!info_.has_store_values && !was_created_temp_vector_) { - stored_values_ = new std::vector; - was_created_temp_vector_ = true; - } - - return new ConcreteArgument(info_, default_value_, stored_value_, stored_values_); - } - - [[nodiscard]] const ArgumentInformation& GetInfo() const override { - return info_; - } - - [[nodiscard]] std::string GetDefaultValue() const override { - std::ostringstream stream; - stream << default_value_; - return stream.str(); - } - - private: - ArgumentInformation info_; - T default_value_; - T* stored_value_; - std::vector* stored_values_; - bool was_created_temp_vector_; -}; - -} // namespace ArgumentParser - -#endif //CONCRETEARGUMENTBUILDER_HPP_ diff --git a/lib/argparser/basic/BasicFunctions.cpp b/lib/argparser/basic/BasicFunctions.cpp deleted file mode 100644 index 82955f1..0000000 --- a/lib/argparser/basic/BasicFunctions.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include "BasicFunctions.hpp" - -void ArgumentParser::SetRedColor() { - /* Changes the color of the console output to red if not running - * on Windows. */ - - std::cout << (IsWindows() ? "" : "\x1B[31m"); - - /* Conditional block to set the console text color to red if the program is - * running on Windows, using the Windows API functions. */ - - if (IsWindows()) { - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - SetConsoleTextAttribute(hConsole, 12); - } -} - -void ArgumentParser::ResetColor() { - if (IsWindows()) { - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - SetConsoleTextAttribute(hConsole, 15); - } - - std::cout << (IsWindows() ? "" : "\x1B[0m"); -} - -void ArgumentParser::DisplayError(const std::string& message, ConditionalOutput error_output) { - if (!error_output.print_messages) { - return; - } - - bool is_console_output = &error_output.out_stream == &std::cout || &error_output.out_stream == &std::cerr; - - if (is_console_output) { - SetRedColor(); - } - - error_output.out_stream << message; - - if (is_console_output) { - ResetColor(); - } -} - -bool ArgumentParser::IsWindows() { - return -#if defined _WIN32 || defined _WIN64 || defined __CYGWIN__ - true -#else - false -#endif - ; -} - -bool ArgumentParser::IsValidFilename(std::string& pre_filename) { - if (pre_filename.size() > 7) { - if (pre_filename.substr(0, 7) == "file://") { - pre_filename = pre_filename.substr(7); - } - } - - if (IsWindows() && pre_filename.size() > 2) { - for (uint64_t position = 2; position < pre_filename.size(); ++position) { - char current = pre_filename[position]; - if (!(std::isalnum(current) || current == '\\' || current == '.' || - current == '-' || current == ' ' || current == '_')) { - return false; - } - } - } - - /* This Windows-specific check is important because different code pages can - * corrupt non-alphanumeric filenames, but UNIX-like systems (like MacOS or - * Linux) handle unicode correctly. */ - - for (uint64_t position = 0; position < pre_filename.size() - 1; ++position) { - char current = pre_filename[position]; - char next = pre_filename[position + 1]; - - if ((current == '\\' || current == '/') && next == current) { - return false; - } - } - - return true; -} - -bool ArgumentParser::IsRegularFile(std::string& filename) { - std::filesystem::path path(filename); - return std::filesystem::is_regular_file(path); -} - -bool ArgumentParser::IsDirectory(std::string& dirname) { - std::filesystem::path path(dirname); - return std::filesystem::is_directory(path); -} - -/* The code provides dummy function definitions for Windows console-related - * functions when the code is being compiled in a non-Windows environment. - * This ensures that the code can compile and run without errors in such - * environments. The dummy functions have minimal functionality and simply - * return their input parameters. */ - -#if not(defined _WIN32 || defined _WIN64 || defined __CYGWIN__) -int GetStdHandle(int a) { return a; } -int SetConsoleTextAttribute(int a, int b) { return a + b; } -#endif \ No newline at end of file diff --git a/lib/argparser/basic/BasicFunctions.hpp b/lib/argparser/basic/BasicFunctions.hpp deleted file mode 100644 index 805acc0..0000000 --- a/lib/argparser/basic/BasicFunctions.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef ARGPARSER_BASICFUNCTIONS_HPP_ -#define ARGPARSER_BASICFUNCTIONS_HPP_ - -#include -#include -#include - -#include "ConditionalOutput.hpp" - - -#if defined _WIN32 || defined _WIN64 || defined __CYGWIN__ -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#else -#define STD_OUTPUT_HANDLE 0 -#define HANDLE int -inline int GetStdHandle(int a); -inline int SetConsoleTextAttribute(int a, int b); -#endif - -namespace ArgumentParser { - -/**\n This function sets the console text color to red. */ - -void SetRedColor(); - -/**\n This function resets the console text color to white. */ - -void ResetColor(); - -/**\n This function prints a error message. */ - -void DisplayError(const std::string& message, ConditionalOutput error_output); - -/**\n This function checks if the code is running on Windows. */ - -bool IsWindows(); - -/**\n The code validates the validity of a filename based on rules specific to - * Windows. The filename should consist of alphanumeric characters, backslashes, - * periods, hyphens, and spaces. Additionally, the code checks for consecutive - * slashes in the filename, which is also considered invalid. */ - -bool IsValidFilename(std::string& pre_filename); - -/**\n This function is a wrapper for the std::filesystem::is_regular_file function. */ - -bool IsRegularFile(std::string& filename); - -/**\n This function is a wrapper for the std::filesystem::is_directory function. */ - -bool IsDirectory(std::string& dirname); - -} - -#endif //ARGPARSER_BASICFUNCTIONS_HPP_ diff --git a/lib/argparser/basic/CMakeLists.txt b/lib/argparser/basic/CMakeLists.txt deleted file mode 100644 index 26148ae..0000000 --- a/lib/argparser/basic/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_library(argparser_basic STATIC - BasicFunctions.cpp - BasicFunctions.hpp - ConditionalOutput.hpp -) diff --git a/lib/argparser/basic/ConditionalOutput.hpp b/lib/argparser/basic/ConditionalOutput.hpp deleted file mode 100644 index d18f3d3..0000000 --- a/lib/argparser/basic/ConditionalOutput.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ERROROUTPUT_HPP_ -#define ERROROUTPUT_HPP_ - -#include - -/**\n Structure for error output in ArgumentParser */ - -struct ConditionalOutput { - std::ostream& out_stream = std::cout; - bool print_messages = false; - - template - ConditionalOutput& operator<<(const T& t) { - if (print_messages) { - out_stream << t; - } - return *this; - } -}; - -#endif //ERROROUTPUT_HPP_ diff --git a/lib/ui/TextUserInterface.cpp b/lib/ui/TextUserInterface.cpp index 0cc271c..0ded59c 100644 --- a/lib/ui/TextUserInterface.cpp +++ b/lib/ui/TextUserInterface.cpp @@ -7,7 +7,7 @@ #include "ConfigParser.hpp" const std::string TextUserInterface::kProgramName = "weather-forecast"; -const std::string TextUserInterface::kVersion = "1.3.0 Ferdinando II de' Medici"; +const std::string TextUserInterface::kVersion = "1.3.5 Ferdinando II de' Medici"; const std::string TextUserInterface::kHelpText = "A program for displaying the weather forecast in the terminal.\nCurrent version is " + kVersion + "."; const CompositeString TextUserInterface::kDefaultConfigPath = "default_config.json"; const CompositeString TextUserInterface::kDefaultLogPath = "Print to standard output"; diff --git a/lib/ui/TextUserInterface.hpp b/lib/ui/TextUserInterface.hpp index 145b562..ed37376 100644 --- a/lib/ui/TextUserInterface.hpp +++ b/lib/ui/TextUserInterface.hpp @@ -6,10 +6,11 @@ #include #include +#include + #include "ConfigParser.hpp" #include "lib/utils/utils.hpp" -#include "lib/argparser/ArgParser.hpp" #include "lib/forecast/Forecaster.hpp" class TextUserInterface { diff --git a/tests/ArgParserUnitTestSuite.hpp b/tests/ArgParserUnitTestSuite.hpp index 26eb9ab..7dc2586 100644 --- a/tests/ArgParserUnitTestSuite.hpp +++ b/tests/ArgParserUnitTestSuite.hpp @@ -5,7 +5,7 @@ #include #include -#include "lib/argparser/basic/BasicFunctions.hpp" +#include struct ArgParserUnitTestSuite : public testing::Test { // special test structure const std::string kTemporaryDirectoryName = (ArgumentParser::IsWindows() ? "" : "./") + std::string("gtest_argparser_tmp"); diff --git a/tests/WeatherForecastIntegrationTestSuite.cpp b/tests/WeatherForecastIntegrationTestSuite.cpp index 1956769..fb171f7 100644 --- a/tests/WeatherForecastIntegrationTestSuite.cpp +++ b/tests/WeatherForecastIntegrationTestSuite.cpp @@ -2,7 +2,7 @@ const std::string WeatherForecastIntegrationTestSuite::kExpectedHelp = "weather-forecast\n" "A program for displaying the weather forecast in the terminal.\n" - "Current version is 1.3.0 Ferdinando II de' Medici.\n" + "Current version is 1.3.5 Ferdinando II de' Medici.\n" "\n" "OPTIONS:\n" "-l, --location=: Name of the location for which the forecast is requested [default = First location in config]\n" diff --git a/tests/argparser_unit_tests.cpp b/tests/argparser_unit_tests.cpp index 7e7857d..ce42b08 100644 --- a/tests/argparser_unit_tests.cpp +++ b/tests/argparser_unit_tests.cpp @@ -1,9 +1,9 @@ #include -#include "lib/argparser/ArgParser.hpp" +#include +#include #include "test_functions.hpp" #include "ArgParserUnitTestSuite.hpp" -#include using namespace ArgumentParser; From 0c1923c290cde87e0cba12a93cb4f53814ec739c Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 12 Aug 2024 22:15:11 +0300 Subject: [PATCH 2/4] Reworked documentation - deleted argparser docs, added GitHub links --- docs/README.md | 2 +- docs/dev/architecture.md | 174 +--------------- lib/argparser/docs/ArgParser.md | 136 ------------ lib/argparser/docs/ConcreteArgumentBuilder.md | 193 ------------------ lib/argparser/docs/README.md | 15 -- lib/argparser/docs/dev/architecture.md | 185 ----------------- lib/argparser/docs/dev/problem.md | 5 - lib/argparser/docs/dev/requirements.md | 65 ------ 8 files changed, 6 insertions(+), 769 deletions(-) delete mode 100644 lib/argparser/docs/ArgParser.md delete mode 100644 lib/argparser/docs/ConcreteArgumentBuilder.md delete mode 100644 lib/argparser/docs/README.md delete mode 100644 lib/argparser/docs/dev/architecture.md delete mode 100644 lib/argparser/docs/dev/problem.md delete mode 100644 lib/argparser/docs/dev/requirements.md diff --git a/docs/README.md b/docs/README.md index f4190a3..eced614 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,5 +11,5 @@ ## Итоговая документация -* [Модуль ArgParser](../lib/argparser/docs/README.md) +* [Модуль ArgParser, v1.1.0](https://github.com/bialger/ArgParser/blob/v1.1.0/lib/argparser/docs/README.md) * [Мануал weather-forecast](WeatherForecast.md) 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/docs/ArgParser.md b/lib/argparser/docs/ArgParser.md deleted file mode 100644 index e274de5..0000000 --- a/lib/argparser/docs/ArgParser.md +++ /dev/null @@ -1,136 +0,0 @@ -# Документация класса ArgParser - -Этот класс является основным классом модуля, именно с ним обычно взаимодействует -пользователь. Он предоставляет следующие возможности: добавление обрабатываемого -аргумента (любого из указанных) с указанным ключом, парсинг набора аргументов командной -строки, а также добавление аргумента указанного типа. Кроме того, он имеет функцию -составления справки и обработки ошибки в синтаксисе аргументов командной строки, а -также их вывода. Находится в пространстве имён `ArgumentParser`. - -## Объявление и определение - -Объявлен в [ArgParser.hpp](../ArgParser.hpp).
-Определен там же (шаблонные функции) и в [ArgParser.cpp](../ArgParser.cpp) - -## Зависимости - -Зависит от [BasicFunctions.hpp](../basic/BasicFunctions.hpp), -[ConcreteArgument.hpp](../ConcreteArgument.hpp), -[ConcreteArgumentBuilder.hpp](../ConcreteArgumentBuilder.hpp). - -## Связанные документы - -* Документация класса [ConcreteArgumentBuilder](ConcreteArgumentBuilder.md) - -информация о задании параметров аргументов. - -## Публичные поля - -Класс не имеет публичных полей. - -## Публичные методы - -### ArgParser - -Принимает имя программы, явный. Ожидается, вызов пользователем именно его. -```cpp -explicit ArgParser(const char* name = ""); -``` -Удален конструктор копирования (как и оператор присваивания) -```cpp -ArgParser(const ArgParser& other) = delete; -ArgParser& operator=(const ArgParser& other) = delete; -``` - -### Parse -Функция парсинга. Вызывает приватный метод Parse_, который выполняет парсинг -аргументов командной строки, переданных в виде `std::vector` из `std::string` -(параметр *args*). Принимает `ConditionalOutput` параметр error_output, по умолчанию -не выводящий ошибки. Возвращает `true` при успешном завершении парсинга, -и `false` в случае его провала. - -Синтаксис аргументов частично POSIX-совместимый (поддерживается передача значений -через "=" или пробел после ключа, коротки и длинные ключи, комбинация коротких -ключей, остановка парсинга по аргументу "--", получение множества значений в аргумент). -```cpp -bool Parse(const std::vector& args, ConditionalOutput error_output = {std::cout, false}); -``` -Перегрузка Parse с тем же функционалом, но принимающая *C-style array* из -*C-style string* длиной *argc* вместо `std::vector` из `std::string`. -```cpp -bool Parse(int argc, char** argv, ConditionalOutput error_output = {std::cout, false}); -``` - -### Help -Функция, проверяющая необходимость вывода помощи. Возвращает `true` при получении -положительного значения HelpArgument, и `false` в случае его отсутствия или -негативного значения после парсинга. -```cpp -bool Help(); -``` - -### HelpDescription -Функция, возвращающая `std::string`, содержащую помощь для пользователя. -```cpp -std::string HelpDescription(); -``` -Пример вывода возвращаемого значения: - -```text -My Parser -Some Description about program - -OPTIONS: --i, --input=: File path for input file [repeated, min args = 1] - --number=: Some Number --s, --flag1: Use some logic [default = true] --p, --flag2: Use some logic - --h, --help: Display this help and exit -``` - -### GetValue -Шаблонная функция, возвращающая значение типа `T` аргумента с длинным ключом -*long_name*, полученное на *index* позиции (с нуля, по умолчанию - `0`). В случае -вызова функции с типом, не принадлежащему к поддерживаемым, при не добавленном -значении *long_name* или индекса, большего, чем количество полученных значений, -выбрасывается исключение `std::out_of_range`. В случае вызова до применения функции -парсинга, выбрасывается исключение `std::runtime_error`. -```cpp -template -T GetValue(const char* long_name, size_t index = 0); -``` - -### AddArgument -Шаблонная функция, возвращающая ссылку на экземпляр класса -[ConcreteArgumentBuilder](ConcreteArgumentBuilder.md), который будет строить -аргумент с переданными параметрами. Принимает `char` значение короткого ключа, -*constant C-style string* значение длинного ключа и, опционально, *constant C-style -string* описание ключа (по умолчанию - пустая строка). -```cpp -template -ConcreteArgumentBuilder& AddArgument(char short_name, const char* long_name, const char* description = ""); -``` -Эта перегрузка не принимает никакого значения короткого ключа. -```cpp -template -ConcreteArgumentBuilder& AddArgument(const char* long_name, const char* description = ""); -``` - -### AddFlag, AddShortArgument, ... AddStringArgument, AddCompositeArgument -Функции-псевдонимы для соответственно `AddArgument`, `AddArgument`, ... -`AddArgument` и `AddArgument` - -### AddHelp -Функция, вызывающая соответственную перегрузку `AddArgument`, возвращающая -результат и запоминающая аргумент помощи. -```cpp -ConcreteArgumentBuilder& AddHelp(char short_name, const char* long_name, const char* description = ""); -``` -Эта перегрузка не принимает никакого значения короткого ключа. -```cpp -ConcreteArgumentBuilder& AddHelp(const char* long_name, const char* description); -``` - -### GetFlag, GetShortValue, ... GetStringValue, GetCompositeValue -Функции-псевдонимы для соответственно `GetValue`, `GetValue`, -`GetValue` и `GetValue` diff --git a/lib/argparser/docs/ConcreteArgumentBuilder.md b/lib/argparser/docs/ConcreteArgumentBuilder.md deleted file mode 100644 index 6197927..0000000 --- a/lib/argparser/docs/ConcreteArgumentBuilder.md +++ /dev/null @@ -1,193 +0,0 @@ -# Документация класса ConcreteArgumentBuilder - -Этот шаблонный класс реализует паттерн проектирования "Builder": ссылки на объекты этого -класса должна возвращать функция добавления аргумента из `ArgParser`, к нему должен -обращаться пользователь, добавляя информацию об аргументе. Реализует функции добавления -любой информации про аргумент и функцию построения. Наследует абстрактному классу -`ArgumentBuilder`. Параметр шаблона - имя типа `T`. Находится в пространстве имён -`ArgumentParser`. - -## Объявление и определение - -Объявлен в [ConcreteArgumentBuilder.hpp](../ConcreteArgumentBuilder.hpp).
-Определен там же. - -## Зависимости - -Зависит от [ConcreteArgument.hpp](../ConcreteArgument.hpp) и -[ArgumentBuilder.hpp](../ArgumentBuilder.hpp). - -## Связанные документы - -* Документация класса [ConcreteArgumentBuilder](ConcreteArgumentBuilder.md) - - информация о задании параметров аргументов. - -## Публичные поля - -Класс не имеет публичных полей. - -## Публичные методы - -### ConcreteArgumentBuilder - -Принимает короткий ключ в виде `char`, длинный ключ в виде *constant C-style string*, -описание аргумента в виде *constant C-style string*. Не предназначен для прямого вызова -пользователем, поскольку имеет смысл только во внутренней логике класса `ArgParser`. -```cpp -ConcreteArgumentBuilder(char short_name, const char* long_name, const char* description); -``` -Конструктор без параметров и конструктор копирования, а также оператор присваивания с -копированием удалены. -```cpp -ConcreteArgumentBuilder() = delete; -ConcreteArgumentBuilder(const ConcreteArgumentBuilder& other) = delete; -ConcreteArgumentBuilder& operator=(const ConcreteArgumentBuilder& other) = delete; -``` - -### MultiValue - -Метод, отвечающий за придание аргументу свойства принятия множества значений. Принимает -минимальное обязательно число значений (по умолчанию ноль). Возвращает ссылку на этот -аргумент. -```cpp -ConcreteArgumentBuilder& MultiValue(size_t min = 0); -``` - -### Positional - -Метод, отвечающий за придание аргументу свойства позиционности - считывания значения -аргумента без ключа. Возвращает ссылку на этот аргумент. -```cpp -ConcreteArgumentBuilder& Positional(); -``` - -### StoreValue - -Метод, отвечающий за придание аргументу свойства хранения значения во внешней -переменной. Принимает ссылку на переменную, где должно храниться значение. -Возвращает ссылку на этот аргумент. -```cpp -ConcreteArgumentBuilder& StoreValue(T& value); -``` - -### StoreValues - -Метод, отвечающий за придание аргументу свойства хранения значений во внешнем -`std::vector`. Принимает ссылку на `std::vector`, где должны храниться значения. -Возвращает ссылку на этот аргумент. -```cpp -ConcreteArgumentBuilder& StoreValues(std::vector& values); -``` - -### Default - -Метод, отвечающий за придание аргументу значения по умолчанию. Принимает значение по -умолчанию. Возвращает ссылку на этот аргумент. -```cpp -ConcreteArgumentBuilder& Default(T value); -``` - -### AddValidate - -Метод, отвечающий за определение функции валидации для аргумента. Принимает -`std::function` валидации, которая должна принимать единственный аргумент: ссылку на -`std::string`, и возвращать `bool`. Под валидацией подразумевается проверка на общую -корректность потенциального значения. Функция валидации по умолчанию всегда принимает -истинное значение. Возвращает ссылку на этот аргумент. -```cpp -ConcreteArgumentBuilder& AddValidate(const std::function& validate); -``` - -### AddIsGood - -Метод, отвечающий за определение функции валидации для аргумента. Принимает -`std::function` проверки, которая должна принимать единственный аргумент: ссылку на -`std::string`, и возвращать `bool`. Под проверкой подразумевается проверка на полную -корректность потенциального значения. Функция проверки по умолчанию всегда принимает -истинное значение. Возвращает ссылку на этот аргумент. -```cpp -ConcreteArgumentBuilder& AddIsGood(const std::function& is_good); -``` - -### build - -Метод, отвечающий за создание аргумента по переданным параметрам. Не принимает никаких -аргументов. Возвращает указатель на интерфейс аргумента. Если значения по умолчанию -нет, а также аргумент не является MultiValue, то считается, что он обязательный. Если -аргумент логического типа (`Flag`), то считается, что его значение по умолчанию - -`false`, если пользователь не указал иного. Не предназначен для прямого вызова -пользователем, поскольку имеет смысл только во внутренней логике класса`ArgParser`. -```cpp -Argument* build() override; -``` - -### GetInfo - -Метод, предоставляющий информацию об аргументе в виде структуры `ArgumentInformation`, -хранящая типонезависимую информацию об аргументе. Ничего не принимает. Возвращает -неизменяемую ссылку на объект `ArgumentInformation`. Не модифицирует объект. Не должен -вызываться без использования значения. -```cpp -[[nodiscard]] const ArgumentInformation& GetInfo() const override; -``` - -### GetDefaultValue() - -Метод, предоставляющий информацию о значении аргумента по умолчанию в виде строки. -Ничего не принимает. Возвращает `std::string` со строковым представлением значения -по умолчанию. Не модифицирует объект. Не должен вызываться без использования значения. -```cpp -[[nodiscard]] std::string GetDefaultValue() const override; -``` - -## Приложение 1. Поддерживаемые типы аргументов, логика их парсинга - -### Целочисленные типы -* `Short` - `int16_t`: 16-битное знаковое число. Получается из целочисленного - литерала, подходящего под ограничения 16-битного знакового числа и являющегося - _подходящим_ (таким, что функция проверки принимает истинное значение). -* `Int` - `int32_t`: 32-битное знаковое число. Получается из целочисленного - литерала, подходящего под ограничения 32-битного знакового числа и являющегося - _подходящим_. -* `LongLong` - `int64_t`: 64-битное знаковое число. Получается из целочисленного - литерала, подходящего под ограничения 64-битного знакового числа и являющегося - _подходящим_. -* `UnsignedShort` - `uint16_t`: 16-битное беззнаковое число. Получается из - целочисленного литерала, подходящего под ограничения 16-битного беззнакового числа и - являющегося _подходящим_. -* `UnsignedInt` - `uint32_t`: 32-битное беззнаковое число. Получается из - целочисленного литерала, подходящего под ограничения 32-битного беззнакового числа и - являющегося _подходящим_. -* `UnsignedLongLong` - `uint64_t`: 64-битное беззнаковое число. Получается из - целочисленного литерала, подходящего под ограничения 64-битного беззнакового числа и - являющегося _подходящим_. - -### Дробные типы -* `Float` - `float`: 32-битное число с плавающей точкой. Получается из - дробного литерала, подходящего под ограничения 32-битного числа с плавающей точкой и - являющегося _подходящим_. -* `Double` - `double`: 64-битное число с плавающей точкой. Получается из - дробного литерала, подходящего под ограничения 64-битного числа с плавающей точкой и - являющегося _подходящим_. -* `LongDouble` - `long double`: 80-битное число с плавающей точкой. Получается из - дробного литерала, подходящего под ограничения 80-битного числа с плавающей точкой и - являющегося _подходящим_. - -### Элементарные типы -* `Flag` - `bool`: логическая переменная. Значение по умолчанию всегда `false`, при - наличии среди аргументов командной строки флага считается `true`. Также возможно - явное указание значения по аналогии с прочими аргументами: *false* и *0* считываются - как `false`, *true* и *1* считываются как `true`. -* `Char` - `char`: символ. Получается из _подходящего_ символьного литерала - escape - sequence или одного символа, также возможно задание в виде `\xXX`, при этом `0xXX` - - код символа в шестнадцатеричной системе счисления, а также в виде `\XXX`, при этом - `0XXX` - код символа в восьмеричной системе счисления. - -### Строковые типы -* `String` - `std::string`: строка. Получается из строкового литерала без пробелов, - являющегося _подходящим_. -* `CompositeString` - `CompositeString`: удовлетворяющая требованию строка, - возможно, содержащая пробелы. Получается из одного или нескольких идущих подряд - (разделённых пробелами) строковых литералов, прошедших _валидацию_ и обладающих - следующим свойством: вся строка является _подходящей_, но если убрать из нее любое - ненулевое количество литералов, то она перестанет быть таковой. diff --git a/lib/argparser/docs/README.md b/lib/argparser/docs/README.md deleted file mode 100644 index 91b3b9b..0000000 --- a/lib/argparser/docs/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Документация проекта - -Данный документ - сборник документации по проекту ArgParser. Здесь будут -все ссылки на документацию. - -## Документация разработки - -* [Проблема](dev/problem.md) -* [Требования](dev/requirements.md) -* [Архитектура](dev/architecture.md) - -## Итоговая документация - -* [Парсер](ArgParser.md) -* [Настройка параметров аргумента](ConcreteArgumentBuilder.md) diff --git a/lib/argparser/docs/dev/architecture.md b/lib/argparser/docs/dev/architecture.md deleted file mode 100644 index c7e0f69..0000000 --- a/lib/argparser/docs/dev/architecture.md +++ /dev/null @@ -1,185 +0,0 @@ -# Архитектура продукта - -В этом документе описывается архитектура продукта - парсера аргументов командной -строки, разработанная на основании [требований](requirements.md). - -## Системная архитектура - -* Продукт не имеет системной архитектуры, поскольку его предполагается использовать - в качестве подсистемы, встраиваемой в иные продукты. - -#### UML-диаграмма -```mermaid ---- -title: Diagram of the system of the project ---- -flowchart TB - nodeArgParser([ArgParser]) -``` - -## Архитектура подсистем - -* Исходя из вышеуказанного предполагаемого использования продукта, весь продукт - представляет собой одну подсистему - библиотеку argparer, которая должна обрабатывать - данные аргументы командной строки. - -### Архитектура подсистемы "ArgParser" - -#### 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 -``` - -Эта подсистема представляет собой набор классов и связей между ними, которые выполняют -непосредственно парсинг аргументов командной строки, передаваемых в подсистему. Все -классы находятся в пространстве имён ArgumentParser. - -#### Класс ArgParser - -Этот класс является основным классом модуля, именно с ним обычно взаимодействует -пользователь. Он должен предоставлять следующие возможности: добавление обрабатываемого -аргумента (любого из указанных) с указанным ключом, парсинг набора аргументов командной -строки, а также функция добавления аргумента. Кроме того, должен иметь функцию -составления справки и обрабатывать ошибки в синтаксисе аргументов командной строки, -и, в некоторых случаях, выводить их. - -#### Класс ArgumentBuilder - -Этот класс реализует паттерн проектирования "Builder": ссылки на объекты наследников -этого класса должна возвращать функция добавления аргумента из ArgParser, к нему -должен обращаться пользователь, добавляя информацию об аргументе. Должен -реализовывать функции добавления любой информации про аргумент, представленные в -[тестах](../../../../tests/argparser_unit_tests.cpp) и функцию построения. Ему должен -наследовать шаблонизированный класс конкретного Builder, который будет реализовывать -вышеуказанный функционал для каждого из типов аргумента. - -#### Класс Argument - -Этот класс является родительским классом для всех классов аргументов. Должен иметь -функции возврата статуса парсинга и возврата информации об аргументе, а также функцию -получения значения аргумента из аргументов командной строки. Необходимая информация, -не изменяемая в процессе парсинга, должна храниться в виде экземпляра структуры. -На данный момент планируется аргументы всех базовых значащих типов (кроме 8-битных -чисел), StringArgument и ComplexArgument (строка с валидацией и чтением пробелов). diff --git a/lib/argparser/docs/dev/problem.md b/lib/argparser/docs/dev/problem.md deleted file mode 100644 index 7a4bee5..0000000 --- a/lib/argparser/docs/dev/problem.md +++ /dev/null @@ -1,5 +0,0 @@ -# Проблема - -Необходимо разработать библиотеку для парсинга аргументов командной строке на языке -C++, стандарт C++20. Библиотека должна быть POSIX-совместимой и проходить все -[тесты](../../../../tests/argparser_unit_tests.cpp) из указанного файла. diff --git a/lib/argparser/docs/dev/requirements.md b/lib/argparser/docs/dev/requirements.md deleted file mode 100644 index 4866b46..0000000 --- a/lib/argparser/docs/dev/requirements.md +++ /dev/null @@ -1,65 +0,0 @@ -# Требования к продукту - -В этом документе описаны требования к продукту - парсеру аргументов командной строки. - -## Функциональные требования - -Поскольку необходимо разработать библиотеку, подразумевающую дальнейшее использование -в качестве компонента других программ, требования не подразумевают прямо некий формат -UI, а описывают взаимодействие программистов, использующих библиотеку с ней. - -### Требования к формату входных данных - -* Входные данные должны представлять собой строки, несущие всю необходимую информацию - об аргументах, которые надо распарсить, а также непосредственно строку вызова - программы. -* Входные данные могут быть представлены в разных форматах: как вектор строк, так и динамический - массив C-style строк. -* Формат входных данных должен соответствовать [тестам](../../../../tests/argparser_unit_tests.cpp) - из соответствующего файла. То есть, должны быть реализованы все функции из тестов - со всеми возможными комбинациями аргументов функций из представленных. - -### Требования к формату выходных данных - -* Выходные данные - исключительно возвращаемые значения функций библиотеки. -* Формат выходных данных должен соответствовать [тестам](../../../../tests/argparser_unit_tests.cpp) - из соответствующего файла. То есть, должны быть реализованы все функции из тестов - с необходимыми типами возвращаемых значений. - -### Требования к функциональности продукта - -* Итоговый продукт должен проходить все [тесты](../../../../tests/argparser_unit_tests.cpp) - - главный приоритет. Первые 15 - строго обязательно. -* Кроме того, должна корректно работать программа, описанная в - [main.cpp](../../../../bin/main.cpp). -* Продукт должен настолько, насколько это возможно, соответствовать стандарту POSIX. -* К предоставленным тестам должны быть добавлены дополнительные, проверяющие - соответствие стандарту POSIX. -* Полученные значения аргументов должен валидироваться (на корректность). -* Должна быть реализована поддержка "сложного аргумента" - например, имени файла - с пробелами (последнее опционально). - -## Прочие требования - -### Требования к быстродействию - -* Требования к быстродействию отсутствуют исходя из специфики проблемы. Парсер - аргументов командной строки - модуль, который запускается всего один раз за всё - время работы программы, и всегда получает небольшое количество данных. Значит, - его быстродействие слабо влияет на быстродействие системы. - -### Требования к безопасности - -* Требования безопасности ограничены валидацией значений аргументов на корректность, - поскольку выявление угроз безопасности не относится к зоне ответственности парсера - аргументов командной строки. - -### Требования к масштабируемости - -* Масштабируемость не требуется исходя из специфики парсера аргументов командной - строки. - -### Требования к возможности доработки - -* Продукт должен обладать гибкой архитектурой с возможностью доработки и внесения - нового функционала. From e39c5211f0c3d116ba1f729ddef5840d3fab0091 Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 12 Aug 2024 23:18:33 +0300 Subject: [PATCH 3/4] Updated common project documentation - separated task and readme --- README.md | 227 +++++++++++++++++++++++++++++++++++----- TASK.md | 43 ++++++++ docs/README.md | 4 - docs/WeatherForecast.md | 212 ------------------------------------- 4 files changed, 245 insertions(+), 241 deletions(-) create mode 100644 TASK.md delete mode 100644 docs/WeatherForecast.md 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 eced614..f581a4e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,8 +8,4 @@ * [Проблема](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) -* [Мануал weather-forecast](WeatherForecast.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` - переход к предыдущей локации из списка. При достижении - начала списка следующим считается последний элемент. From d02893b3ecb5bb2591102c20e45ab716f57682da Mon Sep 17 00:00:00 2001 From: bialger Date: Mon, 12 Aug 2024 23:19:33 +0300 Subject: [PATCH 4/4] Reworked ftxui_interface - deleted the empty cpp file, added INTERFACE property --- lib/ftxui/CMakeLists.txt | 8 ++++---- lib/ftxui/ftxui_interface.cpp | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 lib/ftxui/ftxui_interface.cpp diff --git a/lib/ftxui/CMakeLists.txt b/lib/ftxui/CMakeLists.txt index 65b887e..b7c28ed 100644 --- a/lib/ftxui/CMakeLists.txt +++ b/lib/ftxui/CMakeLists.txt @@ -11,14 +11,14 @@ FetchContent_Declare(ftxui FetchContent_MakeAvailable(ftxui) -add_library(ftxui_interface STATIC - ftxui_interface.cpp +add_library(ftxui_interface INTERFACE + ftxui_interface.hpp ) -target_link_libraries(ftxui_interface PUBLIC +target_link_libraries(ftxui_interface INTERFACE ftxui::screen ftxui::dom ftxui::component ) -target_include_directories(ftxui_interface PUBLIC ${PROJECT_SOURCE_DIR}) +target_include_directories(ftxui_interface INTERFACE ${PROJECT_SOURCE_DIR}) diff --git a/lib/ftxui/ftxui_interface.cpp b/lib/ftxui/ftxui_interface.cpp deleted file mode 100644 index f35fec5..0000000 --- a/lib/ftxui/ftxui_interface.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "ftxui_interface.hpp"