Skip to content

Commit 16f8f5a

Browse files
committed
CPP-AP: version 3.0.0
- Renamed the `bypass_required` argument attribute to `suppress_arg_checks` - Introduced the `suppress_group_checks` argument attribute - Aligned the tutorial page and documentation comments - Made code cleanup changes
1 parent 4b81d69 commit 16f8f5a

19 files changed

Lines changed: 452 additions & 349 deletions

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ else()
77
endif()
88

99
project(cpp-ap
10-
VERSION 3.0.0.8
10+
VERSION 3.0.0
1111
DESCRIPTION "Command-line argument parser for C++20"
1212
HOMEPAGE_URL "https://github.com/SpectraL519/cpp-ap"
1313
LANGUAGES CXX

Doxyfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ PROJECT_NAME = CPP-AP
4848
# could be handy for archiving the generated documentation or if some version
4949
# control system is used.
5050

51-
PROJECT_NUMBER = 3.0.0.8
51+
PROJECT_NUMBER = 3.0.0
5252

5353
# Using the PROJECT_BRIEF tag one can provide an optional one line description
5454
# for a project that appears at the top of each page and should give viewer a

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
module(
22
name = "cpp-ap",
3-
version = "3.0.0.8",
3+
version = "3.0.0",
44
)

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Command-line argument parser for C++20
3434

3535
> [!NOTE]
3636
>
37-
> [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*.
37+
> [v1.0](https://github.com/SpectraL519/cpp-ap/releases/tag/v1.0) of the library has been developed for the *Team Programming* course at the *Wrocław University of Science and Technology*.
3838
>
3939
> Faculty: *W04N - Faculty of Information and Communication Technology*
4040
>
@@ -62,6 +62,11 @@ Command-line argument parser for C++20
6262
- [Parameters Specific for Optional Arguments](/docs/tutorial.md#parameters-specific-for-optional-arguments)
6363
- [Default Arguments](/docs/tutorial.md#default-arguments)
6464
- [Argument Groups](/docs/tutorial.md#argument-groups)
65+
- [Creating New Groups](/docs/tutorial.md#creating-new-groups)
66+
- [Adding Arguments to Groups](/docs/tutorial.md#adding-arguments-to-groups)
67+
- [Group Attributes](/docs/tutorial.md#group-attributes)
68+
- [Complete Example](/docs/tutorial.md#complete-example)
69+
- [Suppressing Argument Group Checks](/docs/tutorial.md#suppressing-argument-group-checks)
6570
- [Parsing Arguments](/docs/tutorial.md#parsing-arguments)
6671
- [Basic Argument Parsing Rules](/docs/tutorial.md#basic-argument-parsing-rules)
6772
- [Compound Arguments](/docs/tutorial.md#compound-arguments)
@@ -72,6 +77,7 @@ Command-line argument parser for C++20
7277
- [Using Multiple Subparsers](/docs/tutorial.md#using-multiple-subparsers)
7378
- [Parsing Arguments with Subparsers](/docs/tutorial.md#parsing-arguments-with-subparsers)
7479
- [Tracking Parser State](/docs/tutorial.md#tracking-parser-state)
80+
- [Suppressing Argument Group Checks](/docs/tutorial.md#suppressing-argument-group-checks)
7581
- [Examples](/docs/tutorial.md#examples)
7682
- [Common Utility](/docs/tutorial.md#common-utility)
7783
- [Dev notes](/docs/dev_notes.md#dev-notes)

cpp-ap-demo

docs/tutorial.md

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,26 @@
1212
- [Boolean Flags](#boolean-flags)
1313
- [Argument Parameters](#argument-parameters)
1414
- [Common Parameters](#common-parameters)
15-
- [help](#1-help---the-arguments-description-which-will-be-printed-when-printing-the-parser-class-instance)
16-
- [hidden](#2-hidden---if-this-option-is-set-for-an-argument-then-it-will-not-be-included-in-the-program-description)
17-
- [required](#3-required---if-this-option-is-set-for-an-argument-and-its-value-is-not-passed-in-the-command-line-an-exception-will-be-thrown)
18-
- [bypass required](#4-bypass_required---if-this-option-is-set-for-an-argument-the-required-option-for-other-arguments-will-be-discarded-if-the-bypassing-argument-is-used-in-the-command-line)
19-
- [nargs](#5-nargs---sets-the-allowed-number-of-values-to-be-parsed-for-an-argument)
20-
- [greedy](#6-greedy---if-this-option-is-set-the-argument-will-consume-all-command-line-values-until-its-upper-nargs-bound-is-reached)
21-
- [choices](#7-choices---a-list-of-valid-argument-values)
22-
- [value actions](#8-value-actions---functions-that-are-called-after-parsing-an-arguments-value)
23-
- [default values](#9-default_values---a-list-of-values-which-will-be-used-if-no-values-for-an-argument-have-been-parsed)
15+
- [help](#1-help---the-arguments-description-which-will-be-printed-when-printing-the-parser-class-instance) - the text shown in the help message to describe an argument
16+
- [hidden](#2-hidden---if-this-option-is-set-for-an-argument-then-it-will-not-be-included-in-the-program-description) - hides the argument from the generated program description and help output
17+
- [required](#3-required---if-this-option-is-set-for-an-argument-and-its-value-is-not-passed-in-the-command-line-an-exception-will-be-thrown) - marks the argument as mandatory; not using it will cause an error
18+
- [suppress arg checks](#4-suppress_arg_checks---using-a-suppressing-argument-results-in-suppressing-requirement-checks-for-other-arguments) - if a suppressing argument is used, other requirement validation will be skipped for other arguments
19+
- [nargs](#5-nargs---sets-the-allowed-number-of-values-to-be-parsed-for-an-argument) - defines how many values an argument can or must accept
20+
- [greedy](#6-greedy---if-this-option-is-set-the-argument-will-consume-all-command-line-values-until-its-upper-nargs-bound-is-reached) - makes the argument consume all following values until its limit is reached
21+
- [choices](#7-choices---a-list-of-valid-argument-values) - restricts the valid inputs to a predefined set of values
22+
- [value actions](#8-value-actions---functions-that-are-called-after-parsing-an-arguments-value) - allows you to run custom code after the argument’s value is parsed
23+
- [default values](#9-default_values---a-list-of-values-which-will-be-used-if-no-values-for-an-argument-have-been-parsed) - specifies fallback values to use if none are provided
2424
- [Parameters Specific for Optional Arguments](#parameters-specific-for-optional-arguments)
25-
- [on-flag actions](#1-on-flag-actions---functions-that-are-called-immediately-after-parsing-an-arguments-flag)
26-
- [implicit values](#2-implicit_values---a-list-of-values-which-will-be-set-for-an-argument-if-only-its-flag-but-no-values-are-parsed-from-the-command-line)
25+
- [on-flag actions](#1-on-flag-actions---functions-that-are-called-immediately-after-parsing-an-arguments-flag) - executes custom code immediately when the argument’s flag is present
26+
- [implicit values](#2-implicit_values---a-list-of-values-which-will-be-set-for-an-argument-if-only-its-flag-but-no-values-are-parsed-from-the-command-line) - automatically assigns a value if an argument flag is used without an explicit value
2727
- [Predefined Parameter Values](#predefined-parameter-values)
2828
- [Default Arguments](#default-arguments)
2929
- [Argument Groups](#argument-groups)
3030
- [Creating New Groups](#creating-new-groups)
3131
- [Adding Arguments to Groups](#adding-arguments-to-groups)
3232
- [Group Attributes](#group-attributes)
3333
- [Complete Example](#complete-example)
34+
- [Suppressing Argument Group Checks](#suppressing-argument-group-checks)
3435
- [Parsing Arguments](#parsing-arguments)
3536
- [Basic Argument Parsing Rules](#basic-argument-parsing-rules)
3637
- [Compound Arguments](#compound-arguments)
@@ -222,7 +223,7 @@ parser.add_optional_argument("n", ap::n_secondary);
222223
>
223224
> - The default value type of any argument is `std::string`.
224225
> - If the argument's value type is `ap::none_type`, the argument will not accept any values and therefore no value-related parameters can be set for such argument. This includes:
225-
> - [nargs](#5-nargs---sets-the-allowed-number-of-values-to-be-parsed-for-an-argument-this-can-be-set-as-a)
226+
> - [nargs](#5-nargs---sets-the-allowed-number-of-values-to-be-parsed-for-an-argument)
226227
> - [greedy](#6-greedy---if-this-option-is-set-the-argument-will-consume-all-command-line-values-until-its-upper-nargs-bound-is-reached)
227228
> - [choices](#7-choices---a-list-of-valid-argument-values)
228229
> - [value actions](#8-value-actions---functions-that-are-called-after-parsing-an-arguments-value)
@@ -318,9 +319,7 @@ Optional arguments:
318319
> [!WARNING]
319320
>
320321
> - If a positional argument is defined as non-required, then no required positional argument can be defined after (only other non-required positional arguments and optional arguments will be allowed).
321-
> - For both positional and optional arguments:
322-
> - enabling the `required` option disables the `bypass_required` option
323-
> - disabling the `required` option has no effect on the `bypass_required` option.
322+
> - If an argument is suppressing (see [suppress arg checks](#4-suppress_arg_checks---using-a-suppressing-argument-results-in-suppressing-requirement-checks-for-other-arguments) and [Suppressing Argument Group Checks](#suppressing-argument-group-checks)), then it cannot be required (an exception will be thrown).
324323
325324
```cpp
326325
// example: positional arguments
@@ -377,24 +376,27 @@ Command Result
377376

378377
<br />
379378

380-
#### 4. `bypass_required` - If this option is set for an argument, the `required` option for other arguments will be discarded if the bypassing argument is used in the command-line.
379+
#### 4. `suppress_arg_checks` - Using a suppressing argument results in suppressing requirement checks for other arguments.
380+
381+
If an argument is defined with the `suppress_arg_checks` option enabled and such argument is explicitly used in the command-line, then requirement validation will be suppressed/skipped for other arguments. This includes validating whether:
382+
- a required argument has been parsed
383+
- the number of values parsed for an argument matches the specified [nargs](#5-nargs---sets-the-allowed-number-of-values-to-be-parsed-for-an-argument) range.
381384

382385
> [!NOTE]
383386
>
384-
> - Both all arguments have the `bypass_required` option disabled.
385-
> - The default value of the value parameter of the `argument::bypass_required(bool)` method is `true` for all arguments.
387+
> - All arguments have the `suppress_arg_checks` option disabled by default.
388+
> - The default value of the value parameter of the `argument::suppress_arg_checks(bool)` method is `true` for all arguments.
386389
387390
> [!WARNING]
388391
>
389-
> For both positional and optional arguments:
390-
> - enabling the `bypass_required` option disables the `required` option
391-
> - disabling the `bypass_required` option has no effect on the `required` option.
392+
> - Enabling the `suppress_arg_checks` option has no effect on [argument group](#argument-groups) requirements validation.
393+
> - Enabling argument checks suppressing is not possible for required arguments (an exception will be thrown).
392394
393395
```cpp
394396
// example: optional arguments
395397
parser.add_positional_argument("input");
396398
parser.add_optional_argument("output", "o").required();
397-
parser.add_optional_argument("version", "v").bypass_required();
399+
parser.add_optional_argument("version", "v").suppress_arg_checks();
398400

399401
parser.parse_args(argc, argv);
400402

@@ -522,7 +524,7 @@ Actions are represented as functions, which take the argument's value as an argu
522524
```cpp
523525
void is_valid_user_tag(const std::string& tag) {
524526
if (tag.empty() or tag.front() != '@')
525-
throw std::runtime_error(std::format("Invalid user tag: `{}` must start with '@'", tag));
527+
throw std::runtime_error(std::format("Invalid user tag: `{}` - must start with '@'", tag));
526528
}
527529

528530
parser.add_optional_argument<std::string>("user", "u")
@@ -934,6 +936,26 @@ Output Options: (required, mutually exclusive)
934936
--print, -p : Print output to the console
935937
```
936938
939+
### Suppressing Argument Group Checks
940+
941+
Similarly to [suppressing argument checks](#4-suppress_arg_checks---using-a-suppressing-argument-results-in-suppressing-requirement-checks-for-other-arguments), an argument can suppress the requirement checks of argument groups:
942+
943+
```c++
944+
argument.suppress_group_checks();
945+
```
946+
947+
If such argument is used the requirement checks associated with the [group attributes](#group-attributes) will not be validated.
948+
949+
> [!NOTE]
950+
>
951+
> - All arguments have the `suppress_group_checks` option disabled by default.
952+
> - The default value of the value parameter of the `argument::suppress_group_checks(bool)` method is `true` for all arguments.
953+
954+
> [!WARNING]
955+
>
956+
> - Enabling the `suppress_group_checks` option has no effect on argument requirements validation.
957+
> - Enabling argument group checks suppressing is not possible for required arguments (an exception will be thrown).
958+
937959
<br/>
938960
<br/>
939961
<br/>

include/ap/argument.hpp

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,14 @@ class argument : public detail::argument_base {
117117
return this->_required;
118118
}
119119

120-
/// @return `true` if required argument bypassing is enabled for the argument, `false` otherwise.
121-
/// @note Required argument bypassing is enabled only if the argument is not required.
122-
[[nodiscard]] bool is_bypass_required_enabled() const noexcept override {
123-
return not this->_required and this->_bypass_required;
120+
/// @return `true` if argument checks suppressing is enabled for the argument, `false` otherwise.
121+
[[nodiscard]] bool suppresses_arg_checks() const noexcept override {
122+
return this->_suppress_arg_checks;
123+
}
124+
125+
/// @return `true` if argument group checks suppressing is enabled for the argument, `false` otherwise.
126+
[[nodiscard]] bool suppresses_group_checks() const noexcept override {
127+
return this->_suppress_group_checks;
124128
}
125129

126130
/// @return `true` if the argument is greedy, `false` otherwise.
@@ -152,40 +156,62 @@ class argument : public detail::argument_base {
152156

153157
/**
154158
* @brief Set the `required` attribute of the argument
155-
* @param r The attribute value.
159+
* @param value The attribute value (default: `true`).
156160
* @return Reference to the argument instance.
157-
* @attention Setting the `required` attribute to `true` disables the `bypass_required` attribute.
161+
* @throws ap::invalid_configuration if the argument is configured to suppress argument/group checks.
158162
*/
159-
argument& required(const bool r = true) noexcept {
160-
this->_required = r;
161-
if (this->_required)
162-
this->_bypass_required = false;
163+
argument& required(const bool value = true) {
164+
if (value and (this->_suppress_arg_checks or this->_suppress_group_checks))
165+
throw invalid_configuration(
166+
std::format("A suppressing argument [{}] cannot be required!", this->_name.str())
167+
);
168+
169+
this->_required = value;
163170
return *this;
164171
}
165172

166173
/**
167-
* @brief Enable/disable bypassing the `required` attribute for the argument.
168-
* @param br The attribute value.
174+
* @brief Enable/disable suppressing argument checks for other arguments.
175+
* @param value The attribute value (default: `true`).
169176
* @return Reference to the argument instance.
170-
* @attention Setting the `bypass_required` option to `true` disables the `required` attribute.
177+
* @throws ap::invalid_configuration if the argument is configured to be required.
171178
*/
172-
argument& bypass_required(const bool br = true) noexcept {
173-
this->_bypass_required = br;
174-
if (this->_bypass_required)
175-
this->_required = false;
179+
argument& suppress_arg_checks(const bool value = true) {
180+
if (value and this->_required)
181+
throw invalid_configuration(std::format(
182+
"A required argument [{}] cannot suppress argument checks!", this->_name.str()
183+
));
184+
185+
this->_suppress_arg_checks = value;
186+
return *this;
187+
}
188+
189+
/**
190+
* @brief Enable/disable suppressing argument group checks.
191+
* @param value The attribute value (default: `true`).
192+
* @return Reference to the argument instance.
193+
* @throws ap::invalid_configuration if the argument is configured to be required.
194+
*/
195+
argument& suppress_group_checks(const bool value = true) {
196+
if (value and this->_required)
197+
throw invalid_configuration(std::format(
198+
"A required argument [{}] cannot suppress argument group checks!", this->_name.str()
199+
));
200+
201+
this->_suppress_group_checks = value;
176202
return *this;
177203
}
178204

179205
/**
180206
* @brief Set the `greedy` attribute of the argument.
181-
* @param g The attribute value.
207+
* @param value The attribute value (default: `true`).
182208
* @return Reference to the argument instance.
183209
* @note The method is enabled only if `value_type` is not `none_type`.
184210
*/
185-
argument& greedy(const bool g = true) noexcept
211+
argument& greedy(const bool value = true) noexcept
186212
requires(not util::c_is_none<value_type>)
187213
{
188-
this->_greedy = g;
214+
this->_greedy = value;
189215
return *this;
190216
}
191217

@@ -438,8 +464,10 @@ class argument : public detail::argument_base {
438464
bld.params.reserve(6ull);
439465
if (this->_required != _default_required)
440466
bld.add_param("required", std::format("{}", this->_required));
441-
if (this->is_bypass_required_enabled())
442-
bld.add_param("bypass required", "true");
467+
if (this->_suppress_arg_checks)
468+
bld.add_param("suppress arg checks", "true");
469+
if (this->_suppress_group_checks)
470+
bld.add_param("suppress group checks", "true");
443471
if (this->_nargs_range != _default_nargs_range)
444472
bld.add_param("nargs", this->_nargs_range);
445473
if constexpr (util::c_writable<value_type>) {
@@ -546,12 +574,19 @@ class argument : public detail::argument_base {
546574
return this->_values_impl();
547575
}
548576

577+
/// @return Reference to the vector of parsed values for the argument.
578+
/// @note For none-type arguments, the method always returns an empty vector.
549579
[[nodiscard]] const std::vector<std::any>& _values_impl() const noexcept
550580
requires(util::c_is_none<value_type>)
551581
{
552582
return this->_values;
553583
}
554584

585+
/**
586+
* @return Reference to the vector of parsed values for the argument.
587+
* @note If no parsed values are available, the method attempts to return the predefined values (default/implicit).
588+
* @note The method is enabled only if `value_type` is not `none_type`.
589+
*/
555590
[[nodiscard]] const std::vector<std::any>& _values_impl() const noexcept
556591
requires(not util::c_is_none<value_type>)
557592
{
@@ -670,11 +705,15 @@ class argument : public detail::argument_base {
670705
}
671706
else {
672707
if (not (std::istringstream(str_value) >> value))
673-
throw parsing_failure::invalid_value(this->_name, str_value);
708+
throw parsing_failure(std::format(
709+
"Cannot parse value `{}` for argument [{}].", str_value, this->_name.str()
710+
));
674711
}
675712

676713
if (not this->_is_valid_choice(value))
677-
throw parsing_failure::invalid_choice(this->_name, str_value);
714+
throw parsing_failure(std::format(
715+
"Value `{}` is not a valid choice for argument [{}].", str_value, this->_name.str()
716+
));
678717

679718
const auto apply_visitor = action::util::apply_visitor<value_type>{value};
680719
for (const auto& action : this->_value_actions)
@@ -700,7 +739,10 @@ class argument : public detail::argument_base {
700739
_value_actions; ///< The argument's value actions collection.
701740

702741
bool _required : 1; ///< The argument's `required` attribute value.
703-
bool _bypass_required : 1 = false; ///< The argument's `bypass_required` attribute value.
742+
bool _suppress_arg_checks : 1 =
743+
false; ///< The argument's `suppress_arg_checks` attribute value.
744+
bool _suppress_group_checks : 1 =
745+
false; ///< The argument's `suppress_group_checks` attribute value.
704746
bool _greedy : 1 = false; ///< The argument's `greedy` attribute value.
705747
bool _hidden : 1 = false; ///< The argument's `hidden` attribute value.
706748

0 commit comments

Comments
 (0)