changeset 53:c4e999f55ba9

Include changes: - Better way to pre-parse include parameters. - Added support for simple include templating. - Added unit tests.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 31 Jan 2013 22:41:07 -0800
parents 8167b9b6925a
children 9dfbc2a40b71
files tests/test_page.py wikked/formatter.py
diffstat 2 files changed, 76 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/tests/test_page.py	Thu Jan 31 22:40:12 2013 -0800
+++ b/tests/test_page.py	Thu Jan 31 22:41:07 2013 -0800
@@ -4,6 +4,11 @@
 
 
 class PageTest(WikkedTest):
+    def _getWikiFromStructure(self, structure):
+        wiki = self.getWiki(use_db=False, fs_factory=lambda cfg: MockFileSystem(structure))
+        wiki.start()
+        return wiki
+
     def testSimplePage(self):
         self.wiki = self._getWikiFromStructure({
             'foo.txt': 'A test page.'
@@ -58,11 +63,6 @@
         self.assertEqual("Follow a link to the <a class=\"wiki-link\" data-wiki-url=\"sandbox\">Sandbox</a>. Or to <a class=\"wiki-link missing\" data-wiki-url=\"other-sandbox\">this page</a>.", page.formatted_text)
         self.assertEqual(set(['sandbox', 'other-sandbox']), set(page.local_links))
 
-    def _getWikiFromStructure(self, structure):
-        wiki = self.getWiki(use_db=False, fs_factory=lambda cfg: MockFileSystem(structure))
-        wiki.start()
-        return wiki
-
     def testPageRelativeOutLinks(self):
         self.wiki = self._getWikiFromStructure({
             'first.txt': "Go to [[First Sibling]].",
@@ -81,3 +81,37 @@
         second2 = Page(self.wiki, 'sub_dir/second-sibling')
         self.assertEqual(['sub_dir/second'], second2.local_links)
 
+    def testPageInclude(self):
+        self.wiki = self._getWikiFromStructure({
+            'Foo.txt': "A test page.\n{{include: trans-desc}}\n",
+            'Trans Desc.txt': "BLAH\n"
+            })
+        foo = Page(self.wiki, 'foo')
+        self.assertEqual(['trans-desc'], foo.local_includes)
+        self.assertEqual("A test page.\n<div class=\"wiki-include\" data-wiki-url=\"trans-desc\"></div>\n", foo.formatted_text)
+        self.assertEqual("A test page.\nBLAH\n\n", foo.text)
+
+    def testPageIncludeWithMeta(self):
+        self.wiki = self._getWikiFromStructure({
+            'Foo.txt': "A test page.\n{{include: trans-desc}}\n",
+            'Trans Desc.txt': "BLAH: [[Somewhere]]\n{{bar: 42}}\n{{__secret: love}}\n{{+given: hope}}"
+            })
+        foo = Page(self.wiki, 'foo')
+        self.assertEqual(['trans-desc'], foo.local_includes)
+        self.assertEqual([], foo.local_links)
+        self.assertEqual({'include': 'trans-desc'}, foo.local_meta)
+        self.assertEqual("A test page.\n<div class=\"wiki-include\" data-wiki-url=\"trans-desc\"></div>\n", foo.formatted_text)
+        self.assertEqual("A test page.\nBLAH: <a class=\"wiki-link missing\" data-wiki-url=\"somewhere\">Somewhere</a>\n\n\n\n", foo.text)
+        self.assertEqual(['trans-desc'], foo.all_includes)
+        self.assertEqual(['somewhere'], foo.all_links)
+        self.assertEqual({'bar': '42', 'given': 'hope', 'include': 'trans-desc'}, foo.all_meta)
+
+    def testPageIncludeWithTemplating(self):
+        self.wiki = self._getWikiFromStructure({
+            'Foo.txt': "A test page.\n{{include: greeting|name=Dave|what=drink}}\n",
+            'Greeting.txt': "Hello {{name}}, would you like a {{what}}?"
+            })
+        foo = Page(self.wiki, 'foo')
+        self.assertEqual("A test page.\n<div class=\"wiki-include\" data-wiki-url=\"greeting\">name=Dave|what=drink</div>\n", foo.formatted_text)
+        self.assertEqual("A test page.\nHello Dave, would you like a drink?\n", foo.text)
+
--- a/wikked/formatter.py	Thu Jan 31 22:40:12 2013 -0800
+++ b/wikked/formatter.py	Thu Jan 31 22:41:07 2013 -0800
@@ -111,10 +111,16 @@
         return text
 
     def _processInclude(self, ctx, value):
-        included_url = ctx.getAbsoluteUrl(value)
+        pipe_idx = value.find('|')
+        if pipe_idx < 0:
+            included_url = ctx.getAbsoluteUrl(value)
+            parameters = ''
+        else:
+            included_url = ctx.getAbsoluteUrl(value[:pipe_idx])
+            parameters = value[pipe_idx + 1:]
         ctx.included_pages.append(included_url)
         # Includes are run on the fly.
-        return '<div class="wiki-include">%s</div>\n' % included_url
+        return '<div class="wiki-include" data-wiki-url="%s">%s</div>\n' % (included_url, parameters)
 
     def _processQuery(self, ctx, query):
         # Queries are run on the fly.
@@ -177,12 +183,12 @@
 
     def run(self):
         def repl(m):
-            meta_name = str(m.group(1))
-            meta_value = str(m.group(2))
+            meta_name = str(m.group('name'))
+            meta_value = str(m.group('value'))
             if meta_name == 'query':
                 return self._runQuery(meta_value)
             elif meta_name == 'include':
-                return self._runInclude(meta_value)
+                return self._runInclude(str(m.group('url')), meta_value)
             return ''
 
         self.ctx.url_trail = [self.page.url]
@@ -191,17 +197,30 @@
         self.ctx.meta = self.page.local_meta
 
         text = self.page.formatted_text
-        return re.sub(r'^<div class="wiki-([a-z]+)">(.*)</div>$', repl, text,
+        return re.sub(r'^<div class="wiki-(?P<name>[a-z]+)"( data-wiki-url="(?P<url>[^"]+)")?>(?P<value>.*)</div>$', repl, text,
             flags=re.MULTILINE)
 
-    def _runInclude(self, include_url):
+    def _runInclude(self, include_url, include_args):
         if include_url in self.ctx.url_trail:
             raise CircularIncludeError("Circular include detected at: %s" % include_url, self.ctx.url_trail)
+
+        parameters = None
+        if include_args:
+            parameters = {}
+            arg_pattern = r"(^|\|)(?P<name>[a-zA-Z][a-zA-Z0-9_\-]+)=(?P<value>[^\|]+)"
+            for m in re.finditer(arg_pattern, include_args):
+                key = str(m.group('name')).lower()
+                parameters[key] = str(m.group('value'))
+
         page = self.wiki.getPage(include_url)
         child_ctx = ResolvingContext()
         child = PageResolver(page, child_ctx)
         text = child.run()
         self.ctx.add(child_ctx)
+
+        if parameters:
+            text = self._renderTemplate(text, parameters)
+
         return text
 
     def _runQuery(self, query):
@@ -210,12 +229,12 @@
         meta_query = {}
         arg_pattern = r"(^|\|)(?P<name>[a-zA-Z][a-zA-Z0-9_\-]+)="\
             r"(?P<value>[^\|]+)"
-        for m in re.findall(arg_pattern, query):
-            key = m[1].lower()
+        for m in re.finditer(arg_pattern, query):
+            key = m.group('name').lower()
             if key not in parameters:
-                meta_query[key] = m[2]
+                meta_query[key] = m.group('value')
             else:
-                parameters[key] = m[2]
+                parameters[key] = m.group('value')
 
         # Find pages that match the query, excluding any page
         # that is in the URL trail.
@@ -234,14 +253,11 @@
         # Combine normal templates to build the output.
         text = parameters['header']
         for p in matched_pages:
-            item_str = parameters['item']
             tokens = {
                     'url': p.url,
                     'title': p.title
                     }
-            for tk, tv in tokens.iteritems():
-                item_str = item_str.replace('{{%s}}' % tk, tv)
-            text += item_str
+            text += self._renderTemplate(parameters['item'], tokens)
         text += parameters['footer']
 
         return text
@@ -266,3 +282,9 @@
             p = self.wiki.getPage(url)
             if self._isPageMatch(p, name, value, level + 1):
                 return True
+
+    def _renderTemplate(self, text, parameters):
+        for token, value in parameters.iteritems():
+            text = text.replace('{{%s}}' % token, value)
+        return text
+