For a developer, trying to blog about code is a frustrating process. WYSIWYG content editors mangle code and whitespace. Tools like gist and other code-snippet displays can help, but they also distance your code from your writing. With Dexy, we can write blog posts that incorporate code just where we want it, in the format we want it, and with confidence that the code we are writing is correct and easy to modify as we go.
In this tutorial we’ll walk through creating and then modifying a WordPress blog post. All the features mentioned in this blog post are available in Dexy 0.5.7. In order to post content to WordPress we will use its XMLRPC API, so before you try this yourself make sure you have enabled this option; it is disabled by default.
We’ll start in an empty directory. We need to configure our directory to know where our WordPress installation is, and to provide our username and password. Fortunately Dexy’s new filter commands make this really easy. The create_keyfile
command from the WordPress filter will create the configuration file we need to store our credentials:
$ dexy help -on fcmd
====================
Help for 'dexy fcmd'
====================
Run a command defined in a dexy filter.
Arguments:
alias - The alias of the filter which defines the custom command,
[required] e.g. 'dexy fcmd --alias <value>'
cmd - The name of the command to run,
[required] e.g. 'dexy fcmd --cmd <value>'
help - If true, just print docstring rather than running command
[optional, defaults to 'False'] e.g. 'dexy fcmd --help False'
Keyword Arguments:
Additional arguments to be passed to the command
$ dexy fcmd -alias wp -cmd create_keyfile -help
Creates a key file for WordPress in the local directory.
We could also call the create_keyfile
filter command on the ApiFilter classs (the parent class of WordPressFilter), and this would create a keyfile in the user’s home directory that we could use to store all our API credentials:
$ dexy fcmd -alias apis -cmd create_keyfile -help
Creates a key file in location specified by MASTER_API_KEY_FILE.
The user-wide approach is usually more convenient, since you can run your dexy scripts from anywhere and only need to have your credentials in one place. On the other hand, per-project config is useful if you need to override the defaults to post to a different blog or if you prefer to keep the credentials closer to where you will be using them.
Now we’ll call the filter command:
$ dexy fcmd -alias wp -cmd create_keyfile
$ ls -l .dexyapis
-rw-r--r-- 1 ana ana 108 2012-03-14 01:06 .dexyapis
This has created a JSON file named .dexyapis which looks like this:
{ "wordpress": { "password": "TODO", "url": "TODO", "username": "TODO" } }
You should replace the TODO items with the values appropriate for your website. The url required is the base url for your blog. Here is the config file that I used to create this example:
{ "wordpress" : { "url" : "http://dexydemo.wordpress.com", "username" : "$WP_USERNAME", "password" : "$WP_PASSWORD" } }
You’ll notice that I didn’t actually type my username and password into the .dexyapis file. You can type your actual username and password, or if you have environment variables set up to store your useranme and password then you can put references to environment variables by starting with a $, and the ApiFilter will fetch these for you. The advantage of using environment variables is that you can commit your .dexyapis
file to your project repository without committing sensitive information.
Let’s test this out to make sure it’s working before we actually start writing our blog post. Let’s get a list of all the filter commands that are provided by the WordPressFilter:
$ dexy fcmds -alias wp
Filter commands defined in WordPressFilter...
create_keyfile
list_categories
list_methods
The list_categories
filter command will print out the categories that are defined in your blog. It has to authenticate and visit the correct URL to do this, so it’s a good test (especially if you have custom categories set up):
$ dexy fcmd -alias wp -cmd list_categories -help
List available blog post categories.
$ dexy fcmd -alias wp -cmd list_categories
categoryName
Dexy
Uncategorized
Ok, now that we have that working let’s move on to an actual blog post. To start with, let’s just try to post a simple static HTML file like this:
We also need to create a configuration file named wordpress.json
to hold some simple metadata about our blog post.
{ "title" : "My First Automated Blog Post" }
Here is the .dexy
configuration file we need:
The WordPress filter alias is just wp
(you can see the filter reference here). We specify wordpress.json
as an input so that if there are any changes to that file, Dexy will upload our blog post to wordpress again. You could omit this and just touch
your blog post file to trigger an upload.
And that’s all we need to do to create our first blog post! Because this is a new dexy project, we need to run dexy setup:
$ dexy setup
Ok, we've created directories called logs and artifacts.
You are now ready to run dexy! If you have problems,
please check the log file at logs/dexy.log for clues.
Online help is available from dexy.it/help
And then we can run dexy:
$ dexy -loglevel DEBUG
batch id is 1
sorting 2 documents into run order, there are 1 total dependencies
ratio of dependencies to documents is 0.5
running Output
running LongOutput
running Run
running Source
source files saved in logs/batch-source-00001
If this has completed successfully, then our wordpress.json
has changed. It now looks like this:
{ "postid": "163", "publish": false, "title": "My First Automated Blog Post" }
The postid
has been filled in. This is very important since next time we run this filter, we don’t want to create another blog post, we want to update this same blog post. You can fill in the postid yourself if you already have created a draft post via your WordPress admin interface. Also notice that there is a key called publish
with a value of false. By default, we create draft blog posts, so they aren’t visible to the public yet. But, you can get a preview if you are logged in. Here’s our preview:
Let’s go ahead and publish this before we move on to creating a more interesting example. To make this visible, just change the value of publish
from false
to true
, and run dexy again.
Now this is published and anyone can read it.
Where things really get interesting is when we start making use of Dexy to create blog post content that includes code examples and results, so let’s do an example of that next.
One thing I’m not going to cover in this post, but will cover in detail very soon, is how to include dexy-generated images in your blog post. The WordPress filter will actually already upload images for you to WordPress, but there is a snag. The overwrite
option in the WordPress API is broken, so each time Dexy thinks your image has changed, another copy will be uploaded to WordPress. This clutters up your Media Library very quickly. (See this bug report for more information.) My approach is to use Amazon S3 for image hosting, and there is a boto
filter in Dexy which will upload images to S3 and return the URL, which I can then use to reference the image. That’s how I am displaying the dexy-generated screenshots in this blog post. I’m also working on adding filters for other image and hosting services. There will be a comprehensive blog post on this topic soon, so watch this space (and if you are in a position to do anything to help that WordPress bug get fixed, please do).
When we include code snippets and examples, we probably want to include syntax highlighting. The approach I find easiest is to use pygments within Dexy to apply syntax highlighting, and then to have a pygments stylesheet as part of my blog CSS. If you can’t modify the CSS for your blog, then you can still use pygments with the "noclasses" : true
option, and this will embed the styles directly.
If you would like to use a different syntax highlighting system, and are having trouble getting it to work, then please open a support ticket.
For this example, we will tell pygments to use inline styles rather than classes, so no modification to the CSS is required (which is good since I’m doing this demo using a free wordpress.com blog, so I can’t modify the CSS).
We will write a short blog post that shows parallel code written in Python and JavaScript, and executed using the python REPL and the rhino interpreter respectively. Pygments has support for python console transcripts, so we will have syntax highlighting on the Python output. However, there is not (yet) a comparable highlighter for JavaScript, so we will just show the raw output and surround it with <pre> tags.
We’ll use markdown rather than HTML, so we don’t have to type as much markup. Here is the source for our blog post:
Let's look at defining and calling functions in Python and JavaScript.
Here is an example of defining a function in Python:
{{ d['example.py|idio|pycon|pyg']['define-function'] }}
Here is how this function might be defined in JavaScript:
<pre>
{{ d['example.js|idio|rhinoint']['define-function'] }}
</pre>
Now we'll call this function in each language:
{{ d['example.py|idio|pycon|pyg']['call-function-1'] }}
<pre>
{{ d['example.js|idio|rhinoint']['call-function-1'] }}
</pre>
And again, with different arguments:
{{ d['example.py|idio|pycon|pyg']['call-function-2'] }}
<pre>
{{ d['example.js|idio|rhinoint']['call-function-2'] }}
</pre>
We’ll apply the jinja and markdown filters first, then post to wordpress. We also have several inputs, including a python script and a JavaScript example. Here is the .dexy
config:
{
"example.js|idio|rhinoint": {},
"example.py|idio|pycon|pyg": {
"pygments": {
"noclasses": true
}
},
"index.md|jinja|markdown|wp": {
"allinputs": true
},
"wordpress.json": {}
}
We will also tweak our wordpress.json to change the title of our blog post, and assign it to a category:
{ "categories": [ "Dexy" ], "postid": "163", "publish": true, "title": "My Fancier Automated Blog Post" }
And, here’s the screenshot of our updated blog post:
If you are new to Dexy, then reviewing tutorials 0 and 1 will help you understand how the HTML for that blog post was created.
That’s all for this tutorial! You can check out the source code of this blog post at github. If you have any questions please leave a comment, or if you need help getting this to work please open a support ticket. You can also download an example project directory like the one described here to help you get started (although for learning it’s better to do it yourself).