# HG changeset patch # User Ludovic Chabant # Date 1359700867 28800 # Node ID c4e999f55ba9388cce82dd78a79caadb1eaea520 # Parent 8167b9b6925ac864939c9856e51b14d05eaf2c18 Include changes: - Better way to pre-parse include parameters. - Added support for simple include templating. - Added unit tests. diff -r 8167b9b6925a -r c4e999f55ba9 tests/test_page.py --- 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 Sandbox. Or to this page.", 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
\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
\n", foo.formatted_text) + self.assertEqual("A test page.\nBLAH: Somewhere\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
name=Dave|what=drink
\n", foo.formatted_text) + self.assertEqual("A test page.\nHello Dave, would you like a drink?\n", foo.text) + diff -r 8167b9b6925a -r c4e999f55ba9 wikked/formatter.py --- 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 '
%s
\n' % included_url + return '
%s
\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'^
(.*)
$', repl, text, + return re.sub(r'^
(?P.*)
$', 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[a-zA-Z][a-zA-Z0-9_\-]+)=(?P[^\|]+)" + 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[a-zA-Z][a-zA-Z0-9_\-]+)="\ r"(?P[^\|]+)" - 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 +