This is really the last stop before the rubber starts to hit the road—we've got various small bits of functionality implemented, now we have to weave them together into actual operations.
The first thing we need to be able to do, given a buffer in which
someone has written a post, is figure out where we might go posting it.
Remember, in the buffer, the blog is identified with a simple
#+POST_BLOG: <name>
property. It's value is just going to be a text
string. And it may not even be present!
So what we have here is a pair of functions that, given a post
structure, will furnish us with a complete blog
structure, or throw an
exception indicating we should give up if the user declined to furnish
us with all the info we needed.
(defun org-blog-post-to-blog (post)
"Determine the blog to use for the given post.
It will ask for the blog name and blog engine if necessary, and
then hand off to the particular engine's `-params' function, so
it may make a number of interactive queries to the user."
(let* ((name (org-blog-get-name post))
(blog (cdr (assoc name org-blog-alist)))
(engine (org-blog-blog-to-engine blog))
(funcname (concat "org-blog-" engine "-params"))
(func (intern funcname)))
(unless (functionp func)
(error (format "Can't find params function for %s engine" engine)))
(apply func blog nil)))
(defun org-blog-blog-to-engine (blog)
"Get the blog engine name from the blog structure.
If it's not present, ask the user to choose from among those
available in org-blog-alist."
(let ((engine (or (cdr (assq :engine blog))
(empty-string-is-nil (completing-read
"Blog software: "
(mapcar 'car org-blog-engine-alist) nil t)))))
(unless engine
(error (format "Can't find engine %s" engine)))
engine))
The important thing to note, I think, is that these functions don't
presume to "know" anything about the structure of a blog
—that is,
while a WordPress blog may require various bits of information (XML-RPC
endpoint, username, password, blog-id), some other back-end might
require an entirely different set of attributes…and these functions
don't care. By delegating all the work of making sure that all
attributes are satisfied to functions that are written alongside the
particular blogging back-end, we allow back-ends that have very
different requirements. I could see this being used not just for
WordPress-like server-oriented back-ends but also for static site
generators and the like.
Testing is fairly straightforward:
(ert-deftest ob-test-org-blog-post-to-blog ()
"Test getting the blog information from a blog post"
(let* ((blog-passwd (read-passwd "Password for blog listing: "))
(org-blog-alist `(("bar" . ((:engine . "wp")
(:xmlrpc . "http://wordpress.com/xmlrpc.php")
(:username . "mdorman@ironicdesign.com")
(:password . ,blog-passwd)))))
(final-blog-param `((:blog-id . "46183217")
(:engine . "wp")
(:password . ,blog-passwd)
(:username . "mdorman@ironicdesign.com")
(:xmlrpc . "https://orgblogtest.wordpress.com/xmlrpc.php"))))
(org-blog-new)
(should (equal (org-blog-post-to-blog (org-blog-buffer-extract-post)) final-blog-param))))
We mock up the org-blog-alist
, create a new post (which will
automatically be assigned to the one available blog), and then we go
through the process to get our blog
structure out.
I will admit, I could probably be a little more adventurous in testing this—testing failure modes, etc.—but that will have to wait for future days when I'm just looking for something small to do.
Tomorrow I think we'll add the XML-RPC code for WordPress, as well as the generic machinery that calls it.