Skip to content

Commit

Permalink
Psycho-rebased branch 77-template-engine-header on top of master
Browse files Browse the repository at this point in the history
  • Loading branch information
benoitbryon committed Apr 16, 2014
2 parents dcacb19 + f060c7c commit 3b5752b
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 14 deletions.
37 changes: 25 additions & 12 deletions diecutter/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import diecutter
import diecutter.validators
import diecutter.utils
from diecutter.settings import TEMPLATE_ENGINES_MAPPING
from diecutter.writers import (zip_directory_response,
file_response,
targz_directory_response)
Expand Down Expand Up @@ -40,27 +41,39 @@ def get_resource(self, request):
"""Return the resource object (instance) matching request."""
raise NotImplementedError()

def get_engine_factory(self, request, filename=False):
""" Returns the class of an engine """
param_name = 'diecutter{}filename_template_engine' if filename \
else 'diecutter{}template_engine'

if param_name.format('_') in request.headers:
try:
engine_path = TEMPLATE_ENGINES_MAPPING[
request.headers[param_name.format('_')]
]
except KeyError:
raise HTTPNotAcceptable('Supported template engines: %s'
% ', '.join(sorted(
TEMPLATE_ENGINES_MAPPING.keys())))
else:
engine_path = request.registry.settings[param_name.format('.')]

config = Configurator(request.registry.settings)
engine_factory = config.maybe_dotted(engine_path)

return engine_factory

def get_engine(self, request):
"""Return configured template engine to render templates."""
settings = request.registry.settings
config = Configurator(settings)
engine_factory_path = settings['diecutter.template_engine']
engine_factory = config.maybe_dotted(engine_factory_path)
engine = engine_factory()
return engine
return self.get_engine_factory(request)()

def get_filename_engine(self, request):
"""Return configured template engine to render filenames.
This is not used for dynamic trees.
"""
settings = request.registry.settings
config = Configurator(settings)
engine_factory_path = settings['diecutter.filename_template_engine']
engine_factory = config.maybe_dotted(engine_factory_path)
engine = engine_factory()
return engine
return self.get_engine_factory(request, filename=True)()

def get_writers(self, request, resource, context):
"""Return iterable of writers."""
Expand Down
12 changes: 10 additions & 2 deletions diecutter/settings.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
# -*- coding: utf-8 -*-
"""Parse settings, set defaults."""

#: Mapping between engine name and engines.
#: Used when getting the engine name from the user.
TEMPLATE_ENGINES_MAPPING = {
'django': 'piecutter.engines.django:DjangoEngine',
'jinja2': 'piecutter.engines.jinja:Jinja2Engine',
'filename': 'piecutter.engines.filename:FilenameEngine',
}

#: Default values for settings.
defaults = {
DEFAULTS = {
'diecutter.service': 'diecutter.local:LocalService',
'diecutter.template_engine': 'piecutter.engines.jinja:Jinja2Engine',
'diecutter.filename_template_engine': 'piecutter.engines.filename'
Expand All @@ -17,6 +25,6 @@ def normalize(settings={}):
"""
normalized = settings.copy()
for key, value in defaults.items():
for key, value in DEFAULTS.items():
normalized.setdefault(key, value)
return normalized
37 changes: 37 additions & 0 deletions diecutter/tests/engine_selector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
"""Tests around the functions to select templates."""
import unittest
try:
from unittest import mock
except ImportError:
import mock

from piecutter.engines.django import DjangoEngine
from piecutter.engines.jinja import Jinja2Engine
from pyramid.httpexceptions import HTTPNotAcceptable

from diecutter.service import Service
from diecutter.settings import DEFAULTS


class EngineSelectorTestCase(unittest.TestCase):
"""Tests around the functions to select templates."""
def setUp(self):
self.service = Service()

def test_engine_factory(self):
request = mock.Mock()
request.registry = mock.Mock()
request.registry.settings = DEFAULTS

request.headers = {}
self.assertEquals(self.service.get_engine_factory(request),
Jinja2Engine)

request.headers = {"diecutter_template_engine": 'django'}
self.assertEquals(self.service.get_engine_factory(request),
DjangoEngine)

request.headers = {"diecutter_template_engine": "<invalid>"}
self.assertRaises(HTTPNotAcceptable,
self.service.get_engine_factory, request)
21 changes: 21 additions & 0 deletions diecutter/tests/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,27 @@ def test_post_file(self):
# Check content.
self.assertEqual(response.body, "Hello world!")

def test_header_for_specific_template_engine(self):
""" Try to use the Django template engine by setting a header. """
content = "Hello {{ who }}!"
server_filename = os.path.join(self.template_dir.path, 'hello')
open(server_filename, 'w').write(content)
headers = {'diecutter_template_engine': 'django'}
# Perform request.
response = self.app.post('/hello', {'who': 'world'},
headers=headers, status=200)
# Check content.
self.assertEqual(response.body, "Hello world!")

def test_invalid_header_template_engine(self):
""" Try to us an invalid template engine by setting a header. """
content = "Hello {{ who }}!"
server_filename = os.path.join(self.template_dir.path, 'hello')
open(server_filename, 'w').write(content)
headers = {'diecutter_template_engine': 'invalid'}
# Perform request, and check if the status code is 406
self.app.post('/hello', {'who': 'world'}, headers=headers, status=406)

def test_post_directory_targz(self):
"""POST context for directory returns TAR.GZ file content."""
# Setup.
Expand Down

0 comments on commit 3b5752b

Please sign in to comment.