From 26092878961330a089b2245387fc98a1036c9325 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 1 Aug 2011 09:25:45 +0100 Subject: [PATCH 1/2] New formatter functions: list_sort, list_difference, list_intersection. Make merge_lists not sort its result. --- src/calibre/utils/formatter_functions.py | 62 ++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py index 599769300f..79713c432c 100644 --- a/src/calibre/utils/formatter_functions.py +++ b/src/calibre/utils/formatter_functions.py @@ -507,7 +507,7 @@ class BuiltinSelect(BuiltinFormatterFunction): arg_count = 2 category = 'List Lookup' __doc__ = doc = _('select(val, key) -- interpret the value as a comma-separated list ' - 'of items, with the items being "id:value". Find the pair with the' + 'of items, with the items being "id:value". Find the pair with the ' 'id equal to key, and return the corresponding value.' ) @@ -851,7 +851,58 @@ class BuiltinMergeLists(BuiltinFormatterFunction): for i in l2: if icu_lower(i) not in lcl1: res.append(i) - return ', '.join(sorted(res, key=sort_key)) + return ', '.join(res) + +class BuiltinListDifference(BuiltinFormatterFunction): + name = 'list_difference' + arg_count = 3 + category = 'List Manipulation' + __doc__ = doc = _('list_difference(list1, list2, separator) -- ' + 'return a list made by removing from list1 any item found in list2, ' + 'using a case-insensitive compare. The items in list1 and list2 ' + 'are separated by separator, as are the items in the returned list.') + + def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator): + l1 = [l.strip() for l in list1.split(separator) if l.strip()] + l2 = [icu_lower(l.strip()) for l in list2.split(separator) if l.strip()] + + res = [] + for i in l1: + if icu_lower(i) not in l2: + res.append(i) + return ', '.join(res) + +class BuiltinListIntersection(BuiltinFormatterFunction): + name = 'list_intersection' + arg_count = 3 + category = 'List Manipulation' + __doc__ = doc = _('list_intersection(list1, list2, separator) -- ' + 'return a list made by removing from list1 any item not found in list2, ' + 'using a case-insensitive compare. The items in list1 and list2 ' + 'are separated by separator, as are the items in the returned list.') + + def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator): + l1 = [l.strip() for l in list1.split(separator) if l.strip()] + l2 = [icu_lower(l.strip()) for l in list2.split(separator) if l.strip()] + + res = [] + for i in l1: + if icu_lower(i) in l2: + res.append(i) + return ', '.join(res) + +class BuiltinListSort(BuiltinFormatterFunction): + name = 'list_sort' + arg_count = 3 + category = 'List Manipulation' + __doc__ = doc = _('list_sort(list, direction, separator) -- ' + 'return list sorted using a case-insensitive sort. If direction is ' + 'zero, the list is sorted ascending, otherwise descending. The list items ' + 'are separated by separator, as are the items in the returned list.') + + def evaluate(self, formatter, kwargs, mi, locals, list1, direction, separator): + res = [l.strip() for l in list1.split(separator) if l.strip()] + return ', '.join(sorted(res, key=sort_key, reverse=direction != 0)) class BuiltinToday(BuiltinFormatterFunction): name = 'today' @@ -893,12 +944,13 @@ formatter_builtins = [ BuiltinFirstNonEmpty(), BuiltinField(), BuiltinFormatDate(), BuiltinFormatNumber(), BuiltinFormatsModtimes(), BuiltinFormatsSizes(), BuiltinHasCover(), BuiltinHumanReadable(), BuiltinIdentifierInList(), - BuiltinIfempty(), BuiltinInList(), BuiltinListitem(), BuiltinLookup(), + BuiltinIfempty(), BuiltinInList(), BuiltinListDifference(), + BuiltinListIntersection(), BuiltinListitem(), BuiltinListSort(), BuiltinLookup(), BuiltinLowercase(), BuiltinMergeLists(), BuiltinMultiply(), BuiltinNot(), BuiltinOndevice(), BuiltinOr(), BuiltinPrint(), BuiltinRawField(), BuiltinRe(), BuiltinSelect(), BuiltinShorten(), BuiltinStrcat(), - BuiltinStrcmp(), BuiltinStrInList(), BuiltinSubitems(), BuiltinSublist(), - BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundComma(), + BuiltinStrcmp(), BuiltinStrInList(), BuiltinSubitems(), + BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundComma(), BuiltinSwitch(), BuiltinTemplate(), BuiltinTest(), BuiltinTitlecase(), BuiltinToday(), BuiltinUppercase(), ] From 03e9e929838630a79256faa70f8ce1cb5b881a05 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 1 Aug 2011 09:31:52 +0100 Subject: [PATCH 2/2] Documentation for new functions. --- src/calibre/manual/template_lang.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/calibre/manual/template_lang.rst b/src/calibre/manual/template_lang.rst index 10c2c751f5..b452525848 100644 --- a/src/calibre/manual/template_lang.rst +++ b/src/calibre/manual/template_lang.rst @@ -263,6 +263,9 @@ The following functions are available in addition to those described in single-f * ``formats_sizes()`` -- return a comma-separated list of colon_separated items representing sizes in bytes of the formats of a book. You can use the select function to get the size for a specific format. Note that format names are always uppercase, as in EPUB. * ``has_cover()`` -- return ``Yes`` if the book has a cover, otherwise return the empty string * ``not(value)`` -- returns the string "1" if the value is empty, otherwise returns the empty string. This function works well with test or first_non_empty. You can have as many values as you want. + * ``list_difference(list1, list2, separator)`` -- return a list made by removing from `list1` any item found in `list2`, using a case-insensitive compare. The items in `list1` and `list2` are separated by separator, as are the items in the returned list. + * ``list_intersection(list1, list2, separator)`` -- return a list made by removing from `list1` any item not found in `list2`, using a case-insensitive compare. The items in `list1` and `list2` are separated by separator, as are the items in the returned list. + * ``list_sort(list, direction, separator)`` -- return list sorted using a case-insensitive sort. If `direction` is zero, the list is sorted ascending, otherwise descending. The list items are separated by separator, as are the items in the returned list. * ``merge_lists(list1, list2, separator)`` -- return a list made by merging the items in list1 and list2, removing duplicate items using a case-insensitive compare. If items differ in case, the one in list1 is used. The items in list1 and list2 are separated by separator, as are the items in the returned list. * ``multiply(x, y)`` -- returns x * y. Throws an exception if either x or y are not numbers. * ``ondevice()`` -- return the string "Yes" if ondevice is set, otherwise return the empty string