Example #1
0
 def install(cls):
     ''' Installs various shortcuts intended to be used with Jinja (version 2) templates.
     
     Specifically, allows for the following markup in templates:
     
     1. Automatic generation of appropriate closing tags for template instructions:
     
     % if
         ...
     % else
         ...
     
     2. '% tag' shortcut as a replacement for '{% tag %}', and corresponding
        shpaml-style self-closing tag:
     
     % block bar
         ...
     
     % >block
     
     3. '>tag' is equivalent to '> tag'.
     
     4. '= expression' is equivalent to '{{ expression }}'
     
     5. '~ text' is equivalent to '{% trans %}text{% endtrans %}'
     '''
     
     @shpaml.syntax(r'{% > *((\w+).*)')
     def SELF_CLOSING_TEMPLATE_STATEMENT(m):
         tag = m.group(1).strip()
         return '{%% %s{%% end%s %%}' % (m.group(1), m.group(2))
     
     shpaml.LINE_METHODS.insert(0, SELF_CLOSING_TEMPLATE_STATEMENT)
     
     TEMPLATE_STATEMENT = re.compile(r'{% (\w+)')
     
     def html_block_tag_with_template_statement(html_block_tag_without_template_statement, output, block, recurse):
         append = output.append
         prefix, tag = block[0]
         if shpaml.RAW_HTML.regex.match(tag):
             match = TEMPLATE_STATEMENT.match(tag)
             if match:
                 append(prefix + whitespace_removal.TextWithoutWhitespace(tag))
                 recurse(block[1:])
                 append(prefix + whitespace_removal.TextWithoutWhitespace('{% end' + match.group(1) + ' %}'))
                 return
         html_block_tag_without_template_statement(output, block, recurse)
     
     runtime.hook_module_function(shpaml, 'html_block_tag', html_block_tag_with_template_statement)
Example #2
0
    def install(cls):
        """ Installs various shortcuts intended to be used with Embedded Ruby (ERb) templates.
        
        Specifically, allows for the following markup in templates:
        
        1. Automatic generation of appropriate closing tags for template instructions:
        
        % if
            ...
        % else
            ...
        
        2. '% stmt' shortcut as a replacement for '<% stmt %>', and corresponding
           shpaml-style self-closing tag:
        
        % for post in @posts
            ...
        
        % >content_for :foo do
        
        3. '>tag' is equivalent to '> tag'.
        
        4. '= expression' is equivalent to '<%= expression %>'
        """

        @shpaml.syntax(r"<% > *((\w+).*)")
        def SELF_CLOSING_TEMPLATE_STATEMENT(m):
            tag = m.group(1).strip()
            return "<%% %s<%% end %%>" % (m.group(1))

        shpaml.LINE_METHODS.insert(0, SELF_CLOSING_TEMPLATE_STATEMENT)

        TEMPLATE_STATEMENT = re.compile(r"<%(!?) (\w+)")

        def html_block_tag_with_template_statement(html_block_tag_without_template_statement, output, block, recurse):
            append = output.append
            prefix, tag = block[0]
            if shpaml.RAW_HTML.regex.match(tag):
                match = TEMPLATE_STATEMENT.match(tag)
                if match:
                    append(prefix + whitespace_removal.TextWithoutWhitespace(tag))
                    recurse(block[1:])
                    finalizer = "<%%%s end %%>" % match.group(1)
                    append(prefix + whitespace_removal.TextWithoutWhitespace(finalizer))
                    return
            html_block_tag_without_template_statement(output, block, recurse)

        runtime.hook_module_function(shpaml, "html_block_tag", html_block_tag_with_template_statement)
Example #3
0
 def install(cls):
     ''' Installs smart whitespace removal logic.
     
     Shpaml provides for two syntaxes for putting text inside tags:
     
     a href=foo
         bar
     
     generates:
     
     <a href="foo">
         bar
     </a>
     
     and
     
     a href=foo |bar
     
     generates:
     
     <a href="foo">bar</a>
     
     "bar" in this example can become quite complex if a template engine
     is used and it is actually an expression. Furthermore jinja shortcuts
     above work on line level only.
     
     Whitespace removal allows this markup:
     
     a href=foo
         ~ bar
     
     to be converted to:
     
     <a href="foo">{% trans %}bar{% endtrans %}</a>
     
     instead of:
     
     <a href="foo">
         {% trans %}bar{% endtrans %}
     </a>
     
     The assumption is that whitespace can always be removed between a block
     tag and its children.
     
     Nested tags behave as expected:
     
     ul
         li
             a href=foo
                 bar
     
     generates:
     
     <ul><li><a href="foo">bar</a></li></ul>
     
     Significant whitespace may be emitted via tools provided by template
     engine, for example:
     
     a href=foo
         = ' bar'
     
     If whitespace removal is installed, leading whitespace on lines containing
     only template instructions (% shortcut) or that start with block tags will
     also be removed.
     '''
     
     class StartBlockTag(TextWithoutWhitespace):
         pass
     
     class EndBlockTag(TextWithoutWhitespace):
         pass
     
     class Line(TextWithoutWhitespace):
         pass
     
     def convert_line_with_whitespace_removal(convert_line_without_whitespace_removal, line):
         line = convert_line_without_whitespace_removal(line)
         return Line(line)
     
     def apply_jquery_sugar_with_whitespace_removal(apply_jquery_sugar_without_whitespace_removal, markup):
         start_tag, end_tag = apply_jquery_sugar_without_whitespace_removal(markup)
         return (StartBlockTag(start_tag), EndBlockTag(end_tag))
     
     class Indentation(unicode):
         def __add__(self, other):
             if isinstance(other, TextWithoutWhitespace):
                 return other
             else:
                 return unicode.__add__(self, other)
     
     def indent_lines_with_whitespace_removal(
         indent_lines_without_whitespace_removal,
         lines,
         output,
         branch_method,
         leaf_method,
         pass_syntax,
         flush_left_syntax,
         flush_left_empty_line,
         indentation_method,
         get_block,
     ):
         # output is modified
         indent_lines_without_whitespace_removal(
             lines,
             output,
             branch_method,
             leaf_method,
             pass_syntax,
             flush_left_syntax,
             flush_left_empty_line,
             indentation_method,
             get_block,
         )
         
         # need to modify output in place
         copy = list(output)
         while len(output) > 0:
             output.pop()
         while len(copy) > 1:
             first, second = copy[:2]
             if len(copy) >= 3:
                 third = copy[2]
             else:
                 third = None
             if isinstance(second, EndBlockTag):
                 if isinstance(third, EndBlockTag):
                     copy[1] = EndBlockTag(second + third)
                     copy.pop(2)
                 else:
                     output.append(first + second)
                     copy.pop(0)
                     copy.pop(0)
             elif isinstance(first, StartBlockTag):
                 cls = second.__class__
                 copy[0] = cls(first + second)
                 copy.pop(1)
             else:
                 output.append(first)
                 copy.pop(0)
         if len(copy) > 0:
             output.append(copy[0])
     
     def find_indentation_with_whitespace_removal(find_indentation_without_whitespace_removal, line):
         prefix, line = find_indentation_without_whitespace_removal(line)
         return (Indentation(prefix), line)
     
     runtime.hook_module_function(shpaml, 'convert_line', convert_line_with_whitespace_removal)
     runtime.hook_module_function(shpaml, 'apply_jquery_sugar', apply_jquery_sugar_with_whitespace_removal)
     runtime.hook_module_function(shpaml, 'indent_lines', indent_lines_with_whitespace_removal)
     runtime.hook_module_function(shpaml, 'find_indentation', find_indentation_with_whitespace_removal)