Skip to content

Commit

Permalink
Improved documentation. Loaders are callable.
Browse files Browse the repository at this point in the history
  • Loading branch information
benoitbryon committed Nov 28, 2015
1 parent 9add968 commit 8267c92
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 98 deletions.
19 changes: 10 additions & 9 deletions README.rst
Expand Up @@ -16,24 +16,25 @@ Let's import ``piecutter`` and initialize data, as a dictionary:

>>> from __future__ import print_function
>>> import piecutter
>>> data = {u'who': u'world'}

>>> data = {'who': 'world'}

Render text template against data using Python's builtin ``format()``:
Render text template against data using Python's format:

>>> render = piecutter.PythonFormatEngine()
>>> template = "Hello {who}!"
>>> print(render(template, data))
>>> template = u"Hello {who}!"
>>> output = render(template, data)
>>> print(output)
Hello world!

Templates can be loaded from custom locations. Let's load a file:

>>> loader = piecutter.LocalLoader(root='../demo/')
>>> with loader.open('hello.txt') as template:
>>> load = piecutter.LocalLoader(root=u'../demo/')
>>> with load(u'hello.txt') as template:
... print(template)
... print(render(template, data))
... output = render(template, data)
Hello {who}!
<BLANKLINE>
>>> print(output)
Hello world!
<BLANKLINE>

Expand All @@ -46,7 +47,7 @@ a template loaded from the internet and send output to standard output stream:
... writer=piecutter.StreamWriter(),
... )
>>> render(
... 'https://raw.github.com/diecutter/piecutter/cutter-api-reloaded/demo/hello.txt',
... u'https://raw.github.com/diecutter/piecutter/cutter-api-reloaded/demo/hello.txt',
... data)
Hello world!

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Expand Up @@ -46,7 +46,7 @@
# The full version, including alpha/beta/rc tags.
release = open(version_file).read().strip()
# The short X.Y version.
version = '.'.join(release.split('.')[0:1])
version = '.'.join(release.split('.')[0:2])

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
24 changes: 15 additions & 9 deletions docs/loaders.txt
Expand Up @@ -4,6 +4,12 @@ Loaders

This document describes usage for `piecutter`'s loaders.

Loaders are callables that accept location as input argument then return a
template object.

Within `piecutter`'s implementation, loaders typically are classes that
inherit from ``piecutter.Loader`` and override ``open(location)`` method.


************************************
Load templates from local filesystem
Expand All @@ -14,14 +20,14 @@ You can load local files:
.. doctest::

>>> import piecutter
>>> loader = piecutter.LocalLoader(root='../demo')
>>> load = piecutter.LocalLoader(root='../demo')

>>> with loader.open('hello.txt') as template:
>>> with load('hello.txt') as template:
... print(template)
Hello {who}!
<BLANKLINE>

>>> with loader.open('i-dont-exist.txt') as template: # Doctest: +ELLIPSIS
>>> with load('i-dont-exist.txt') as template: # Doctest: +ELLIPSIS
... print(template)
Traceback (most recent call last):
...
Expand All @@ -32,9 +38,9 @@ And local directories:
.. doctest::

>>> import piecutter
>>> loader = piecutter.LocalLoader(root='../demo')
>>> load = piecutter.LocalLoader(root='../demo')

>>> with loader.open('.') as template:
>>> with load('.') as template:
... print(template)
[{"template": "hello.txt"}]

Expand All @@ -47,9 +53,9 @@ Load files on github.com

>>> from piecutter.utils.files import temporary_directory
>>> with temporary_directory() as checkout_dir:
... loader = piecutter.GithubLoader(checkout_dir)
... load = piecutter.GithubLoader(checkout_dir)
... try:
... template = loader.open(
... template = load(
... 'diecutter/diecutter/0.7/demo/templates/greetings.txt')
... print(template)
... finally:
Expand All @@ -64,10 +70,10 @@ Load files over HTTP

.. doctest::

>>> loader = piecutter.HttpLoader()
>>> load = piecutter.HttpLoader()
>>> location = 'https://raw.githubusercontent.com' \
... '/diecutter/diecutter/0.7/demo/templates/greetings.txt'
>>> with loader.open(location) as template:
>>> with load(location) as template:
... print(template)
{{ greetings|default('Hello') }} {{ name }}!
<BLANKLINE>
109 changes: 62 additions & 47 deletions docs/overview.txt
Expand Up @@ -2,34 +2,55 @@
Overview
########

This document describes `piecutter`'s concepts and main features.
This document introduces `piecutter`'s concepts and main features.
See also :doc:`/about/vision`.

.. testsetup::

from __future__ import print_function


****************
Import piecutter
****************

Provided :doc:`piecutter is installed </install>`, let's import ``piecutter``
library:

.. doctest::

>>> import piecutter # All-in-one API.
>>> data = {'who': 'world'} # Prepare data as a dictionary.


*********
Renderers
*********

:doc:`Renderers </renderers>` are the core feature of `piecutter`. They use
:doc:`Renderers </renderers>` are the core components of `piecutter`. They use
template engines to generate output using templates and context data.

Renderers typically are classes that implement a ``render(template, context)``
method which generates output.
Renderers are callables that accept template and data as input then return
generated output.

`piecutter` supports several template engines with a single API:
.. doctest::

* Python's builtin string format
* Jinja2
* Django
* ... and all you can implement!
>>> render = piecutter.PythonFormatEngine()
>>> output = render(u'Hello {who}!', {u'who': u'world'})
>>> print(output)
Hello world!

`piecutter` also provides a special engine that guesses the adequate template
engine based on the content of the template.
`piecutter`'s initial concept is to provide a single API to handle multiple
template engines. `piecutter`'s core currently supports the following
third-party engines:

* `Python's builtin string format`_;
* `Jinja2`_;
* `Django`_.

Of course, you can implement custom renderers.

`piecutter` also provides a special renderer that tries to guess the engine
based on the content of the template.

Learn more in :doc:`/renderers`.

Expand All @@ -40,43 +61,22 @@ Loaders

:doc:`Loaders </loaders>` load :doc:`templates </templates>`.

Loaders typically are classes that define a ``load(location)`` method. This
method returns a template object.

`piecutter` provides builtin support for various locations:

* files on local filesystem:
Loaders are callables that accept location as input argument then return a
template object.

.. doctest::

>>> loader = piecutter.LocalLoader(root='../demo')
>>> with loader.open('hello.txt') as template:
... print(template)
Hello {who}!
<BLANKLINE>

* remote files over HTTP:

.. doctest::

>>> loader = piecutter.HttpLoader()
>>> location = 'https://raw.githubusercontent.com' \
... '/diecutter/diecutter/0.7/demo/templates/greetings.txt'
>>> with loader.open(location) as template:
... print(template)
{{ greetings|default('Hello') }} {{ name }}!
<BLANKLINE>
.. doctest::

* remote files on Github:
>>> load = piecutter.LocalLoader(root=u'../demo')
>>> with load(u'hello.txt') as template:
... print(template)
Hello {who}!
<BLANKLINE>

.. code:: pycon
`piecutter` provides builtin support for various locations:

>>> loader = piecutter.GithubLoader()
>>> location = 'diecutter/piecutter/master/demo/hello.txt'
>>> with loader.open(location) as template:
... print(template)
Hello {who}!
<BLANKLINE>
* files on local filesystem;
* remote files over HTTP;
* remote files on Github.

Of course, you can write your own loaders!

Expand All @@ -97,7 +97,7 @@ Templates can represent either single units (files) or collections

.. doctest::

>>> render = piecutter.PythonFormatEngine() # Tip: renderers are callables.
>>> render = piecutter.PythonFormatEngine()

>>> print(render('Hello {who}!', {'who': 'world'}))
Hello world!
Expand All @@ -112,7 +112,12 @@ Data
****

`piecutter` uses mappings as context data. Any dictionary-like object can be
used. See :doc:`context` for details.
used.

During rendering, additional contextual data is added to the original, such as
``piecutter.engine``, which represents template engine name.

See :doc:`context` for details.


*******
Expand Down Expand Up @@ -186,3 +191,13 @@ template engine is called, context data is updated with some `piecutter`'s
internals... Everywhere processing could be done by either one or several
functions, you can use dispatchers: they look like one function but encapsulate
several calls.


.. rubric:: Notes & references

.. target-notes::

.. _`Python's builtin string format`:
https://docs.python.org/2.7/library/string.html#formatstrings
.. _`Jinja2`: http://jinja.pocoo.org/
.. _`Django`: https://docs.djangoproject.com/en/1.8/topics/templates/
59 changes: 28 additions & 31 deletions docs/renderers.txt
Expand Up @@ -4,9 +4,17 @@ Renderers & engines

This document explains `piecutter`'s renderers.

Renderers use template engines to generate output using templates and context
data. They typically are classes that implement a ``render(template, context)``
method which generates output.
.. testsetup::

from __future__ import print_function

Renderers use template engines to generate output using templates and data.

Renderers are callables that accept ``template, data`` as input then return
generated output.

Within `piecutter`'s implementation, renderers typically are classes that
inherit ``piecutter.Engine`` and override ``render(template, context)`` method.


*************
Expand All @@ -16,8 +24,9 @@ Python format
.. doctest::

>>> import piecutter
>>> renderer = piecutter.PythonFormatEngine()
>>> print renderer.render('Hello {who}!', {'who': 'world'})
>>> render = piecutter.PythonFormatEngine()
>>> output = render(u'Hello {who}!', {u'who': u'world'})
>>> print(output)
Hello world!


Expand All @@ -28,8 +37,9 @@ Jinja2
.. doctest::

>>> import piecutter
>>> renderer = piecutter.Jinja2Engine()
>>> print renderer.render('Hello {{ who }}!', {'who': 'world'})
>>> render = piecutter.Jinja2Engine()
>>> output = render(u'Hello {{ who }}!', {u'who': u'world'})
>>> print(output)
Hello world!


Expand All @@ -40,8 +50,9 @@ Django
.. doctest::

>>> import piecutter
>>> renderer = piecutter.DjangoEngine()
>>> print renderer.render('Hello {{ who }}!', {'who': 'world'})
>>> render = piecutter.DjangoEngine()
>>> output = render(u'Hello {{ who }}!', {u'who': u'world'})
>>> print(output)
Hello world!


Expand All @@ -53,18 +64,18 @@ This is a special renderer that tries to detect best engine depending on
template and environment (installed engines).

>>> import piecutter
>>> renderer = piecutter.SmartEngine(
>>> render = piecutter.SmartEngine(
... engines=[
... piecutter.Jinja2Engine(),
... piecutter.DjangoEngine(),
... piecutter.PythonFormatEngine(),
... ],
... )
>>> print renderer.render("{# Jinja2 #}Hello {{ who }}!", {'who': 'world'})
>>> print(render(u"{# Jinja2 #}Hello {{ who }}!", {u'who': u'world'}))
Hello world!
>>> print renderer.render("{# Django #}Hello {{ who }}!", {'who': 'world'})
>>> print(render(u"{# Django #}Hello {{ who }}!", {u'who': u'world'}))
Hello world!
>>> print renderer.render("Hello {who}!", {'who': 'world'})
>>> print(render(u"Hello {who}!", {u'who': u'world'}))
Hello world!


Expand All @@ -77,27 +88,13 @@ Renderers can also handle directories, as collections of single templates:
.. doctest::

>>> data = {'who': 'world'}
>>> renderer = piecutter.PythonFormatEngine()
>>> render = piecutter.PythonFormatEngine()
>>> loader = piecutter.LocalLoader(root='../demo/')
>>> with loader.open('.') as parent_template:
... for child_template in renderer.render(parent_template, data):
... print child_template.name
... for child_template in render(parent_template, data):
... print(child_template.name)
... with loader.open(child_template.name) as child_opened:
... print child_opened
... print(child_opened)
hello.txt
Hello {who}!
<BLANKLINE>


***********************
Renderers are callables
***********************

Builtin `piecutter` renderers are callables:

.. doctest::

>>> import piecutter
>>> render = piecutter.PythonFormatEngine()
>>> print render('Hello {who}!', {'who': 'world'})
Hello world!

0 comments on commit 8267c92

Please sign in to comment.