Commits

Oben Sonne committed b6c7838

Introduce pre- and post-convert hooks

A project's `macros.py` may define several pre- and post-convert hooks
using function starting with `hook_{pre|post}convert_`. Pre-convert
hooks are run before any page is processed and converted. Post-convert
hooks are run after page sources has been converted from markdwon to
HTML.

This deprecates `once_`-functions in a projects `macros.py`. These
functions should be renamed to start with `hook_preconvert_`. To stay
backwards compatible, `once_`-function still work as before.

This patch is based on ideas by Justin Forest (a.k.a umonkey). See
<http://bitbucket.org/obensonne/poole/issue/2>; for details.

Comments (0)

Files changed (2)

     </url>
     """
 
-    def once_sitemap():
+    def hook_preconvert_sitemap():
         """Generate Google sitemap.xml file."""
         date = datetime.strftime(datetime.now(), "%Y-%m-%d")
         urls = []
 
 You probably want to adjust the default values for *changefreq* and *priority*.
 
-**Info:** Every function in `macros.py` whose name starts with `once_` is
-executed exactly once per project build.
+**Info:** Every function in `macros.py` whose name starts with
+`hook_preconvert_` or `hook_postconvert_` is executed exactly once per project
+build -- either before or after converting pages from markdown to HTML. In
+post-convert hooks the HTML content of a page (yet without header and footer)
+can be accessed with `page.html`. This is useful to generate full-content RSS
+feeds.
 
 #### RSS feed for blog posts
 
     </item>
     """
 
-    def once_rss():
+    def hook_postconvert_rss():
         items = []
         posts = [p for p in pages if "post" in p] # get all blog post pages
         posts.sort(key=lambda p: p.date, reverse=True)
     import glob
     import os.path
     
-    def once_ccss():
+    def hook_preconvert_ccss(): # pre- or post-convert hook, doesn't matter
         for ccss in glob.glob(os.path.join(input, "**.ccss")):
             css = ccss[len(input):].lstrip("/")
             css = "%s.css" % os.path.splitext(css)[0]
         if date and "date" not in self: self["date"] = date
         if post and "post" not in self: self["post"] = post
 
+        self.html = ""
+
     def __getattribute__(self, name):
 
         try:
             else:
                 shutil.copy(opj(cwd, f), opj(dir_out, cwd_site))
 
+    pages.sort(key=lambda p: int(p.get("sval", "0")))
+
     macros["pages"] = pages
     macmod.pages = pages
 
     # -------------------------------------------------------------------------
-    # run 'once' functions in macro module
+    # run pre-convert hooks in macro module (named 'once' before)
     # -------------------------------------------------------------------------
 
-    for fn in sorted([a for a in dir(macmod) if a.startswith("once_")]):
+    hooks = [a for a in dir(macmod) if re.match(r'hook_preconvert_|once_', a)]
+    for fn in sorted(hooks):
         getattr(macmod, fn)()
 
     # -------------------------------------------------------------------------
-    # convert pages
+    # convert pages (markdown to HTML)
+    # -------------------------------------------------------------------------
+
+    for page in pages:
+
+        print("info   : convert %s" % page.fname)
+
+        # replace expressions and statements in page source
+        macmod.page = page
+        macros["page"] = page
+        out = regx_eval.sub(repl_eval, page.source)
+        out = regx_exec.sub(repl_exec, out)
+
+        # convert to HTML
+        page.html = markdown.Markdown(extensions=opts.md_ext).convert(out)
+
+    # -------------------------------------------------------------------------
+    # run post-convert hooks in macro module
+    # -------------------------------------------------------------------------
+
+    hooks = [a for a in dir(macmod) if a.startswith("hook_postconvert_")]
+    for fn in sorted(hooks):
+        getattr(macmod, fn)()
+
+    # -------------------------------------------------------------------------
+    # render complete HTML pages
     # -------------------------------------------------------------------------
 
     with codecs.open(opj(project, "page.html"), 'r', opts.input_enc) as fp:
         skeleton = fp.read()
 
-    pages.sort(key=lambda p: int(p.get("sval", "0")))
-
     for page in pages:
 
-        print("info   : processing %s" % page.fname)
+        print("info   : render %s" % page.url)
 
+        # replace expressions and statements in page.html
+        macmod.page = page
         macros["page"] = page
-        macmod.page = page
-
-        # replacements, phase 1 (expressions and statements in page source)
-        out = regx_eval.sub(repl_eval, page.source)
-        out = regx_exec.sub(repl_exec, out)
-
-        # convert to HTML
-        out = markdown.Markdown(extensions=opts.md_ext).convert(out)
-
-        # replacements, phase 2 (variables and code blocks used in page.html)
-        macros["__content__"] = out
+        macros["__content__"] = page.html
         out = regx_eval.sub(repl_eval, skeleton)
         out = regx_exec.sub(repl_exec, out)