Skip to content

Commit 8d9b358

Browse files
committed
Write "Customization of reports" section
1 parent 4448893 commit 8d9b358

1 file changed

Lines changed: 141 additions & 15 deletions

File tree

docs/index.md

Lines changed: 141 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,6 @@ Customizable validation implementer. Adapter performs actual validation when the
116116
##### *Aggregation*
117117
Combination of validating [operators](#operator) or other [validators](#validator) that make up a compound [validator](#validator). There are logical aggregations such as _AND_, _OR_, _NOT_ and [element](#element) aggregations such as _ANY_, _ALL_.
118118

119-
##### *Backend formatter*
120-
String formatter used for [reports](#report) building. One of the following backend formatters can be used:
121-
* *(preferred)* [fmt](https://github.com/fmtlib/fmt) based backend formatter;
122-
* std::stringstream based backend formatter.
123-
124119
##### *Concrete phrase*
125120
Immutable string that will be used in final [report](#report).
126121

@@ -1294,13 +1289,13 @@ There are three built-in adapter types implemented in `cpp-validator` library:
12941289

12951290
### Default adapter
12961291

1297-
`Default adapter` wraps *lvalue* reference to the [object](#object) to be validated and invokes [operators](#operator) one by one as specified in a [validator](#validator). To make a `default adapter` call `make_default_adapter(object_to_validate)` with the [object](#object) as an argument. If a [validator](#validator) is applied directly to the [object](#object) then `default adapter` is constructed implicitly. See examples in [Using validator for data validation](#using-validator-for-data-validation) section.
1292+
*Default adapter* wraps *lvalue* reference to the [object](#object) to be validated and invokes [operators](#operator) one by one as specified in a [validator](#validator). To make a *default adapter* call `make_default_adapter(object_to_validate)` with the [object](#object) as an argument. If a [validator](#validator) is applied directly to the [object](#object) then *default adapter* is constructed implicitly. See examples in [Using validator for data validation](#using-validator-for-data-validation) section.
12981293

1299-
`Default adapter` supports implicit check of [member existence](#member-existence).
1294+
*Default adapter* supports implicit check of [member existence](#member-existence).
13001295

13011296
### Single member adapter
13021297

1303-
`Single member adapter` validates only a single member. This adapter is best suitable for *pre-validation*, i.e. validating the data before updating an object in the object's setters. `Single member adapter` is constructed by calling `make_single_member_adapter()` that can have one of the following signatures:
1298+
*Single member adapter* validates only a single member. This adapter is best suitable for *pre-validation*, i.e. validating the data before updating an object in the object's setters. *Single member adapter* is constructed by calling `make_single_member_adapter()` helper that can have one of the following signatures:
13041299
- `make_single_member_adapter(member_path,val,reporter)` where
13051300
- `member_path` is a [member](#member) specified in [member notation](#member-notation);
13061301
- `val` is a variable to validate;
@@ -1310,7 +1305,7 @@ There are three built-in adapter types implemented in `cpp-validator` library:
13101305
- `val` is a variable to validate;
13111306
- `dst` destination object (e.g. string) where to put the validation [report](#report) to constructed with the default [reporter](#reporter) if validation fails.
13121307

1313-
If the [member](#member) used in a `single member adapter` is not found in a [validator](#validator) then the validation will be considered as successful.
1308+
If the [member](#member) used in a *single member adapter* is not found in a [validator](#validator) then the validation will be considered as successful.
13141309

13151310
See example of object setter with validation below.
13161311

@@ -1392,7 +1387,7 @@ Examples of *custom adapter* implementation can be found in `validator/adapters/
13921387

13931388
### Reporting adapter
13941389

1395-
`Reporting adapter` does the same validation as [default adapter](#default-adapter) with addition of constructing a text [report](#report) describing the validation error. `Reporting adapter` is constructed by calling `make_reporting_adapter()` that can have one of the following signatures:
1390+
*Reporting adapter* does the same validation as [default adapter](#default-adapter) with addition of constructing a text [report](#report) describing the validation error. *Reporting adapter* is constructed by calling `make_reporting_adapter()` that can have one of the following signatures:
13961391
- `make_reporting_adapter(object,reporter)` where
13971392
- `object` is an [object](#object) to validate;
13981393
- `reporter` is a custom [reporter](#reporter) used for [report](#report) constructing if validation fails;
@@ -1428,17 +1423,19 @@ return 0;
14281423
}
14291424
```
14301425

1431-
`Reporting adapter` supports implicit check of [member existence](#member-existence).
1426+
*Reporting adapter* supports implicit check of [member existence](#member-existence).
14321427

14331428
### Customization of reports
14341429

14351430
[Reports](#report) can be customized with help of custom [reporters](#reporter) that are given to adapters supporting [reports](#reports) construction.
14361431

14371432
#### Report construction
14381433

1439-
A [report](#report) is constructed by a [reporter](#reporter) given to an adapter that supports [reports](#reports) construction. Default [reporter](#reporter) is implemented by `reporter` template class defined in `validator/reporting/reporter.hpp` header file. There are two ways to customize report construction:
1434+
##### Default reporter
1435+
1436+
A [report](#report) is constructed by a [reporter](#reporter) given to an adapter that supports [reports](#reports) construction. *Default [reporter](#reporter)* is implemented by `reporter` template class defined in `validator/reporting/reporter.hpp` header file. There are two ways to customize report construction:
14401437
- implement a custom reporter *from scratch* and give it to the corresponding adapter;
1441-
- use default `reporter` template class with custom [formatter](#formatter) - a helper function `make_reporter(report_destination,custom_formatter)` can be used for convenience, e.g.:
1438+
- use default `reporter` template class with custom [formatter](#formatter), a helper function `make_reporter(report_destination,custom_formatter)` can be used for convenience, e.g.:
14421439
```cpp
14431440

14441441
// object_for_validation must be defined elsewhere
@@ -1447,22 +1444,151 @@ A [report](#report) is constructed by a [reporter](#reporter) given to an adapte
14471444
std::string report;
14481445

14491446
// create reporting adapter with custom report formatter
1450-
auto reporting_adapter1=make_reporting_adapter(
1447+
auto ra=make_reporting_adapter(
14511448
object_for_validation,
14521449
make_reporter(report,custom_formatter)
14531450
);
14541451
```
1452+
##### Report with object's name
1453+
1454+
Typically, [report](#report) does not include a name of the object being validated. For example, `validator(gt,100)` will result in error message "must be greater than 100". If [report](#report) must include the object's name, e.g. "*the object under validation* must be greater than 100", then `reporter_with_object_name` must be used instead of [default reporter](#default-reporter). `reporter_with_object_name` template class is defined `validator/reporting/reporter_with_object_name.hpp` header file. A helper function `make_reporter_with_object_name()` can be used for convenience. See example below.
1455+
1456+
```cpp
1457+
// object_for_validation must be defined elsewhere
1458+
1459+
std::string report;
1460+
1461+
// create reporting adapter with custom report formatter
1462+
auto ra=make_reporting_adapter(
1463+
object_for_validation,
1464+
make_reporter_with_object_name(report,get_default_formatter(),"the object under validation")
1465+
);
1466+
```
14551467
14561468
#### Formatters
14571469
1470+
[Formatter](#formatter) of [reports](#report) uses four components that can be customized:
1471+
- [formatter of member names](#members-formatter);
1472+
- [formatter of miscellaneous strings](#miscellaneous-strings-formatter) such as descriptions of [special](#special-operators) and [built-in](#built-in-operators) operators as well as keywords used in the library;
1473+
- [formatter of operands](#operands-formatter);
1474+
- traits that perform [final ordering and presentation](strings-order-and-presentation) of strings prepared with the partial formatters listed above.
1475+
1476+
Actual strings formatting is performed by a [backend formatter](backend-formatter).
1477+
1478+
Base `formatter` template class is defined in `validator/reporting/formatter.hpp` header file. Default *formatter* implementation can be obtained with `get_default_formatter()`.
1479+
1480+
Use `make_formatter()` helper to construct *formatters* with custom components and [translators](#translator). There is a number of `make_formatter()` signatures defined in `validator/reporting/formatter.hpp` header file, choose the most suitable for certain cases.
1481+
1482+
Reporting strings prepared with either top-level *formatter* or partial formatters can be overwritten with [reporting hints](#reporting-hints).
1483+
1484+
##### Backend formatter
1485+
1486+
*Backend formatter* is a *variable-to-string* formatter. One of the following string formatters can be used:
1487+
- *(preferred)* [fmt](https://github.com/fmtlib/fmt) based backend formatter;
1488+
- `std::stringstream` based backend formatter.
1489+
1490+
To use [fmt](https://github.com/fmtlib/fmt) for strings formatting define `DRACOSHA_VALIDATOR_FMT` macro, see [Building and installation](#building-and-installation) for details of formatter configuration.
1491+
14581492
##### Members formatter
14591493
1494+
[Reports](#report) must display human readable names of [members](#members). Member names formatting is performed by a *member names formatter* with base template class `member_names` defined in `validator/reporting/member_names.hpp` header file. For custom *member names formatting* the custom traits must be implemented and used as a template argument of `member_names`. There is `make_member_names()` helper to construct *member names formatter* from the custom traits.
1495+
1496+
Default implementation of *member names formatter* joins member names in reverse order using *of* conjunction, e.g. `["field1"]["subfield1_1"]["subfield1_1_1"]` will be formatted as "*subfield1_1_1 of subfield1_1 of field1*". Default member names formatter can be obtained with `get_default_member_names()`.
1497+
1498+
There is also `dotted_member_names` formatter that displays member names similar to their declaration, e.g. `["field1"]["subfield1_1"]["subfield1_1_1"]`` will be formatted as "*[field1].[subfield1_1].[subfield1_1_1]*".
1499+
1500+
If [localization](#localization) of member names must be supported then original *member names formatter* must be wrapped with *locale-aware member names formatter* using one of `make_translated_member_names()` helpers.
1501+
1502+
To [decorate](#decorator) member names the original *member names formatter* must be wrapped with *decorating member names formatter* using `make_decorated_member_names()` helper. See example below.
1503+
1504+
```cpp
1505+
// define validator
1506+
auto v=validator(
1507+
["field1"]["subfield1_1"]["subfield1_1_1"](gt,100)
1508+
);
1509+
1510+
// wrap default member names formatter with quoted member names decorator
1511+
auto decorated_mn=make_decorated_member_names(get_default_member_names(),quotes_decorator);
1512+
1513+
// object_for_validation must be defined elsewhere
1514+
1515+
std::string report;
1516+
1517+
// create reporting adapter with quoted member names
1518+
auto ra_decorated=make_reporting_adapter(
1519+
object_for_validation,
1520+
make_reporter(report,make_formatter(decorated_mn))
1521+
);
1522+
1523+
if (!v.apply(ra))
1524+
{
1525+
std::cerr << report << std::endl;
1526+
/* prints:
1527+
'"subfield1_1_1" of "subfield1_1" of "field1" must be greater than 100'
1528+
*/
1529+
}
1530+
```
1531+
14601532
##### Operands formatter
14611533

1534+
By default [operands](#operand) are formatted at the discretion of [backend formatter](#backend-formatter). Sometimes [operands](#operand) may require special formatting. The obvious example is a boolean value which can be displayed in different ways, e.g. as 1/0, true/false, yes/not, checked/unchecked, etc. Another example is when the [operands](#operand) must be decorated, e.g. with quotes or HTML tags.
1535+
1536+
[Operands](#operand) formatting is performed by the *operands formatter* with base template class `operand_formatter` defined in `validator/reporting/operand_formatter.hpp` header file. For custom *operands formatting* the custom traits must be implemented and used as a template argument of `operand_formatter`. There is also `default_operand_formatter` which forwards operands to [backend formatter](#backend-formatter) "as is".
1537+
1538+
If [localization](#localization) of operands must be supported then *locale-aware operands formatter* must be used that can be constructed with one of `make_translated_operand_formatter()` helpers.
1539+
1540+
To [decorate](#decorator) operands the *decorating member names formatter* can be constructed with `make_operand_formatter()` or `make_translated_operand_formatter()` helpers. See example below.
1541+
1542+
```cpp
1543+
// define validator
1544+
auto v=validator(
1545+
[size](gt,100)
1546+
);
1547+
1548+
// operands formatter with quoted decorator
1549+
auto decorated_operands=make_operand_formatter(quotes_decorator);
1550+
1551+
// object_for_validation must be defined elsewhere
1552+
1553+
std::string report;
1554+
1555+
// create reporting adapter with quoted member names
1556+
auto ra_decorated=make_reporting_adapter(
1557+
object_for_validation,
1558+
make_reporter(report,make_formatter(get_default_member_names(),decorated_operands))
1559+
);
1560+
1561+
if (!v.apply(ra))
1562+
{
1563+
std::cerr << report << std::endl;
1564+
/* prints:
1565+
'size must be greater than "100"'
1566+
*/
1567+
}
1568+
```
1569+
14621570
##### Miscellaneous strings formatter
14631571
1572+
This formatter is used to format [operators](#operator) and some other strings.
1573+
1574+
Conversion of a generic *ID* to the string is performed as follows.
1575+
- If string *ID* is a [property](#property) then `name()` of the [property](#property) is used.
1576+
- If string *ID* is convertible to `std::string` then that conversion is used, e.g. all validation [operators](#operator) are formatted using the *to string conversion operator*.
1577+
- If string *ID* is of some scalar type that can be forwarded to `std::to_string(id)` then `std::to_string()` is used.
1578+
- In the rest cases "*\<?????\>*" string is used as a result.
1579+
1580+
After *ID* is converted to the string the conversion result goes to [translator](#translator). Translator returns either translated or original string.
1581+
1582+
Base template class `strings` for *miscellaneous strings formatting* is defined in `validator/reporting/strings.hpp` header file. Customization of *miscellaneous strings formatting* can be done with use of custom [translators](#translator) or *[aggregation](#aggregation) strings* which are used as template arguments in `strings` template class. Default *miscellaneous strings formatting* is implemented with `default_strings` formatter that uses default `aggregation_strings` formatter and no [translators](#translator).
1583+
1584+
If [localization](#localization) of miscellaneous strings must be supported then *locale-aware miscellaneous strings formatter* must be used that can be constructed with one of `make_translated_strings()` helpers.
1585+
14641586
##### Strings order and presentation
14651587
1588+
Resulting strings from the partial [formatters](#formatters) must be ordered and joined to construct the final [report](#report). By default that is performed by `default_order_and_presentation` helper defined in `validator/reporting/order_and_presentation.hpp` header file.
1589+
1590+
For custom strings ordering and presentation a custom implementation of the *strings order and presentation* must be used in `formatter` that can be constructed with corresponding `make_formatter()` helper.
1591+
14661592
#### Decorator
14671593
14681594
Decorators can be used to decorate [members](#members-formatter) and [operands](#operands-formatter). For example, if one wants to mark [operands](#operands-formatter) with bold text using HTML tags to highlight them in user interface then a `decorator` that wraps operands with `<b>...</b>` might be implemented and used in [operands formatter](#operands-formatter). See examples of `decorator` use in [members formatter](#members-formatter) and [operands formatter](#operands-formatter) sections.
@@ -1502,7 +1628,7 @@ constexpr bold_decorator_t bold_decorator{};
15021628

15031629
### Reporting hints
15041630

1505-
To override strings constructed by [reporter](#reporter) one can use *hints*. *Hint* is an explicit string that must be used in a [report](#report) for certain part of the report instead of automatically generated string.
1631+
To override strings constructed by [formatters](#formatters) one can use *hints*. *Hint* is an explicit string that must be used in a [report](#report) for certain part of the report instead of automatically generated string.
15061632

15071633
#### Override the whole report
15081634

0 commit comments

Comments
 (0)