Moving to the 8.0 exporter

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.