ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
propertyformatter.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_format of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace format {
9
10//==================================================================================================
11/// # Introduction # {#alib_ns_strings_propertyformatter_overview}
12///
13/// This class can be used to offer customized format strings to end users. For example, when
14/// it should be allowed to end-users to store output format strings of complex type.
15///
16/// For this, the format string definition of \alib {format;Formatter}
17/// types is extended to support identifiers,
18/// which act as placeholders for object values. The identifiers placed in the string have to match
19/// to the normal formatting placeholders in respect to their total number and value type.
20///
21/// \note
22/// In other words: This class allows not only to have custom format strings which consume a
23/// list of data objects that is hard-coded, but also to have the replacement data objects defined
24/// by the end user.
25///
26/// In the constructor of this class, a custom format string which whose syntax is based on
27/// \ref alib_format_intro "standard ALib format strings" is passed.
28/// However, before using the format string, it is processed as follows:
29/// - It is searched for <em>"custom identifiers"</em> within the format string.
30/// - For each identifier found, a reference to an associated callback function is stored.
31/// - The <em>"custom identifier"</em> found is removed from the format string.
32///
33/// It could be said, that the format string given "is compiled" with the constructor of this class.
34///
35/// The only interface method #Format then accepts a
36/// \ref alib::boxing "boxed object" of custom type that is used to collect the format string's
37/// placeholder data, by using the stored callback functions.
38///
39/// The identifiers are denoted by prefixing them with (customizable) character <c>'@'</c>.
40///
41/// A vector of objects of inner type \b IdentifierEntry needs to be defined and passed to the
42/// constructor of this class.
43/// Field #IdentifierEntry::Name contains the \e 'identifier' string which is removed from the
44/// format string if found. Field #IdentifierEntry::Callback has to point to a callback function
45/// used to retrieve the data when the identifier is found in the format string.
46///
47/// The whole approach is useful in cases where an application wants to allow a customizable output
48/// format of data objects.
49///
50/// # Sample # {#alib_ns_strings_propertyformatter_sample}
51/// Let us assume, an application uses an enumeration and a simple struct:
52/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_1
53///
54/// In the application's configuration file, a custom output format for objects of type \b Person
55/// should be user-defined. We document to the user that she can use Python-style or
56/// Java-style output formats - extended by the ability to place the following three identifiers in
57/// the string:
58/// - \@name
59/// - \@age
60/// - \@hobby.
61///
62/// A possible format string then would be:
63///
64/// "{@name} is aged {@age} and his/her hobby is {@hobby}"
65///
66/// \note
67/// The custom identifiers might appear anywhere in the format string. But as sampled above,
68/// placing them in directly in the formatter replacement fields, makes the string very well
69/// readable. Also, it is important to have exactly one identifier for each replacement field,
70/// which this notation of course supports well.
71///
72/// To tell this class how to retrieve the replacement values, we need to define three callback
73/// functions:
74/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_2
75/// It is a good idea to place the callback functions in an anonymous (sub-) namespace as they
76/// are only referred to once (in the next step).<br>
77/// As this sample is very trivial, the second parameter <c>AString&</c> is not used and named.
78/// Details on the purpose and use of this parameter is addressed
79/// \ref alib_ns_strings_propertyformatter_callbacks "below".
80///
81/// As a next step, these functions need to be collected together in a "translation table".
82/// The table primarily holds a string denoting the replacement identifier and a pointer to the
83/// corresponding callback function. For convenience, the table type is provided with <c>using</c>
84/// definition #TCallbackTable.
85///
86/// In our sample, the definition of the table looks like this:
87/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_3
88///
89/// This is all we need! Of course, an external declaration of our table \b PersonCallbacks
90/// should be placed somewhere in the project's header-file. With this, a code like this may now use
91/// the custom formatter strings:
92/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_4
93///
94/// Running the code above produces the following output:
95/// \verbinclude "DOX_STRINGS_PROPERTY_FORMATTER.txt"
96///
97/// Serializing objects in a custom format (e.g., a user could define its own \b JSon object output)
98/// should be the most obvious and frequent use case. And this is what the classes name suggests.
99/// Nevertheless, the callback methods might be more complex than just returning "properties" of
100/// objects. The next sections gives more details on the custom callbacks.
101///
102/// \I{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
103/// # Callback Functions # {#alib_ns_strings_propertyformatter_callbacks}
104/// The call back function's signature is defined with <c>using</c>-statement #TCallback which
105/// evaluates to
106///
107/// Box (*)(const Box&, AString&)
108///
109/// The return type is \ref alib::boxing::Box "Box", which allows the callback function to
110/// return objects of an arbitrary type, respectively all types that are equipped to be used
111/// with \alib formatters.
112///
113/// The first input parameter provides the data object passed to method #Format.
114/// If the callback functions are dedicated to a property formatter that receives a certain
115/// object type (what they usually are), the custom type can be straightly unboxed.
116///
117/// \note
118/// The name of the class, as well as the sample above, indicate that the data objects are
119/// simple objects with rather simple "properties" to read. While this is the usual use case,
120/// a user of this class might pass more complex objects, or even the root object of the
121/// application to the formatter. Then, the callback function may retrieve (or calculate)
122/// any data that the application provides.
123///
124/// The second parameter is an \b AString object which optionally can be used to assemble
125/// string objects in more complex callback methods. Note, that if this string is not
126/// empty after the callback invocation, the result is copied to a string buffer allocated
127/// in the heap memory. In this case, the box object returned by the callback is ignored
128/// and instead the copy of the string is passed to the formatter. If C++ string constants
129/// (e.g <c>"true"</c> are to be returned by the callbacks, those constants do not need
130/// to be copied to the buffer, as their memory is statically allocated. In other words,
131/// the \b %AString buffer provided in the second parameter is needed to be used
132/// only in cases that a string gets assembled in the callback function!
133///
134/// \I{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
135/// # Identifiers And The Escape Character '@' # {#alib_ns_strings_propertyformatter_escape}
136/// The escape character used to find custom identifiers in the format string is defined
137/// with parameter \p{ESCCharacter} of the constructor and defaults to \b '\@'.
138/// This escape character is searched in the format string. If found, the identifier is
139/// read by consuming alphabetic characters. Optionally, the end of a custom identifier can be
140/// marked with an additional escape character.
141/// Hence, the two format strings
142///
143/// "{@name}"
144/// "{@name@}"
145/// are both valid and equal.<br>
146///
147/// In case of
148/// \alib{format;FormatterPythonStyle;FormatterPythonStyle} format strings,
149/// it is a good idea to place the identifier right inside the brackets. It just looks very intuitive.
150/// However, these versions:
151///
152/// "@name{}"
153/// "{}@name"
154/// are also valid custom format strings.
155///
156/// In case of
157/// \alib{format;FormatterJavaStyle;FormatterJavaStyle}, which uses \b '\%'
158/// as its escape character, we consider the best option to put the custom identifier in front
159/// of each \b '\%' symbol. The string of the example given above would then look like this:
160///
161/// "@name%s is aged @age%d and his/her hobby is @hobby%s"
162/// Doing it this way, the \b '\%' symbol acts as a very natural delimiter for the custom identifier.
163///
164/// Furthermore, field #IdentifierEntry::MinimumRecognitionLength allows abbreviations of identifier
165/// names. It denotes the minimum number of characters to be* matched. As in the above sample a
166/// value of \c 1 is provided, each identifier of the custom format string can be abbreviated down
167/// to one character. Consequently, the following format string samples are all equal and allowed:
168///
169/// "{@name}"
170/// "{@nam}"
171/// "{@na}"
172/// "{@n}"
173///
174/// Finally, to insert the escape character itself into the format string, it has to be doubly
175/// inserted (<c>"@@"</c>).
176///
177/// \I{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
178/// # Alternative # {#alib_ns_strings_propertyformatter_alternative}
179/// If \alib_expressions is compiled with the library, a utility class similar to this one
180/// is available with \alib{expressions::util;ExpressionFormatter}.
181/// With this, complex expressions and calculations might be used instead of only having simple
182/// identifiers as replacements.
183///
184/// \I{#############################################################################################}
185/// # Reference Documentation #
186/// @throws #alib::format::FMTExceptions::UnknownPropertyInFormatString \I{CLANGDUMMY}
187//==================================================================================================
189{
190 public:
191 /// The signature of the callback functions.
192 /// See \ref alib_ns_strings_propertyformatter_callbacks for more information.
193 using TCallback= Box (*)(const Box&, AString&);
194
195 /// The entry type of translation table.
197 {
198 /// The identifier string to search in the original format string.
200
201 /// The minimum characters of the identifier to read in the format string.
202 /// If less or equal to zero, abbreviations are not allowed.
204
205 /// The callback function for this identifier.
206 /// See \ref alib_ns_strings_propertyformatter_callbacks.
208 };
209
210 /// Type definition of the callback table.
211 using TCallbackTable= std::vector<IdentifierEntry>;
212
213
214 protected:
215 /// Internal type definition for the list of callback table entries collected in the
216 /// constructor by parsing the extended format string.
217 using TCallbackResultTable= std::vector<const IdentifierEntry*>;
218
219 /// The formatter (as given in the constructor).
221
222 /// The original format string. Used only for exception information.
224
225 /// The resulting format string passed to \alib formatters.
227
228 /// The callback functions to receive the format data.
230
231 public:
232
233 //==========================================================================================
234 /// Constructor. Processes the given format string and builds internal structures
235 /// which are then used with invocations of method #Format.
236 ///
237 /// @param customFormatString The format string as described in the class documentation.
238 /// @param propertyTable Table with property identifier names and callback functions
239 /// to retrieve the property values.
240 /// @param formatter The formatter to use. Defaults to \c nullptr which selects
241 /// the \alib{format;Formatter::Default;default formatter}.
242 /// @param ESCCharacter The prefix used to search identifiers in
243 /// \p{customFormatString}.<br>
244 /// Defaults to <c>'@'</c>.
245 ///
246 /// @throws Exception \alib{format;FMTExceptions;FMTExceptions::UnknownPropertyInFormatString}.
247 //==========================================================================================
249 PropertyFormatter( const String customFormatString,
250 const TCallbackTable& propertyTable,
251 SPFormatter formatter = nullptr,
252 character ESCCharacter = '@' );
253
254 //==========================================================================================
255 /// Writes the formatted output of the properties of the given \p{TFormattable} object
256 /// to a given \p{target} string.
257 ///
258 /// @param target The target string to write into.
259 /// @param src The custom object which is passed to the callback methods to collect
260 /// the formatter arguments.
261 //==========================================================================================
263 void Format( AString& target, const Box& src );
264}; // class PropertyFormatter
265
266} // namespace alib[::format]
267
268/// Type alias in namespace \b alib.
270
271} // namespace [alib]
272
TCallbackResultTable callBacks
The callback functions to receive the format data.
Box(*)(const Box &, AString &) TCallback
AString formatString
The resulting format string passed to ALib formatters.
SPFormatter stdFormatter
The formatter (as given in the constructor).
std::vector< IdentifierEntry > TCallbackTable
Type definition of the callback table.
ALIB_DLL PropertyFormatter(const String customFormatString, const TCallbackTable &propertyTable, SPFormatter formatter=nullptr, character ESCCharacter='@')
AString propertyFormatString
The original format string. Used only for exception information.
ALIB_DLL void Format(AString &target, const Box &src)
std::vector< const IdentifierEntry * > TCallbackResultTable
#define ALIB_DLL
Definition alib.inl:496
#define ALIB_EXPORT
Definition alib.inl:488
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
format::PropertyFormatter PropertyFormatter
Type alias in namespace alib.
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1216
containers::SharedPtr< format::Formatter > SPFormatter
Definition formatter.inl:42
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2381
characters::character character
Type alias in namespace alib.
String Name
The identifier string to search in the original format string.