From 49f481e399af45bf12f53afd129bd6a873dc2f27 Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Sun, 28 Oct 2012 07:37:53 -0700 Subject: [PATCH] Add asciidoc reader support http://www.methods.co.nz/asciidoc/index.html Processes files ending in .asc with asciidoc. Extra arguments can be passed by using the ASCIIDOC_OPTIONS config setting --- docs/changelog.rst | 1 + docs/getting_started.rst | 4 ++ docs/index.rst | 3 +- docs/internals.rst | 10 ++--- docs/settings.rst | 2 + pelican/readers.py | 36 ++++++++++++++++ tests/content/article_with_asc_extension.asc | 12 ++++++ tests/content/article_with_asc_options.asc | 9 ++++ tests/test_readers.py | 43 ++++++++++++++++++++ 9 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 tests/content/article_with_asc_extension.asc create mode 100644 tests/content/article_with_asc_options.asc diff --git a/docs/changelog.rst b/docs/changelog.rst index f60c6e47..f25ee3d9 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -24,6 +24,7 @@ Release history * Add the gzip_cache plugin which compresses common text files into a ``.gz`` file within the same directory as the original file to prevent the server (e.g. Nginx) from compressing files during an HTTP call. +* Add AsciiDoc support 3.0 (2012-08-08) ================== diff --git a/docs/getting_started.rst b/docs/getting_started.rst index bc3d2bbe..8959f536 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -42,6 +42,10 @@ Markdown library as well:: $ pip install Markdown +If you want to use AsciiDoc you need to install it from `source +`_ or use your operating +system's package manager. + Upgrading --------- diff --git a/docs/index.rst b/docs/index.rst index fd99b449..8206727c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,7 +4,7 @@ Pelican Pelican is a static site generator, written in Python_. * Write your weblog entries directly with your editor of choice (vim!) - in reStructuredText_ or Markdown_ + in reStructuredText_, Markdown_ or AsciiDoc_ * Includes a simple CLI tool to (re)generate the weblog * Easy to interface with DVCSes and web hooks * Completely static output is easy to host anywhere @@ -74,6 +74,7 @@ A French version of the documentation is available at :doc:`fr/index`. .. _Python: http://www.python.org/ .. _reStructuredText: http://docutils.sourceforge.net/rst.html .. _Markdown: http://daringfireball.net/projects/markdown/ +.. _AsciiDoc: http://www.methods.co.nz/asciidoc/index.html .. _Jinja2: http://jinja.pocoo.org/ .. _`Pelican documentation`: http://docs.getpelican.com/latest/ .. _`Pelican's internals`: http://docs.getpelican.com/en/latest/internals.html diff --git a/docs/internals.rst b/docs/internals.rst index a6264476..280e14d7 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -12,8 +12,8 @@ original author wrote with some software design information. Overall structure ================= -What Pelican does is take a list of files and process them into some -sort of output. Usually, the input files are reStructuredText and Markdown +What Pelican does is take a list of files and process them into some sort of +output. Usually, the input files are reStructuredText, Markdown and AsciiDoc files, and the output is a blog, but both input and output can be anything you want. @@ -23,9 +23,9 @@ The logic is separated into different classes and concepts: on. Since those operations are commonly used, the object is created once and then passed to the generators. -* **Readers** are used to read from various formats (Markdown and - reStructuredText for now, but the system is extensible). Given a file, they return - metadata (author, tags, category, etc.) and content (HTML-formatted). +* **Readers** are used to read from various formats (AsciiDoc, Markdown and + reStructuredText for now, but the system is extensible). Given a file, they + return metadata (author, tags, category, etc.) and content (HTML-formatted). * **Generators** generate the different outputs. For instance, Pelican comes with ``ArticlesGenerator`` and ``PageGenerator``. Given a configuration, they can do diff --git a/docs/settings.rst b/docs/settings.rst index a7cf107b..7d73afe0 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -121,6 +121,8 @@ Setting name (default value) What doe This templates need to use ``DIRECT_TEMPLATES`` setting `MARKDOWN_EXTENSIONS` (``['toc',]``) A list of any Markdown extensions you want to use. +`ASCIIDOC_OPTIONS` (``[]``) A list of options to pass to asciidoc, see the `manpage + `_ ===================================================================== ===================================================================== .. [#] Default is the system locale. diff --git a/pelican/readers.py b/pelican/readers.py index 42995688..f04b4a03 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -13,6 +13,11 @@ try: from markdown import Markdown except ImportError: Markdown = False # NOQA +try: + from asciidocapi import AsciiDocAPI + asciidoc = True +except ImportError: + asciidoc = False import re from pelican.contents import Category, Tag, Author @@ -162,6 +167,37 @@ class HtmlReader(Reader): return content, metadata +class AsciiDocReader(Reader): + enabled = bool(asciidoc) + file_extensions = ['asc'] + default_options = ["--no-header-footer", "-a newline=\\n"] + + def read(self, filename): + """Parse content and metadata of asciidoc files""" + from cStringIO import StringIO + text = StringIO(pelican_open(filename)) + content = StringIO() + ad = AsciiDocAPI() + + options = self.settings.get('ASCIIDOC_OPTIONS', []) + if isinstance(options, (str, unicode)): + options = [m.strip() for m in options.split(',')] + options = self.default_options + options + for o in options: + ad.options(*o.split()) + + ad.execute(text, content, backend="html4") + content = content.getvalue() + + metadata = {} + for name, value in ad.asciidoc.document.attributes.items(): + name = name.lower() + metadata[name] = self.process_metadata(name, value) + if 'doctitle' in metadata: + metadata['title'] = metadata['doctitle'] + return content, metadata + + _EXTENSIONS = {} for cls in Reader.__subclasses__(): diff --git a/tests/content/article_with_asc_extension.asc b/tests/content/article_with_asc_extension.asc new file mode 100644 index 00000000..9ce2166c --- /dev/null +++ b/tests/content/article_with_asc_extension.asc @@ -0,0 +1,12 @@ +Test AsciiDoc File Header +========================= +:Author: Author O. Article +:Email: +:Date: 2011-09-15 09:05 +:Category: Blog +:Tags: Linux, Python, Pelican + +Used for pelican test +--------------------- + +The quick brown fox jumped over the lazy dog's back. diff --git a/tests/content/article_with_asc_options.asc b/tests/content/article_with_asc_options.asc new file mode 100644 index 00000000..bafb3a4a --- /dev/null +++ b/tests/content/article_with_asc_options.asc @@ -0,0 +1,9 @@ +Test AsciiDoc File Header +========================= + +Used for pelican test +--------------------- + +version {revision} + +The quick brown fox jumped over the lazy dog's back. diff --git a/tests/test_readers.py b/tests/test_readers.py index 406027c1..c9d22c18 100644 --- a/tests/test_readers.py +++ b/tests/test_readers.py @@ -109,3 +109,46 @@ class MdReaderTest(unittest.TestCase): '

Level2

' self.assertEqual(content, expected) + +class AdReaderTest(unittest.TestCase): + + @unittest.skipUnless(readers.asciidoc, "asciidoc isn't installed") + def test_article_with_asc_extension(self): + # test to ensure the asc extension is being processed by the correct reader + reader = readers.AsciiDocReader({}) + content, metadata = reader.read(_filename('article_with_asc_extension.asc')) + expected = '
\n

Used for pelican test

\n'\ + '

The quick brown fox jumped over the lazy dog’s back.

\n' + self.assertEqual(content, expected) + expected = { + 'category': 'Blog', + 'author': 'Author O. Article', + 'title': 'Test AsciiDoc File Header', + 'date': datetime.datetime(2011, 9, 15, 9, 5), + 'tags': ['Linux', 'Python', 'Pelican'], + } + + for key, value in expected.items(): + self.assertEquals(value, metadata[key], key) + + + expected = { + 'category': 'Blog', + 'author': 'Author O. Article', + 'title': 'Test AsciiDoc File Header', + 'date': datetime.datetime(2011, 9, 15, 9, 5), + 'tags': ['Linux', 'Python', 'Pelican'], + } + + for key, value in expected.items(): + self.assertEquals(value, metadata[key], key) + + @unittest.skipUnless(readers.asciidoc, "asciidoc isn't installed") + def test_article_with_asc_options(self): + # test to ensure the ASCIIDOC_OPTIONS is being used + reader = readers.AsciiDocReader(dict(ASCIIDOC_OPTIONS=["-a revision=1.0.42"])) + content, metadata = reader.read(_filename('article_with_asc_options.asc')) + expected = '
\n

Used for pelican test

\n'\ + '

version 1.0.42

\n'\ + '

The quick brown fox jumped over the lazy dog’s back.

\n' + self.assertEqual(content, expected)