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

Pass positional arguments to template-based shortcodes #2320

Merged
merged 1 commit into from
Apr 19, 2016
Merged
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
Pass positional arguments to template-based shortcodes (implements #2319
)

Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
  • Loading branch information
SpotlightKid committed Apr 18, 2016
commit b6aa4310fa722a282226459380880900eaadb571
33 changes: 24 additions & 9 deletions nikola/nikola.py
Original file line number Diff line number Diff line change
Expand Up @@ -1316,24 +1316,39 @@ def url_replacer(self, src, dst, lang=None, url_type=None):

return result

def _make_renderfunc(self, t_data):
"""Return a function that can be registered as a template shortcode.

The returned function has access to the passed template data and
accepts any number of positional and keyword arguments. Positional
arguments values are added as a tuple under the key ``_args`` to the
keyword argument dict and then the latter provides the template
context.

"""
def render_shortcode(*args, **kw):
kw['_args'] = args
return self.template_system.render_template_to_string(t_data, kw)
return render_shortcode

def _register_templated_shortcodes(self):
"""Register shortcodes provided by templates in shortcodes/ folders."""
builtin_sc_dir = resource_filename('nikola', os.path.join('data', 'shortcodes', utils.get_template_engine(self.THEMES)))
sc_dirs = [builtin_sc_dir, 'shortcodes']
builtin_sc_dir = resource_filename(
'nikola',
os.path.join('data', 'shortcodes', utils.get_template_engine(self.THEMES)))

for sc_dir in sc_dirs:
for sc_dir in [builtin_sc_dir, 'shortcodes']:
if not os.path.isdir(sc_dir):
continue

for fname in os.listdir(sc_dir):
name, ext = os.path.splitext(fname)
if ext == '.tmpl':
with open(os.path.join(sc_dir, fname)) as fd:
template_data = fd.read()

def render_shortcode(t_data=template_data, **kw):
return self.template_system.render_template_to_string(t_data, kw)
if ext != '.tmpl':
continue

self.register_shortcode(name, render_shortcode)
with open(os.path.join(sc_dir, fname)) as fd:
self.register_shortcode(name, self._make_renderfunc(fd.read()))

def register_shortcode(self, name, f):
"""Register function f to handle shortcode "name"."""
Expand Down
86 changes: 86 additions & 0 deletions tests/test_template_shortcodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
# vim: set wrap textwidth=100
"""Test template-based shortcodes."""

from __future__ import unicode_literals

import pytest
from nikola import Nikola


class ShortcodeFakeSite(Nikola):
def _get_template_system(self):
if self._template_system is None:
# Load template plugin
self._template_system = self.plugin_manager.getPluginByName(
'jinja', "TemplateSystem").plugin_object
self._template_system.set_directories('.', 'cache')
self._template_system.set_site(self)

return self._template_system

template_system = property(_get_template_system)


@pytest.fixture(scope="module")
def fakesite():
s = ShortcodeFakeSite()
s.init_plugins()
s._template_system = None
return s


def test_mixedargs(fakesite):
TEST_TMPL = """
arg1: {{ _args[0] }}
arg2: {{ _args[1] }}
kwarg1: {{ kwarg1 }}
kwarg2: {{ kwarg2 }}
"""

fakesite.shortcode_registry['test1'] = \
fakesite._make_renderfunc(TEST_TMPL)
fakesite.shortcode_registry['test2'] = \
fakesite._make_renderfunc('Something completely different')

res = fakesite.apply_shortcodes(
'{{% test1 kwarg1=spamm arg1 kwarg2=foo,bar arg2 %}}')

assert res.strip() == """
arg1: arg1
arg2: arg2
kwarg1: spamm
kwarg2: foo,bar""".strip()


def test_onearg(fakesite):
fakesite.shortcode_registry['test1'] = \
fakesite._make_renderfunc('arg={{ _args[0] }}')

assert fakesite.apply_shortcodes('{{% test1 onearg %}}') == 'arg=onearg'
assert fakesite.apply_shortcodes('{{% test1 "one two" %}}') == 'arg=one two'


def test_kwarg(fakesite):
fakesite.shortcode_registry['test1'] = \
fakesite._make_renderfunc('foo={{ foo }}')

res = fakesite.apply_shortcodes('{{% test1 foo=bar %}}')
assert res == 'foo=bar'
res = fakesite.apply_shortcodes('{{% test1 foo="bar baz" %}}')
assert res == 'foo=bar baz'
res = fakesite.apply_shortcodes('{{% test1 foo="bar baz" spamm=ham %}}')
assert res == 'foo=bar baz'


def test_data(fakesite):
fakesite.shortcode_registry['test1'] = \
fakesite._make_renderfunc('data={{ data }}')

res = fakesite.apply_shortcodes('{{% test1 %}}spamm spamm{{% /test1 %}}')
assert res == 'data=spamm spamm'
res = fakesite.apply_shortcodes('{{% test1 spamm %}}')
assert res == 'data='
# surprise!
res = fakesite.apply_shortcodes('{{% test1 data=dummy %}}')
assert res == 'data='