Shpaml block construct

5 views
Skip to first unread message

Erez

unread,
Mar 8, 2011, 4:17:05 AM3/8/11
to shpaml
Recently we discussed the problem of inconsistent indentation caused
by running templating engines (or other preprocessors) before Shpaml.
To recap, Shpaml requires strict indentation, which can't always be
predicted, and most engines don't support indenting their output.

I proposed to add a block tag that will automatically consider
anything within it as "indented" (i.e belonging to the current
indentation block, regardless of it's actual indentation):
http://groups.google.com/group/shpaml/msg/4f93fa0946665830

I went ahead and implemented it. For example, the following text:
a
b
::BLOCK
c
d
::END
Gets translated into:
<a>
<b>
<c>
d
</c>
</b>
</a>

This allows me to use mako's functions and inclusions without worrying
about indentation.

Appended to this message is the git diff to shpaml 1.00b, in case
anyone is interested.

------------------------------------------------------------------------------------------

diff --git a/usr/lib64/python2.7/site-packages/shpaml.py b/shpaml.py
index 6e78962..6bae8b6 100644
--- a/usr/lib64/python2.7/site-packages/shpaml.py
+++ b/shpaml.py
@@ -18,7 +18,8 @@ TAG_AND_REST = re.compile(r'((?:[^ \t\.#]|\.\.)+)
(.*)')
CLASS_OR_ID = re.compile(r'([.#])((?:[^ \t\.#]|\.\.)+)')
COMMENT_SYNTAX = re.compile(r'^::comment$')
VERBATIM_SYNTAX = re.compile('(.+) VERBATIM$')
-
+BLOCK_OPEN_SYNTAX = re.compile(r'^::BLOCK$')
+BLOCK_CLOSE_SYNTAX = re.compile(r'^::END$')
DIV_SHORTCUT = re.compile(r'^(?:#|(?:\.(?!\.)))')

quotedText = r"""(?:(?:'(?:\\'|[^'])*')|(?:"(?:\\"|[^"])*"))"""
@@ -123,6 +124,8 @@ def html_block_tag(output, block, recurse):
append(prefix + start_tag)
stream(append, block[1:])
append(prefix + end_tag)
+ elif BLOCK_OPEN_SYNTAX.match(tag) or
BLOCK_CLOSE_SYNTAX.match(tag):
+ recurse(block[1:])
else:
start_tag, end_tag = apply_jquery_sugar(tag)
append(prefix + start_tag)
@@ -221,17 +224,30 @@ def get_indented_block(prefix_lines):
first element of each pair is indentation. The second is the
remaining part of the line, except for trailing newline.
"""
+ block_indent = 0
prefix, line = prefix_lines[0]
+ if BLOCK_OPEN_SYNTAX.match(line):
+ block_indent += 1
len_prefix = len(prefix)

# Find the first nonempty line with len(prefix) <= len(prefix)
i = 1
while i < len(prefix_lines):
new_prefix, line = prefix_lines[i]
- if line and len(new_prefix) <= len_prefix:
+ if BLOCK_OPEN_SYNTAX.match(line):
+ block_indent += 1
+ elif BLOCK_CLOSE_SYNTAX.match(line):
+ block_indent -= 1
+ if block_indent < 0:
+ raise ValueError("Unmatched ENDBLOCK tag")
+
+ if line and block_indent==0 and len(new_prefix) <=
len_prefix:
break
i += 1

+ if block_indent > 0:
+ raise ValueError("Unmatched BLOCK tag")
+
# Rewind to exclude empty lines
while i-1 > 0 and prefix_lines[i-1][1] == '':
i -= 1
@@ -341,6 +357,8 @@ def indent_lines(lines,
prefix_lines.pop(0)
if line == pass_syntax:
pass
+ if BLOCK_CLOSE_SYNTAX.match(line):
+ pass
elif line.startswith(flush_left_syntax):
append(line[len(flush_left_syntax):])
elif line.startswith(flush_left_empty_line):
Reply all
Reply to author
Forward
0 new messages