[formatter] implement 'C' format specifier (#5647)
to apply a conversion after ':' or
to apply multiple conversions
for example {tags:CSl} or {tags:J - /Cl}
to convert list to string and lowercase it
This commit is contained in:
@@ -192,6 +192,12 @@ Format specifiers can be used for advanced formatting by using the options provi
|
|||||||
<td><code>{foo:Ro/()/}</code></td>
|
<td><code>{foo:Ro/()/}</code></td>
|
||||||
<td><code>F()() Bar</code></td>
|
<td><code>F()() Bar</code></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>C<conversion(s)>/</code></td>
|
||||||
|
<td>Apply <a href="#conversions">Conversions</a> to the current value</td>
|
||||||
|
<td><code>{tags:CSgc/}</code></td>
|
||||||
|
<td><code>"Sun-tree-water"</code></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>S<order>/</code></td>
|
<td><code>S<order>/</code></td>
|
||||||
<td>Sort a list. <code><order></code> can be either <strong>a</strong>scending or <strong>d</strong>escending/<strong>r</strong>everse. (default: <strong>a</strong>)</td>
|
<td>Sort a list. <code><order></code> can be either <strong>a</strong>scending or <strong>d</strong>escending/<strong>r</strong>everse. (default: <strong>a</strong>)</td>
|
||||||
|
|||||||
@@ -325,6 +325,26 @@ def _parse_slice(format_spec, default):
|
|||||||
return apply_slice
|
return apply_slice
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_conversion(format_spec, default):
|
||||||
|
conversions, _, format_spec = format_spec.partition(_SEPARATOR)
|
||||||
|
convs = [_CONVERSIONS[c] for c in conversions[1:]]
|
||||||
|
fmt = _build_format_func(format_spec, default)
|
||||||
|
|
||||||
|
if len(conversions) <= 2:
|
||||||
|
|
||||||
|
def convert_one(obj):
|
||||||
|
return fmt(conv(obj))
|
||||||
|
conv = _CONVERSIONS[conversions[1]]
|
||||||
|
return convert_one
|
||||||
|
|
||||||
|
def convert_many(obj):
|
||||||
|
for conv in convs:
|
||||||
|
obj = conv(obj)
|
||||||
|
return fmt(obj)
|
||||||
|
convs = [_CONVERSIONS[c] for c in conversions[1:]]
|
||||||
|
return convert_many
|
||||||
|
|
||||||
|
|
||||||
def _parse_maxlen(format_spec, default):
|
def _parse_maxlen(format_spec, default):
|
||||||
maxlen, replacement, format_spec = format_spec.split(_SEPARATOR, 2)
|
maxlen, replacement, format_spec = format_spec.split(_SEPARATOR, 2)
|
||||||
maxlen = text.parse_int(maxlen[1:])
|
maxlen = text.parse_int(maxlen[1:])
|
||||||
@@ -447,6 +467,7 @@ _CONVERSIONS = {
|
|||||||
_FORMAT_SPECIFIERS = {
|
_FORMAT_SPECIFIERS = {
|
||||||
"?": _parse_optional,
|
"?": _parse_optional,
|
||||||
"[": _parse_slice,
|
"[": _parse_slice,
|
||||||
|
"C": _parse_conversion,
|
||||||
"D": _parse_datetime,
|
"D": _parse_datetime,
|
||||||
"L": _parse_maxlen,
|
"L": _parse_maxlen,
|
||||||
"J": _parse_join,
|
"J": _parse_join,
|
||||||
|
|||||||
@@ -267,6 +267,11 @@ class TestFormatter(unittest.TestCase):
|
|||||||
"{a:Sort-reverse}", # starts with 'S', contains 'r'
|
"{a:Sort-reverse}", # starts with 'S', contains 'r'
|
||||||
"['w', 'r', 'o', 'l', 'h', 'd', 'O', 'L', 'L', 'E', ' ']")
|
"['w', 'r', 'o', 'l', 'h', 'd', 'O', 'L', 'L', 'E', ' ']")
|
||||||
|
|
||||||
|
def test_specifier_conversions(self):
|
||||||
|
self._run_test("{a:Cl}" , "hello world")
|
||||||
|
self._run_test("{h:CHC}" , "Foo & Bar")
|
||||||
|
self._run_test("{l:CSulc}", "A, b, c")
|
||||||
|
|
||||||
def test_chain_special(self):
|
def test_chain_special(self):
|
||||||
# multiple replacements
|
# multiple replacements
|
||||||
self._run_test("{a:Rh/C/RE/e/RL/l/}", "Cello wOrld")
|
self._run_test("{a:Rh/C/RE/e/RL/l/}", "Cello wOrld")
|
||||||
|
|||||||
Reference in New Issue
Block a user