Skip to content

Commit

Permalink
YT-CPPAP-8: Fix typos and rename some elements
Browse files Browse the repository at this point in the history
- Fixed some typos and incorrect examples in the readme file
- Added markdown alerts in the readme file
- Renamed and refactored the `ap::action::check_file_exists_action()` function
  • Loading branch information
SpectraL519 committed May 14, 2024
1 parent 60dd035 commit 2e32489
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 257 deletions.
96 changes: 96 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
cmake_minimum_required(VERSION 3.12)

# check if CPP-AP is a top level project
if (NOT DEFINED PROJECT_NAME)
set(CPP_AP_IS_TOP_LEVEL_PROJECT ON)
else()
set(CPP_AP_IS_TOP_LEVEL_PROJECT OFF)
endif()

project(
cpp-ap
VERSION 1.0
DESCRIPTION "Command-line argument parser for C++20"
HOMEPAGE_URL "https://github.com/SpectraL519/cpp-ap"
LANGUAGES CXX
)

# define the library target
add_library(cpp-ap INTERFACE)
target_include_directories(cpp-ap INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)

# installation rules
include(GNUInstallDirs)
install(TARGETS cpp-ap
EXPORT cpp-ap-targets
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

# generate and install the CMake package configuration files
install(EXPORT cpp-ap-targets
FILE cpp-ap-targets.cmake
NAMESPACE cpp-ap::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpp-ap
)

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/cpp-ap-config-version.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY ExactVersion
)

configure_package_config_file(
${CMAKE_CURRENT_LIST_DIR}/cmake/cpp-ap-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/cpp-ap-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpp-ap
)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/cpp-ap-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/cpp-ap-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpp-ap
)

if (CPP_AP_IS_TOP_LEVEL_PROJECT)
option(CPP_AP_BUILD_TESTS "Build tests" ON)
option(CPP_AP_BUILD_EXAMPLES "Build examples" OFF)

if(CPP_AP_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()

if(CPP_AP_BUILD_TESTS)
enable_testing()
add_subdirectory(test)
endif()

if(CPP_AP_INSTALL)
install(EXPORT cpp-ap-targets
FILE cpp-ap-config.cmake
NAMESPACE ap::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpp-ap
)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/cpp-ap-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpp-ap
)
endif()

set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}")
set(CPACK_PACKAGE_VENDOR "SpectraL519")
set(CPACK_PACKAGE_CONTACT "Jakub Musiał jmusial2003@gmail.com")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")

include(CPack)
endif()
112 changes: 66 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ Command-line argument parser for C++20

## Overview

The `CPP-AP` library has been developed for the *Team Programming* course at the *Wrocław University of Science and Technology*.

Faculty: *W04N - Faculty of Information and Communication Technology*

Field of study: *Algorithmic Computer Science*

<br />

The goal of the project was to create a light, intuitive and simple to use command-line argument parser library for the `C++20` and newer standards.

The `CPP-AP` library does not require installing any additional tools or heavy libraries, like with `boost::program_options`. Much like with the `Doctest` framework - the only thing you need to do is copy the `argument_parser.hpp` file into the include directory of your project and you're set to go.

> [!NOTE]
> [v1.0](https://github.com/SpectraL519/cpp-ap/commit/9a9e5360766b732f322ae2efe3cf5ec5f9268eef) of the library has been developed for the *Team Programming* course at the *Wrocław University of Science and Technology*.
>
> Faculty: *W04N - Faculty of Information and Communication Technology*
>
> Field of study: *Algorithmic Computer Science*
>
> The project has received the 1st place at the 2024 CreatiWITy competition organized by the faculty. The article in Polish can be found on the [faculty website](https://wit.pwr.edu.pl/aktualnosci/oto-laureaci-konkursu-creatiwity-273.html). Please note that this is not a technical article :)
<br />
<br />

Expand All @@ -47,6 +48,8 @@ The `CPP-AP` library does not require installing any additional tools or heavy l

## Tutorial

<!-- TODO: download project release and add include directory to the project -->

To use the `CPP-AP` library in your project, copy the [argument_parser.hpp](include/ap/argument_parser.hpp) file into your include directory, e.g. `include/ap`. No other setup is necessary - you only need to include this header in your code:

```c++
Expand Down Expand Up @@ -74,25 +77,28 @@ parser.program_name("Name of the program")

The parser supports both positional and optional arguments. Both argument types are identified by their names represented as strings. Arguments can be defined with only a primary name or with a primary and a secondary (short) name.

**NOTE:** The basic rules of parsing positional and optional arguments are described in the [Parsing arguments](#parsing-arguments) section.
> [!NOTE]
> The basic rules of parsing positional and optional arguments are described in the [Parsing arguments](#parsing-arguments) section.
To add an argument to the parameter's configurations use the following syntax:

```c++
parser.add_<positional/optional>_argument<value_type>("argument_name");
parser.add_<positional/optional>_argument<value_type>("argument");
```

or

```c++
parser.add_<positional/optional>_argument<value_type>("argument_name", "a");
parser.add_<positional/optional>_argument<value_type>("argument", "a");
```

**NOTE:** The library supports any argument value types which meet the following requirements:
* The `std::ostream& operator<<` must be overloaded for a value type
* The type must have a copy constructor and an assignment operator
> [!NOTE]
> The library supports any argument value types which meet the following requirements:
* The `std::ostream& operator<<` is overloaded for the value type
* The value type has a copy constructor and an assignment operator

**NOTE:** If the `value_type` is not provided, `std::string` will be used.
> [!IMPORTANT]
> If the `value_type` is not provided, `std::string` will be used.
You can also add boolean flags:

Expand Down Expand Up @@ -135,12 +141,13 @@ Parameters which can be specified for both positional and optional arguments inc
* `choices` - a list of valid argument values.
The `choices` parameter takes a `const std::vector<value_type>&` as an argument.

**NOTE:** To use the `choices` the `value_type` must overload the equaility comparison operator: `==`;

```c++
parser.add_optional_argument<char>("method", "m").choices({'a', 'b', 'c'});
```

> [!IMPORTANT]
> To use the `choices` the `value_type` must overload the equaility comparison operator: `==`;
* `action` - a function performed after reading an argument's value.

Actions are represented as functions, which take the argument's value as an argument. There are two types of actions:
Expand All @@ -160,10 +167,10 @@ Parameters which can be specified for both positional and optional arguments inc
.action<ap::valued_action>([](const double& value) { return 1. / value; });
```

Actions can also be used to perform some value checking logic, e.g. the predefined `check_file_exists_action` which checks if a file with a given name exists:
Actions can also be used to perform some value checking logic, e.g. the predefined `check_file_exists` which checks if a file with a given name exists:
```c++
parser.add_optional_argument("input", "i")
.action<ap::void_action>(ap::action::check_file_exists_action);
.action<ap::void_action>(ap::action::check_file_exists());
```

**Optional argument specific parameters**
Expand Down Expand Up @@ -196,7 +203,8 @@ Parameters which can be specified for both positional and optional arguments inc
parser.add_optional_argument("input", "i").nargs(ap::nargs::any());
```
**NOTE:** The default nargs value is `1`.
> [!NOTE]
> The default nargs value is `1`.
* `default_value` - the default value for an argument which will be used if no values for this argument are parsed
```c++
Expand Down Expand Up @@ -231,7 +239,7 @@ The supported default arguments are:
```c++
// equivalent to:
parser.add_positional_argument<std::string>("input")
.action<ap::void_action>(ap::action::check_file_exists_action)
.action<ap::void_action>(ap::action::check_file_exists())
.help("Input file path");
```

Expand All @@ -247,29 +255,30 @@ The supported default arguments are:
parser.add_flag("help", "h").bypass_required().help("Display help message");
```

**Note:** As of now the *on flag action* functionality is not implemented in the library - this will be added in a future release.
To properly use the help argument in the current release add the following right beneath the `parser.parse_args(argc, argv)` try-catch block:
```c++
if (parser.has_value("help")) {
std::cout << parser << std::endl;
std::exit(EXIT_SUCCESS);
}
```
> [!NOTE]
> As of now the *on flag action* functionality is not implemented in the library - this will be added in a future release.
> To properly use the help argument in the current release add the following right beneath the `parser.parse_args(argc, argv)` try-catch block:
> ```c++
> if (parser.value<bool>("help")) {
> std::cout << parser << std::endl;
> std::exit(EXIT_SUCCESS);
> }
> ```
* `optional::input` and `optional::multi_input`:
```c++
// input - equivalent to:
parser.add_optional_argument("input", "i")
.required()
.nargs(1)
.action<ap::void_action>(ap::action::check_file_exists_action)
.action<ap::void_action>(ap::action::check_file_exists())
.help("Input file path");
// multi_input - equivalent to:
parser.add_optional_argument("input", "i")
.required()
.nargs(ap::nargs::at_least(1))
.action<ap::void_action>(ap::action::check_file_exists_action)
.action<ap::void_action>(ap::action::check_file_exists())
.help("Input files paths");
```
Expand All @@ -288,7 +297,8 @@ The supported default arguments are:
.help("Output files paths");
```

**NOTE:** The `argument_parser::default_<positional/optional>_arguments` functions will be modified to use a variadic argument list instead of a `std::vector` in a future release.
> [!NOTE]
> The `argument_parser::default_<positional/optional>_arguments` functions will be modified to use a variadic argument list instead of a `std::vector` in a future release.

### Parsing arguments

Expand All @@ -298,14 +308,14 @@ To parse the command-line arguments use the `argument_parser::parse_args` method
// power.cpp
#include <ap/argument_parser.hpp>

#include <iostream>
#include <cmath>
#include <iostream>

int main(int argc, char* argv[]) {
// create the parser class instance
ap::argument_parser parser;
parser.program_name("power calculator")
.program_description("calculates the value of an expression: base & exponent");
.program_description("calculates the value of an expression: base ^ exponent");

// add arguments
parser.add_positional_argument<double>("base").help("the exponentation base value");
Expand All @@ -325,7 +335,7 @@ int main(int argc, char* argv[]) {
}

// check for the help argument presence
if (parser.has_value("help")) {
if (parser.value<bool>("help")) {
std::cout << parser << std::endl;
std::exit(EXIT_SUCCESS);
}
Expand Down Expand Up @@ -361,18 +371,20 @@ int main(int argc, char* argv[]) {
# no exponent values given
```

**NOTE:** For each positional argument there must be **exactly one value**.
```shell
./test_program
./power
# out:
# [ERROR] : No values parsed for a required argument [base]
# power calculator
# calculates the value of an expression: base & exponent
# calculates the value of an expression: base ^ exponent
# [base] : the exponentation base value
# [exponent,e] : the exponent value
# [help,h] : Display help message
```

> [!IMPORTANT]
> For each positional argument there must be **exactly one value**.
* Optional arguments are parsed only with a flag:
```shell
./power 2 --exponent 1 2 3
Expand Down Expand Up @@ -400,7 +412,8 @@ int main(int argc, char* argv[]) {
# [help,h] : Display help message
```

**NOTE:** The parser behaviour depends on the argument definitions. The argument parameters are described int the [Argument parameters](#argument-parameters) section.
> [!IMPORTANT]
> The parser behaviour depends on the argument definitions. The argument parameters are described int the [Argument parameters](#argument-parameters) section.

<br />
<br />
Expand All @@ -416,7 +429,8 @@ cd <project-root>/example
The examples' source files are in the `<project-root>/example/source` directory.

> **Note:** Each source file is a sepparate example.
> [!NOTE]
> Each source file is a sepparate example.

Building the examples:

Expand Down Expand Up @@ -461,11 +475,13 @@ cmake ..
make
```

> **NOTE:** Building on Windows - use the `-G "Unix Makefiles"` option when running CMake to build a GNU Make project instead of a default Visual Studio project.
> [!TIP]
> Building on Windows - use the `-G "Unix Makefiles"` option when running CMake to build a GNU Make project instead of a default Visual Studio project.

Run the tests:

> **NOTE:** The test executable is generated in the `<project-root>/test/build` directory.
> [!NOTE]
> The test executable is generated in the `<project-root>/test/build` directory.

* All tests:

Expand All @@ -479,18 +495,21 @@ Run the tests:
./test -ts="<test-suite-name>"
```

> **Note**: Test suites in the project have the same name as the files they're in.
> [!NOTE]
> Test suites in the project have the same names as the files they're in.
<br />
### Formatting
> **NOTE:** To ensure new line encoding compatibility the project uses unix new line encoding.
> [!IMPORTANT]
> To ensure new line encoding compatibility the project uses unix new line encoding.
>
> This can be set using the `git config --global core.autocrlf true` command.
> More details can be found [here](https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings)
> **NOTE:** The project uses `clang-format-17`.
> [!NOTE]
> The project uses `clang-format-17`.
>
> To install this tool on ubuntu run `sudo bash ./scripts/env/install_clang17_toolchain.sh`.
>
Expand Down Expand Up @@ -534,7 +553,8 @@ The documentation for this project can be generated using Doxygen:
As of now the project supports the **GNU G++** and **Clang++** compilers with `C++20` support on Linux and Windows.
> **NOTE:** To build the project using clang you will need to install the `clang-17` toolchain using the script or website mentioned in the [Formatting](#formatting) section.
> [!NOTE]
> To build the project using clang you will need to install the `clang-17` toolchain using the script or website mentioned in the [Formatting](#formatting) section.
<br />
<br />
Expand Down
Loading

0 comments on commit 2e32489

Please sign in to comment.