Better syntax for listing indexing terms inside an index paragraph tag attribute.
authorjonas
Mon, 08 Jun 2009 15:15:46 +0000
changeset 3171 c94c900d9263
parent 3170 91786d2240d0
child 3172 425aa215185f
Better syntax for listing indexing terms inside an index paragraph tag attribute.
src/reportlab/lib/utils.py
src/reportlab/platypus/tableofcontents.py
tests/test_platypus_index.py
--- a/src/reportlab/lib/utils.py	Thu Jun 04 15:27:28 2009 +0000
+++ b/src/reportlab/lib/utils.py	Mon Jun 08 15:15:46 2009 +0000
@@ -1021,3 +1021,49 @@
     except StopIteration:
         pass
     return itertools.izip(prev, this, next)
+
+def commasplit(s):
+    '''
+    Splits the string s at every unescaped comma and returns the result as a list.
+    To escape a comma, double it. Individual items are stripped.
+    To avoid the ambiguity of 3 successive commas to denote a comma at the beginning
+    or end of an item, add a space between the item seperator and the escaped comma.
+    
+    >>> commasplit('a,b,c')
+    ['a', 'b', 'c']
+    >>> commasplit('a,, , b , c    ')
+    ['a,', 'b', 'c']
+    >>> commasplit('a, ,,b, c')
+    ['a', ',b', 'c']
+    '''
+    n = len(s)-1
+    s += ' '
+    i = 0
+    r=['']
+    while i<=n:
+        if s[i]==',':
+            if s[i+1]==',':
+                r[-1]+=','
+                i += 1
+            else:
+                r[-1] = r[-1].strip()
+                if i!=n: r.append('')
+        else:
+            r[-1] += s[i]
+        i+=1
+    r[-1] = r[-1].strip()
+    return r
+    
+def commajoin(l):
+    '''
+    Inverse of commasplit, except that whitespace around items is not conserved.
+    Adds more whitespace than needed for simplicity and performance.
+    
+    >>> commasplit(commajoin(['a', 'b', 'c']))
+    ['a', 'b', 'c']
+    >>> commasplit((commajoin(['a,', ' b ', 'c']))
+    ['a,', 'b', 'c']
+    >>> commasplit((commajoin(['a ', ',b', 'c']))
+    ['a', ',b', 'c']    
+    '''
+    return ','.join([ ' ' + i.replace(',', ',,') + ' ' for i in l ])
--- a/src/reportlab/platypus/tableofcontents.py	Thu Jun 04 15:27:28 2009 +0000
+++ b/src/reportlab/platypus/tableofcontents.py	Mon Jun 08 15:15:46 2009 +0000
@@ -46,6 +46,7 @@
 
 from reportlab.lib import enums
 from reportlab.lib.units import cm
+from reportlab.lib.utils import commasplit
 from reportlab.lib.styles import ParagraphStyle
 from reportlab.platypus.paragraph import Paragraph
 from reportlab.platypus.doctemplate import IndexingFlowable
@@ -295,16 +296,12 @@
         self.name = name
 
     def __call__(self,canv,kind,label):
-        label = unquote(label)
-        try:
-            label = eval(label,{'__builtins__':{}})
-        except (NameError, SyntaxError):
-            label = makeTuple(label)
-        key = 'ix_%s_%s_p_%s' % (self.name,','.join(label), canv.getPageNumber())
+        terms = commasplit(label)
+        key = 'ix_%s_%s_p_%s' % (self.name, label, canv.getPageNumber())
 
         info = canv._curr_tx_info
         canv.bookmarkHorizontal(key, info['cur_x'], info['cur_y'] + info['leading'])
-        self.addEntry(label, canv.getPageNumber(), key)
+        self.addEntry(terms, canv.getPageNumber(), key)
 
     def getCanvasMaker(self, canvasmaker=canvas.Canvas):
 
--- a/tests/test_platypus_index.py	Thu Jun 04 15:27:28 2009 +0000
+++ b/tests/test_platypus_index.py	Mon Jun 08 15:15:46 2009 +0000
@@ -10,6 +10,7 @@
 from math import sqrt
 import unittest
 from reportlab.lib.units import cm
+from reportlab.lib.utils import commajoin
 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
 from reportlab.platypus.paragraph import Paragraph
 from reportlab.platypus.xpreformatted import XPreformatted
@@ -78,6 +79,7 @@
         '''
         Test case for Indexes. This will draw an index %sat the end of the
         document with dots seperating the indexing terms from the page numbers.
+        Index terms are grouped by their first 2, and first 3 characters.
         The page numbers should be clickable and link to the indexed word.
         '''
         # Build story.
@@ -95,7 +97,7 @@
     
             for i in range(20):
                 words = randomtext.randomText(randomtext.PYTHON, 5).split(' ')
-                txt = ' '.join([(len(w) > 5 and '<onDraw name="_indexAdd" label=%s/>%s' % (quoteattr(repr(w)), w) or w) for w in words])
+                txt = ' '.join([(len(w) > 5 and '<index item=%s/>%s' % (quoteattr(commajoin([w[:2], w[:3], w])), w) or w) for w in words])
                 para = Paragraph(txt, makeBodyStyle())
                 story.append(para)
             story.append(index)