diff --git a/README.md b/README.md index 6ea94d44..c682cb5a 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,15 @@ Cactus makes it easy to relatively link to pages and static assets inside your p Just use the URL you would normally use: don't forget the leading slash. +You can add extra context to your pages. Just insert it on the top of the file like this: + + name: koen + age: 29 + + {% extends "base.html" %} + … + +which will be converted to a dict: `{'name': 'koen', 'age': '29'}` and added to the context. ### Templates diff --git a/cactus/page.py b/cactus/page.py index 7816e6b3..eceab8c8 100644 --- a/cactus/page.py +++ b/cactus/page.py @@ -24,10 +24,13 @@ def __init__(self, site, source_path): # The URL where this element should be linked in "base" pages self.link_url = '/{0}'.format(self.source_path) + self.is_html = urlparse.urlparse(self.source_path).path.endswith('.html') + self.is_index = urlparse.urlparse(self.source_path).path.endswith('index.html') + if self.site.prettify_urls: # The URL where this element should be linked in "built" pages - if self.is_html(): - if self.is_index(): + if self.is_html: + if self.is_index: self.final_url = self.link_url.rsplit('index.html', 1)[0] else: self.final_url = '{0}/'.format(self.link_url.rsplit('.html', 1)[0]) @@ -35,7 +38,7 @@ def __init__(self, site, source_path): self.final_url = self.link_url # The path where this element should be built to - if not self.is_html() or self.source_path.endswith('index.html'): + if not self.is_html or self.source_path.endswith('index.html'): self.build_path = self.source_path else: self.build_path = '{0}/{1}'.format(self.source_path.rsplit('.html', 1)[0], 'index.html') @@ -43,11 +46,7 @@ def __init__(self, site, source_path): self.final_url = self.link_url self.build_path = self.source_path - def is_html(self): - return urlparse.urlparse(self.source_path).path.endswith('.html') - - def is_index(self): - return urlparse.urlparse(self.source_path).path.endswith('index.html') + self.data = self.read_data() @property def absolute_final_url(self): @@ -64,14 +63,14 @@ def full_source_path(self): def full_build_path(self): return os.path.join(self.site.build_path, self.build_path) - def data(self): + def read_data(self): with open(self.full_source_path, 'rU') as f: try: return f.read().decode('utf-8') except: logger.warning("Template engine could not process page: %s", self.path) - def context(self, data=None, extra=None): + def context(self, extra=None): """ The page context. """ @@ -79,8 +78,8 @@ def context(self, data=None, extra=None): extra = {} context = {'__CACTUS_CURRENT_PAGE__': self,} - - page_context, data = self.parse_context(data or self.data()) + + page_context = self.parse_context() context.update(self.site.context()) context.update(extra) @@ -93,15 +92,10 @@ def render(self): Takes the template data with context and renders it to the final output file. """ - data = self.data() - context = self.context(data=data) - - # This is not very nice, but we already used the header context in the - # page context, so we don't need it anymore. - page_context, data = self.parse_context(data) + context = self.context() context, data = self.site.plugin_manager.preBuildPage( - self.site, self, context, data) + self.site, self, context, self.data) return Template(data).render(context) @@ -125,23 +119,27 @@ def build(self): self.site.plugin_manager.postBuildPage(self) - def parse_context(self, data, splitChar=':'): + def parse_context(self, splitChar=':'): """ Values like name: koen age: 29 - will be converted in a dict: {'name': 'koen', 'age': '29'} + from the top of the input file will be converted into a dict: + + {'name': 'koen', 'age': '29'} + + and these lines are deleted from 'self.data' """ - if not self.is_html(): - return {}, data + if not self.is_html: + return {} values = {} - lines = data.splitlines() + lines = self.data.splitlines() if not lines: - return {}, '' + return {} for i, line in enumerate(lines): @@ -149,13 +147,14 @@ def parse_context(self, data, splitChar=':'): continue elif splitChar in line: - line = line.split(splitChar) - values[line[0].strip()] = (splitChar.join(line[1:])).strip() + line = line.split(splitChar, 1) + values[line[0].strip()] = line[1].strip() else: break - return values, '\n'.join(lines[i:]) + self.data = '\n'.join(lines[i:]) + return values def __repr__(self): return ''.format(self.source_path) diff --git a/cactus/site.py b/cactus/site.py index 052366a7..6cd4f999 100644 --- a/cactus/site.py +++ b/cactus/site.py @@ -175,7 +175,7 @@ def context(self): """ ctx = { 'CACTUS': { - 'pages': [p for p in self.pages() if p.is_html()], + 'pages': [p for p in self.pages() if p.is_html], 'static': [p for p in self.static()] }, '__CACTUS_SITE__': self, @@ -267,6 +267,9 @@ def build(self): else: os.remove(path) + # read pages for each built + self._read_pages() + # Render the pages to their output files mapper = map if self._parallel >= PARALLEL_AGGRESSIVE: @@ -340,24 +343,23 @@ def buildStatic(self): def pages(self): """ List of pages. + This routine is called from different places, + but builds the page list only once """ - if not hasattr(self, "_page_cache"): - self._page_cache = {} - - pages = [] + self._read_pages() + return self._page_cache.values() + def _read_pages(self): + """ + Read the pages into self._page_cache + """ + self._page_cache = {} for path in fileList(self.page_path, relative=True): - + # ignore backup files if path.endswith("~"): continue - - if not self._page_cache.has_key(path): - self._page_cache[path] = Page(self, path) - - pages.append(self._page_cache[path]) - - return pages + self._page_cache[path] = Page(self, path) def _rebuild_should_ignore(self, file_path):