2010-10-01 1 views
1

Привет, Я пытался создать расширение для jinja2, которое объединило бы несколько элементов с разделителем, а пропуская элементы (фрагменты шаблона), которые оцениваются в пробелы.Как написать расширение «столяр» для Jinja2?

Есть несколько таких фрагментов, и вы никогда не знаете заранее, какие из них будут не пустыми и какие будут.

Звучит как тривиальная задача, но у меня было очень тяжелое время, чтобы это работало в jinja2. Возможно, причина в том, что jinja не позволяет определять пользовательские узлы шаблонов.

У вас есть предложения? Ниже приведен фрагмент, который будет выполнять синтаксический анализ, но ему не хватает части оценки.

class JoinerExtension(Extension): 
    """Template tag that joins non-whitespace (string) items 
    with a specified separator 

    Usage syntax: 

    {% joinitems separator='|' %} 
    .... 
    {% separator %} 
    .... 
    {% separator %} 
    .... 
    {% endjoinitems %} 

    where value of "separator" within the joinitems tag 
    can be an expression, not necessarily a sting 
    """ 

    tags = set(['joinitems']) 

    def parse(self, parser): 
     """parse function for the 
     joinitems template tag 
     """ 
     lineno = next(parser.stream).lineno 

     #1) read separator 
     separator = None 
     while parser.stream.current.type != 'block_end': 
      name = parser.stream.expect('name') 
      if name.value != 'separator': 
       parser.fail('found %r, "separator" expected' % 
          name.value, name.lineno, 
          exc=TemplateAssertionError) 

      # expressions 
      if parser.stream.current.type == 'assign': 
       next(parser.stream) 
       separator = parser.parse_expression() 
      else: 
       var = parser.stream.current 
       parser.fail('assignment expected after the separator' % 
          var.value, var.lineno, 
          exc=TemplateAssertionError) 

     #2) read the items 
     items = list() 
     end_tags = ['name:separator', 'name:endjoinitems'] 
     while True: 
      item = parser.parse_statements(end_tags) 
      items.append(item) 
      if parser.stream.current.test('name:separator'): 
       next(parser.stream) 
      else: 
       next(parser.stream) 
       break 

ответ

4

Может ли функционировать класс joiner? Вот простой пример из документации.

{% set pipe = joiner("|") %} 
{% if categories %} {{ pipe() }} 
    Categories: {{ categories|join(", ") }} 
{% endif %} 
{% if author %} {{ pipe() }} 
    Author: {{ author() }} 
{% endif %} 
{% if can_edit %} {{ pipe() }} 
    <a href="?action=edit">Edit</a> 
{% endif %} 

Вы упомянули, что заранее не известно, какие фрагменты будут пустыми; возможно, можно сохранить значение каждого фрагмента в переменной перед «отображением», чтобы вы могли определить, какие фрагменты действительно пусты. Например:

{% set pipe = joiner("|") %} 
{% set fragment = gen_fragment1() %} 
{% if fragment|trim is not "" %} 
    {{ pipe() }} {{ fragment }} 
{% endif %} 
... 

Можно даже инкапсулировать выше шаблон в макросе, чтобы уменьшить повторение:

{% set pipe = joiner("|") %} 
{{ print_if_notblank(pipe, gen_fragment1()) }} 
{{ print_if_notblank(pipe, gen_fragment2()) }} 
... 

где print_if_notblank макрос определяется как:

{% macro print_if_notblank(separator, content) %} 
    {% if content|trim is not "" %} 
     {{ separator() }} {{ content }} 
    {% endif %} 
{% endmacro %} 
+0

, который будет работать, используя встроенный в настоящее время со стратегически размещенными {{pipe()}} вызовами. – Evgeny