This commit is contained in:
Kovid Goyal 2024-11-15 16:18:26 +05:30
commit e16a167f72
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 64 additions and 51 deletions

View File

@ -166,31 +166,44 @@ Functions are evaluated before format specifications and the prefix/suffix. See
**Do not use subtemplates (`{ ... }`) as function arguments.** Instead, use :ref:`Template Program Mode <template_mode>` and :ref:`General Program Mode <general_mode>`. **Do not use subtemplates (`{ ... }`) as function arguments.** Instead, use :ref:`Template Program Mode <template_mode>` and :ref:`General Program Mode <general_mode>`.
Some functions require regular expressions. In the template language regular expression matching is case-insensitive. Notes on calling functions in Single Function Mode:
In the function documentation below, the notation ``[something]*`` means that ``something`` can be repeated zero or more times. The notation ``[something]+`` means that the ``something`` is repeated one or more times (must exist at least one time). * When functions are used in Single Function Mode, the first parameter, ``value``, is automatically replaced by the content of the field specified in the template. For example, when the template ``{title:capitalize()}`` is processed, the content of the ``title`` field is passed as the parameter ``value`` to the capitalize function.
* In the function documentation, the notation ``[something]*`` means that ``something`` can be repeated zero or more times. The notation ``[something]+`` means that the ``something`` is repeated one or more times (must exist at least one time).
The functions intended for use in Single Function Mode are: * Some functions use regular expressions. In the template language regular expression matching is case-insensitive.
The following functions can be used in Single Function Mode because their first parameter is ``value``.
* :ffdoc:`capitalize` * :ffdoc:`capitalize`
* :ffdoc:`ceiling`
* :ffdoc:`cmp`
* :ffdoc:`contains` * :ffdoc:`contains`
* :ffdoc:`list_count` * :ffdoc:`date_arithmetic`
* :ffdoc:`floor`
* :ffdoc:`format_date`
* :ffdoc:`format_number` * :ffdoc:`format_number`
* :ffdoc:`fractional_part`
* :ffdoc:`human_readable` * :ffdoc:`human_readable`
* :ffdoc:`ifempty` * :ffdoc:`ifempty`
* :ffdoc:`list_contains`
* :ffdoc:`language_strings` * :ffdoc:`language_strings`
* :ffdoc:`list_contains`
* :ffdoc:`list_count`
* :ffdoc:`list_count_matching`
* :ffdoc:`list_item` * :ffdoc:`list_item`
* :ffdoc:`list_sort`
* :ffdoc:`lookup` * :ffdoc:`lookup`
* :ffdoc:`lowercase` * :ffdoc:`lowercase`
* :ffdoc:`mod`
* :ffdoc:`rating_to_stars` * :ffdoc:`rating_to_stars`
* :ffdoc:`re` * :ffdoc:`re`
* :ffdoc:`re_group`
* :ffdoc:`round`
* :ffdoc:`select` * :ffdoc:`select`
* :ffdoc:`shorten` * :ffdoc:`shorten`
* :ffdoc:`str_in_list` * :ffdoc:`str_in_list`
* :ffdoc:`subitems` * :ffdoc:`subitems`
* :ffdoc:`sublist` * :ffdoc:`sublist`
* :ffdoc:`substr`
* :ffdoc:`swap_around_articles` * :ffdoc:`swap_around_articles`
* :ffdoc:`swap_around_comma` * :ffdoc:`swap_around_comma`
* :ffdoc:`switch` * :ffdoc:`switch`

View File

@ -300,18 +300,18 @@ class BuiltinCmp(BuiltinFormatterFunction):
arg_count = 5 arg_count = 5
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``cmp(x, y, lt, eq, gt)`` -- compares ``x`` and ``y`` after converting both to ``cmp(value, y, lt, eq, gt)`` -- compares ``value`` and ``y`` after converting both to
numbers. Returns ``lt`` if ``x <# y``, ``eq`` if ``x ==# y``, otherwise ``gt``. numbers. Returns ``lt`` if ``value <# y``, ``eq`` if ``value ==# y``, otherwise ``gt``.
This function can usually be replaced with one of the numeric compare operators This function can usually be replaced with one of the numeric compare operators
(``==#``, ``<#``, ``>#``, etc). (``==#``, ``<#``, ``>#``, etc).
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt): def evaluate(self, formatter, kwargs, mi, locals, value, y, lt, eq, gt):
x = float(x if x and x != 'None' else 0) value = float(value if value and value != 'None' else 0)
y = float(y if y and y != 'None' else 0) y = float(y if y and y != 'None' else 0)
if x < y: if value < y:
return lt return lt
if x == y: if value == y:
return eq return eq
return gt return gt
@ -458,13 +458,13 @@ class BuiltinCeiling(BuiltinFormatterFunction):
category = 'Arithmetic' category = 'Arithmetic'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``ceiling(x)`` -- returns the smallest integer greater than or equal to ``x``. ``ceiling(value)`` -- returns the smallest integer greater than or equal to ``value``.
Throws an exception if ``x`` is not a number. Throws an exception if ``value`` is not a number.
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, x): def evaluate(self, formatter, kwargs, mi, locals, value):
x = float(x if x and x != 'None' else 0) value = float(value if value and value != 'None' else 0)
return str(int(ceil(x))) return str(int(ceil(value)))
class BuiltinFloor(BuiltinFormatterFunction): class BuiltinFloor(BuiltinFormatterFunction):
@ -473,13 +473,13 @@ class BuiltinFloor(BuiltinFormatterFunction):
category = 'Arithmetic' category = 'Arithmetic'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``floor(x)`` -- returns the largest integer less than or equal to ``x``. Throws ``floor(value)`` -- returns the largest integer less than or equal to ``value``. Throws
an exception if ``x`` is not a number. an exception if ``value`` is not a number.
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, x): def evaluate(self, formatter, kwargs, mi, locals, value):
x = float(x if x and x != 'None' else 0) value = float(value if value and value != 'None' else 0)
return str(int(floor(x))) return str(int(floor(value)))
class BuiltinRound(BuiltinFormatterFunction): class BuiltinRound(BuiltinFormatterFunction):
@ -488,13 +488,13 @@ class BuiltinRound(BuiltinFormatterFunction):
category = 'Arithmetic' category = 'Arithmetic'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``round(x)`` -- returns the nearest integer to ``x``. Throws an exception if ``round(value)`` -- returns the nearest integer to ``value``. Throws an exception if
``x`` is not a number. ``value`` is not a number.
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, x): def evaluate(self, formatter, kwargs, mi, locals, value):
x = float(x if x and x != 'None' else 0) value = float(value if value and value != 'None' else 0)
return str(int(round(x))) return str(int(round(value)))
class BuiltinMod(BuiltinFormatterFunction): class BuiltinMod(BuiltinFormatterFunction):
@ -503,14 +503,14 @@ class BuiltinMod(BuiltinFormatterFunction):
category = 'Arithmetic' category = 'Arithmetic'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``mod(x, y)`` -- returns the ``floor`` of the remainder of ``x / y``. Throws an ``mod(value, y)`` -- returns the ``floor`` of the remainder of ``value / y``. Throws an
exception if either ``x`` or ``y`` is not a number. exception if either ``value`` or ``y`` is not a number.
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, x, y): def evaluate(self, formatter, kwargs, mi, locals, value, y):
x = float(x if x and x != 'None' else 0) value = float(value if value and value != 'None' else 0)
y = float(y if y and y != 'None' else 0) y = float(y if y and y != 'None' else 0)
return str(int(x % y)) return str(int(value % y))
class BuiltinFractionalPart(BuiltinFormatterFunction): class BuiltinFractionalPart(BuiltinFormatterFunction):
@ -524,9 +524,9 @@ point. For example, ``fractional_part(3.14)`` returns ``0.14``. Throws an
exception if ``value`` is not a number. exception if ``value`` is not a number.
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, x): def evaluate(self, formatter, kwargs, mi, locals, value):
x = float(x if x and x != 'None' else 0) value = float(value if value and value != 'None' else 0)
return str(modf(x)[0]) return str(modf(value)[0])
class BuiltinTemplate(BuiltinFormatterFunction): class BuiltinTemplate(BuiltinFormatterFunction):
@ -701,16 +701,16 @@ class BuiltinSubstr(BuiltinFormatterFunction):
category = 'String manipulation' category = 'String manipulation'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``substr(str, start, end)`` -- returns the ``start``'th through the ``end``'th ``substr(value, start, end)`` -- returns the ``start``'th through the ``end``'th
characters of ``str``. The first character in ``str`` is the zero'th character. characters of ``value``. The first character in ``value`` is the zero'th character.
If ``end`` is negative then it indicates that many characters counting from the If ``end`` is negative then it indicates that many characters counting from the
right. If ``end`` is zero, then it indicates the last character. For example, right. If ``end`` is zero, then it indicates the last character. For example,
``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)`` ``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)``
returns ``'234'``. returns ``'234'``.
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, str_, start_, end_): def evaluate(self, formatter, kwargs, mi, locals, value, start_, end_):
return str_[int(start_): len(str_) if int(end_) == 0 else int(end_)] return value[int(start_): len(value) if int(end_) == 0 else int(end_)]
class BuiltinLookup(BuiltinFormatterFunction): class BuiltinLookup(BuiltinFormatterFunction):
@ -1130,16 +1130,16 @@ class BuiltinListCountMatching(BuiltinFormatterFunction):
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``list_count_matching(list, pattern, separator)`` -- interprets ``list`` as a ``list_count_matching(value, pattern, separator)`` -- interprets ``value`` as a
list of items separated by ``separator``, returning the number of items in the list of items separated by ``separator``, returning the number of items in the
list that match the regular expression ``pattern``. list that match the regular expression ``pattern``.
Aliases: ``list_count_matching()``, ``count_matching()`` Aliases: ``list_count_matching()``, ``count_matching()``
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, list_, pattern, sep): def evaluate(self, formatter, kwargs, mi, locals, value, pattern, sep):
res = 0 res = 0
for v in [x.strip() for x in list_.split(sep) if x.strip()]: for v in [x.strip() for x in value.split(sep) if x.strip()]:
if re.search(pattern, v, flags=re.I): if re.search(pattern, v, flags=re.I):
res += 1 res += 1
return str(res) return str(res)
@ -1998,14 +1998,14 @@ class BuiltinListSort(BuiltinFormatterFunction):
category = 'List manipulation' category = 'List manipulation'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``list_sort(list, direction, separator)`` -- return ``list`` sorted using a ``list_sort(value, direction, separator)`` -- return ``value`` sorted using a
case-insensitive lexical sort. If ``direction`` is zero (number or character), case-insensitive lexical sort. If ``direction`` is zero (number or character),
``list`` is sorted ascending, otherwise descending. The list items are separated ``value`` is sorted ascending, otherwise descending. The list items are separated
by ``separator``, as are the items in the returned list. by ``separator``, as are the items in the returned list.
''') ''')
def evaluate(self, formatter, kwargs, mi, locals, list1, direction, separator): def evaluate(self, formatter, kwargs, mi, locals, value, direction, separator):
res = [l.strip() for l in list1.split(separator) if l.strip()] res = [l.strip() for l in value.split(separator) if l.strip()]
if separator == ',': if separator == ',':
return ', '.join(sorted(res, key=sort_key, reverse=direction != "0")) return ', '.join(sorted(res, key=sort_key, reverse=direction != "0"))
return separator.join(sorted(res, key=sort_key, reverse=direction != "0")) return separator.join(sorted(res, key=sort_key, reverse=direction != "0"))
@ -2150,7 +2150,7 @@ class BuiltinDateArithmetic(BuiltinFormatterFunction):
category = 'Date functions' category = 'Date functions'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``date_arithmetic(date, calc_spec, fmt)`` -- Calculate a new date from ``date`` ``date_arithmetic(value, calc_spec, fmt)`` -- Calculate a new date from ``value``
using ``calc_spec``. Return the new date formatted according to optional using ``calc_spec``. Return the new date formatted according to optional
``fmt``: if not supplied then the result will be in ISO format. The calc_spec is ``fmt``: if not supplied then the result will be in ISO format. The calc_spec is
a string formed by concatenating pairs of ``vW`` (``valueWhat``) where ``v`` is a string formed by concatenating pairs of ``vW`` (``valueWhat``) where ``v`` is
@ -2175,9 +2175,9 @@ Example: ``'1s3d-1m'`` will add 1 second, add 3 days, and subtract 1 minute from
'y': lambda v: timedelta(days=v * 365), 'y': lambda v: timedelta(days=v * 365),
} }
def evaluate(self, formatter, kwargs, mi, locals, date, calc_spec, fmt=None): def evaluate(self, formatter, kwargs, mi, locals, value, calc_spec, fmt=None):
try: try:
d = parse_date(date) d = parse_date(value)
if d == UNDEFINED_DATE: if d == UNDEFINED_DATE:
return '' return ''
while calc_spec: while calc_spec:
@ -2202,11 +2202,11 @@ class BuiltinLanguageStrings(BuiltinFormatterFunction):
category = 'Get values from metadata' category = 'Get values from metadata'
__doc__ = doc = _( __doc__ = doc = _(
r''' r'''
``language_strings(lang_codes, localize)`` -- return the ``language_strings(value, localize)`` -- return the
language names for the language codes language names for the language codes
([URL href="https://www.loc.gov/standards/iso639-2/php/code_list.php"] ([URL href="https://www.loc.gov/standards/iso639-2/php/code_list.php"]
see here for names and codes[/URL]) see here for names and codes[/URL])
passed in ``lang_codes``. Example: ``{languages:language_strings()}``. passed in ``value``. Example: ``{languages:language_strings()}``.
If ``localize`` is zero, return the strings in English. If ``localize`` is not zero, If ``localize`` is zero, return the strings in English. If ``localize`` is not zero,
return the strings in the language of the current locale. ``lang_codes`` is a comma-separated list. return the strings in the language of the current locale. ``lang_codes`` is a comma-separated list.
''') ''')