[Checkins] SVN: manuel/trunk/src/manuel/ make the capture directive use the current indentation to determine how

Benji York benji at zope.com
Sat Aug 15 17:43:59 EDT 2009


Log message for revision 102842:
  make the capture directive use the current indentation to determine how
  much to capture
  

Changed:
  U   manuel/trunk/src/manuel/README.txt
  U   manuel/trunk/src/manuel/capture.py
  A   manuel/trunk/src/manuel/capture.txt
  U   manuel/trunk/src/manuel/tests.py

-=-
Modified: manuel/trunk/src/manuel/README.txt
===================================================================
--- manuel/trunk/src/manuel/README.txt	2009-08-15 20:43:56 UTC (rev 102841)
+++ manuel/trunk/src/manuel/README.txt	2009-08-15 21:43:58 UTC (rev 102842)
@@ -179,15 +179,15 @@
             result = region.evaluated
             if not result.passed:
                 region.formatted = (
-                    "the numbers aren't in sorted order: "
-                    + ', '.join(map(str, result.test.numbers)))
+                    "the numbers aren't in sorted order: %s\n"
+                    % ', '.join(map(str, result.test.numbers)))
 
 Since one of the test cases failed we get an appropriate message out of the
 formatter.
 
     >>> format(document)
     >>> [region.formatted for region in document]
-    [None, None, None, "the numbers aren't in sorted order: 3, 5, 1"]
+    [None, None, None, "the numbers aren't in sorted order: 3, 5, 1\n"]
 
 
 Manuel Objects
@@ -301,14 +301,15 @@
 create a single document that has both.
 
     >>> document = manuel.Document("""
-    ... We can test Python...
+    ... We can have a list of numbers...
     ...
+    ...     a very nice list: 3, 6, 2
+    ...
+    ... ... and we can test Python.
+    ...
     ...     >>> 1 + 1
     ...     42
     ...
-    ... ...and lists of numbers.
-    ...
-    ...     a very nice list: 3, 6, 2
     ... """)
 
 Obviously both of those tests will fail, but first we have to configure Manuel
@@ -332,10 +333,11 @@
 
     >>> for region in document:
     ...     print (region.lineno, region.parsed or region.source)
-    (1, '\nWe can test Python...\n\n')
-    (4, <doctest.Example instance at 0x...>)
-    (6, '\n...and lists of numbers.\n\n')
-    (9, <NumbersTest object at 0x...>)
+    (1, '\nWe can have a list of numbers...\n\n')
+    (4, <NumbersTest object at 0x...>)
+    (5, '\n... and we can test Python.\n\n')
+    (8, <doctest.Example instance at 0x...>)
+    (10, '\n')
 
 We can look at the formatted output to see that each of the two tests failed.
 
@@ -344,15 +346,15 @@
     ...         print '-'*70
     ...         print region.formatted,
     ----------------------------------------------------------------------
-    File "<memory>", line 4, in <memory>
+    the numbers aren't in sorted order: 3, 6, 2
+    ----------------------------------------------------------------------
+    File "<memory>", line 8, in <memory>
     Failed example:
         1 + 1
     Expected:
         42
     Got:
         2
-    ----------------------------------------------------------------------
-    the numbers aren't in sorted order:  3, 6, 2
 
 
 Priorities

Modified: manuel/trunk/src/manuel/capture.py
===================================================================
--- manuel/trunk/src/manuel/capture.py	2009-08-15 20:43:56 UTC (rev 102841)
+++ manuel/trunk/src/manuel/capture.py	2009-08-15 21:43:58 UTC (rev 102842)
@@ -3,7 +3,9 @@
 import string
 import textwrap
 
-CAPTURE_DIRECTIVE = re.compile(r'^\.\.\s*->\s*(?P<name>\S+).*$', re.MULTILINE)
+CAPTURE_DIRECTIVE = re.compile(
+    r'^(?P<indent>(\t| )*)\.\.\s*->\s*(?P<name>\S+).*$',
+    re.MULTILINE)
 
 
 class Capture(object):
@@ -11,15 +13,42 @@
         self.name = name
         self.block = block
 
+def normalize_whitespace(s):
+    return s.replace('\t', ' '*8) # turn tabs into spaces
 
+
 @manuel.timing(manuel.EARLY)
 def find_captures(document):
-    for region in document.find_regions(CAPTURE_DIRECTIVE):
+    while True:
+        regions = document.find_regions(CAPTURE_DIRECTIVE)
+        if not regions:
+            break
+        region = regions[-1]
         # note that start and end have different bases, "start" is the offset
         # from the begining of the region, "end" is a document line number
-        end = region.lineno-2
+        end = region.lineno - 2
 
-        # not that we've extracted the information we need, lets slice up the
+        indent = region.start_match.group('indent')
+        indent = normalize_whitespace(indent)
+
+        def indent_matches(line):
+            """Is the indentation of a line match what we're looking for?"""
+            line = normalize_whitespace(line)
+
+            if not line.strip():
+                # the line consists entirely of whitespace (or nothing at all),
+                # so is not considered to be of the appropriate indentation
+                return False
+
+            if line.startswith(indent):
+                if line[len(indent)] not in string.whitespace:
+                    return True
+
+            # if none of the above found the indentation to be a match, it is
+            # not a match
+            return False
+
+        # now that we've extracted the information we need, lets slice up the
         # document's regions to match
 
         for candidate in document:
@@ -32,13 +61,13 @@
             raise RuntimeError('both start and end lines must be in the '
                 'same region')
 
+        start = None
         for offset, line in reversed(list(enumerate(lines))):
             if offset > end - found_region.lineno:
                 continue
-            if line and line[0] in string.whitespace:
-                start = offset
-            if line and line[0] not in string.whitespace:
+            if indent_matches(line):
                 break
+            start = offset + 1
         else:
             raise RuntimeError("couldn't find the start of the block")
 

Added: manuel/trunk/src/manuel/capture.txt
===================================================================
--- manuel/trunk/src/manuel/capture.txt	                        (rev 0)
+++ manuel/trunk/src/manuel/capture.txt	2009-08-15 21:43:58 UTC (rev 102842)
@@ -0,0 +1,59 @@
+manuel.capture
+==============
+
+This document explores the edge cases and boundry conditions of the
+manuel.capture module.  It is not meant as end-user documentation, but is
+rather a set of tests.
+
+
+Respecting indentation
+----------------------
+
+The text captured is determined by the indentation of the capture directive.
+
+::
+
+    First level of indentation.
+
+        Second level of indentation.
+
+            Third level of indentation.
+
+        .. -> foo
+
+.. -> source
+
+    >>> import manuel
+    >>> document = manuel.Document(source)
+    >>> import manuel.capture
+    >>> manuel.capture.find_captures(document)
+    >>> [r.parsed.block for r in document if r.parsed]
+    ['Third level of indentation.\n']
+
+
+Nested directives
+-----------------
+
+If two capture directives are nested, the outer one is effective.
+
+::
+
+    First level of indentation.
+
+        Second level of indentation.
+
+            Third level of indentation.
+
+        .. -> foo
+
+    .. -> bar
+
+.. -> source
+
+    >>> import manuel
+    >>> document = manuel.Document(source)
+    >>> import manuel.capture
+    >>> manuel.capture.find_captures(document)
+    >>> [r.parsed.block for r in document if r.parsed]
+    ['Second level of indentation.\n\n    Third level of indentation.\n\n.. -> foo\n']
+


Property changes on: manuel/trunk/src/manuel/capture.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: manuel/trunk/src/manuel/tests.py
===================================================================
--- manuel/trunk/src/manuel/tests.py	2009-08-15 20:43:56 UTC (rev 102841)
+++ manuel/trunk/src/manuel/tests.py	2009-08-15 21:43:58 UTC (rev 102842)
@@ -31,7 +31,8 @@
         (re.compile(r'<zope\.testing\.doctest\.'), '<doctest.'),
         ])
 
-    tests = ['../index.txt', 'table-example.txt', 'README.txt', 'bugs.txt']
+    tests = ['../index.txt', 'table-example.txt', 'README.txt', 'bugs.txt',
+        'capture.txt']
 
     m = manuel.ignore.Manuel()
     m += manuel.doctest.Manuel(optionflags=optionflags, checker=checker)



More information about the Checkins mailing list