AsciiDoc API
============

'asciidocapi' -- a Python API module for 'AsciiDoc'.


Introduction
------------
The 'asciidocapi' module implements a Python API for AsciiDoc. It
allows you to set `asciidoc(1)` program options, compile an AsciiDoc
source file and then interrogate the results.  The `asciidocapi.py`
module file contains the `AsciiDocAPI` wrapper class for
`asciidoc.py`.

.Benefits
- Stable API Shields the user from the undocumented and possibly
  volatile `asciidoc.py` internals.
- Easier to use and more flexible than the alternative of running
  `asciidoc(1)` as a separate process.
- Executes inside your application (better performance than running
  separate `asciidoc(1)` command processes).


Using asciidocapi
-----------------
To use the API just drop the `asciidocapi.py` file into your
application directory, import it and use the `AsciiDocAPI` class.  The
only requirement is that a compatible version of 'AsciiDoc' is already
installed -- simple, no setuptools to run, no Eggs to install, no
non-standard library dependencies.

You can find `asciidocapi.py` in the AsciiDoc
http://asciidoc.org/INSTALL.html#X1[distribution
archives] (version 8.4.1 or better).

Once you have `asciidocapi.py` Verify everything is working by running
the module doctests:

  python asciidocapi.py

If there are no messages then all is well.

The following minimal example compiles `mydoc.txt` to `mydoc.html`:

[source,python]
-------------------------------------------------------------------------------
from asciidocapi import AsciiDocAPI
asciidoc = AsciiDocAPI()
asciidoc.execute('mydoc.txt')
-------------------------------------------------------------------------------

The next interactive example uses file-like objects for input and output:

-------------------------------------------------------------------------------
$ python
Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from asciidocapi import AsciiDocAPI
>>> import StringIO
>>> infile = StringIO.StringIO('Hello *{author}*')
>>> outfile = StringIO.StringIO()
>>> asciidoc = AsciiDocAPI()
>>> asciidoc.options('--no-header-footer')
>>> asciidoc.attributes['author'] = 'Joe Bloggs'
>>> asciidoc.execute(infile, outfile, backend='html4')
>>> print outfile.getvalue()
<p>Hello <strong>Joe Bloggs</strong></p>

>>>
-------------------------------------------------------------------------------


Implementation Rationale
------------------------
.Leverage existing knowledge
The API maps directly onto the `asciidoc(1)` command -- this is
deliberate -- if you know the `asciidoc(1)` command learning the API
will be trivial. A nice side effect of this goal is that API and
command-line modes share the same code -- virtually no `asciidoc(1)`
code is specific to API usage.

.Simplicity
Implemented with a single Python module file (`asciidocapi.py`)
containing the 'AsciiDocAPI' API class. 'AsciiDocAPI'  contains just
one method plus a few attributes for processing options and result
messages.  No external setup tools and no non-standard library
dependencies are used or required.

.Loose coupling
The dependency between `asciidocapi.py` and `asciidoc.py` is minimal
-- the current `asciidocapi.py` module uses only two attributes and
one function from the `asciidoc.py` module.

.Why isn't the API baked right into the asciidoc.py command script?
1. You can't just drop `asciidoc.py` into your application because it
   requires all the related config files and filters -- complex and
   unnecessary since all this was already done when you installed
   AsciiDoc.
2. This scheme separates the API from the AsciiDoc application -- the
   API implementation can be extended or replaced independently of
   AsciiDoc.


API reference
-------------

[[X2]]
Class `AsciiDocAPI(object)`
~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the 'AsciiDoc' API class.

Instance attributes
^^^^^^^^^^^^^^^^^^^
`asciidoc`::
The imported `asciidoc.py` module.

`attributes`::
A dictionary of AsciiDoc attribute values passed to AsciiDoc.

- Setting an attribute value to `None` (`name: None`) will undefine
  (delete) the attribute (this in addition to the `name!` attribute
  name format that the `asciidoc(1)` command uses).
- To simply define an attribute set the attribute value to a blank
  string (`name: ''`) 

`cmd`::
The file path of the `asciidoc.py` script. Set by the `__init__`
method.

`messages`::
A chronologically ordered list of message strings generated during
AsciiDoc execution (last message at the end of the list).

`options`::
An instance of the <<X1,Options class>>. Contains a list of command
options passed to AsciiDoc.

Instance methods
^^^^^^^^^^^^^^^^
`__init__(self, asciidoc_py=None)`::
Locate and import `asciidoc.py` module and verify API compatibility.
Initialize instance attributes. A search for the `asciidoc` module is
made in the following order:

. Use the `ASCIIDOC_PY` environment variable if it is set.
. Use the `asciidoc_py` argument if it is set.
. Search the environment 'PATH' for `asciidoc.py`, `asciidoc.pyc` and
  `asciidoc` (in that order).
. Finally repeat the previous search in the current working directory.

`execute(self, infile, outfile=None, backend=None)`::
Compile `infile` to `outfile` using `backend` format.  `infile` and
`outfile` can be file path strings or file-like objects. `backend` is
name of 'AsciiDoc' backend (takes same values as `asciidoc(1)` command
`--backend` option). If `outfile` or `backend` are `None` then their
respective `asciidoc(1)` defaults are used.


[[X1]]
Class `Options(object)`
~~~~~~~~~~~~~~~~~~~~~~~
Stores `asciidoc(1)` command options. You can use any `asciidoc(1)`
options with the exception of the `--doctest` and `--filter` options.

Instance attributes
^^^^^^^^^^^^^^^^^^^
`values`::
The list of `(name,value)` command option tuples.

Instance methods
^^^^^^^^^^^^^^^^
`__call__(self, name, value=None)`::
A shortcut for the `append` method. Example:

  opts = Options()
  opts('--verbose')

`append(self, name, value=None)`::
Append `(name,value)` to the options list. Example:

  opts = Options()
  opts.append('--conf-file', 'blog.conf')


Class `AsciiDocError(Exception)`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thrown by the <<X2,AsciiDocAPI class>> when an 'AsciiDoc' execution
error occurs.
