forked from github/pelican
Added some more notes about how this is working on the documentation. I do think that the overall structure is clearer now, and easiest to understand. After all, that's how it should always be ! --HG-- rename : pelican/processors.py => pelican/generators.py rename : pelican/generators.py => pelican/writers.py
81 lines
3.4 KiB
ReStructuredText
81 lines
3.4 KiB
ReStructuredText
Pelican internals
|
|
#################
|
|
|
|
This section describe how pelican is working internally. As you'll see, it's
|
|
quite simple, but a bit of documentation doesn't hurt :)
|
|
|
|
Overall structure
|
|
=================
|
|
|
|
What `pelican` does, is taking a list of files, and processing them, to some
|
|
sort of output. Usually, the files are restructured text and markdown files,
|
|
and the output is a blog, but it can be anything you want.
|
|
|
|
I've separated the logic in different classes and concepts:
|
|
|
|
* `writers` are responsible of all the writing process of the
|
|
files. It's writing .html files, RSS feeds and so 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 Restructured
|
|
Text for now, but the system is extensible). Given a file, they return
|
|
metadata (author, tags, category etc) and content (HTML formated)
|
|
|
|
* `generators` generate the different outputs. For instance, pelican comes with
|
|
`ArticlesGenerator` and `PageGenerator`, into others. Given
|
|
a configurations, they can do whatever they want. Most of the time it's
|
|
generating files from inputs.
|
|
|
|
* `pelican` also uses `templates`, so it's easy to write you own theme. The
|
|
syntax is `jinja2`, and, trust me, really easy to learn, so don't hesitate
|
|
a second.
|
|
|
|
How to implement a new reader ?
|
|
===============================
|
|
|
|
There is an awesome markup language you want to add to pelican ?
|
|
Well, the only thing you have to do is to create a class that have a `read`
|
|
method, that is returning an HTML content and some metadata.
|
|
|
|
Take a look to the Markdown reader::
|
|
|
|
class MarkdownReader(object):
|
|
|
|
def read(self, filename):
|
|
"""Parse content and metadata of markdown files"""
|
|
text = open(filename)
|
|
md = Markdown(extensions = ['meta', 'codehilite'])
|
|
content = md.convert(text)
|
|
|
|
metadatas = {}
|
|
for name, value in md.Meta.items():
|
|
if name in _METADATAS_FIELDS:
|
|
meta = _METADATAS_FIELDS[name](value[0])
|
|
else:
|
|
meta = value[0]
|
|
metadatas[name.lower()] = meta
|
|
return content, metadatas
|
|
|
|
Simple isn't it ?
|
|
|
|
How to implement a new generator ?
|
|
==================================
|
|
|
|
Generators have basically two important methods. You're not forced to create
|
|
both, only the existing ones will be called.
|
|
|
|
* `generate_context`, that is called in a first place, for all the generators.
|
|
Do whatever you have to do, and update the global context if needed. This
|
|
context is shared between all generators, and will be passed to the
|
|
templates. For instance, the `PageGenerator` `generate_context` method find
|
|
all the pages, transform them into objects, and populate the context with
|
|
them. Be careful to *not* output anything using this context at this stage,
|
|
as it is likely to change by the effect of others generators.
|
|
|
|
* `generate_output` is then called. And guess what is it made for ? Oh,
|
|
generating the output :) That's here that you may want to look at the context
|
|
and call the methods of the `writer` object, that is passed at the first
|
|
argument of this function. In the `PageGenerator` example, this method will
|
|
look at all the pages recorded in the global context, and output a file on
|
|
the disk (using the writer method `write_file`) for each page encountered.
|