From fe287c87f2860c6683c7ee88d3c5d72bcb4f107f Mon Sep 17 00:00:00 2001 From: Barry Coughlan Date: Wed, 5 Sep 2012 12:05:55 +0200 Subject: [PATCH 01/48] Minor clarity change --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c9d5a64..c91fe71 100644 --- a/readme.md +++ b/readme.md @@ -115,6 +115,6 @@ HamlPy currently: ## Contributing -Very happy to have contributions to this project. Please write tests for any new features and always ensure the current tests pass. You can run the tests from the hamlpy/test using nosetests by typing +Very happy to have contributions to this project. Please write tests for any new features and always ensure the current tests pass. You can run the tests from the **hamlpy/test** folder using nosetests by typing nosetests *.py From 1c36d67f8cf2440f9352e00c9c118389446becc7 Mon Sep 17 00:00:00 2001 From: Jesse Miller Date: Wed, 5 Sep 2012 12:46:38 -0700 Subject: [PATCH 02/48] roll version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2eef6cc..a9fe101 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ # Note to Jesse - only push sdist to PyPi, bdist seems to always break pip installer setup(name='hamlpy', - version = '0.82.1', + version = '0.82.2', download_url = 'git@github.com:jessemiller/HamlPy.git', packages = ['hamlpy', 'hamlpy.template'], author = 'Jesse Miller', From 16be72532990139865ef7c9282ab2c250e815059 Mon Sep 17 00:00:00 2001 From: Barry Coughlan Date: Thu, 13 Sep 2012 22:26:22 +0100 Subject: [PATCH 03/48] Don't remove backslash at start of lines inside filter nodes --- hamlpy/hamlpy.py | 2 +- hamlpy/nodes.py | 19 ++++++++++++------- hamlpy/test/hamlpy_test.py | 7 +++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/hamlpy/hamlpy.py b/hamlpy/hamlpy.py index 2bd3f1d..71ea75a 100755 --- a/hamlpy/hamlpy.py +++ b/hamlpy/hamlpy.py @@ -18,7 +18,7 @@ def process_lines(self, haml_lines, options=None): for line_number, line in enumerate(line_iter): node_lines = line - if root.parent_of(HamlNode(line)).should_treat_children_as_multiline(): + if not root.parent_of(HamlNode(line)).inside_filter_node(): if line.count('{') - line.count('}') == 1: start_multiline=line_number # For exception handling diff --git a/hamlpy/nodes.py b/hamlpy/nodes.py index 1a7e7f8..763c117 100644 --- a/hamlpy/nodes.py +++ b/hamlpy/nodes.py @@ -49,7 +49,7 @@ def create_node(haml_line): return PlaintextNode(haml_line) if stripped_line[0] == HAML_ESCAPE: - return PlaintextNode(haml_line.replace(HAML_ESCAPE, '', 1)) + return PlaintextNode(haml_line) if stripped_line.startswith(DOCTYPE): return DoctypeNode(haml_line) @@ -153,11 +153,11 @@ def parent_of(self, node): else: return self - def should_treat_children_as_multiline(self): + def inside_filter_node(self): if self.parent: - return self.parent.should_treat_children_as_multiline() + return self.parent.inside_filter_node() else: - return True + return False def _render_children(self): for child in self.children: @@ -223,7 +223,12 @@ def __repr__(self): class PlaintextNode(HamlNode): '''Node that is not modified or processed when rendering''' def _render(self): - self.before = '%s%s' % (self.spaces, self.replace_inline_variables(self.haml)) + text = self.replace_inline_variables(self.haml) + # Remove escape character unless inside filter node + if text and text[0]==HAML_ESCAPE and not self.inside_filter_node(): + text = text.replace(HAML_ESCAPE, '', 1) + + self.before = '%s%s' % (self.spaces, text) if self.children: self.before += self.render_newlines() else: @@ -449,8 +454,8 @@ class FilterNode(HamlNode): def add_node(self, node): self.add_child(node) - def should_treat_children_as_multiline(self): - return False + def inside_filter_node(self): + return True def _render_children_as_plain_text(self,remove_indentation=True): if self.children: diff --git a/hamlpy/test/hamlpy_test.py b/hamlpy/test/hamlpy_test.py index c96b370..84d6122 100755 --- a/hamlpy/test/hamlpy_test.py +++ b/hamlpy/test/hamlpy_test.py @@ -274,6 +274,13 @@ def test_plain_filter_with_no_children(self): result = hamlParser.process(haml) eq_(html, result) + def test_filters_render_escaped_backslash(self): + haml = ":plain\n \\Something" + html = "\\Something\n" + hamlParser = hamlpy.Compiler() + result = hamlParser.process(haml) + eq_(html, result) + def test_xml_namespaces(self): haml = "%fb:tag\n content" html = "\n content\n\n" From f93245f04ab3b8d90954dd9443bec4b25d343749 Mon Sep 17 00:00:00 2001 From: Barry Coughlan Date: Thu, 27 Sep 2012 12:32:33 +0100 Subject: [PATCH 04/48] Allow use of filters in inline variables --- hamlpy/nodes.py | 4 ++-- hamlpy/test/hamlpy_test.py | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hamlpy/nodes.py b/hamlpy/nodes.py index 763c117..150052f 100644 --- a/hamlpy/nodes.py +++ b/hamlpy/nodes.py @@ -22,8 +22,8 @@ VARIABLE = '=' TAG = '-' -INLINE_VARIABLE = re.compile(r'(?blah\n" From 6520df023caf97fcab9a2e28df473baa715e2bdb Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Tue, 9 Oct 2012 17:05:06 -0600 Subject: [PATCH 05/48] - Fix space after key in attribute syntax --- hamlpy/elements.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hamlpy/elements.py b/hamlpy/elements.py index de4539c..204ffdf 100644 --- a/hamlpy/elements.py +++ b/hamlpy/elements.py @@ -21,16 +21,16 @@ class Element(object): (?P/)? (?P=)? (?P[^\w\.#\{].*)? - """, re.X|re.MULTILINE|re.DOTALL) + """, re.X | re.MULTILINE | re.DOTALL) _ATTRIBUTE_KEY_REGEX = r'(?P[a-zA-Z_][a-zA-Z0-9_-]*)' #Single and double quote regexes from: http://stackoverflow.com/a/5453821/281469 _SINGLE_QUOTE_STRING_LITERAL_REGEX = r"'([^'\\]*(?:\\.[^'\\]*)*)'" _DOUBLE_QUOTE_STRING_LITERAL_REGEX = r'"([^"\\]*(?:\\.[^"\\]*)*)"' - _ATTRIBUTE_VALUE_REGEX = r'(?P\d+|None(?![A-Za-z0-9_])|%s|%s)'%(_SINGLE_QUOTE_STRING_LITERAL_REGEX, _DOUBLE_QUOTE_STRING_LITERAL_REGEX) + _ATTRIBUTE_VALUE_REGEX = r'(?P\d+|None(?![A-Za-z0-9_])|%s|%s)' % (_SINGLE_QUOTE_STRING_LITERAL_REGEX, _DOUBLE_QUOTE_STRING_LITERAL_REGEX) - RUBY_HAML_REGEX = re.compile(r'(:|\")%s(\"|) =>'%(_ATTRIBUTE_KEY_REGEX)) - ATTRIBUTE_REGEX = re.compile(r'(?P
\{\s*|,\s*)%s:\s*%s'%(_ATTRIBUTE_KEY_REGEX, _ATTRIBUTE_VALUE_REGEX))
+    RUBY_HAML_REGEX = re.compile(r'(:|\")%s(\"|) =>' % (_ATTRIBUTE_KEY_REGEX))
+    ATTRIBUTE_REGEX = re.compile(r'(?P
\{\s*|,\s*)%s\s*:\s*%s' % (_ATTRIBUTE_KEY_REGEX, _ATTRIBUTE_VALUE_REGEX))
     DJANGO_VARIABLE_REGEX = re.compile(r'^\s*=\s(?P[a-zA-Z_][a-zA-Z0-9._-]*)\s*$')
 
 
@@ -65,7 +65,7 @@ def _parse_class_from_attributes_dict(self):
         if not isinstance(clazz, str):
             clazz = ''
             for one_class in self.attributes_dict.get('class'):
-                clazz += ' '+one_class
+                clazz += ' ' + one_class
         return clazz.strip()
 
     def _parse_id(self, id_haml):
@@ -79,26 +79,26 @@ def _parse_id_dict(self, id_dict):
         text = ''
         id_dict = self.attributes_dict.get('id')
         if isinstance(id_dict, str):
-            text = '_'+id_dict
+            text = '_' + id_dict
         else:
             text = ''
             for one_id in id_dict:
-                text += '_'+one_id
+                text += '_' + one_id
         return text
 
-    def _escape_attribute_quotes(self,v):
+    def _escape_attribute_quotes(self, v):
         '''
         Escapes quotes with a backslash, except those inside a Django tag
         '''
-        escaped=[]
+        escaped = []
         inside_tag = False
         for i, _ in enumerate(v):
-            if v[i:i+2] == '{%':
-                inside_tag=True
-            elif v[i:i+2] == '%}':
-                inside_tag=False
+            if v[i:i + 2] == '{%':
+                inside_tag = True
+            elif v[i:i + 2] == '%}':
+                inside_tag = False
 
-            if v[i]=="'" and not inside_tag:
+            if v[i] == "'" and not inside_tag:
                 escaped.append('\\')
 
             escaped.append(v[i])
@@ -113,7 +113,7 @@ def _parse_attribute_dictionary(self, attribute_dict_string):
                 # converting all allowed attributes to python dictionary style
   
                 # Replace Ruby-style HAML with Python style
-                attribute_dict_string = re.sub(self.RUBY_HAML_REGEX, '"\g":',attribute_dict_string)
+                attribute_dict_string = re.sub(self.RUBY_HAML_REGEX, '"\g":', attribute_dict_string)
                 # Put double quotes around key
                 attribute_dict_string = re.sub(self.ATTRIBUTE_REGEX, '\g
"\g":\g', attribute_dict_string)
                 # Parse string as dictionary
@@ -129,7 +129,7 @@ def _parse_attribute_dictionary(self, attribute_dict_string):
                             v = re.sub(self.DJANGO_VARIABLE_REGEX, '{{\g}}', attributes_dict[k])
                             if v != attributes_dict[k]:
                                 sys.stderr.write("\n---------------------\nDEPRECATION WARNING: %s" % self.haml.lstrip() + \
-                                                 "\nThe Django attribute variable feature is deprecated and may be removed in future versions." +
+                                                 "\nThe Django attribute variable feature is deprecated and may be removed in future versions." + 
                                                  "\nPlease use inline variables ={...} instead.\n-------------------\n")
                                 
                             attributes_dict[k] = v
@@ -137,7 +137,7 @@ def _parse_attribute_dictionary(self, attribute_dict_string):
                             self.attributes += "%s='%s' " % (k, self._escape_attribute_quotes(v))
                 self.attributes = self.attributes.strip()
             except Exception, e:
-                raise Exception('failed to decode: %s'%attribute_dict_string)
+                raise Exception('failed to decode: %s' % attribute_dict_string)
                 #raise Exception('failed to decode: %s. Details: %s'%(attribute_dict_string, e))
 
         return attributes_dict

From 71aea50bac44e3aa9dbea0e4c271393aa1b05b2c Mon Sep 17 00:00:00 2001
From: Richard Eames 
Date: Tue, 9 Oct 2012 17:49:32 -0600
Subject: [PATCH 06/48] - Fix the nuke whitespace template tests

---
 hamlpy/test/template_compare_test.py | 40 ++++++++++++++--------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/hamlpy/test/template_compare_test.py b/hamlpy/test/template_compare_test.py
index 23ad78d..0d77f9f 100644
--- a/hamlpy/test/template_compare_test.py
+++ b/hamlpy/test/template_compare_test.py
@@ -6,10 +6,10 @@
 class TestTemplateCompare(unittest.TestCase):
 
     def test_nuke_inner_whitespace(self):
-        self._compare_test_files('nukeInnerWhitespace')
+        self._compare_test_files('nukeInnerWhiteSpace')
 
     def test_nuke_outer_whitespace(self):
-        self._compare_test_files('nukeOuterWhitespace')
+        self._compare_test_files('nukeOuterWhiteSpace')
 
     def test_comparing_simple_templates(self):
         self._compare_test_files('simple')
@@ -57,52 +57,52 @@ def test_whitespace_preservation(self):
         self._compare_test_files('whitespacePreservation')
 
     def _print_diff(self, s1, s2):
-        if len(s1)>len(s2):
-            shorter=s2
+        if len(s1) > len(s2):
+            shorter = s2
         else:
-            shorter=s1
+            shorter = s1
 
-        line=1
-        col=1
+        line = 1
+        col = 1
         
         for i, _ in enumerate(shorter):
-            if len(shorter) <= i+1:
+            if len(shorter) <= i + 1:
                 print 'Ran out of characters to compare!'
-                print 'Actual len=%d'%len(s1)
-                print 'Expected len=%d'%len(s2)
+                print 'Actual len=%d' % len(s1)
+                print 'Expected len=%d' % len(s2)
                 break
             if s1[i] != s2[i]:
                 print 'Difference begins at line', line, 'column', col
-                actual_line = s1.splitlines()[line-1]
-                expected_line = s2.splitlines()[line-1]
+                actual_line = s1.splitlines()[line - 1]
+                expected_line = s2.splitlines()[line - 1]
                 print 'HTML (actual, len=%2d)   : %s' % (len(actual_line), actual_line)
                 print 'HTML (expected, len=%2d) : %s' % (len(expected_line), expected_line)
                 print 'Character code (actual)  : %d (%s)' % (ord(s1[i]), s1[i])
                 print 'Character code (expected): %d (%s)' % (ord(s2[i]), s2[i])
                 break
 
-            if shorter[i]=='\n':
+            if shorter[i] == '\n':
                 line += 1
-                col=1
+                col = 1
             else:
-                col+=1
+                col += 1
         else:
             print "No Difference Found"
 
     def _compare_test_files(self, name):
-        haml_lines = codecs.open('templates/'+name+'.hamlpy', encoding='utf-8').readlines()
-        html = open('templates/'+name+'.html').read()
+        haml_lines = codecs.open('templates/' + name + '.hamlpy', encoding = 'utf-8').readlines()
+        html = open('templates/' + name + '.html').read()
         
         haml_compiler = hamlpy.Compiler()
         parsed = haml_compiler.process_lines(haml_lines)
 
         # Ignore line ending differences
-        parsed=parsed.replace('\r','')
-        html=html.replace('\r','')
+        parsed = parsed.replace('\r', '')
+        html = html.replace('\r', '')
         
         if parsed != html:
             print '\nHTML (actual): '
-            print '\n'.join(["%d. %s" % (i+1, l) for i, l in enumerate(parsed.split('\n')) ])
+            print '\n'.join(["%d. %s" % (i + 1, l) for i, l in enumerate(parsed.split('\n')) ])
             self._print_diff(parsed, html)
         eq_(parsed, html)
         

From 358b21e553e30453a6018343a17d18ad125e6461 Mon Sep 17 00:00:00 2001
From: Richard Eames 
Date: Tue, 9 Oct 2012 17:55:43 -0600
Subject: [PATCH 07/48] - Add a test for whitespace after attribute key

---
 hamlpy/test/regression.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/hamlpy/test/regression.py b/hamlpy/test/regression.py
index 5a4bff6..3309fc6 100644
--- a/hamlpy/test/regression.py
+++ b/hamlpy/test/regression.py
@@ -16,4 +16,10 @@ def test_haml_comment_nodes_dont_post_render_children(self):
         hamlParser = hamlpy.Compiler()
         result = hamlParser.process(haml)
         eq_(html, result.strip())
-        
\ No newline at end of file
+        
+    def test_whitespace_after_attribute_key(self):
+        haml = '%form{id : "myform"}'
+        html = "
" + hamlParser = hamlpy.Compiler() + result = hamlParser.process(haml) + eq_(html, result.strip()) From 6fb7fe118be3baee3f7b10a8de93154486061536 Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Fri, 19 Oct 2012 16:39:03 -0600 Subject: [PATCH 08/48] - Added options to hamlpy_watcher --- hamlpy/hamlpy_watcher.py | 81 +++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index add5f3c..dd5bd9b 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -4,6 +4,7 @@ # Watch a folder for files with the given extensions and call the HamlPy # compiler if the modified time has changed since the last check. from time import gmtime, strftime +import argparse import sys import codecs import os @@ -11,37 +12,66 @@ import time import hamlpy -CHECK_INTERVAL = 3 # in seconds -DEBUG = False # print file paths when a file is compiled +try: + str = unicode +except NameError: + pass + +class Options(object): + CHECK_INTERVAL = 3 # in seconds + DEBUG = False # print file paths when a file is compiled + VERBOSE = False + OUTPUT_EXT = '.html' # dict of compiled files [fullpath : timestamp] compiled = dict() + +arg_parser = argparse.ArgumentParser() +arg_parser.add_argument('-v', '--verbose', help = 'Display verbose output', action = 'store_true') +arg_parser.add_argument('-i', '--input-extension', metavar = 'EXT', default = '.hamlpy', help = 'The file extensions to look for', type = str, nargs = '+') +arg_parser.add_argument('-ext', '--extension', metavar = 'EXT', default = Options.OUTPUT_EXT, help = 'The output file extension. Default is .html', type = str) +arg_parser.add_argument('-r', '--refresh', metavar = 'S', default = Options.CHECK_INTERVAL, help = 'Refresh interval for files. Default is {} seconds'.format(Options.CHECK_INTERVAL), type = int) +arg_parser.add_argument('input_dir', help = 'Folder to watch', type = str) +arg_parser.add_argument('output_dir', help = 'Destination folder', type = str, nargs = '?') + def watched_extension(extension): """Return True if the given extension is one of the watched extensions""" for ext in hamlpy.VALID_EXTENSIONS: - if extension.endswith('.'+ext): + if extension.endswith('.' + ext): return True return False def watch_folder(): """Main entry point. Expects one or two arguments (the watch folder + optional destination folder).""" - argv_len = len(sys.argv) - if argv_len in (2, 3): - folder = os.path.realpath(sys.argv[1]) - destination = os.path.realpath(argv_len == 3 and os.path.realpath(sys.argv[2]) or folder) - - print "Watching %s at refresh interval %s seconds" % (folder,CHECK_INTERVAL) - while True: - try: - _watch_folder(folder, destination) - time.sleep(CHECK_INTERVAL) - except KeyboardInterrupt: - # allow graceful exit (no stacktrace output) - sys.exit(0) - pass + argv = sys.argv[1:] if len(sys.argv) > 1 else [] + args = arg_parser.parse_args(sys.argv[1:]) + + input_folder = os.path.realpath(args.input_dir) + if not args.output_dir: + output_folder = input_folder else: - print "Usage: hamlpy-watcher.py [destination_folder]" + output_folder = os.path.realpath(args.output_dir) + + if args.verbose: + Options.VERBOSE = True + print "Watching {} at refresh interval {} seconds".format(input_folder, args.refresh) + + if args.extension: + Options.OUTPUT_EXT = args.extension + + print args + + if args.input_extension: + hamlpy.VALID_EXTENSIONS += args.input_extension + + while True: + try: + _watch_folder(input_folder, output_folder) + time.sleep(args.refresh) + except KeyboardInterrupt: + # allow graceful exit (no stacktrace output) + sys.exit(0) def _watch_folder(folder, destination): """Compares "modified" timestamps against the "compiled" dict, calls compiler @@ -53,12 +83,12 @@ def _watch_folder(folder, destination): fullpath = os.path.join(dirpath, filename) subfolder = os.path.relpath(dirpath, folder) mtime = os.stat(fullpath).st_mtime - + # Create subfolders in target directory if they don't exist compiled_folder = os.path.join(destination, subfolder) if not os.path.exists(compiled_folder): os.makedirs(compiled_folder) - + compiled_path = _compiled_path(compiled_folder, filename) if (not fullpath in compiled or compiled[fullpath] < mtime or @@ -67,18 +97,19 @@ def _watch_folder(folder, destination): compiled[fullpath] = mtime def _compiled_path(destination, filename): - return os.path.join(destination, filename[:filename.rfind('.')] + '.html') + return os.path.join(destination, filename[:filename.rfind('.')] + Options.OUTPUT_EXT) def compile_file(fullpath, outfile_name): """Calls HamlPy compiler.""" - print '%s %s -> %s' % ( strftime("%H:%M:%S", gmtime()), fullpath, outfile_name ) + if Options.VERBOSE: + print '%s %s -> %s' % (strftime("%H:%M:%S", gmtime()), fullpath, outfile_name) try: - if DEBUG: + if Options.DEBUG: print "Compiling %s -> %s" % (fullpath, outfile_name) - haml_lines = codecs.open(fullpath, 'r', encoding='utf-8').read().splitlines() + haml_lines = codecs.open(fullpath, 'r', encoding = 'utf-8').read().splitlines() compiler = hamlpy.Compiler() output = compiler.process_lines(haml_lines) - outfile = codecs.open(outfile_name, 'w', encoding='utf-8') + outfile = codecs.open(outfile_name, 'w', encoding = 'utf-8') outfile.write(output) except Exception, e: # import traceback From cb42cd3bad8b87ea429be9caa12ec8540b7e700c Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Fri, 19 Oct 2012 16:41:24 -0600 Subject: [PATCH 09/48] - Update readme --- readme.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c91fe71..52ea81f 100644 --- a/readme.md +++ b/readme.md @@ -90,7 +90,21 @@ For caching, just add `django.template.loaders.cached.Loader` to your TEMPLATE_L HamlPy can also be used as a stand-alone program. There is a script which will watch for changed hamlpy extensions and regenerate the html as they are edited: - hamlpy-watcher [destination_folder] + hamlpy-watcher [-h] [-v] [-i EXT [EXT ...]] [-ext EXT] [-r S] input_dir [output_dir] + + positional arguments: + input_dir Folder to watch + output_dir Destination folder + + optional arguments: + -h, --help show this help message and exit + -v, --verbose Display verbose output + -i EXT [EXT ...], --input-extension EXT [EXT ...] + The file extensions to look for + -ext EXT, --extension EXT + The output file extension. Default is .html + -r S, --refresh S Refresh interval for files. Default is 3 seconds + Or to simply convert a file and output the result to your console: From 7128e03ac24d681a5b9413636103999d1e5d41d9 Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Fri, 19 Oct 2012 16:51:45 -0600 Subject: [PATCH 10/48] - Remove debugging print --- hamlpy/hamlpy_watcher.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index dd5bd9b..7b9f308 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -60,7 +60,6 @@ def watch_folder(): if args.extension: Options.OUTPUT_EXT = args.extension - print args if args.input_extension: hamlpy.VALID_EXTENSIONS += args.input_extension From 305115b9a645d6f1acd179a6efeb5bad67768275 Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Fri, 19 Oct 2012 17:27:21 -0600 Subject: [PATCH 11/48] - Allow custom self closing tags for templating languages like jinja that use "macro" and "call" --- hamlpy/hamlpy_watcher.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index 7b9f308..617d645 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -11,6 +11,7 @@ import os.path import time import hamlpy +import nodes as hamlpynodes try: str = unicode @@ -26,6 +27,16 @@ class Options(object): # dict of compiled files [fullpath : timestamp] compiled = dict() +class StoreNameValueTagPair(argparse.Action): + def __call__(self, parser, namespace, values, option_string = None): + tags = getattr(namespace, 'tags', {}) + if tags is None: + tags = {} + for item in values: + n, v = item.split(':') + tags[n] = v + + setattr(namespace, 'tags', tags) arg_parser = argparse.ArgumentParser() arg_parser.add_argument('-v', '--verbose', help = 'Display verbose output', action = 'store_true') @@ -34,6 +45,7 @@ class Options(object): arg_parser.add_argument('-r', '--refresh', metavar = 'S', default = Options.CHECK_INTERVAL, help = 'Refresh interval for files. Default is {} seconds'.format(Options.CHECK_INTERVAL), type = int) arg_parser.add_argument('input_dir', help = 'Folder to watch', type = str) arg_parser.add_argument('output_dir', help = 'Destination folder', type = str, nargs = '?') +arg_parser.add_argument('--tag', help = 'Add self closing tag. eg. --tag macro:endmacro', type = str, nargs = 1, action = StoreNameValueTagPair) def watched_extension(extension): """Return True if the given extension is one of the watched extensions""" @@ -59,7 +71,9 @@ def watch_folder(): if args.extension: Options.OUTPUT_EXT = args.extension - + + if args.tags: + hamlpynodes.TagNode.self_closing.update(args.tags) if args.input_extension: hamlpy.VALID_EXTENSIONS += args.input_extension From f6a788e65c9588a8a0a414eee7f1f0248535e232 Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Thu, 25 Oct 2012 17:19:28 -0600 Subject: [PATCH 12/48] - Add a new line after the closing conditional comment --- hamlpy/nodes.py | 94 +++++++++---------- hamlpy/test/regression.py | 7 ++ .../test/templates/nukeOuterWhiteSpace.html | 3 +- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/hamlpy/nodes.py b/hamlpy/nodes.py index 150052f..de745fe 100644 --- a/hamlpy/nodes.py +++ b/hamlpy/nodes.py @@ -42,7 +42,7 @@ def create_node(haml_line): stripped_line = haml_line.strip() - if len(stripped_line)==0: + if len(stripped_line) == 0: return None if re.match(INLINE_VARIABLE, stripped_line) or re.match(ESCAPED_INLINE_VARIABLE, stripped_line): @@ -105,21 +105,21 @@ def create_node(haml_line): class TreeNode(object): ''' Generic parent/child tree class''' def __init__(self): - self.parent=None - self.children=[] + self.parent = None + self.children = [] def left_sibling(self): - siblings=self.parent.children - index=siblings.index(self) - return siblings[index-1] if index>0 else None + siblings = self.parent.children + index = siblings.index(self) + return siblings[index - 1] if index > 0 else None def right_sibling(self): - siblings=self.parent.children - index=siblings.index(self) - return siblings[index+1] if index\n" - self.before='' + self.before = '' # Rendered text at end of node, e.g. "\n

" - self.after='' + self.after = '' # Indicates that a node does not render anything (for whitespace removal) - self.empty_node=False + self.empty_node = False def render(self): # Render (sets self.before and self.after) @@ -144,7 +144,7 @@ def render(self): return self._generate_html() def render_newlines(self): - return '\n'*(self.newlines+1) + return '\n' * (self.newlines + 1) def parent_of(self, node): if (self._should_go_inside_last_node(node)): @@ -168,7 +168,7 @@ def _post_render(self): child._post_render() def _generate_html(self): - output=[] + output = [] output.append(self.before) for child in self.children: output.append(child.before) @@ -184,7 +184,7 @@ def add_node(self, node): self.add_child(node) def _should_go_inside_last_node(self, node): - return len(self.children)>0 and (node.indentation > self.children[-1].indentation + return len(self.children) > 0 and (node.indentation > self.children[-1].indentation or (node.indentation == self.children[-1].indentation and self.children[-1].should_contain(node))) def should_contain(self, node): @@ -194,9 +194,9 @@ def debug_tree(self): return '\n'.join(self._debug_tree([self])) def _debug_tree(self, nodes): - output=[] + output = [] for n in nodes: - output.append('%s%s' % (' '*(n.indentation+2), n)) + output.append('%s%s' % (' ' * (n.indentation + 2), n)) if n.children: output += self._debug_tree(n.children) return output @@ -225,7 +225,7 @@ class PlaintextNode(HamlNode): def _render(self): text = self.replace_inline_variables(self.haml) # Remove escape character unless inside filter node - if text and text[0]==HAML_ESCAPE and not self.inside_filter_node(): + if text and text[0] == HAML_ESCAPE and not self.inside_filter_node(): text = text.replace(HAML_ESCAPE, '', 1) self.before = '%s%s' % (self.spaces, text) @@ -238,7 +238,7 @@ def _render(self): class ElementNode(HamlNode): '''Node which represents a HTML tag''' def __init__(self, haml): - HamlNode.__init__(self,haml) + HamlNode.__init__(self, haml) self.django_variable = False def _render(self): @@ -254,7 +254,7 @@ def _render_before(self, element): if element.id: start.append(" id='%s'" % self.replace_inline_variables(element.id)) if element.classes: - start.append(" class='%s'" % self.replace_inline_variables(element.classes) ) + start.append(" class='%s'" % self.replace_inline_variables(element.classes)) if element.attributes: start.append(' ' + self.replace_inline_variables(element.attributes)) @@ -264,7 +264,7 @@ def _render_before(self, element): content = content.strip() if element.self_close and not content: - start.append(" />" ) + start.append(" />") elif content: start.append(">%s" % (content)) elif self.children: @@ -291,18 +291,18 @@ def _post_render(self): self.after = self.after.lstrip() if self.children: - node=self + node = self # If node renders nothing, do removal on its first child instead - if node.children[0].empty_node==True: - node=node.children[0] + if node.children[0].empty_node == True: + node = node.children[0] if node.children: - node.children[0].before=node.children[0].before.lstrip() + node.children[0].before = node.children[0].before.lstrip() - node=self - if node.children[-1].empty_node==True: - node=node.children[-1] + node = self + if node.children[-1].empty_node == True: + node = node.children[-1] if node.children: - node.children[-1].after=node.children[-1].after.rstrip() + node.children[-1].after = node.children[-1].after.rstrip() # Outer whitespace removal if self.element.nuke_outer_whitespace: @@ -330,7 +330,7 @@ def _post_render(self): super(ElementNode, self)._post_render() def _render_inline_content(self, inline_content): - if inline_content == None or len(inline_content)==0: + if inline_content == None or len(inline_content) == 0: return None if self.django_variable: @@ -341,31 +341,31 @@ def _render_inline_content(self, inline_content): class CommentNode(HamlNode): def _render(self): - self.after = "-->\n" + self.after = "-->\n" if self.children: - self.before ="" + self.after = "\n" self._render_children() class DoctypeNode(HamlNode): def _render(self): doctype = self.haml.lstrip(DOCTYPE).strip() - parts=doctype.split() + parts = doctype.split() if parts and parts[0] == "XML": encoding = parts[1] if len(parts) > 1 else 'utf-8' self.before = "" % encoding @@ -419,11 +419,11 @@ class TagNode(HamlNode): 'cache': 'endcache', 'localize': 'endlocalize', 'compress': 'endcompress'} - may_contain = {'if':['else', 'elif'], + may_contain = {'if':['else', 'elif'], 'ifchanged':'else', 'ifequal':'else', 'ifnotequal':'else', - 'for':'empty', + 'for':'empty', 'with':'with'} def __init__(self, haml): @@ -447,7 +447,7 @@ def _render(self): self._render_children() def should_contain(self, node): - return isinstance(node,TagNode) and node.tag_name in self.may_contain.get(self.tag_name,'') + return isinstance(node, TagNode) and node.tag_name in self.may_contain.get(self.tag_name, '') class FilterNode(HamlNode): @@ -457,7 +457,7 @@ def add_node(self, node): def inside_filter_node(self): return True - def _render_children_as_plain_text(self,remove_indentation=True): + def _render_children_as_plain_text(self, remove_indentation = True): if self.children: initial_indentation = len(self.children[0].spaces) for child in self.children: @@ -477,7 +477,7 @@ def _post_render(self): class PlainFilterNode(FilterNode): def __init__(self, haml): FilterNode.__init__(self, haml) - self.empty_node=True + self.empty_node = True def _render(self): if self.children: @@ -515,19 +515,19 @@ class JavascriptFilterNode(FilterNode): def _render(self): self.before = '\n' - self._render_children_as_plain_text(remove_indentation=False) + self._render_children_as_plain_text(remove_indentation = False) class CoffeeScriptFilterNode(FilterNode): def _render(self): self.before = '\n' - self._render_children_as_plain_text(remove_indentation=False) + self._render_children_as_plain_text(remove_indentation = False) class CssFilterNode(FilterNode): def _render(self): self.before = '\n' - self._render_children_as_plain_text(remove_indentation=False) + self._render_children_as_plain_text(remove_indentation = False) class StylusFilterNode(FilterNode): def _render(self): @@ -539,7 +539,7 @@ class CDataFilterNode(FilterNode): def _render(self): self.before = self.spaces + '\n' - self._render_children_as_plain_text(remove_indentation=False) + self._render_children_as_plain_text(remove_indentation = False) class PygmentsFilterNode(FilterNode): def _render(self): diff --git a/hamlpy/test/regression.py b/hamlpy/test/regression.py index 3309fc6..ded65c6 100644 --- a/hamlpy/test/regression.py +++ b/hamlpy/test/regression.py @@ -23,3 +23,10 @@ def test_whitespace_after_attribute_key(self): hamlParser = hamlpy.Compiler() result = hamlParser.process(haml) eq_(html, result.strip()) + + def test_for_newline_after_conditional_comment(self): + haml = '/[if lte IE 7]\n\ttest\n#test' + haml = '\n
' + hamlParser = hamlpy.Compiler() + result = hamlParser.process(haml) + eq_(html, result.strip()) diff --git a/hamlpy/test/templates/nukeOuterWhiteSpace.html b/hamlpy/test/templates/nukeOuterWhiteSpace.html index c95a95a..171d1b3 100644 --- a/hamlpy/test/templates/nukeOuterWhiteSpace.html +++ b/hamlpy/test/templates/nukeOuterWhiteSpace.html @@ -13,7 +13,8 @@

+ +

\n' self._render_children_as_plain_text(remove_indentation = False) class CoffeeScriptFilterNode(FilterNode): def _render(self): - self.before = '\n' self._render_children_as_plain_text(remove_indentation = False) class CssFilterNode(FilterNode): def _render(self): - self.before = '\n' self._render_children_as_plain_text(remove_indentation = False) class StylusFilterNode(FilterNode): def _render(self): - self.before = '\n' self._render_children_as_plain_text() From 787ef4b23211dcf363550f97a4c32aa25fc1e3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bielawski?= Date: Fri, 25 Jan 2013 09:31:40 +0100 Subject: [PATCH 28/48] Escaping attr_wrapper instead of hard-coded apostrophe. --- hamlpy/elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hamlpy/elements.py b/hamlpy/elements.py index d1cb1d6..abff139 100644 --- a/hamlpy/elements.py +++ b/hamlpy/elements.py @@ -102,7 +102,7 @@ def _escape_attribute_quotes(self, v): elif v[i:i + 2] == '%}': inside_tag = False - if v[i] == "'" and not inside_tag: + if v[i] == self.attr_wrapper and not inside_tag: escaped.append('\\') escaped.append(v[i]) From d1c055b03f6f08cc8ffb6e62e538fc6a1209b256 Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Mon, 4 Mar 2013 16:34:07 -0700 Subject: [PATCH 29/48] - Added a Jinja compatibility option for the watcher. --- hamlpy/hamlpy_watcher.py | 19 +++++++++++++++++-- readme.md | 3 +++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index 084288b..87346dc 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -46,7 +46,8 @@ def __call__(self, parser, namespace, values, option_string = None): arg_parser.add_argument('input_dir', help = 'Folder to watch', type = str) arg_parser.add_argument('output_dir', help = 'Destination folder', type = str, nargs = '?') arg_parser.add_argument('--tag', help = 'Add self closing tag. eg. --tag macro:endmacro', type = str, nargs = 1, action = StoreNameValueTagPair) -arg_parser.add_argument('--attr-wrapper', dest='attr_wrapper', type=str, choices=('"', "'"), default="'", action='store', help="The character that should wrap element attributes. This defaults to ' (an apostrophe).") +arg_parser.add_argument('--attr-wrapper', dest = 'attr_wrapper', type = str, choices = ('"', "'"), default = "'", action = 'store', help = "The character that should wrap element attributes. This defaults to ' (an apostrophe).") +arg_parser.add_argument('--jinja', help = 'Makes the necessary changes to be used with Jinja2', default = False, action = 'store_true') def watched_extension(extension): """Return True if the given extension is one of the watched extensions""" @@ -81,7 +82,21 @@ def watch_folder(): hamlpy.VALID_EXTENSIONS += args.input_extension if args.attr_wrapper: - compiler_args['attr_wrapper'] = args.attr_wrapper + compiler_args['attr_wrapper'] = args.attr_wrapper + + if args.jinja: + for k in ('ifchanged', 'ifequal', 'ifnotequal', 'autoescape', 'blocktrans', + 'spaceless', 'comment', 'cache', 'localize', 'compress'): + del hamlpynodes.TagNode.self_closing[k] + + hamlpynodes.TagNode.may_contain.pop(k, None) + + hamlpynodes.TagNode.self_closing.update({ + 'macro' : 'endmacro', + 'call' : 'endcall', + }) + + hamlpy.nodes.TagNode.may_contain['for'] = 'else' while True: try: diff --git a/readme.md b/readme.md index eb585a1..6355243 100644 --- a/readme.md +++ b/readme.md @@ -116,6 +116,7 @@ HamlPy can also be used as a stand-alone program. There is a script which will w --tag TAG Add self closing tag. eg. --tag macro:endmacro --attr-wrapper {",'} The character that should wrap element attributes. This defaults to ' (an apostrophe). + --jinja Makes the necessary changes to be used with Jinja2 Or to simply convert a file and output the result to your console: @@ -129,6 +130,8 @@ Optionally, `--attr-wrapper` can be specified: hamlpy inputFile.haml --attr-wrapper='"' +Using the `--jinja` compatibility option adds macro and call tags, and changes the `empty` node in the `for` tag to `else`. + For HamlPy developers, the `-d` switch can be used with `hamlpy` to debug the internal tree structure. ## Reference From c873dd4b1e86160b6c5fc963fde7730ab674839d Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Mon, 4 Mar 2013 16:43:54 -0700 Subject: [PATCH 30/48] - Small fix to watcher option "tag" --- hamlpy/hamlpy_watcher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index 084288b..1ba8af2 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -46,7 +46,7 @@ def __call__(self, parser, namespace, values, option_string = None): arg_parser.add_argument('input_dir', help = 'Folder to watch', type = str) arg_parser.add_argument('output_dir', help = 'Destination folder', type = str, nargs = '?') arg_parser.add_argument('--tag', help = 'Add self closing tag. eg. --tag macro:endmacro', type = str, nargs = 1, action = StoreNameValueTagPair) -arg_parser.add_argument('--attr-wrapper', dest='attr_wrapper', type=str, choices=('"', "'"), default="'", action='store', help="The character that should wrap element attributes. This defaults to ' (an apostrophe).") +arg_parser.add_argument('--attr-wrapper', dest = 'attr_wrapper', type = str, choices = ('"', "'"), default = "'", action = 'store', help = "The character that should wrap element attributes. This defaults to ' (an apostrophe).") def watched_extension(extension): """Return True if the given extension is one of the watched extensions""" @@ -74,7 +74,7 @@ def watch_folder(): if args.extension: Options.OUTPUT_EXT = args.extension - if args.tags: + if getattr(args, 'tags', False): hamlpynodes.TagNode.self_closing.update(args.tags) if args.input_extension: From 954c81d25a0921594b25e2b9e37c8c6cf5f7e2cc Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Mon, 4 Mar 2013 16:56:09 -0700 Subject: [PATCH 31/48] - typo fix. --- hamlpy/hamlpy_watcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index 87346dc..30a0c1c 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -96,7 +96,7 @@ def watch_folder(): 'call' : 'endcall', }) - hamlpy.nodes.TagNode.may_contain['for'] = 'else' + hamlpynodes.TagNode.may_contain['for'] = 'else' while True: try: From 3859dc9ace8b5e78ad89b7994069fdb7f424da34 Mon Sep 17 00:00:00 2001 From: Jesse Miller Date: Tue, 5 Mar 2013 19:39:16 -0800 Subject: [PATCH 32/48] Add tests around javascript filter with attr set --- hamlpy/test/hamlpy_test.py | 7 ++++++- hamlpy/test/templates/classIdMixtures.hamlpy | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/hamlpy/test/hamlpy_test.py b/hamlpy/test/hamlpy_test.py index a43a0e4..f0d050f 100755 --- a/hamlpy/test/hamlpy_test.py +++ b/hamlpy/test/hamlpy_test.py @@ -321,7 +321,8 @@ def test_attr_wrapper(self): %html{'xmlns':'http://www.w3.org/1999/xhtml', 'xml:lang':'en', 'lang':'en'} %body#main %div.wrap - %a{:href => '/'}""" + %a{:href => '/'} +:javascript""" hamlParser = hamlpy.Compiler(options_dict={'attr_wrapper': '"'}) result = hamlParser.process(haml) self.assertEqual(result, @@ -332,6 +333,10 @@ def test_attr_wrapper(self): + ''') if __name__ == '__main__': diff --git a/hamlpy/test/templates/classIdMixtures.hamlpy b/hamlpy/test/templates/classIdMixtures.hamlpy index 52ba3ca..06be022 100644 --- a/hamlpy/test/templates/classIdMixtures.hamlpy +++ b/hamlpy/test/templates/classIdMixtures.hamlpy @@ -1,2 +1,2 @@ %div#Article.article.entry{'id':'123', 'class':'true'} - Now this is interesting \ No newline at end of file + Now this is interesting From 284faac2e6c50163661dfed74fc0d5209f3273cc Mon Sep 17 00:00:00 2001 From: Jesse Miller Date: Tue, 5 Mar 2013 19:54:32 -0800 Subject: [PATCH 33/48] Added to test to confirm fixes issue #125 --- hamlpy/test/hamlpy_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hamlpy/test/hamlpy_test.py b/hamlpy/test/hamlpy_test.py index f0d050f..32559af 100755 --- a/hamlpy/test/hamlpy_test.py +++ b/hamlpy/test/hamlpy_test.py @@ -156,8 +156,8 @@ def test_inline_variables_in_attributes_work_in_class(self): eq_(html, result) def test_inline_variables_in_attributes_are_escaped_correctly(self): - haml = "%a{'b': '\\\\={greeting} test'} blah" - html = "blah\n" + haml = "%a{'b': '\\\\={greeting} test', title: \"It can't be removed\"} blah" + html = "blah\n" hamlParser = hamlpy.Compiler() result = hamlParser.process(haml) eq_(html, result) From d434fd48a6fb23eace47bf907be70d0ca9f193e0 Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Tue, 5 Mar 2013 21:13:25 -0700 Subject: [PATCH 34/48] - Added a basic testcase and output. --- hamlpy/test/templates/basic_jinja.hamlpy | 16 ++++++++++++++++ hamlpy/test/templates/basic_jinja.html | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 hamlpy/test/templates/basic_jinja.hamlpy create mode 100644 hamlpy/test/templates/basic_jinja.html diff --git a/hamlpy/test/templates/basic_jinja.hamlpy b/hamlpy/test/templates/basic_jinja.hamlpy new file mode 100644 index 0000000..7b8265c --- /dev/null +++ b/hamlpy/test/templates/basic_jinja.hamlpy @@ -0,0 +1,16 @@ +-# Jinja has macro and call for self closing nodes +-macro mymacro(a,b,c=3) + ={a} + ={b} + ={c} + ={caller} + +-call mymacro(1,2) + Hello World + +-# Jinja also uses "else" instead of "empty" in for loops + +-for a in () + -# nothing +-else + There were no elements diff --git a/hamlpy/test/templates/basic_jinja.html b/hamlpy/test/templates/basic_jinja.html new file mode 100644 index 0000000..72c5589 --- /dev/null +++ b/hamlpy/test/templates/basic_jinja.html @@ -0,0 +1,16 @@ +{% macro mymacro(a,b,c=3) %} + {{ a }} + {{ b }} + {{ c }} + {{ caller }} + +{% endmacro %} +{% call mymacro(1,2) %} + Hello World + +{% endcall %} + +{% for a in () %} +{% else %} + There were no elements +{% endfor %} From 3f6b96241e2a1a67eff06a890415b615efa84ca7 Mon Sep 17 00:00:00 2001 From: Jesse Miller Date: Tue, 5 Mar 2013 20:37:42 -0800 Subject: [PATCH 35/48] remove unused test templates --- hamlpy/test/templates/basic_jinja.hamlpy | 16 ---------------- hamlpy/test/templates/basic_jinja.html | 16 ---------------- 2 files changed, 32 deletions(-) delete mode 100644 hamlpy/test/templates/basic_jinja.hamlpy delete mode 100644 hamlpy/test/templates/basic_jinja.html diff --git a/hamlpy/test/templates/basic_jinja.hamlpy b/hamlpy/test/templates/basic_jinja.hamlpy deleted file mode 100644 index 7b8265c..0000000 --- a/hamlpy/test/templates/basic_jinja.hamlpy +++ /dev/null @@ -1,16 +0,0 @@ --# Jinja has macro and call for self closing nodes --macro mymacro(a,b,c=3) - ={a} - ={b} - ={c} - ={caller} - --call mymacro(1,2) - Hello World - --# Jinja also uses "else" instead of "empty" in for loops - --for a in () - -# nothing --else - There were no elements diff --git a/hamlpy/test/templates/basic_jinja.html b/hamlpy/test/templates/basic_jinja.html deleted file mode 100644 index 72c5589..0000000 --- a/hamlpy/test/templates/basic_jinja.html +++ /dev/null @@ -1,16 +0,0 @@ -{% macro mymacro(a,b,c=3) %} - {{ a }} - {{ b }} - {{ c }} - {{ caller }} - -{% endmacro %} -{% call mymacro(1,2) %} - Hello World - -{% endcall %} - -{% for a in () %} -{% else %} - There were no elements -{% endfor %} From bd5c044de812f9598ca7aebbd6f47ebb43649e3a Mon Sep 17 00:00:00 2001 From: Vasily Alexeev Date: Fri, 29 Mar 2013 17:29:21 +0400 Subject: [PATCH 36/48] Updated reference.md (:stylus, :coffeescript, :css) Documented :stylus, :coffeescript; fixed documentation for :css --- reference.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/reference.md b/reference.md index 25d7f89..3c126b3 100644 --- a/reference.md +++ b/reference.md @@ -402,7 +402,11 @@ Does not parse the filtered text. This is useful for large blocks of text withou ### :javascript -Surrounds the filtered text with <script> and CDATA tags. Useful for including inline Javascript. +Surrounds the filtered text with <script type="text/javascript"> and CDATA tags. Useful for including inline Javascript. + +### :coffeescript or :coffee + +Surrounds the filtered text with <script type="text/coffeescript"> and CDATA tags. Useful for including inline Coffeescript. ### :cdata @@ -410,7 +414,11 @@ Surrounds the filtered text with CDATA tags. ### :css -Surrounds the filtered text with <script> and CDATA tags. Useful for including inline CSS. +Surrounds the filtered text with <style type="text/css"> and CDATA tags. Useful for including inline CSS. + +### :stylus + +Surrounds the filtered text with <style type="text/stylus"> and CDATA tags. Useful for including inline Stylus. ### :markdown From adc1840dc591194ed6f56044fa6694814a2f811f Mon Sep 17 00:00:00 2001 From: Dan Ring Date: Wed, 8 May 2013 18:59:39 -0700 Subject: [PATCH 37/48] Remove strict dependencies on django, pygments, markdown, jinja2 * addresses Issue #132 * include dependent functionality only if the required package is available * duplicate TemplateDoesNotExist() if django is not present * add `NotAvailableError` for nodes which depend on non-present packages * move pygments_filter test into template tests * fix test for Pygments version 1.6 --- hamlpy/__init__.py | 5 +--- hamlpy/ext.py | 30 +++++++++++-------- hamlpy/nodes.py | 27 +++++++++++++---- hamlpy/template/loaders.py | 25 +++++++++++----- hamlpy/template/utils.py | 8 ++++- hamlpy/templatize.py | 10 +++++-- hamlpy/test/hamlpy_test.py | 21 ------------- hamlpy/test/loader_test.py | 10 ++++--- hamlpy/test/template_compare_test.py | 17 +++++++++++ hamlpy/test/templates/filters.hamlpy | 7 ----- hamlpy/test/templates/filters.html | 5 ---- hamlpy/test/templates/filtersMarkdown.hamlpy | 7 +++++ hamlpy/test/templates/filtersMarkdown.html | 5 ++++ hamlpy/test/templates/filtersPygments.hamlpy | 7 +++++ hamlpy/test/templates/filtersPygments.html | 8 +++++ .../test/templates/filtersPygments16.hamlpy | 7 +++++ hamlpy/test/templates/filtersPygments16.html | 8 +++++ setup.py | 3 -- 18 files changed, 138 insertions(+), 72 deletions(-) create mode 100644 hamlpy/test/templates/filtersMarkdown.hamlpy create mode 100644 hamlpy/test/templates/filtersMarkdown.html create mode 100644 hamlpy/test/templates/filtersPygments.hamlpy create mode 100644 hamlpy/test/templates/filtersPygments.html create mode 100644 hamlpy/test/templates/filtersPygments16.hamlpy create mode 100644 hamlpy/test/templates/filtersPygments16.html diff --git a/hamlpy/__init__.py b/hamlpy/__init__.py index b0ad793..b61a1f3 100755 --- a/hamlpy/__init__.py +++ b/hamlpy/__init__.py @@ -1,4 +1 @@ -try: - import templatize -except ImportError: - pass +import templatize diff --git a/hamlpy/ext.py b/hamlpy/ext.py index 450fb25..096b8cc 100644 --- a/hamlpy/ext.py +++ b/hamlpy/ext.py @@ -1,5 +1,10 @@ # coding=utf-8 -import jinja2.ext +try: + import jinja2.ext + _jinja2_available = True +except ImportError, e: + _jinja2_available = False + import hamlpy import os @@ -23,14 +28,15 @@ def has_any_extension(file_path, extensions): file_ext = get_file_extension(file_path) return file_ext and extensions and file_ext in [clean_extension(e) for e in extensions] -class HamlPyExtension(jinja2.ext.Extension): - - def preprocess(self, source, name, filename=None): - if name and has_any_extension(name, HAML_FILE_NAME_EXTENSIONS): - compiler = hamlpy.Compiler() - try: - return compiler.process(source) - except Exception as e: - raise jinja2.TemplateSyntaxError(e, 1, name=name, filename=filename) - else: - return source +if _jinja2_available: + class HamlPyExtension(jinja2.ext.Extension): + + def preprocess(self, source, name, filename=None): + if name and has_any_extension(name, HAML_FILE_NAME_EXTENSIONS): + compiler = hamlpy.Compiler() + try: + return compiler.process(source) + except Exception as e: + raise jinja2.TemplateSyntaxError(e, 1, name=name, filename=filename) + else: + return source diff --git a/hamlpy/nodes.py b/hamlpy/nodes.py index 024d952..89daabe 100644 --- a/hamlpy/nodes.py +++ b/hamlpy/nodes.py @@ -4,11 +4,22 @@ from elements import Element -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import guess_lexer - -from markdown import markdown +try: + from pygments import highlight + from pygments.formatters import HtmlFormatter + from pygments.lexers import guess_lexer + _pygments_available = True +except ImportError, e: + _pygments_available = False + +try: + from markdown import markdown + _markdown_available = True +except ImportError, e: + _markdown_available = False + +class NotAvailableError(Exception): + pass ELEMENT = '%' ID = '#' @@ -567,6 +578,9 @@ def _render(self): class PygmentsFilterNode(FilterNode): def _render(self): if self.children: + if not _pygments_available: + raise NotAvailableError("Pygments is not available") + self.before = self.render_newlines() indent_offset = len(self.children[0].spaces) text = ''.join(''.join([c.spaces[indent_offset:], c.haml, c.render_newlines()]) for c in self.children) @@ -577,6 +591,9 @@ def _render(self): class MarkdownFilterNode(FilterNode): def _render(self): if self.children: + if not _markdown_available: + raise NotAvailableError("Markdown is not available") + self.before = self.render_newlines()[1:] indent_offset = len(self.children[0].spaces) text = ''.join(''.join([c.spaces[indent_offset:], c.haml, c.render_newlines()]) for c in self.children) diff --git a/hamlpy/template/loaders.py b/hamlpy/template/loaders.py index 64a4e30..4d80c09 100644 --- a/hamlpy/template/loaders.py +++ b/hamlpy/template/loaders.py @@ -1,7 +1,14 @@ import os -from django.template import TemplateDoesNotExist -from django.template.loaders import filesystem, app_directories +try: + from django.template import TemplateDoesNotExist + from django.template.loaders import filesystem, app_directories + _django_available = True +except ImportError, e: + class TemplateDoesNotExist(Exception): + pass + + _django_available = False from hamlpy import hamlpy from hamlpy.template.utils import get_django_template_loaders @@ -9,9 +16,11 @@ # Get options from Django settings options_dict = {} -from django.conf import settings -if hasattr(settings, 'HAMLPY_ATTR_WRAPPER'): - options_dict.update(attr_wrapper=settings.HAMLPY_ATTR_WRAPPER) + +if _django_available: + from django.conf import settings + if hasattr(settings, 'HAMLPY_ATTR_WRAPPER'): + options_dict.update(attr_wrapper=settings.HAMLPY_ATTR_WRAPPER) def get_haml_loader(loader): @@ -54,6 +63,6 @@ def _generate_template_name(self, name, extension="hamlpy"): haml_loaders = dict((name, get_haml_loader(loader)) for (name, loader) in get_django_template_loaders()) - -HamlPyFilesystemLoader = get_haml_loader(filesystem) -HamlPyAppDirectoriesLoader = get_haml_loader(app_directories) +if _django_available: + HamlPyFilesystemLoader = get_haml_loader(filesystem) + HamlPyAppDirectoriesLoader = get_haml_loader(app_directories) diff --git a/hamlpy/template/utils.py b/hamlpy/template/utils.py index 46e4cf9..c9187e8 100644 --- a/hamlpy/template/utils.py +++ b/hamlpy/template/utils.py @@ -2,11 +2,17 @@ from os import listdir from os.path import dirname, splitext -from django.template import loaders +try: + from django.template import loaders + _django_available = True +except ImportError, e: + _django_available = False MODULE_EXTENSIONS = tuple([suffix[0] for suffix in imp.get_suffixes()]) def get_django_template_loaders(): + if not _django_available: + return [] return [(loader.__name__.rsplit('.',1)[1], loader) for loader in get_submodules(loaders) if hasattr(loader, 'Loader')] diff --git a/hamlpy/templatize.py b/hamlpy/templatize.py index 927dcde..998d4f2 100644 --- a/hamlpy/templatize.py +++ b/hamlpy/templatize.py @@ -3,7 +3,12 @@ before the translation utility extracts tags from it. """ -from django.utils.translation import trans_real +try: + from django.utils.translation import trans_real + _django_available = True +except ImportError, e: + _django_available = False + import hamlpy @@ -15,5 +20,6 @@ def templatize(src, origin=None): return templatize -trans_real.templatize = decorate_templatize(trans_real.templatize) +if _django_available: + trans_real.templatize = decorate_templatize(trans_real.templatize) diff --git a/hamlpy/test/hamlpy_test.py b/hamlpy/test/hamlpy_test.py index 32559af..e201730 100755 --- a/hamlpy/test/hamlpy_test.py +++ b/hamlpy/test/hamlpy_test.py @@ -295,27 +295,6 @@ def test_xml_namespaces(self): result = hamlParser.process(haml) eq_(html, result) - def test_pygments_filter(self): - haml = ''' - :highlight - print "hi" - - if x: - print "y": - else: - print "z": - ''' - html = '\n

print "hi"' \
-                + '\n\nif x:' \
-                + '\n    print "y":' \
-                + '\nelse:' \
-                + '\n    print "z":' \
-                + '\n
\n' - - hamlParser = hamlpy.Compiler() - result = hamlParser.process(haml) - eq_(html, result) - def test_attr_wrapper(self): haml = """ %html{'xmlns':'http://www.w3.org/1999/xhtml', 'xml:lang':'en', 'lang':'en'} diff --git a/hamlpy/test/loader_test.py b/hamlpy/test/loader_test.py index b723e70..27643aa 100644 --- a/hamlpy/test/loader_test.py +++ b/hamlpy/test/loader_test.py @@ -1,12 +1,14 @@ import unittest import sys -from django.template.base import TemplateDoesNotExist -from django.conf import settings +try: + from django.conf import settings -settings.configure(DEBUG=True, TEMPLATE_DEBUG=True) + settings.configure(DEBUG=True, TEMPLATE_DEBUG=True) +except ImportError, e: + pass -from hamlpy.template.loaders import get_haml_loader +from hamlpy.template.loaders import get_haml_loader, TemplateDoesNotExist class DummyLoader(object): """ diff --git a/hamlpy/test/template_compare_test.py b/hamlpy/test/template_compare_test.py index 0d77f9f..3d20485 100644 --- a/hamlpy/test/template_compare_test.py +++ b/hamlpy/test/template_compare_test.py @@ -41,6 +41,23 @@ def test_nested_django_tags(self): def test_filters(self): self._compare_test_files('filters') + def test_filters_markdown(self): + try: + import markdown + self._compare_test_files('filtersMarkdown') + except ImportError: + pass + + def test_filters_pygments(self): + try: + import pygments + if pygments.__version__ == '1.6': + self._compare_test_files('filtersPygments16') + else: + self._compare_test_files('filtersPygments') + except ImportError: + pass + def test_nested_if_else_blocks(self): self._compare_test_files('nestedIfElseBlocks') diff --git a/hamlpy/test/templates/filters.hamlpy b/hamlpy/test/templates/filters.hamlpy index 76b838c..72d7669 100644 --- a/hamlpy/test/templates/filters.hamlpy +++ b/hamlpy/test/templates/filters.hamlpy @@ -16,10 +16,3 @@ a=1 for i in range(5): print a+i -:markdown - hello - no paragraph - - New paragraph - - test \ No newline at end of file diff --git a/hamlpy/test/templates/filters.html b/hamlpy/test/templates/filters.html index a1e35c9..fab181f 100644 --- a/hamlpy/test/templates/filters.html +++ b/hamlpy/test/templates/filters.html @@ -24,8 +24,3 @@ 3 4 5 -

hello -no paragraph

-

New paragraph

-
test
-
\ No newline at end of file diff --git a/hamlpy/test/templates/filtersMarkdown.hamlpy b/hamlpy/test/templates/filtersMarkdown.hamlpy new file mode 100644 index 0000000..c97726c --- /dev/null +++ b/hamlpy/test/templates/filtersMarkdown.hamlpy @@ -0,0 +1,7 @@ +:markdown + hello + no paragraph + + New paragraph + + test diff --git a/hamlpy/test/templates/filtersMarkdown.html b/hamlpy/test/templates/filtersMarkdown.html new file mode 100644 index 0000000..49f148a --- /dev/null +++ b/hamlpy/test/templates/filtersMarkdown.html @@ -0,0 +1,5 @@ +

hello +no paragraph

+

New paragraph

+
test
+
diff --git a/hamlpy/test/templates/filtersPygments.hamlpy b/hamlpy/test/templates/filtersPygments.hamlpy new file mode 100644 index 0000000..4dc3852 --- /dev/null +++ b/hamlpy/test/templates/filtersPygments.hamlpy @@ -0,0 +1,7 @@ +:highlight + print "hi" + + if x: + print "y": + else: + print "z": diff --git a/hamlpy/test/templates/filtersPygments.html b/hamlpy/test/templates/filtersPygments.html new file mode 100644 index 0000000..2b87052 --- /dev/null +++ b/hamlpy/test/templates/filtersPygments.html @@ -0,0 +1,8 @@ + +
print "hi"
+
+if x:
+    print "y":
+else:
+    print "z":
+
diff --git a/hamlpy/test/templates/filtersPygments16.hamlpy b/hamlpy/test/templates/filtersPygments16.hamlpy new file mode 100644 index 0000000..4dc3852 --- /dev/null +++ b/hamlpy/test/templates/filtersPygments16.hamlpy @@ -0,0 +1,7 @@ +:highlight + print "hi" + + if x: + print "y": + else: + print "z": diff --git a/hamlpy/test/templates/filtersPygments16.html b/hamlpy/test/templates/filtersPygments16.html new file mode 100644 index 0000000..380bf83 --- /dev/null +++ b/hamlpy/test/templates/filtersPygments16.html @@ -0,0 +1,8 @@ + +
print "hi"
+
+if x:
+    print "y":
+else:
+    print "z":
+
diff --git a/setup.py b/setup.py index a9fe101..58de695 100644 --- a/setup.py +++ b/setup.py @@ -12,9 +12,6 @@ url = 'http://github.com/jessemiller/HamlPy', license = 'MIT', install_requires = [ - 'django', - 'pygments', - 'markdown' ], entry_points = { 'console_scripts' : ['hamlpy = hamlpy.hamlpy:convert_files', From 52ec4d344749ba015eb2754380afce6a5b1756b6 Mon Sep 17 00:00:00 2001 From: JobJob Date: Fri, 10 May 2013 16:26:52 +1000 Subject: [PATCH 38/48] Output local time instead of gmttime in hamlpy_watcher when in verbose mode --- hamlpy/hamlpy_watcher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index ae15358..421c2f6 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -3,7 +3,7 @@ # # Watch a folder for files with the given extensions and call the HamlPy # compiler if the modified time has changed since the last check. -from time import gmtime, strftime +from time import strftime import argparse import sys import codecs @@ -135,7 +135,7 @@ def _compiled_path(destination, filename): def compile_file(fullpath, outfile_name, compiler_args): """Calls HamlPy compiler.""" if Options.VERBOSE: - print '%s %s -> %s' % (strftime("%H:%M:%S", gmtime()), fullpath, outfile_name) + print '%s %s -> %s' % (strftime("%H:%M:%S"), fullpath, outfile_name) try: if Options.DEBUG: print "Compiling %s -> %s" % (fullpath, outfile_name) From 32cd4d0b6d183aad3e168009c9e030269de6ad26 Mon Sep 17 00:00:00 2001 From: Noel Bush Date: Wed, 29 May 2013 14:08:44 +0200 Subject: [PATCH 39/48] allow attributes to have any letter at all (not just ascii) --- hamlpy/elements.py | 22 +++++++++++----------- hamlpy/test/hamlpy_test.py | 7 +++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/hamlpy/elements.py b/hamlpy/elements.py index abff139..3bb5d3d 100644 --- a/hamlpy/elements.py +++ b/hamlpy/elements.py @@ -4,7 +4,7 @@ class Element(object): """contains the pieces of an element and can populate itself from haml element text""" - + self_closing_tags = ('meta', 'img', 'link', 'br', 'hr', 'input', 'source', 'track') ELEMENT = '%' @@ -21,16 +21,16 @@ class Element(object): (?P/)? (?P=)? (?P[^\w\.#\{].*)? - """, re.X | re.MULTILINE | re.DOTALL) + """, re.X | re.MULTILINE | re.DOTALL | re.UNICODE) _ATTRIBUTE_KEY_REGEX = r'(?P[a-zA-Z_][a-zA-Z0-9_-]*)' #Single and double quote regexes from: http://stackoverflow.com/a/5453821/281469 _SINGLE_QUOTE_STRING_LITERAL_REGEX = r"'([^'\\]*(?:\\.[^'\\]*)*)'" _DOUBLE_QUOTE_STRING_LITERAL_REGEX = r'"([^"\\]*(?:\\.[^"\\]*)*)"' - _ATTRIBUTE_VALUE_REGEX = r'(?P\d+|None(?![A-Za-z0-9_])|%s|%s)' % (_SINGLE_QUOTE_STRING_LITERAL_REGEX, _DOUBLE_QUOTE_STRING_LITERAL_REGEX) + _ATTRIBUTE_VALUE_REGEX = r'(?P\d+|None(?!\w)|%s|%s)' % (_SINGLE_QUOTE_STRING_LITERAL_REGEX, _DOUBLE_QUOTE_STRING_LITERAL_REGEX) RUBY_HAML_REGEX = re.compile(r'(:|\")%s(\"|) =>' % (_ATTRIBUTE_KEY_REGEX)) - ATTRIBUTE_REGEX = re.compile(r'(?P
\{\s*|,\s*)%s\s*:\s*%s' % (_ATTRIBUTE_KEY_REGEX, _ATTRIBUTE_VALUE_REGEX))
+    ATTRIBUTE_REGEX = re.compile(r'(?P
\{\s*|,\s*)%s\s*:\s*%s' % (_ATTRIBUTE_KEY_REGEX, _ATTRIBUTE_VALUE_REGEX), re.UNICODE)
     DJANGO_VARIABLE_REGEX = re.compile(r'^\s*=\s(?P[a-zA-Z_][a-zA-Z0-9._-]*)\s*$')
 
 
@@ -53,7 +53,7 @@ def attr_wrap(self, value):
 
     def _parse_haml(self):
         split_tags = self.HAML_REGEX.search(self.haml).groupdict('')
-        
+
         self.attributes_dict = self._parse_attribute_dictionary(split_tags.get('attributes'))
         self.tag = split_tags.get('tag').strip(self.ELEMENT) or 'div'
         self.id = self._parse_id(split_tags.get('id'))
@@ -78,7 +78,7 @@ def _parse_id(self, id_haml):
             id_text += self._parse_id_dict(self.attributes_dict['id'])
         id_text = id_text.lstrip('_')
         return id_text
-    
+
     def _parse_id_dict(self, id_dict):
         text = ''
         id_dict = self.attributes_dict.get('id')
@@ -115,7 +115,7 @@ def _parse_attribute_dictionary(self, attribute_dict_string):
             attribute_dict_string = attribute_dict_string.replace('\n', ' ')
             try:
                 # converting all allowed attributes to python dictionary style
-  
+
                 # Replace Ruby-style HAML with Python style
                 attribute_dict_string = re.sub(self.RUBY_HAML_REGEX, '"\g":', attribute_dict_string)
                 # Put double quotes around key
@@ -133,9 +133,9 @@ def _parse_attribute_dictionary(self, attribute_dict_string):
                             v = re.sub(self.DJANGO_VARIABLE_REGEX, '{{\g}}', attributes_dict[k])
                             if v != attributes_dict[k]:
                                 sys.stderr.write("\n---------------------\nDEPRECATION WARNING: %s" % self.haml.lstrip() + \
-                                                 "\nThe Django attribute variable feature is deprecated and may be removed in future versions." + 
+                                                 "\nThe Django attribute variable feature is deprecated and may be removed in future versions." +
                                                  "\nPlease use inline variables ={...} instead.\n-------------------\n")
-                                
+
                             attributes_dict[k] = v
                             v = v.decode('utf-8')
                             self.attributes += "%s=%s " % (k, self.attr_wrap(self._escape_attribute_quotes(v)))
@@ -147,5 +147,5 @@ def _parse_attribute_dictionary(self, attribute_dict_string):
         return attributes_dict
 
 
-        
-        
+
+
diff --git a/hamlpy/test/hamlpy_test.py b/hamlpy/test/hamlpy_test.py
index 32559af..8191481 100755
--- a/hamlpy/test/hamlpy_test.py
+++ b/hamlpy/test/hamlpy_test.py
@@ -12,6 +12,13 @@ def test_applies_id_properly(self):
         result = hamlParser.process(haml)
         self.assertEqual(html, result.replace('\n', ''))
 
+    def test_non_ascii_id_allowed(self):
+        haml = '%div#これはテストです test'
+        html = "
test
" + hamlParser = hamlpy.Compiler() + result = hamlParser.process(haml) + self.assertEqual(html, result.replace('\n', '')) + def test_applies_class_properly(self): haml = '%div.someClass Some text' html = "
Some text
" From eb2e66573569430db5604954e0b6d741e5862865 Mon Sep 17 00:00:00 2001 From: Noel Bush Date: Mon, 10 Jun 2013 15:46:33 +0200 Subject: [PATCH 40/48] make the test of non-ascii filenames actually pass, by marking strings as unicode --- hamlpy/test/hamlpy_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hamlpy/test/hamlpy_test.py b/hamlpy/test/hamlpy_test.py index 1458c55..5601c96 100755 --- a/hamlpy/test/hamlpy_test.py +++ b/hamlpy/test/hamlpy_test.py @@ -13,8 +13,8 @@ def test_applies_id_properly(self): self.assertEqual(html, result.replace('\n', '')) def test_non_ascii_id_allowed(self): - haml = '%div#これはテストです test' - html = "
test
" + haml = u'%div#これはテストです test' + html = u"
test
" hamlParser = hamlpy.Compiler() result = hamlParser.process(haml) self.assertEqual(html, result.replace('\n', '')) From 92021ae82604e53ae5eca4c1123d490210d7802f Mon Sep 17 00:00:00 2001 From: Bosco Ho Date: Fri, 14 Jun 2013 19:28:47 +1000 Subject: [PATCH 41/48] Markdown filter: put back in trailing spaces to handle implicit
--- hamlpy/nodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hamlpy/nodes.py b/hamlpy/nodes.py index 89daabe..0287ca2 100644 --- a/hamlpy/nodes.py +++ b/hamlpy/nodes.py @@ -596,7 +596,7 @@ def _render(self): self.before = self.render_newlines()[1:] indent_offset = len(self.children[0].spaces) - text = ''.join(''.join([c.spaces[indent_offset:], c.haml, c.render_newlines()]) for c in self.children) + text = ''.join(''.join([c.spaces[indent_offset:], c.raw_haml.lstrip(), c.render_newlines()]) for c in self.children) self.before += markdown(text) else: self.after = self.render_newlines() From beda2a005162fe7ea828da9f49d4639e810d075c Mon Sep 17 00:00:00 2001 From: Bosco Ho Date: Mon, 17 Jun 2013 10:11:59 +1000 Subject: [PATCH 42/48] Fixed the markdown unit test --- hamlpy/test/templates/filtersMarkdown.hamlpy | 5 ++++- hamlpy/test/templates/filtersMarkdown.html | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/hamlpy/test/templates/filtersMarkdown.hamlpy b/hamlpy/test/templates/filtersMarkdown.hamlpy index c97726c..becf36a 100644 --- a/hamlpy/test/templates/filtersMarkdown.hamlpy +++ b/hamlpy/test/templates/filtersMarkdown.hamlpy @@ -2,6 +2,9 @@ hello no paragraph + line break + follow + New paragraph - test + code block diff --git a/hamlpy/test/templates/filtersMarkdown.html b/hamlpy/test/templates/filtersMarkdown.html index 49f148a..1b1a9a8 100644 --- a/hamlpy/test/templates/filtersMarkdown.html +++ b/hamlpy/test/templates/filtersMarkdown.html @@ -1,5 +1,7 @@

hello no paragraph

+

line break
+follow

New paragraph

-
test
-
+
code block
+
\ No newline at end of file From f6a56cb4cdfffed0155f8bdd69ea6870672c5f6a Mon Sep 17 00:00:00 2001 From: Bosco Ho Date: Fri, 21 Jun 2013 23:26:57 +1000 Subject: [PATCH 43/48] newline ambiguity resolved in reading raw_haml --- hamlpy/nodes.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hamlpy/nodes.py b/hamlpy/nodes.py index 0287ca2..a5e7e4a 100644 --- a/hamlpy/nodes.py +++ b/hamlpy/nodes.py @@ -593,10 +593,14 @@ def _render(self): if self.children: if not _markdown_available: raise NotAvailableError("Markdown is not available") - self.before = self.render_newlines()[1:] indent_offset = len(self.children[0].spaces) - text = ''.join(''.join([c.spaces[indent_offset:], c.raw_haml.lstrip(), c.render_newlines()]) for c in self.children) - self.before += markdown(text) + lines = [] + for c in self.children: + haml = c.raw_haml.lstrip() + if haml[-1] == '\n': + haml = haml[:-1] + lines.append(c.spaces[indent_offset:] + haml + c.render_newlines()) + self.before += markdown( ''.join(lines)) else: self.after = self.render_newlines() From 7f702b709423cff620cf99f6035b122c8a181014 Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Mon, 24 Jun 2013 11:43:50 -0500 Subject: [PATCH 44/48] - Added missing Jinja2 tag `raw` --- hamlpy/hamlpy_watcher.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hamlpy/hamlpy_watcher.py b/hamlpy/hamlpy_watcher.py index 421c2f6..04012b1 100644 --- a/hamlpy/hamlpy_watcher.py +++ b/hamlpy/hamlpy_watcher.py @@ -94,6 +94,7 @@ def watch_folder(): hamlpynodes.TagNode.self_closing.update({ 'macro' : 'endmacro', 'call' : 'endcall', + 'raw' : 'endraw' }) hamlpynodes.TagNode.may_contain['for'] = 'else' From b364bd28929f6db3019858453e6d4766eeb396ed Mon Sep 17 00:00:00 2001 From: tsouvarev Date: Fri, 12 Jul 2013 13:23:43 +0400 Subject: [PATCH 45/48] Update reference.md --- reference.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference.md b/reference.md index 3c126b3..542bdb0 100644 --- a/reference.md +++ b/reference.md @@ -25,8 +25,10 @@ - [Filters](#filters) - [:plain](#plain) - [:javascript](#javascript) + - [:coffeescript or :coffee](#coffeescript-or-coffee) - [:cdata](#cdata) - [:css](#css) + - [:stylus](#stylus) - [:markdown](#markdown) - [:highlight](#highlight) - [:python](#python) From fd3c93d71e3688c3fdf556cd770ff0f522226872 Mon Sep 17 00:00:00 2001 From: Andrew Cordery Date: Thu, 22 Aug 2013 23:25:30 -0400 Subject: [PATCH 46/48] Modified templatize to ignore non-haml files --- hamlpy/templatize.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/hamlpy/templatize.py b/hamlpy/templatize.py index 998d4f2..8497284 100644 --- a/hamlpy/templatize.py +++ b/hamlpy/templatize.py @@ -1,25 +1,31 @@ """ This module decorates the django templatize function to parse haml templates before the translation utility extracts tags from it. + +--Modified to ignore non-haml files. """ - + try: from django.utils.translation import trans_real _django_available = True except ImportError, e: _django_available = False - + import hamlpy - - +import os + + def decorate_templatize(func): - def templatize(src, origin=None): - hamlParser = hamlpy.Compiler() - html = hamlParser.process(src.decode('utf-8')) - return func(html.encode('utf-8'), origin) - - return templatize - + def templatize(src, origin=None): + #if the template has no origin file then do not attempt to parse it with haml + if origin: + #if the template has a source file, then only parse it if it is haml + if os.path.splitext(origin)[1].lower() in ['.'+x.lower() for x in hamlpy.VALID_EXTENSIONS]: + hamlParser = hamlpy.Compiler() + html = hamlParser.process(src.decode('utf-8')) + src = html.encode('utf-8') + return func(src, origin) + return templatize + if _django_available: - trans_real.templatize = decorate_templatize(trans_real.templatize) - + trans_real.templatize = decorate_templatize(trans_real.templatize) \ No newline at end of file From 62bc8cb5e3c12dc8193bf74eb5cae13b068344be Mon Sep 17 00:00:00 2001 From: Andrew Cordery Date: Thu, 22 Aug 2013 23:30:42 -0400 Subject: [PATCH 47/48] Modified templatize to ignore non-haml files (fix) --- hamlpy/templatize.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hamlpy/templatize.py b/hamlpy/templatize.py index 8497284..9581109 100644 --- a/hamlpy/templatize.py +++ b/hamlpy/templatize.py @@ -1,20 +1,20 @@ """ This module decorates the django templatize function to parse haml templates before the translation utility extracts tags from it. - + --Modified to ignore non-haml files. """ - + try: from django.utils.translation import trans_real _django_available = True except ImportError, e: _django_available = False - + import hamlpy import os - - + + def decorate_templatize(func): def templatize(src, origin=None): #if the template has no origin file then do not attempt to parse it with haml @@ -26,6 +26,6 @@ def templatize(src, origin=None): src = html.encode('utf-8') return func(src, origin) return templatize - + if _django_available: - trans_real.templatize = decorate_templatize(trans_real.templatize) \ No newline at end of file + trans_real.templatize = decorate_templatize(trans_real.templatize) From 7da6f02da42c3c7ed3ff537fb51bc5ece1928f9f Mon Sep 17 00:00:00 2001 From: alexander smishlajev Date: Wed, 4 Sep 2013 11:32:57 +0300 Subject: [PATCH 48/48] Support trailing comma in attribute dictionaries --- hamlpy/attribute_dict_parser.py | 3 +- hamlpy/test/attribute_dict_parser_test.py | 42 +++++++++++++---------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/hamlpy/attribute_dict_parser.py b/hamlpy/attribute_dict_parser.py index 9e4ab80..4b48ee7 100644 --- a/hamlpy/attribute_dict_parser.py +++ b/hamlpy/attribute_dict_parser.py @@ -34,7 +34,8 @@ def consume_end_of_value(self): self.consume_whitespace() if self.s[self.ptr] != self.terminator: if self.s[self.ptr] == ',': - self.ptr+=1 + self.ptr += 1 + self.consume_whitespace() else: raise Exception("Expected comma for end of value (after ...%s), but got '%s' instead" % (self.s[max(self.ptr-10,0):self.ptr], self.s[self.ptr])) diff --git a/hamlpy/test/attribute_dict_parser_test.py b/hamlpy/test/attribute_dict_parser_test.py index 95c80a7..4c2956d 100644 --- a/hamlpy/test/attribute_dict_parser_test.py +++ b/hamlpy/test/attribute_dict_parser_test.py @@ -7,79 +7,83 @@ class TestAttributeDictParser(object): def test_empty_dictionary(self): dict=AttributeDictParser("{}").parse() eq_(len(dict), 0) - + def test_one_string_value(self): dict=AttributeDictParser("{'class': 'test'}").parse() eq_(dict.get('class'), 'test') - + def test_two_string_value(self): dict=AttributeDictParser("{'class': 'test', 'id': 'something'}").parse() eq_(dict.get('class'), 'test') eq_(dict.get('id'), 'something') - + def test_integer_value(self): dict=AttributeDictParser("{'class': 'test', 'data-number': 123}").parse() eq_(dict.get('class'), 'test') eq_(dict.get('data-number'), '123') - + def test_float_value(self): dict=AttributeDictParser("{'class': 'test', 'data-number': 123.456}").parse() eq_(dict.get('class'), 'test') eq_(dict.get('data-number'), '123.456') - + def test_none_value(self): dict=AttributeDictParser("{'controls': None}").parse() eq_(dict.get('controls'), None) - + def test_colon_in_key(self): dict=AttributeDictParser("{'xml:lang': 'en'}").parse() eq_(dict.get('xml:lang'), 'en') - + def test_colon_in_value(self): dict=AttributeDictParser("{'xmllang': 'e:n'}").parse() eq_(dict.get('xmllang'), 'e:n') - + def test_double_quotes(self): dict=AttributeDictParser('{"class": "test", "data-number": "123"}').parse() eq_(dict.get('class'), 'test') eq_(dict.get('data-number'), '123') - + def test_key_quotes_are_optional(self): dict=AttributeDictParser("{class: 'test', data-number: 123}").parse() eq_(dict.get('class'), 'test') eq_(dict.get('data-number'), '123') - + def test_whitespace_between_key_and_value(self): dict=AttributeDictParser("{ class: 'test', data-number: 123}").parse() eq_(dict.get('class'), 'test') eq_(dict.get('data-number'), '123') - + def test_whitespace_before_colon(self): dict=AttributeDictParser("{ class \t: 'test'}").parse() eq_(dict.get('class'), 'test') - + + def test_trailing_comma(self): + dict=AttributeDictParser("{class: 'test', }").parse() + eq_(dict.get('class'), 'test') + def test_multiline_after_values(self): dict=AttributeDictParser("""{class: 'test', data-number: 123}""").parse() eq_(dict.get('class'), 'test') eq_(dict.get('data-number'), '123') - + def test_ruby_haml_arrow(self): dict=AttributeDictParser("{'class' => 'test'}").parse() eq_(dict.get('class'), 'test') - + def test_ruby_haml_colon(self): dict=AttributeDictParser("{ :class => 'test'}").parse() eq_(dict.get('class'), 'test') - + def test_list_value(self): dict=AttributeDictParser("{ class: ['a','b','c']}").parse() eq_(dict.get('class'), ['a','b','c']) - + def test_tuple_value(self): dict=AttributeDictParser("{ class: ('a','b','c')}").parse() eq_(dict.get('class'), ('a','b','c')) - + def test_attribute_value_not_quoted_when_looks_like_key(self): dict=AttributeDictParser('{name:"viewport", content:"width:device-width, initial-scale:1, minimum-scale:1, maximum-scale:1"}').parse() eq_(dict.get('content'), 'width:device-width, initial-scale:1, minimum-scale:1, maximum-scale:1') @@ -100,8 +104,8 @@ def test_multiline_haml_in_attributes(self): dict=AttributeDictParser(s).parse() eq_(dict.get('class'), '{% if forloop.first %} link-first {% else %} {% if forloop.last %} link-last {% endif %} {% endif %}') eq_(dict.get('href'), "{% url 'some_view' %}") - + # \r\n and \n # Curly braces in multiline HAML # Blank lines in Multiline HAML - # Incorrectly indented multiline HAML \ No newline at end of file + # Incorrectly indented multiline HAML