One of the TODO items I wanted to finish before making an org-blog
1.0
release was to convert to the new exporter present in org-mode
8.0.
A couple of weeks ago, I looked at turning a buffer into a post
structure
. I commented at the time that I wasn't 100% certain why the
code even worked. I also commented in a later post that there was some
unfortunate redundancy in the way certain things were being done. I'm
pleased to say that both issues are addressed.
First off, I created a blog
back-end for the new exporter:
(org-export-define-derived-backend 'blog 'html
:options-alist org-blog-buffer-options-alist)
The org-blog-buffer-options-alist
that it references is a structure
that's created on the fly:
(defconst org-blog-buffer-options-alist
(reduce
(lambda (l i)
(let ((field (plist-get (cdr i) :attr)))
(if (string-prefix-p "POST_" field t)
(cons (list (car i) field nil nil t) l)
l)))
org-blog-post-mapping
:initial-value nil))
That's basically plucking all of the items out of the
org-blog-post-mapping
field whose text names start with "POST_".
(defconst org-blog-post-mapping
'((:blog :attr "POST_BLOG" :from-buffer org-blog-property-strip)
(:category :attr "POST_CATEGORY" :from-buffer org-blog-property-split)
(:date :attr "DATE" :from-buffer org-blog-date-format)
(:description :attr "DESCRIPTION" :from-buffer org-blog-property-strip)
(:id :attr "POST_ID" :from-buffer org-blog-property-strip)
(:keywords :attr "KEYWORDS" :from-buffer org-blog-property-split)
(:link :attr "POST_LINK" :from-buffer org-blog-property-strip)
(:name :attr "POST_NAME" :from-buffer org-blog-property-strip)
(:parent :attr "POST_PARENT" :from-buffer org-blog-property-strip)
(:status :attr "POST_STATUS" :from-buffer org-blog-property-strip)
(:title :attr "TITLE" :from-buffer (lambda (v i) (org-blog-property-strip (car v) i)))
(:type :attr "POST_TYPE" :from-buffer org-blog-property-strip)))
Then, to do the actual deed, we call org-export-as
, and use a reduce
loop to do any of the translations called out in the list above.
(defun org-blog-buffer-extract-post ()
"Transform a buffer into a post.
We do as little processing as possible on individual items, to
retain the maximum flexibility for further transformation."
(let ((content
(org-export-as 'blog nil nil t '(:preserve-breaks nil
:section-numbers nil
:with-tags nil
:with-toc nil
:with-todo-keywords nil)))
(attrs
(org-export-get-environment 'blog)))
(sort
(reduce
(lambda (l i)
(let ((v (plist-get attrs (car i)))
(filter (plist-get (cdr i) :from-buffer)))
(if v
(cons (cons (car i) (if filter
(funcall filter v attrs)
v)) l)
l)))
org-blog-post-mapping
:initial-value (when content
(list (cons :content content))))
(lambda (a b)
(string< (car a) (car b))))))
Although the overall code hasn't gotten signficantly shorter, it's much clearer—it uses more centralized structures to gather together information, and it applies more general transformations defined in structures rather than conditional statements.