Hello, I'm back with round 2 of QStringFormatter
=====

The WIP is still located over here:
https://codereview.qt-project.org/#/c/192873/

Name
-----

I think it would be nice to change the class' name as typing
QStringFormatter repeatedly is fairly cumbersome. One suggestion was
QFormat (unless it's already used, though I haven't seen any uses
from searching). If there're no objections or other suggestions then
I will rename the class.

API
-----

Changes since I last wrote about QStringFormatter on the mailing list:

- the in-string formatting's separator was changed from '$' to ':' to
  match other string formatting APIs.
- ::multiArg was introduced
  - Variadic template which simply forwards each parameter to a
    separate ::arg-call
  - Currently returns a QString directly. Should it return
    QStringFormatter& like ::arg?
- Static function ::format
  - Another variadic template, instantiates QStringFormatter and
    forwards arguments to multiArg
    - example:
      `QStringFormatter::format("{} {}", "Hello,", "World!");`
    - Remove? Nice to have?
- (QStringFormatter::)Formatting
  - ::arg methods have an optional Formatting argument which can be
    used to override or augment any previously specified in-string
    formatting
  - Can be constructed from a string of formatting options
    (e.g. "L<10") or using its methods (e.g. setLocale,
    setJustification)
- Named replacements uses an alias for QPair<QString, T> called
  Argument.
  - e.g. `QStringFormatter("Hello, {Name}").arg({"Name", "World"});`
  - A qMakePair-style function called `qArg` for use in
    situations with template argument deduction trouble.
    - e.g.
`QStringFormatter("Hello, {Name}").arg(QStringFormatter::qArg("Name", 47));`

Any feedback on API is appreciated. A proposal for the API for
formatting custom types follows.

Replacement format
-----

The replacement options now have formatting features matching
QString::arg. The current options (open to change) are:

- `L` for localization (localize numbers, like in QString::arg)
- `</>/=` for justification. Left, right and center justification
  - Followed by an optional padding character (excluding 1-9)
  - Followed by field-width
  - e.g. "==16" (pad using '=', centered, field-width 16),
    "<10" (left-justify using spaces, field-width 10),
    ">-3" (right-justify using '-', field-width 3)
- `f/g/G/e/E` for floating-point number formatting
  (https://doc.qt.io/qt-5/qstring.html#argument-formats)
  - followed by a dot and then precision
  - e.g. "f.2"
- `b/B` for setting base. Supports bases 2-36. Using 'b' produces
  lower-case letters for digits 10-35, and 'B' produces upper-case.
  For bases 2-10 they make no difference.
- `:` everything after the colon gets put into an 'extra' field, more
  on this later..
  - e.g. `{:<10:this is the extra field}`
  - or `{::yyyy-MM-dd HH:mm:ss}`

Currently the formatting options can come in any order (e.g. "L<10"
and "<10L" does the same, the only exception being ':').
However it would be good to enforce some sort of order for the sake
of consistency. With a defined order we could also change
justification format from [<>=]cn to c[<>=]n, which would allow
people to use 1-9 as a fill-character. If this is done, what should
the order be like?

QString::arg compatibility
-----

Currently QString::arg compatibility is activated using a parameter
in the constructor. All this does is let you use %nn style tokens and
'disable' use of the brace-style tokens. It also supports `%L` to
enable localization of numbers, but any other formatting must be done
using the `QStringFormatter::Formatting` class.

API for formatting custom types
-----

One idea I've been experimenting with a little bit is using template
specialization to deal with formatting custom types. To support a
custom type you'd create a specialization of a struct called
`Formatter`. It would use the `extra` field in `Formatting` which
you could optionally parse for custom formatting options. The parser
would be a separate class inheriting `Formatting` and be specified in
the Formatter using a typedef.

E.g.
`struct QStringFormatter::Formatter<QDateTime>
{
typedef DateTimeInfo FormatType;
QString operator()(const QDateTime &dateTime, const FormatType &format);
}`

`QStringFormatter` will then instantiate this struct when it receives
a `QDateTime` object, and create a `FormatType` object to parse the
data located in the `extra` field of formatting options. The
`FormatType` object is then expected to store whatever info it needs
and then the `Formatter` will use it later.

Feedback on the approach, pitfalls etc. is much appreciated!

Thanks,

-- Mårten Nordheim
_______________________________________________
Development mailing list
Development@qt-project.org
http://lists.qt-project.org/mailman/listinfo/development

Reply via email to