Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Big refactoring around cutter API #15

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ Initial release.

.. target-notes::

.. _`milestones`: https://github.com/diecutter/piecutter/issues/milestones
.. _`milestones`: https://github.com/diecutter/piecutter/milestones
4 changes: 2 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ environment:
.. _`bugtracker`: https://github.com/diecutter/piecutter/issues
.. _`rebase`: http://git-scm.com/book/en/Git-Branching-Rebasing
.. _`merge-based rebase`: http://tech.novapost.fr/psycho-rebasing-en.html
.. _`Python`: http://python.org
.. _`virtualenv`: http://virtualenv.org
.. _`Python`: https://www.python.org
.. _`virtualenv`: https://pypi.python.org/pypi/virtualenv/
.. _`pip`: https://pypi.python.org/pypi/pip/
.. _`tox`: https://pypi.python.org/pypi/tox/
.. _`Sphinx`: https://pypi.python.org/pypi/Sphinx/
Expand Down
2 changes: 1 addition & 1 deletion INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ You should get `piecutter`'s version.

.. target-notes::

.. _`Python`: http://python.org
.. _`Python`: https://www.python.org
.. _`pip`: https://pypi.python.org/pypi/pip/
174 changes: 105 additions & 69 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,117 +4,153 @@ piecutter

`piecutter` is a template rendering framework, written in `Python`_.

Leitmotiv: **render templates against context**, wherever the templates,
whatever the template engine.
Leitmotiv: **render templates against data**, wherever the templates, whatever
the template engine.


**************
Project status
**************
************
Key features
************

`piecutter` is under active development.
**Simple API**: ``render(template, data)``.

**Yesterday**, `piecutter` was the core of `diecutter`_.
**Render files and directories**, a.k.a. single templates and collections of
templates.

As `diecutter`'s authors, we think `diecutter` has great features related to
templates and file generation. We wanted to share it with a larger audience.
So we just packaged it as a standalone library.
And we are planning to make it better as soon as possible.
`Join us`_ if you like the features ;)
**Multiple template engines**: `Python's format()`_, `Jinja2`_ and `Django`_...
Additional engines such as `Cheetah`_ or non-Python template engines such as
Ruby's `ERB`_ could be supported.

Here are some of our motivations:
**Extensible template loading**: text, bytes, file-like objects, files on
local filesystem, remote resources over HTTP, remote resources on github.com...
Additional storages could be supported.

* third-party projects can use `piecutter`. They do not have to depend on
`diecutter`, which embeds some specific code related to its web service.
**Configurable post-processing pipeline**: write to local filesystem, generate
an archive... It's easy to create your own.

* as a standalone library, `piecutter` should be easier to maintain and
improve.
**Dynamic directory generation**: generate one template multiple times with
different data, exclude some files depending on context, include templates from
external locations, use several template engines...

* `piecutter` is more open than `diecutter`. It can have a larger community.
It also may converge with similar tools.

**Today**, `piecutter` is tied to `diecutter` implementation. The API
reflects `diecutter`'s architecture and concepts, which may sound obscure for
other usage.
********
Examples
********

**Tomorrow**, we are planning to improve `piecutter`. As an example, we think
the API should be refactored, with simplicity in mind.
Hello world!
============

Let's generate the traditional "Hello world!":

*******
Example
*******
>>> import piecutter
>>> template = u'Hello {who}!' # Text is recognized as a template.
>>> data = {u'who': u'world'} # Data can be any dictionary-like object.
>>> render = piecutter.Cutter() # Default engine uses Python's format().
>>> output = render(template, data) # Default output is a file-like object.
>>> print(output.read())
Hello world!

Here is a simple demo of `piecutter`'s API:
.. note::

.. code:: pycon
``piecutter.Cutter`` provides sane defaults. Then every part of the
rendering pipeline can be customized in order to fit specific cases.

>>> import piecutter
>>> cutter = piecutter.Cutter(engine=piecutter.PythonFormatEngine())
>>> print(cutter.render("Hello {who}!", {'who': 'world'}))
Hello world!
Load files
==========

Here is another setup, where several template engines are registered:
Let's load and render a template located on local filesystem:

.. code:: pycon
>>> location = u'file://demo/simple/hello.txt'
>>> output = render(location, data)
>>> print(output.read())
Hello world!
<BLANKLINE>

>>> cutter = piecutter.Cutter(
... engine=piecutter.GuessEngine(
... engines=[
... piecutter.Jinja2Engine(),
... piecutter.DjangoEngine(),
... piecutter.PythonFormatEngine(),
... ],
... )
... )
It works as well with a remote template over HTTP:

Then we can use the cutter to render various templates:
>>> location = u'https://raw.github.com/diecutter/piecutter/cutter-api-reloaded/demo/simple/hello.txt'
>>> output = render(location, data)
>>> print(output.read())
Hello world!
<BLANKLINE>

.. code:: pycon
.. note::

>>> cutter.render("{# Jinja2 #}Hello {{ who }}!", {'who': 'world'})
'Hello world!'
>>> cutter.render("{# Django #}Hello {{ who }}!", {'who': 'world'})
'Hello world!'
>>> cutter.render("Hello {who}!", {'who': 'world'})
'Hello world!'
``piecutter.Cutter``'s default loader detects scheme (``file://`` and
``https://`` in examples above) then delegates actual loading to
specialized loader implementation.

Render directories
==================

************
Key features
************
Given the following directory:

* Simple API: render templates against context.
.. code:: text

* Support multiple template engines: `Jinja2`_ and `Django`_ for now. Later:
`Cheetah`_ and even non-Python template engines such as Ruby's `ERB`_.
demo/simple/
├── hello.txt # Contains "Hello {who}!\n"
└── {who}.txt # Contains "Whatever the content.\n"

* Render files and directories.
By default, directories are rendered as generator of rendered objects. So
can iterate generated items and use their attributes and methods:

* Load templates from almost everywhere: local filesystem and github.com for
now. Later: Django storages...
>>> for item in render(u'file://demo/simple', data):
... if isinstance(item, piecutter.RenderedFile):
... print('File: {}'.format(item.name))
... print('Path: {}'.format(item.path))
... print('Content: {}'.format(item.read()))
... else: # Is instance of ``piecutter.RenderedDirectory``
... pass # We may handle sub-directories recursively here.
File: hello.txt
Path: simple/hello.txt
Content: Hello world!
<BLANKLINE>
File: world.txt
Path: simple/world.txt
Content: Whatever the content.
<BLANKLINE>

Of course, you may want to write output to disk or to an archive. `piecutter`
provides "writers" for that purpose!


**************
Project status
**************

**Yesterday**, `piecutter` was the core of `diecutter`_.

As `diecutter`'s authors, we think `diecutter` has great features related to
templates and file generation. We wanted to share it with a larger audience.
So we just packaged it as a standalone library, and this is `piecutter`.

In early versions, `piecutter` was tied to `diecutter` implementation. The API
reflected `diecutter`'s architecture and concepts, which may sound obscure for
other usage.

* Do what you want with generated content: write to local filesystem, generate
an archive...
**Today**, `piecutter`'s API has been refactored, with simplicity in mind,
independantly from `diecutter`.


*********
Resources
*********

* Documentation: https://piecutter.readthedocs.org
* Documentation: https://piecutter.readthedocs.io
* PyPI page: http://pypi.python.org/pypi/piecutter
* Bugtracker: https://github.com/diecutter/piecutter/issues
* Changelog: https://piecutter.readthedocs.org/en/latest/about/changelog.html
* Roadmap: https://github.com/diecutter/piecutter/issues/milestones
* Changelog: https://piecutter.readthedocs.io/en/latest/about/changelog.html
* Roadmap: https://github.com/diecutter/piecutter/milestones
* Code repository: https://github.com/diecutter/piecutter
* Continuous integration: https://travis-ci.org/diecutter/piecutter


.. _`Python`: https://python.org
.. _`Python`: https://www.python.org
.. _`diecutter`: http://diecutter.io
.. _`join us`: https://piecutter.readthedocs.org/en/latest/contributing.html
.. _`join us`: https://piecutter.readthedocs.io/en/latest/contributing.html
.. _`Python's format()`:
https://docs.python.org/3/library/string.html#formatstrings
.. _`Jinja2`: http://jinja.pocoo.org/
.. _`Django`: https://djangoproject.com
.. _`Django`: https://www.djangoproject.com
.. _`Cheetah`: http://pythonhosted.org/Cheetah/
.. _`ERB`: http://ruby-doc.org/
1 change: 1 addition & 0 deletions demo/nested/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a demo for folder containing files and nested-folders.
1 change: 1 addition & 0 deletions demo/nested/{name}-folder/hello.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello {who}!
1 change: 1 addition & 0 deletions demo/simple/hello.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello {who}!
1 change: 1 addition & 0 deletions demo/simple/{who}.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Whatever the content.
18 changes: 10 additions & 8 deletions docs/about/vision.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,24 @@ Render template against data
* you have a template. To its simplest expression, it is content with
placeholders ;

* you have data ;
* you have data, typically a mapping ;

* you want to render the template against the data.

The important point here is that, as an user, you handle templates and data,
whereas you do not want to bother with the rendering process. You expect
`piecutter` to generate the content, whatever the template and the data you
provide.
The important point here is that, **as an user you want to focus on templates
and data**, because they are your content, the bits that you own and manage.

**As an user, you do not want to bother with the rendering process.** And that
is `piecutter`'s primary goal: encapsulate content generation, whatever the
template and the data you provide.


**********************
Wherever the templates
**********************

Templates can theorically live anywhere: on local filesystem, on remote places,
or they could be generated in some way... As a user, I do not want to bother
or they could be generated in some way... As an user, I do not want to bother
with template loading, I just want templates to be loaded and rendered against
data.

Expand Down Expand Up @@ -60,7 +62,7 @@ Data is dictionary-like
various locations. The `Python`_ language has nice libraries for that purpose.

`piecutter` expects a structured data input, i.e. a dictionary-like object.
That's enough.
And it should be enough.


***********
Expand All @@ -76,4 +78,4 @@ tools. It is easy to extend.

.. target-notes::

.. _`Python`: http://python.org
.. _`Python`: https://www.python.org
Loading