From af4ac6889b98feccdfeabd3d82fe8fa7e717be35 Mon Sep 17 00:00:00 2001 From: Petr Šplíchal Date: Sat, 21 Apr 2012 23:50:06 +0200 Subject: Smarter implementation of the listed() function --- source/api.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/source/api.py b/source/api.py index c16110b..38993b5 100644 --- a/source/api.py +++ b/source/api.py @@ -227,10 +227,56 @@ def _setter(field): # Various Utilities # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -def listed(items, quote=""): - """ Convert provided iterable into a nice, human readable list. """ +def listed(items, singular=None, plural=None, max=None, quote=""): + """ + Convert an iterable into a nice, human readable list or description. + + listed(range(1)) .................... 0 + listed(range(2)) .................... 0 and 1 + listed(range(3), quote='"') ......... "0", "1" and "2" + listed(range(4), max=3) ............. 0, 1, 2 and 1 more + listed(range(5), 'number', max=3) ... 0, 1, 2 and 2 more numbers + listed(range(6), 'category') ........ 6 categories + listed(7, "leaf", "leaves") ......... 7 leaves + + If singular form is provided but max not set the description-only + mode is activated as shown in the last two examples. Also, an int + can be used in this case to get a simple inflection functionality. + """ + + # Convert items to list if necessary + if isinstance(items, int): + items = range(items) + elif not isinstance(items, list): + items = list(items) + more = " more" + # Description mode expected when singular provided but no maximum set + if singular is not None and max is None: + max = 0 + more = "" + # Set the default plural form + if singular is not None and plural is None: + if singular.endswith("y"): + plural = singular[:-1] + "ies" + else: + plural = singular + "s" + # Convert to strings and optionally quote each item items = ["{0}{1}{0}".format(quote, item) for item in items] + # Select the maximum of items and describe the rest if max provided + if max is not None: + # Special case when the list is empty (0 items) + if max == 0 and len(items) == 0: + return "0 {0}".format(plural) + # Cut the list if maximum exceeded + if len(items) > max: + rest = len(items[max:]) + items = items[:max] + if singular is not None: + more += " {0}".format(singular if rest == 1 else plural) + items.append("{0}{1}".format(rest, more)) + + # For two and more items use 'and' instead of the last comma if len(items) < 2: return "".join(items) else: @@ -412,6 +458,22 @@ class Nitrate(object): """ Fetch object data from the server. """ raise NitrateError("To be implemented by respective class") + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # Nitrate Self Test + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + class _test(unittest.TestCase): + def test_listed(self): + """ Function listed() sanity """ + self.assertEqual(listed(range(1)), "0") + self.assertEqual(listed(range(2)), "0 and 1") + self.assertEqual(listed(range(3), quote='"'), '"0", "1" and "2"') + self.assertEqual(listed(range(4), max=3), "0, 1, 2 and 1 more") + self.assertEqual(listed(range(5), 'number', max=3), + "0, 1, 2 and 2 more numbers") + self.assertEqual(listed(range(6), 'category'), "6 categories") + self.assertEqual(listed(7, "leaf", "leaves"), "7 leaves") + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Build Class -- cgit