[
  {
    "path": ".gitignore",
    "content": ".coverage\ncover/\n*.pyc\ndist\nbuild\nhamlpy.egg-info\n/.idea/\n.project\n.pydevproject\n.DS_Store\n"
  },
  {
    "path": "LICENSE",
    "content": "(The MIT License)\n\nCopyright (c) 2011 Jesse Miller\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "hamlpy/__init__.py",
    "content": "import templatize\n"
  },
  {
    "path": "hamlpy/elements.py",
    "content": "import re\nimport sys\nfrom types import NoneType\n\nclass Element(object):\n    \"\"\"contains the pieces of an element and can populate itself from haml element text\"\"\"\n\n    self_closing_tags = ('meta', 'img', 'link', 'br', 'hr', 'input', 'source', 'track')\n\n    ELEMENT = '%'\n    ID = '#'\n    CLASS = '.'\n\n    HAML_REGEX = re.compile(r\"\"\"\n    (?P<tag>%\\w+(\\:\\w+)?)?\n    (?P<id>\\#[\\w-]*)?\n    (?P<class>\\.[\\w\\.-]*)*\n    (?P<attributes>\\{.*\\})?\n    (?P<nuke_outer_whitespace>\\>)?\n    (?P<nuke_inner_whitespace>\\<)?\n    (?P<selfclose>/)?\n    (?P<django>=)?\n    (?P<inline>[^\\w\\.#\\{].*)?\n    \"\"\", re.X | re.MULTILINE | re.DOTALL | re.UNICODE)\n\n    _ATTRIBUTE_KEY_REGEX = r'(?P<key>[a-zA-Z_][a-zA-Z0-9_-]*)'\n    #Single and double quote regexes from: http://stackoverflow.com/a/5453821/281469\n    _SINGLE_QUOTE_STRING_LITERAL_REGEX = r\"'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'\"\n    _DOUBLE_QUOTE_STRING_LITERAL_REGEX = r'\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"'\n    _ATTRIBUTE_VALUE_REGEX = r'(?P<val>\\d+|None(?!\\w)|%s|%s)' % (_SINGLE_QUOTE_STRING_LITERAL_REGEX, _DOUBLE_QUOTE_STRING_LITERAL_REGEX)\n\n    RUBY_HAML_REGEX = re.compile(r'(:|\\\")%s(\\\"|) =>' % (_ATTRIBUTE_KEY_REGEX))\n    ATTRIBUTE_REGEX = re.compile(r'(?P<pre>\\{\\s*|,\\s*)%s\\s*:\\s*%s' % (_ATTRIBUTE_KEY_REGEX, _ATTRIBUTE_VALUE_REGEX), re.UNICODE)\n    DJANGO_VARIABLE_REGEX = re.compile(r'^\\s*=\\s(?P<variable>[a-zA-Z_][a-zA-Z0-9._-]*)\\s*$')\n\n\n    def __init__(self, haml, attr_wrapper=\"'\"):\n        self.haml = haml\n        self.attr_wrapper = attr_wrapper\n        self.tag = None\n        self.id = None\n        self.classes = None\n        self.attributes = ''\n        self.self_close = False\n        self.django_variable = False\n        self.nuke_inner_whitespace = False\n        self.nuke_outer_whitespace = False\n        self.inline_content = ''\n        self._parse_haml()\n\n    def attr_wrap(self, value):\n        return '%s%s%s' % (self.attr_wrapper, value, self.attr_wrapper)\n\n    def _parse_haml(self):\n        split_tags = self.HAML_REGEX.search(self.haml).groupdict('')\n\n        self.attributes_dict = self._parse_attribute_dictionary(split_tags.get('attributes'))\n        self.tag = split_tags.get('tag').strip(self.ELEMENT) or 'div'\n        self.id = self._parse_id(split_tags.get('id'))\n        self.classes = ('%s %s' % (split_tags.get('class').lstrip(self.CLASS).replace('.', ' '), self._parse_class_from_attributes_dict())).strip()\n        self.self_close = split_tags.get('selfclose') or self.tag in self.self_closing_tags\n        self.nuke_inner_whitespace = split_tags.get('nuke_inner_whitespace') != ''\n        self.nuke_outer_whitespace = split_tags.get('nuke_outer_whitespace') != ''\n        self.django_variable = split_tags.get('django') != ''\n        self.inline_content = split_tags.get('inline').strip()\n\n    def _parse_class_from_attributes_dict(self):\n        clazz = self.attributes_dict.get('class', '')\n        if not isinstance(clazz, str):\n            clazz = ''\n            for one_class in self.attributes_dict.get('class'):\n                clazz += ' ' + one_class\n        return clazz.strip()\n\n    def _parse_id(self, id_haml):\n        id_text = id_haml.strip(self.ID)\n        if 'id' in self.attributes_dict:\n            id_text += self._parse_id_dict(self.attributes_dict['id'])\n        id_text = id_text.lstrip('_')\n        return id_text\n\n    def _parse_id_dict(self, id_dict):\n        text = ''\n        id_dict = self.attributes_dict.get('id')\n        if isinstance(id_dict, str):\n            text = '_' + id_dict\n        else:\n            text = ''\n            for one_id in id_dict:\n                text += '_' + one_id\n        return text\n\n    def _escape_attribute_quotes(self, v):\n        '''\n        Escapes quotes with a backslash, except those inside a Django tag\n        '''\n        escaped = []\n        inside_tag = False\n        for i, _ in enumerate(v):\n            if v[i:i + 2] == '{%':\n                inside_tag = True\n            elif v[i:i + 2] == '%}':\n                inside_tag = False\n\n            if v[i] == self.attr_wrapper and not inside_tag:\n                escaped.append('\\\\')\n\n            escaped.append(v[i])\n\n        return ''.join(escaped)\n\n    def _parse_attribute_dictionary(self, attribute_dict_string):\n        attributes_dict = {}\n        if (attribute_dict_string):\n            attribute_dict_string = attribute_dict_string.replace('\\n', ' ')\n            try:\n                # converting all allowed attributes to python dictionary style\n\n                # Replace Ruby-style HAML with Python style\n                attribute_dict_string = re.sub(self.RUBY_HAML_REGEX, '\"\\g<key>\":', attribute_dict_string)\n                # Put double quotes around key\n                attribute_dict_string = re.sub(self.ATTRIBUTE_REGEX, '\\g<pre>\"\\g<key>\":\\g<val>', attribute_dict_string)\n                # Parse string as dictionary\n                attributes_dict = eval(attribute_dict_string)\n                for k, v in attributes_dict.items():\n                    if k != 'id' and k != 'class':\n                        if isinstance(v, NoneType):\n                            self.attributes += \"%s \" % (k,)\n                        elif isinstance(v, int) or isinstance(v, float):\n                            self.attributes += \"%s=%s \" % (k, self.attr_wrap(v))\n                        else:\n                            # DEPRECATED: Replace variable in attributes (e.g. \"= somevar\") with Django version (\"{{somevar}}\")\n                            v = re.sub(self.DJANGO_VARIABLE_REGEX, '{{\\g<variable>}}', attributes_dict[k])\n                            if v != attributes_dict[k]:\n                                sys.stderr.write(\"\\n---------------------\\nDEPRECATION WARNING: %s\" % self.haml.lstrip() + \\\n                                                 \"\\nThe Django attribute variable feature is deprecated and may be removed in future versions.\" +\n                                                 \"\\nPlease use inline variables ={...} instead.\\n-------------------\\n\")\n\n                            attributes_dict[k] = v\n                            v = v.decode('utf-8')\n                            self.attributes += \"%s=%s \" % (k, self.attr_wrap(self._escape_attribute_quotes(v)))\n                self.attributes = self.attributes.strip()\n            except Exception, e:\n                raise Exception('failed to decode: %s' % attribute_dict_string)\n                #raise Exception('failed to decode: %s. Details: %s'%(attribute_dict_string, e))\n\n        return attributes_dict\n\n\n\n\n"
  },
  {
    "path": "hamlpy/ext.py",
    "content": "# coding=utf-8\ntry:\n    import jinja2.ext\n    _jinja2_available = True\nexcept ImportError, e:\n    _jinja2_available = False\n\nimport hamlpy\nimport os\n\nHAML_FILE_NAME_EXTENSIONS = ['haml', 'hamlpy']\n\n\ndef clean_extension(file_ext):\n    if not isinstance(file_ext, basestring):\n        raise Exception('Wrong file extension format: %r' % file_ext)\n    if len(file_ext) > 1 and file_ext.startswith('.'):\n        file_ext = file_ext[1:]\n    return file_ext.lower().strip()\n\n\ndef get_file_extension(file_path):\n    file_ext = os.path.splitext(file_path)[1]\n    return clean_extension(file_ext)\n\n\ndef has_any_extension(file_path, extensions):\n    file_ext = get_file_extension(file_path)\n    return file_ext and extensions and file_ext in [clean_extension(e) for e in extensions]\n\nif _jinja2_available:\n    class HamlPyExtension(jinja2.ext.Extension):\n\n        def preprocess(self, source, name, filename=None):\n            if name and has_any_extension(name, HAML_FILE_NAME_EXTENSIONS):\n                compiler = hamlpy.Compiler()\n                try:\n                    return compiler.process(source)\n                except Exception as e:\n                    raise jinja2.TemplateSyntaxError(e, 1, name=name, filename=filename)\n            else:\n                return source\n"
  },
  {
    "path": "hamlpy/hamlpy.py",
    "content": "#!/usr/bin/env python\nfrom nodes import RootNode, FilterNode, HamlNode, create_node\nfrom optparse import OptionParser\nimport sys\n\nVALID_EXTENSIONS=['haml', 'hamlpy']\n\nclass Compiler:\n\n    def __init__(self, options_dict=None):\n        options_dict = options_dict or {}\n        self.debug_tree = options_dict.pop('debug_tree', False)\n        self.options_dict = options_dict\n\n    def process(self, raw_text):\n        split_text = raw_text.split('\\n')\n        return self.process_lines(split_text)\n\n    def process_lines(self, haml_lines):\n        root = RootNode(**self.options_dict)\n        line_iter = iter(haml_lines)\n\n        haml_node=None\n        for line_number, line in enumerate(line_iter):\n            node_lines = line\n\n            if not root.parent_of(HamlNode(line)).inside_filter_node():\n                if line.count('{') - line.count('}') == 1:\n                    start_multiline=line_number # For exception handling\n\n                    while line.count('{') - line.count('}') != -1:\n                        try:\n                            line = line_iter.next()\n                        except StopIteration:\n                            raise Exception('No closing brace found for multi-line HAML beginning at line %s' % (start_multiline+1))\n                        node_lines += line\n\n            # Blank lines\n            if haml_node is not None and len(node_lines.strip()) == 0:\n                haml_node.newlines += 1\n            else:\n                haml_node = create_node(node_lines)\n                if haml_node:\n                    root.add_node(haml_node)\n\n        if self.options_dict and self.options_dict.get('debug_tree'):\n            return root.debug_tree()\n        else:\n            return root.render()\n\ndef convert_files():\n    import sys\n    import codecs\n\n    parser = OptionParser()\n    parser.add_option(\n        \"-d\", \"--debug-tree\", dest=\"debug_tree\",\n        action=\"store_true\",\n        help=\"Print the generated tree instead of the HTML\")\n    parser.add_option(\n        \"--attr-wrapper\", dest=\"attr_wrapper\",\n        type=\"choice\", choices=('\"', \"'\"), default=\"'\",\n        action=\"store\",\n        help=\"The character that should wrap element attributes. \"\n        \"This defaults to ' (an apostrophe).\")\n    (options, args) = parser.parse_args()\n\n    if len(args) < 1:\n        print \"Specify the input file as the first argument.\"\n    else:\n        infile = args[0]\n        haml_lines = codecs.open(infile, 'r', encoding='utf-8').read().splitlines()\n\n        compiler = Compiler(options.__dict__)\n        output = compiler.process_lines(haml_lines)\n\n        if len(args) == 2:\n            outfile = codecs.open(args[1], 'w', encoding='utf-8')\n            outfile.write(output)\n        else:\n            print output\n\nif __name__ == '__main__':\n    convert_files()\n"
  },
  {
    "path": "hamlpy/hamlpy_watcher.py",
    "content": "# haml-watcher.py\n# Author: Christian Stefanescu (st.chris@gmail.com)\n#\n# Watch a folder for files with the given extensions and call the HamlPy\n# compiler if the modified time has changed since the last check.\nfrom time import strftime\nimport argparse\nimport sys\nimport codecs\nimport os\nimport os.path\nimport time\nimport hamlpy\nimport nodes as hamlpynodes\n\ntry:\n    str = unicode\nexcept NameError:\n    pass\n\nclass Options(object):\n    CHECK_INTERVAL = 3  # in seconds\n    DEBUG = False  # print file paths when a file is compiled\n    VERBOSE = False\n    OUTPUT_EXT = '.html'\n\n# dict of compiled files [fullpath : timestamp]\ncompiled = dict()\n\nclass StoreNameValueTagPair(argparse.Action):\n    def __call__(self, parser, namespace, values, option_string = None):\n        tags = getattr(namespace, 'tags', {})\n        if tags is None:\n            tags = {}\n        for item in values:\n            n, v = item.split(':')\n            tags[n] = v\n        \n        setattr(namespace, 'tags', tags)\n\narg_parser = argparse.ArgumentParser()\narg_parser.add_argument('-v', '--verbose', help = 'Display verbose output', action = 'store_true')\narg_parser.add_argument('-i', '--input-extension', metavar = 'EXT', default = '.hamlpy', help = 'The file extensions to look for', type = str, nargs = '+')\narg_parser.add_argument('-ext', '--extension', metavar = 'EXT', default = Options.OUTPUT_EXT, help = 'The output file extension. Default is .html', type = str)\narg_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)\narg_parser.add_argument('input_dir', help = 'Folder to watch', type = str)\narg_parser.add_argument('output_dir', help = 'Destination folder', type = str, nargs = '?')\narg_parser.add_argument('--tag', help = 'Add self closing tag. eg. --tag macro:endmacro', type = str, nargs = 1, action = StoreNameValueTagPair)\narg_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).\")\narg_parser.add_argument('--jinja', help = 'Makes the necessary changes to be used with Jinja2', default = False, action = 'store_true')\n\ndef watched_extension(extension):\n    \"\"\"Return True if the given extension is one of the watched extensions\"\"\"\n    for ext in hamlpy.VALID_EXTENSIONS:\n        if extension.endswith('.' + ext):\n            return True\n    return False\n\ndef watch_folder():\n    \"\"\"Main entry point. Expects one or two arguments (the watch folder + optional destination folder).\"\"\"\n    argv = sys.argv[1:] if len(sys.argv) > 1 else []\n    args = arg_parser.parse_args(sys.argv[1:])\n    compiler_args = {}\n    \n    input_folder = os.path.realpath(args.input_dir)\n    if not args.output_dir:\n        output_folder = input_folder\n    else:\n        output_folder = os.path.realpath(args.output_dir)\n    \n    if args.verbose:\n        Options.VERBOSE = True\n        print \"Watching {} at refresh interval {} seconds\".format(input_folder, args.refresh)\n    \n    if args.extension:\n        Options.OUTPUT_EXT = args.extension\n    \n    if getattr(args, 'tags', False):\n        hamlpynodes.TagNode.self_closing.update(args.tags)\n    \n    if args.input_extension:\n        hamlpy.VALID_EXTENSIONS += args.input_extension\n    \n    if args.attr_wrapper:\n        compiler_args['attr_wrapper'] = args.attr_wrapper\n    \n    if args.jinja:\n        for k in ('ifchanged', 'ifequal', 'ifnotequal', 'autoescape', 'blocktrans',\n                  'spaceless', 'comment', 'cache', 'localize', 'compress'):\n            del hamlpynodes.TagNode.self_closing[k]\n            \n            hamlpynodes.TagNode.may_contain.pop(k, None)\n        \n        hamlpynodes.TagNode.self_closing.update({\n            'macro'  : 'endmacro',\n            'call'   : 'endcall',\n            'raw'    : 'endraw'\n        })\n        \n        hamlpynodes.TagNode.may_contain['for'] = 'else'\n    \n    while True:\n        try:\n            _watch_folder(input_folder, output_folder, compiler_args)\n            time.sleep(args.refresh)\n        except KeyboardInterrupt:\n            # allow graceful exit (no stacktrace output)\n            sys.exit(0)\n\ndef _watch_folder(folder, destination, compiler_args):\n    \"\"\"Compares \"modified\" timestamps against the \"compiled\" dict, calls compiler\n    if necessary.\"\"\"\n    for dirpath, dirnames, filenames in os.walk(folder):\n        for filename in filenames:\n            # Ignore filenames starting with \".#\" for Emacs compatibility\n            if watched_extension(filename) and not filename.startswith('.#'):\n                fullpath = os.path.join(dirpath, filename)\n                subfolder = os.path.relpath(dirpath, folder)\n                mtime = os.stat(fullpath).st_mtime\n                \n                # Create subfolders in target directory if they don't exist\n                compiled_folder = os.path.join(destination, subfolder)\n                if not os.path.exists(compiled_folder):\n                    os.makedirs(compiled_folder)\n                \n                compiled_path = _compiled_path(compiled_folder, filename)\n                if (not fullpath in compiled or\n                    compiled[fullpath] < mtime or\n                    not os.path.isfile(compiled_path)):\n                    compile_file(fullpath, compiled_path, compiler_args)\n                    compiled[fullpath] = mtime\n\ndef _compiled_path(destination, filename):\n    return os.path.join(destination, filename[:filename.rfind('.')] + Options.OUTPUT_EXT)\n\ndef compile_file(fullpath, outfile_name, compiler_args):\n    \"\"\"Calls HamlPy compiler.\"\"\"\n    if Options.VERBOSE:\n        print '%s %s -> %s' % (strftime(\"%H:%M:%S\"), fullpath, outfile_name)\n    try:\n        if Options.DEBUG:\n            print \"Compiling %s -> %s\" % (fullpath, outfile_name)\n        haml_lines = codecs.open(fullpath, 'r', encoding = 'utf-8').read().splitlines()\n        compiler = hamlpy.Compiler(compiler_args)\n        output = compiler.process_lines(haml_lines)\n        outfile = codecs.open(outfile_name, 'w', encoding = 'utf-8')\n        outfile.write(output)\n    except Exception, e:\n        # import traceback\n        print \"Failed to compile %s -> %s\\nReason:\\n%s\" % (fullpath, outfile_name, e)\n        # print traceback.print_exc()\n\nif __name__ == '__main__':\n    watch_folder()\n"
  },
  {
    "path": "hamlpy/nodes.py",
    "content": "import re\nimport sys\nfrom StringIO import StringIO\n\nfrom elements import Element\n\ntry:\n    from pygments import highlight\n    from pygments.formatters import HtmlFormatter\n    from pygments.lexers import guess_lexer\n    _pygments_available = True\nexcept ImportError, e:\n    _pygments_available = False\n\ntry:\n    from markdown import markdown\n    _markdown_available = True\nexcept ImportError, e:\n    _markdown_available = False\n\nclass NotAvailableError(Exception):\n    pass\n\nELEMENT = '%'\nID = '#'\nCLASS = '.'\nDOCTYPE = '!!!'\n\nHTML_COMMENT = '/'\nCONDITIONAL_COMMENT = '/['\nHAML_COMMENTS = ['-#', '=#']\n\nVARIABLE = '='\nTAG = '-'\n\nINLINE_VARIABLE = re.compile(r'(?<!\\\\)([#=]\\{\\s*(.+?)\\s*\\})')\nESCAPED_INLINE_VARIABLE = re.compile(r'\\\\([#=]\\{\\s*(.+?)\\s*\\})')\n\nCOFFEESCRIPT_FILTERS = [':coffeescript', ':coffee']\nJAVASCRIPT_FILTER = ':javascript'\nCSS_FILTER = ':css'\nSTYLUS_FILTER = ':stylus'\nPLAIN_FILTER = ':plain'\nPYTHON_FILTER = ':python'\nMARKDOWN_FILTER = ':markdown'\nCDATA_FILTER = ':cdata'\nPYGMENTS_FILTER = ':highlight'\n\nELEMENT_CHARACTERS = (ELEMENT, ID, CLASS)\n\nHAML_ESCAPE = '\\\\'\n\ndef create_node(haml_line):\n    stripped_line = haml_line.strip()\n\n    if len(stripped_line) == 0:\n        return None\n\n    if re.match(INLINE_VARIABLE, stripped_line) or re.match(ESCAPED_INLINE_VARIABLE, stripped_line):\n        return PlaintextNode(haml_line)\n\n    if stripped_line[0] == HAML_ESCAPE:\n        return PlaintextNode(haml_line)\n\n    if stripped_line.startswith(DOCTYPE):\n        return DoctypeNode(haml_line)\n\n    if stripped_line[0] in ELEMENT_CHARACTERS:\n        return ElementNode(haml_line)\n\n    if stripped_line[0:len(CONDITIONAL_COMMENT)] == CONDITIONAL_COMMENT:\n        return ConditionalCommentNode(haml_line)\n\n    if stripped_line[0] == HTML_COMMENT:\n        return CommentNode(haml_line)\n\n    for comment_prefix in HAML_COMMENTS:\n        if stripped_line.startswith(comment_prefix):\n            return HamlCommentNode(haml_line)\n\n    if stripped_line[0] == VARIABLE:\n        return VariableNode(haml_line)\n\n    if stripped_line[0] == TAG:\n        return TagNode(haml_line)\n\n    if stripped_line == JAVASCRIPT_FILTER:\n        return JavascriptFilterNode(haml_line)\n\n    if stripped_line in COFFEESCRIPT_FILTERS:\n        return CoffeeScriptFilterNode(haml_line)\n\n    if stripped_line == CSS_FILTER:\n        return CssFilterNode(haml_line)\n\n    if stripped_line == STYLUS_FILTER:\n        return StylusFilterNode(haml_line)\n\n    if stripped_line == PLAIN_FILTER:\n        return PlainFilterNode(haml_line)\n\n    if stripped_line == PYTHON_FILTER:\n        return PythonFilterNode(haml_line)\n\n    if stripped_line == CDATA_FILTER:\n        return CDataFilterNode(haml_line)\n\n    if stripped_line == PYGMENTS_FILTER:\n        return PygmentsFilterNode(haml_line)\n\n    if stripped_line == MARKDOWN_FILTER:\n        return MarkdownFilterNode(haml_line)\n\n    return PlaintextNode(haml_line)\n\nclass TreeNode(object):\n    ''' Generic parent/child tree class'''\n    def __init__(self):\n        self.parent = None\n        self.children = []\n\n    def left_sibling(self):\n        siblings = self.parent.children\n        index = siblings.index(self)\n        return siblings[index - 1] if index > 0 else None\n\n    def right_sibling(self):\n        siblings = self.parent.children\n        index = siblings.index(self)\n        return siblings[index + 1] if index < len(siblings) - 1 else None\n\n    def add_child(self, child):\n        child.parent = self\n        self.children.append(child)\n\nclass RootNode(TreeNode):\n    def __init__(self, attr_wrapper=\"'\"):\n        TreeNode.__init__(self)\n        self.indentation = -2\n        # Number of empty lines to render after node\n        self.newlines = 0\n        # Rendered text at start of node, e.g. \"<p>\\n\"\n        self.before = ''\n        # Rendered text at end of node, e.g. \"\\n</p>\"\n        self.after = ''\n        # Indicates that a node does not render anything (for whitespace removal)\n        self.empty_node = False\n\n        # Options\n        self.attr_wrapper = attr_wrapper\n\n    def add_child(self, child):\n        '''Add child node, and copy all options to it'''\n        super(RootNode, self).add_child(child)\n        child.attr_wrapper = self.attr_wrapper\n\n    def render(self):\n        # Render (sets self.before and self.after)\n        self._render_children()\n        # Post-render (nodes can modify the rendered text of other nodes)\n        self._post_render()\n        # Generate HTML\n        return self._generate_html()\n\n    def render_newlines(self):\n        return '\\n' * (self.newlines + 1)\n\n    def parent_of(self, node):\n        if (self._should_go_inside_last_node(node)):\n            ret = self.children[-1].parent_of(node)\n            return ret\n        else:\n            return self\n\n    def inside_filter_node(self):\n        if self.parent:\n            return self.parent.inside_filter_node()\n        else:\n            return False\n\n    def _render_children(self):\n        for child in self.children:\n            child._render()\n\n    def _post_render(self):\n        for child in self.children:\n            child._post_render()\n\n    def _generate_html(self):\n        output = []\n        output.append(self.before)\n        for child in self.children:\n            output.append(child.before)\n            output += [gc._generate_html() for gc in child.children]\n            output.append(child.after)\n        output.append(self.after)\n        return ''.join(output)\n\n    def add_node(self, node):\n        if (self._should_go_inside_last_node(node)):\n            self.children[-1].add_node(node)\n        else:\n            self.add_child(node)\n\n    def _should_go_inside_last_node(self, node):\n        return len(self.children) > 0 and (node.indentation > self.children[-1].indentation\n            or (node.indentation == self.children[-1].indentation and self.children[-1].should_contain(node)))\n\n    def should_contain(self, node):\n        return False\n\n    def debug_tree(self):\n        return '\\n'.join(self._debug_tree([self]))\n\n    def _debug_tree(self, nodes):\n        output = []\n        for n in nodes:\n            output.append('%s%s' % (' ' * (n.indentation + 2), n))\n            if n.children:\n                output += self._debug_tree(n.children)\n        return output\n\n    def __repr__(self):\n        return '(%s)' % (self.__class__)\n\nclass HamlNode(RootNode):\n    def __init__(self, haml):\n        RootNode.__init__(self)\n        self.haml = haml.strip()\n        self.raw_haml = haml\n        self.indentation = (len(haml) - len(haml.lstrip()))\n        self.spaces = ''.join(haml[0] for i in range(self.indentation))\n\n    def replace_inline_variables(self, content):\n        content = re.sub(INLINE_VARIABLE, r'{{ \\2 }}', content)\n        content = re.sub(ESCAPED_INLINE_VARIABLE, r'\\1', content)\n        return content\n\n    def __repr__(self):\n        return '(%s in=%d, nl=%d: %s)' % (self.__class__, self.indentation, self.newlines, self.haml)\n\nclass PlaintextNode(HamlNode):\n    '''Node that is not modified or processed when rendering'''\n    def _render(self):\n        text = self.replace_inline_variables(self.haml)\n        # Remove escape character unless inside filter node\n        if text and text[0] == HAML_ESCAPE and not self.inside_filter_node():\n            text = text.replace(HAML_ESCAPE, '', 1)\n\n        self.before = '%s%s' % (self.spaces, text)\n        if self.children:\n            self.before += self.render_newlines()\n        else:\n            self.after = self.render_newlines()\n        self._render_children()\n\nclass ElementNode(HamlNode):\n    '''Node which represents a HTML tag'''\n    def __init__(self, haml):\n        HamlNode.__init__(self, haml)\n        self.django_variable = False\n\n    def _render(self):\n        self.element = Element(self.haml, self.attr_wrapper)\n        self.django_variable = self.element.django_variable\n        self.before = self._render_before(self.element)\n        self.after = self._render_after(self.element)\n        self._render_children()\n\n    def _render_before(self, element):\n        '''Render opening tag and inline content'''\n        start = [\"%s<%s\" % (self.spaces, element.tag)]\n        if element.id:\n            start.append(\" id=%s\" % self.element.attr_wrap(self.replace_inline_variables(element.id)))\n        if element.classes:\n            start.append(\" class=%s\" % self.element.attr_wrap(self.replace_inline_variables(element.classes)))\n        if element.attributes:\n            start.append(' ' + self.replace_inline_variables(element.attributes))\n\n        content = self._render_inline_content(self.element.inline_content)\n\n        if element.nuke_inner_whitespace and content:\n            content = content.strip()\n\n        if element.self_close and not content:\n            start.append(\" />\")\n        elif content:\n            start.append(\">%s\" % (content))\n        elif self.children:\n            start.append(\">%s\" % (self.render_newlines()))\n        else:\n            start.append(\">\")\n        return ''.join(start)\n\n    def _render_after(self, element):\n        '''Render closing tag'''\n        if element.inline_content:\n            return \"</%s>%s\" % (element.tag, self.render_newlines())\n        elif element.self_close:\n            return self.render_newlines()\n        elif self.children:\n            return \"%s</%s>\\n\" % (self.spaces, element.tag)\n        else:\n            return \"</%s>\\n\" % (element.tag)\n\n    def _post_render(self):\n        # Inner whitespace removal\n        if self.element.nuke_inner_whitespace:\n            self.before = self.before.rstrip()\n            self.after = self.after.lstrip()\n\n            if self.children:\n                node = self\n                # If node renders nothing, do removal on its first child instead\n                if node.children[0].empty_node == True:\n                    node = node.children[0]\n                if node.children:\n                    node.children[0].before = node.children[0].before.lstrip()\n\n                node = self\n                if node.children[-1].empty_node == True:\n                    node = node.children[-1]\n                if node.children:\n                    node.children[-1].after = node.children[-1].after.rstrip()\n\n        # Outer whitespace removal\n        if self.element.nuke_outer_whitespace:\n            left_sibling = self.left_sibling()\n            if left_sibling:\n                # If node has left sibling, strip whitespace after left sibling\n                left_sibling.after = left_sibling.after.rstrip()\n                left_sibling.newlines = 0\n            else:\n                # If not, whitespace comes from it's parent node,\n                # so strip whitespace before the node\n                self.parent.before = self.parent.before.rstrip()\n                self.parent.newlines = 0\n\n            self.before = self.before.lstrip()\n            self.after = self.after.rstrip()\n\n            right_sibling = self.right_sibling()\n            if right_sibling:\n                right_sibling.before = right_sibling.before.lstrip()\n            else:\n                self.parent.after = self.parent.after.lstrip()\n                self.parent.newlines = 0\n\n        super(ElementNode, self)._post_render()\n\n    def _render_inline_content(self, inline_content):\n        if inline_content == None or len(inline_content) == 0:\n            return None\n\n        if self.django_variable:\n            content = \"{{ \" + inline_content.strip() + \" }}\"\n            return content\n        else:\n            return self.replace_inline_variables(inline_content)\n\nclass CommentNode(HamlNode):\n    def _render(self):\n        self.after = \"-->\\n\"\n        if self.children:\n            self.before = \"<!-- %s\" % (self.render_newlines())\n            self._render_children()\n        else:\n            self.before = \"<!-- %s \" % (self.haml.lstrip(HTML_COMMENT).strip())\n\nclass ConditionalCommentNode(HamlNode):\n    def _render(self):\n        conditional = self.haml[1: self.haml.index(']') + 1 ]\n\n        if self.children:\n            self.before = \"<!--%s>\\n\" % (conditional)\n        else:\n            content = self.haml[len(CONDITIONAL_COMMENT) + len(conditional) - 1:]\n            self.before = \"<!--%s>%s\" % (conditional, content)\n\n        self.after = \"<![endif]-->\\n\"\n        self._render_children()\n\nclass DoctypeNode(HamlNode):\n    def _render(self):\n        doctype = self.haml.lstrip(DOCTYPE).strip()\n\n        parts = doctype.split()\n        if parts and parts[0] == \"XML\":\n            encoding = parts[1] if len(parts) > 1 else 'utf-8'\n            self.before = \"<?xml version=%s1.0%s encoding=%s%s%s ?>\" % (\n                self.attr_wrapper, self.attr_wrapper,\n                self.attr_wrapper, encoding, self.attr_wrapper,\n            )\n        else:\n            types = {\n                \"\": '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">',\n                \"Strict\": '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">',\n                \"Frameset\": '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">',\n                \"5\": '<!DOCTYPE html>',\n                \"1.1\": '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">'\n            }\n\n            if doctype in types:\n                self.before = types[doctype]\n\n        self.after = self.render_newlines()\n\nclass HamlCommentNode(HamlNode):\n    def _render(self):\n        self.after = self.render_newlines()[1:]\n\n    def _post_render(self):\n        pass\n\nclass VariableNode(ElementNode):\n    def __init__(self, haml):\n        ElementNode.__init__(self, haml)\n        self.django_variable = True\n\n    def _render(self):\n        tag_content = self.haml.lstrip(VARIABLE)\n        self.before = \"%s%s\" % (self.spaces, self._render_inline_content(tag_content))\n        self.after = self.render_newlines()\n\n    def _post_render(self):\n        pass\n\nclass TagNode(HamlNode):\n    self_closing = {'for':'endfor',\n                    'if':'endif',\n                    'ifchanged':'endifchanged',\n                    'ifequal':'endifequal',\n                    'ifnotequal':'endifnotequal',\n                    'block':'endblock',\n                    'filter':'endfilter',\n                    'autoescape':'endautoescape',\n                    'with':'endwith',\n                    'blocktrans': 'endblocktrans',\n                    'spaceless': 'endspaceless',\n                    'comment': 'endcomment',\n                    'cache': 'endcache',\n                    'localize': 'endlocalize',\n                    'compress': 'endcompress'}\n    may_contain = {'if':['else', 'elif'],\n                   'ifchanged':'else',\n                   'ifequal':'else',\n                   'ifnotequal':'else',\n                   'for':'empty',\n                   'with':'with'}\n\n    def __init__(self, haml):\n        HamlNode.__init__(self, haml)\n        self.tag_statement = self.haml.lstrip(TAG).strip()\n        self.tag_name = self.tag_statement.split(' ')[0]\n\n        if (self.tag_name in self.self_closing.values()):\n            raise TypeError(\"Do not close your Django tags manually.  It will be done for you.\")\n\n    def _render(self):\n        self.before = \"%s{%% %s %%}\" % (self.spaces, self.tag_statement)\n        if (self.tag_name in self.self_closing.keys()):\n            self.before += self.render_newlines()\n            self.after = '%s{%% %s %%}%s' % (self.spaces, self.self_closing[self.tag_name], self.render_newlines())\n        else:\n            if self.children:\n                self.before += self.render_newlines()\n            else:\n                self.after = self.render_newlines()\n        self._render_children()\n\n    def should_contain(self, node):\n        return isinstance(node, TagNode) and node.tag_name in self.may_contain.get(self.tag_name, '')\n\n\nclass FilterNode(HamlNode):\n    def add_node(self, node):\n        self.add_child(node)\n\n    def inside_filter_node(self):\n        return True\n\n    def _render_children_as_plain_text(self, remove_indentation = True):\n        if self.children:\n            initial_indentation = len(self.children[0].spaces)\n        for child in self.children:\n            child.before = ''\n            if not remove_indentation:\n                child.before = child.spaces\n            else:\n                child.before = child.spaces[initial_indentation:]\n            child.before += child.haml\n            child.after = child.render_newlines()\n\n    def _post_render(self):\n        # Don't post-render children of filter nodes as we don't want them to be interpreted as HAML\n        pass\n\n\nclass PlainFilterNode(FilterNode):\n    def __init__(self, haml):\n        FilterNode.__init__(self, haml)\n        self.empty_node = True\n\n    def _render(self):\n        if self.children:\n            first_indentation = self.children[0].indentation\n        self._render_children_as_plain_text()\n\nclass PythonFilterNode(FilterNode):\n    def _render(self):\n        if self.children:\n            self.before = self.render_newlines()[1:]\n            indent_offset = len(self.children[0].spaces)\n            code = \"\\n\".join([node.raw_haml[indent_offset:] for node in self.children]) + '\\n'\n            compiled_code = compile(code, \"\", \"exec\")\n\n            buffer = StringIO()\n            sys.stdout = buffer\n            try:\n                exec compiled_code\n            except Exception as e:\n                # Change exception message to let developer know that exception comes from\n                # a PythonFilterNode\n                if e.args:\n                    args = list(e.args)\n                    args[0] = \"Error in :python filter code: \" + e.message\n                    e.args = tuple(args)\n                raise e\n            finally:\n                # restore the original stdout\n                sys.stdout = sys.__stdout__\n            self.before += buffer.getvalue()\n        else:\n            self.after = self.render_newlines()\n\nclass JavascriptFilterNode(FilterNode):\n    def _render(self):\n        self.before = '<script type=%(attr_wrapper)stext/javascript%(attr_wrapper)s>\\n// <![CDATA[%(new_lines)s' % {\n            'attr_wrapper': self.attr_wrapper,\n            'new_lines': self.render_newlines(),\n        }\n        self.after = '// ]]>\\n</script>\\n'\n        self._render_children_as_plain_text(remove_indentation = False)\n\nclass CoffeeScriptFilterNode(FilterNode):\n    def _render(self):\n        self.before = '<script type=%(attr_wrapper)stext/coffeescript%(attr_wrapper)s>\\n#<![CDATA[%(new_lines)s' % {\n            'attr_wrapper': self.attr_wrapper,\n            'new_lines': self.render_newlines(),\n        }\n        self.after = '#]]>\\n</script>\\n'\n        self._render_children_as_plain_text(remove_indentation = False)\n\nclass CssFilterNode(FilterNode):\n    def _render(self):\n        self.before = '<style type=%(attr_wrapper)stext/css%(attr_wrapper)s>\\n/*<![CDATA[*/%(new_lines)s' % {\n            'attr_wrapper': self.attr_wrapper,\n            'new_lines': self.render_newlines(),\n        }\n        self.after = '/*]]>*/\\n</style>\\n'\n        self._render_children_as_plain_text(remove_indentation = False)\n\nclass StylusFilterNode(FilterNode):\n    def _render(self):\n        self.before = '<style type=%(attr_wrapper)stext/stylus%(attr_wrapper)s>\\n/*<![CDATA[*/%(new_lines)s' % {\n            'attr_wrapper': self.attr_wrapper,\n            'new_lines': self.render_newlines(),\n        }\n        self.after = '/*]]>*/\\n</style>\\n'\n        self._render_children_as_plain_text()\n\nclass CDataFilterNode(FilterNode):\n    def _render(self):\n        self.before = self.spaces + '<![CDATA[%s' % (self.render_newlines())\n        self.after = self.spaces + ']]>\\n'\n        self._render_children_as_plain_text(remove_indentation = False)\n\nclass PygmentsFilterNode(FilterNode):\n    def _render(self):\n        if self.children:\n            if not _pygments_available:\n                raise NotAvailableError(\"Pygments is not available\")\n\n            self.before = self.render_newlines()\n            indent_offset = len(self.children[0].spaces)\n            text = ''.join(''.join([c.spaces[indent_offset:], c.haml, c.render_newlines()]) for c in self.children)\n            self.before += highlight(text, guess_lexer(self.haml), HtmlFormatter())\n        else:\n            self.after = self.render_newlines()\n\nclass MarkdownFilterNode(FilterNode):\n    def _render(self):\n        if self.children:\n            if not _markdown_available:\n                raise NotAvailableError(\"Markdown is not available\")\n            self.before = self.render_newlines()[1:]\n            indent_offset = len(self.children[0].spaces)\n            lines = []\n            for c in self.children:\n                haml = c.raw_haml.lstrip()\n                if haml[-1] == '\\n':\n                    haml = haml[:-1]\n                lines.append(c.spaces[indent_offset:] + haml + c.render_newlines())\n            self.before += markdown( ''.join(lines))\n        else:\n            self.after = self.render_newlines()\n"
  },
  {
    "path": "hamlpy/template/__init__.py",
    "content": "from loaders import haml_loaders as _loaders\n\nlocals().update(_loaders)\n"
  },
  {
    "path": "hamlpy/template/loaders.py",
    "content": "import os\n\ntry:\n    from django.template import TemplateDoesNotExist\n    from django.template.loaders import filesystem, app_directories\n    _django_available = True\nexcept ImportError, e:\n    class TemplateDoesNotExist(Exception):\n        pass\n\n    _django_available = False\n\nfrom hamlpy import hamlpy\nfrom hamlpy.template.utils import get_django_template_loaders\n\n\n# Get options from Django settings\noptions_dict = {}\n\nif _django_available:\n    from django.conf import settings\n    if hasattr(settings, 'HAMLPY_ATTR_WRAPPER'):\n        options_dict.update(attr_wrapper=settings.HAMLPY_ATTR_WRAPPER)\n\n\ndef get_haml_loader(loader):\n    if hasattr(loader, 'Loader'):\n        baseclass = loader.Loader\n    else:\n        class baseclass(object):\n            def load_template_source(self, *args, **kwargs):\n                return loader.load_template_source(*args, **kwargs)\n\n    class Loader(baseclass):\n        def load_template_source(self, template_name, *args, **kwargs):\n            name, _extension = os.path.splitext(template_name)\n            # os.path.splitext always returns a period at the start of extension\n            extension = _extension.lstrip('.')\n\n            if extension in hamlpy.VALID_EXTENSIONS:\n                try:\n                    haml_source, template_path = super(Loader, self).load_template_source(\n                        self._generate_template_name(name, extension), *args, **kwargs\n                    )\n                except TemplateDoesNotExist:\n                    pass\n                else:\n                    hamlParser = hamlpy.Compiler(options_dict=options_dict)\n                    html = hamlParser.process(haml_source)\n\n                    return html, template_path\n\n            raise TemplateDoesNotExist(template_name)\n\n        load_template_source.is_usable = True\n\n        def _generate_template_name(self, name, extension=\"hamlpy\"):\n            return \"%s.%s\" % (name, extension)\n\n    return Loader\n\n\nhaml_loaders = dict((name, get_haml_loader(loader))\n        for (name, loader) in get_django_template_loaders())\n\nif _django_available:\n    HamlPyFilesystemLoader = get_haml_loader(filesystem)\n    HamlPyAppDirectoriesLoader = get_haml_loader(app_directories)\n"
  },
  {
    "path": "hamlpy/template/utils.py",
    "content": "import imp\nfrom os import listdir\nfrom os.path import dirname, splitext\n\ntry:\n  from django.template import loaders\n  _django_available = True\nexcept ImportError, e:\n  _django_available = False\n\nMODULE_EXTENSIONS = tuple([suffix[0] for suffix in imp.get_suffixes()])\n\ndef get_django_template_loaders():\n    if not _django_available:\n        return []\n    return [(loader.__name__.rsplit('.',1)[1], loader) \n                for loader in get_submodules(loaders)\n                if hasattr(loader, 'Loader')]\n        \ndef get_submodules(package):\n    submodules = (\"%s.%s\" % (package.__name__, module)\n                for module in package_contents(package))\n    return [__import__(module, {}, {}, [module.rsplit(\".\", 1)[-1]]) \n                for module in submodules]\n\ndef package_contents(package):\n    package_path = dirname(loaders.__file__)\n    contents = set([splitext(module)[0]\n            for module in listdir(package_path)\n            if module.endswith(MODULE_EXTENSIONS)])\n    return contents\n"
  },
  {
    "path": "hamlpy/templatize.py",
    "content": "\"\"\"\nThis module decorates the django templatize function to parse haml templates\nbefore the translation utility extracts tags from it.\n\n--Modified to ignore non-haml files.\n\"\"\"\n\ntry:\n    from django.utils.translation import trans_real\n    _django_available = True\nexcept ImportError, e:\n    _django_available = False\n\nimport hamlpy\nimport os\n\n\ndef decorate_templatize(func):\n    def templatize(src, origin=None):\n        #if the template has no origin file then do not attempt to parse it with haml\n        if origin:\n            #if the template has a source file, then only parse it if it is haml\n            if os.path.splitext(origin)[1].lower() in ['.'+x.lower() for x in hamlpy.VALID_EXTENSIONS]:\n                hamlParser = hamlpy.Compiler()\n                html = hamlParser.process(src.decode('utf-8'))\n                src = html.encode('utf-8')\n        return func(src, origin)\n    return templatize\n\nif _django_available:\n    trans_real.templatize = decorate_templatize(trans_real.templatize)\n"
  },
  {
    "path": "hamlpy/test/__init__.py",
    "content": ""
  },
  {
    "path": "hamlpy/test/codecoverage.sh",
    "content": "nosetests *.py --with-coverage --cover-html --cover-inclusive --cover-package=hamlpy.*\n"
  },
  {
    "path": "hamlpy/test/ext_test.py",
    "content": "import unittest\nimport os\nfrom hamlpy.ext import has_any_extension\n\nclass ExtTest(unittest.TestCase):\n    \"\"\"\n    Tests for methods found in ../ext.py\n    \"\"\"\n    \n    def test_has_any_extension(self):\n        extensions = [\n            'hamlpy',\n            'haml',\n            '.txt'\n        ]\n        # no directory\n        self.assertTrue(has_any_extension('dir.hamlpy', extensions))\n        self.assertTrue(has_any_extension('dir.haml', extensions))\n        self.assertTrue(has_any_extension('dir.txt', extensions))\n        self.assertFalse(has_any_extension('dir.html', extensions))\n        # with dot in filename\n        self.assertTrue(has_any_extension('dir.dot.hamlpy', extensions))\n        self.assertTrue(has_any_extension('dir.dot.haml', extensions))\n        self.assertTrue(has_any_extension('dir.dot.txt', extensions))\n        self.assertFalse(has_any_extension('dir.dot.html', extensions))\n        \n        # relative path\n        self.assertTrue(has_any_extension('../dir.hamlpy', extensions))\n        self.assertTrue(has_any_extension('../dir.haml', extensions))\n        self.assertTrue(has_any_extension('../dir.txt', extensions))\n        self.assertFalse(has_any_extension('../dir.html', extensions))\n        # with dot in filename\n        self.assertTrue(has_any_extension('../dir.dot.hamlpy', extensions))\n        self.assertTrue(has_any_extension('../dir.dot.haml', extensions))\n        self.assertTrue(has_any_extension('../dir.dot.txt', extensions))\n        self.assertFalse(has_any_extension('../dir.dot.html', extensions))\n        \n        # absolute paths\n        self.assertTrue(has_any_extension('/home/user/dir.hamlpy', extensions))\n        self.assertTrue(has_any_extension('/home/user/dir.haml', extensions))\n        self.assertTrue(has_any_extension('/home/user/dir.txt', extensions))\n        self.assertFalse(has_any_extension('/home/user/dir.html', extensions))\n        # with dot in filename\n        self.assertTrue(has_any_extension('/home/user/dir.dot.hamlpy', extensions))\n        self.assertTrue(has_any_extension('/home/user/dir.dot.haml', extensions))\n        self.assertTrue(has_any_extension('/home/user/dir.dot.txt', extensions))\n        self.assertFalse(has_any_extension('/home/user/dir.dot.html', extensions))"
  },
  {
    "path": "hamlpy/test/hamlnode_test.py",
    "content": "import unittest\nfrom hamlpy import nodes\n\nclass TestElementNode(unittest.TestCase):\n    def test_calculates_indentation_properly(self):\n        no_indentation = nodes.ElementNode('%div')\n        self.assertEqual(0, no_indentation.indentation)\n        \n        three_indentation = nodes.ElementNode('   %div')\n        self.assertEqual(3, three_indentation.indentation)\n        \n        six_indentation = nodes.ElementNode('      %div')\n        self.assertEqual(6, six_indentation.indentation)\n\n    def test_indents_tabs_properly(self):\n        no_indentation = nodes.ElementNode('%div')\n        self.assertEqual('', no_indentation.spaces)\n\n        one_tab = nodes.HamlNode('\t%div')\n        self.assertEqual('\\t', one_tab.spaces)\n\n        one_space = nodes.HamlNode(' %div')\n        self.assertEqual(' ', one_space.spaces)\n\n        three_tabs = nodes.HamlNode('\t\t\t%div')\n        self.assertEqual('\\t\\t\\t', three_tabs.spaces)\n\n        tab_space = nodes.HamlNode('\t %div')\n        self.assertEqual('\\t\\t', tab_space.spaces)\n\n        space_tab = nodes.HamlNode(' \t%div')\n        self.assertEqual('  ', space_tab.spaces)\n\t\t\t\n    def test_lines_are_always_stripped_of_whitespace(self):\n        some_space = nodes.ElementNode('   %div')\n        self.assertEqual('%div', some_space.haml)\n        \n        lots_of_space = nodes.ElementNode('      %div    ')\n        self.assertEqual('%div', lots_of_space.haml)\n    \n    def test_inserts_nodes_into_proper_tree_depth(self):\n        no_indentation_node = nodes.ElementNode('%div')\n        one_indentation_node = nodes.ElementNode(' %div')\n        two_indentation_node = nodes.ElementNode('  %div')\n        another_one_indentation_node = nodes.ElementNode(' %div')\n        \n        no_indentation_node.add_node(one_indentation_node)\n        no_indentation_node.add_node(two_indentation_node)\n        no_indentation_node.add_node(another_one_indentation_node)\n        \n        self.assertEqual(one_indentation_node, no_indentation_node.children[0])\n        self.assertEqual(two_indentation_node, no_indentation_node.children[0].children[0])\n        self.assertEqual(another_one_indentation_node, no_indentation_node.children[1])\n    \n    def test_adds_multiple_nodes_to_one(self):\n        start = nodes.ElementNode('%div')\n        one = nodes.ElementNode('  %div')\n        two = nodes.ElementNode('  %div')\n        three = nodes.ElementNode('  %div')\n        \n        start.add_node(one)\n        start.add_node(two)\n        start.add_node(three)\n        \n        self.assertEqual(3, len(start.children))\n\n    def test_html_indentation_vs_haml_indentation(self):\n        pass\n\n    def test_node_parent_function(self):\n        root=nodes.ElementNode('%div.a')\n        elements = [\n            {'node': nodes.ElementNode('  %div.b'), 'expected_parent': 'root'},\n            {'node': nodes.ElementNode('  %div.c'), 'expected_parent': 'root'},\n            {'node': nodes.ElementNode('    %div.d'), 'expected_parent': 'elements[1][\"node\"]'},\n            {'node': nodes.ElementNode('      %div.e'), 'expected_parent': 'elements[2][\"node\"]'},\n            {'node': nodes.ElementNode('  %div.f'), 'expected_parent': 'root'},\n        ]\n\n        for el in elements:\n            self.assertEqual(root.parent_of(el['node']), eval(el['expected_parent']))\n            root.add_node(el['node'])\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "hamlpy/test/hamlpy_test.py",
    "content": "# -*- coding: utf-8 -*-\nimport unittest\nfrom nose.tools import eq_, raises\nfrom hamlpy import hamlpy\n\nclass HamlPyTest(unittest.TestCase):\n\n    def test_applies_id_properly(self):\n        haml = '%div#someId Some text'\n        html = \"<div id='someId'>Some text</div>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        self.assertEqual(html, result.replace('\\n', ''))\n\n    def test_non_ascii_id_allowed(self):\n        haml = u'%div#これはテストです test'\n        html = u\"<div id='これはテストです'>test</div>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        self.assertEqual(html, result.replace('\\n', ''))\n\n    def test_applies_class_properly(self):\n        haml = '%div.someClass Some text'\n        html = \"<div class='someClass'>Some text</div>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        self.assertEqual(html, result.replace('\\n', ''))\n\n    def test_applies_multiple_classes_properly(self):\n        haml = '%div.someClass.anotherClass Some text'\n        html = \"<div class='someClass anotherClass'>Some text</div>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        self.assertEqual(html, result.replace('\\n', ''))\n\n    def test_dictionaries_define_attributes(self):\n        haml = \"%html{'xmlns':'http://www.w3.org/1999/xhtml', 'xml:lang':'en', 'lang':'en'}\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        self.assertTrue(\"<html\" in result)\n        self.assertTrue(\"xmlns='http://www.w3.org/1999/xhtml'\" in result)\n        self.assertTrue(\"xml:lang='en'\" in result)\n        self.assertTrue(\"lang='en'\" in result)\n        self.assertTrue(result.endswith(\"></html>\") or result.endswith(\"></html>\\n\"))\n\n    def test_dictionaries_support_arrays_for_id(self):\n        haml = \"%div{'id':('itemType', '5')}\"\n        html = \"<div id='itemType_5'></div>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        self.assertEqual(html, result.replace('\\n', ''))\n\n    def test_dictionaries_can_by_pythonic(self):\n        haml = \"%div{'id':['Article','1'], 'class':['article','entry','visible']} Booyaka\"\n        html = \"<div id='Article_1' class='article entry visible'>Booyaka</div>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        self.assertEqual(html, result.replace('\\n', ''))\n\n\n    def test_html_comments_rendered_properly(self):\n        haml = '/ some comment'\n        html = \"<!-- some comment -->\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_conditional_comments_rendered_properly(self):\n        haml = \"/[if IE]\\n  %h1 You use a shitty browser\"\n        html = \"<!--[if IE]>\\n  <h1>You use a shitty browser</h1>\\n<![endif]-->\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_single_line_conditional_comments_rendered_properly(self):\n        haml = \"/[if IE] You use a shitty browser\"\n        html = \"<!--[if IE]> You use a shitty browser<![endif]-->\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_django_variables_on_tag_render_properly(self):\n        haml = '%div= story.tease'\n        html = '<div>{{ story.tease }}</div>'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_stand_alone_django_variables_render(self):\n        haml = '= story.tease'\n        html = '{{ story.tease }}'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_stand_alone_django_tags_render(self):\n        haml = '- extends \"something.html\"'\n        html = '{% extends \"something.html\" %}'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_if_else_django_tags_render(self):\n        haml = '- if something\\n   %p hello\\n- else\\n   %p goodbye'\n        html = '{% if something %}\\n   <p>hello</p>\\n{% else %}\\n   <p>goodbye</p>\\n{% endif %}\\n'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    @raises(TypeError)\n    def test_throws_exception_when_trying_to_close_django(self):\n        haml = '- endfor'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n\n    def test_handles_dash_in_class_name_properly(self):\n        haml = '.header.span-24.last'\n        html = \"<div class='header span-24 last'></div>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_handles_multiple_attributes_in_dict(self):\n        haml = \"%div{'id': ('article', '3'), 'class': ('newest', 'urgent')} Content\"\n        html = \"<div id='article_3' class='newest urgent'>Content</div>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_are_parsed_correctly(self):\n        haml = \"={greeting} #{name}, how are you ={date}?\"\n        html = \"{{ greeting }} {{ name }}, how are you {{ date }}?\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_can_use_filter_characters(self):\n        haml = \"={value|center:\\\"15\\\"}\"\n        html = \"{{ value|center:\\\"15\\\" }}\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_in_attributes_are_parsed_correctly(self):\n        haml = \"%a{'b': '={greeting} test'} blah\"\n        html = \"<a b='{{ greeting }} test'>blah</a>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_in_attributes_work_in_id(self):\n        haml = \"%div{'id':'package_={object.id}'}\"\n        html = \"<div id='package_{{ object.id }}'></div>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_in_attributes_work_in_class(self):\n        haml = \"%div{'class':'package_={object.id}'}\"\n        html = \"<div class='package_{{ object.id }}'></div>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_in_attributes_are_escaped_correctly(self):\n        haml = \"%a{'b': '\\\\\\\\={greeting} test', title: \\\"It can't be removed\\\"} blah\"\n        html = \"<a b='={greeting} test' title='It can\\\\'t be removed'>blah</a>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_escaping_works(self):\n        haml = \"%h1 Hello, \\\\#{name}, how are you ={ date }?\"\n        html = \"<h1>Hello, #{name}, how are you {{ date }}?</h1>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_escaping_works_at_start_of_line(self):\n        haml = \"\\\\={name}, how are you?\"\n        html = \"={name}, how are you?\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_with_hash_escaping_works_at_start_of_line(self):\n        haml = \"\\\\#{name}, how are you?\"\n        html = \"#{name}, how are you?\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_work_at_start_of_line(self):\n        haml = \"={name}, how are you?\"\n        html = \"{{ name }}, how are you?\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_with_hash_work_at_start_of_line(self):\n        haml = \"#{name}, how are you?\"\n        html = \"{{ name }}, how are you?\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_inline_variables_with_special_characters_are_parsed_correctly(self):\n        haml = \"%h1 Hello, #{person.name}, how are you?\"\n        html = \"<h1>Hello, {{ person.name }}, how are you?</h1>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_plain_text(self):\n        haml = \"This should be plain text\\n    This should be indented\"\n        html = \"This should be plain text\\n    This should be indented\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_plain_text_with_indenting(self):\n        haml = \"This should be plain text\"\n        html = \"This should be plain text\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_escaped_haml(self):\n        haml = \"\\\\= Escaped\"\n        html = \"= Escaped\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_utf8_with_regular_text(self):\n        haml = u\"%a{'href':'', 'title':'링크(Korean)'} Some Link\"\n        html = u\"<a href='' title='\\ub9c1\\ud06c(Korean)'>Some Link</a>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_python_filter(self):\n        haml = \":python\\n   for i in range(0, 5): print \\\"<p>item \\%s</p>\\\" % i\"\n        html = '<p>item \\\\0</p>\\n<p>item \\\\1</p>\\n<p>item \\\\2</p>\\n<p>item \\\\3</p>\\n<p>item \\\\4</p>\\n'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_doctype_html5(self):\n        haml = '!!! 5'\n        html = '<!DOCTYPE html>'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_doctype_xhtml(self):\n        haml = '!!!'\n        html = '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">'\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_doctype_xml_utf8(self):\n        haml = '!!! XML'\n        html = \"<?xml version='1.0' encoding='utf-8' ?>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_doctype_xml_encoding(self):\n        haml = '!!! XML iso-8859-1'\n        html = \"<?xml version='1.0' encoding='iso-8859-1' ?>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.replace('\\n', ''))\n\n    def test_plain_filter_with_indentation(self):\n        haml = \":plain\\n    -This should be plain text\\n    .This should be more\\n      This should be indented\"\n        html = \"-This should be plain text\\n.This should be more\\n  This should be indented\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_plain_filter_with_no_children(self):\n        haml = \":plain\\nNothing\"\n        html = \"Nothing\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_filters_render_escaped_backslash(self):\n        haml = \":plain\\n  \\\\Something\"\n        html = \"\\\\Something\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_xml_namespaces(self):\n        haml = \"%fb:tag\\n  content\"\n        html = \"<fb:tag>\\n  content\\n</fb:tag>\\n\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result)\n\n    def test_attr_wrapper(self):\n        haml = \"\"\"\n%html{'xmlns':'http://www.w3.org/1999/xhtml', 'xml:lang':'en', 'lang':'en'}\n  %body#main\n    %div.wrap\n      %a{:href => '/'}\n:javascript\"\"\"\n        hamlParser = hamlpy.Compiler(options_dict={'attr_wrapper': '\"'})\n        result = hamlParser.process(haml)\n        self.assertEqual(result,\n                         '''<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n  <body id=\"main\">\n    <div class=\"wrap\">\n      <a href=\"/\"></a>\n    </div>\n  </body>\n</html>\n<script type=\"text/javascript\">\n// <![CDATA[\n// ]]>\n</script>\n''')\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "hamlpy/test/loader_test.py",
    "content": "import unittest\nimport sys\n\ntry:\n  from django.conf import settings\n\n  settings.configure(DEBUG=True, TEMPLATE_DEBUG=True)\nexcept ImportError, e:\n  pass\n\nfrom hamlpy.template.loaders import get_haml_loader, TemplateDoesNotExist\n\nclass DummyLoader(object):\n    \"\"\"\n    A dummy template loader that only loads templates from self.templates\n    \"\"\"\n    templates = {\n        \"in_dict.txt\" : \"in_dict content\",\n        \"loader_test.hamlpy\" : \"loader_test content\",\n    }\n    def __init__(self, *args, **kwargs):\n        self.Loader = self.__class__\n    \n    def load_template_source(self, template_name, *args, **kwargs):\n        try:\n            return (self.templates[template_name], \"test:%s\" % template_name)\n        except KeyError:\n            raise TemplateDoesNotExist(template_name)\n\nclass LoaderTest(unittest.TestCase):\n    \"\"\"\n    Tests for the django template loader.\n    \n    A dummy template loader is used that loads only from a dictionary of templates.\n    \"\"\"\n    \n    def setUp(self): \n        dummy_loader = DummyLoader()\n        \n        hamlpy_loader_class = get_haml_loader(dummy_loader)\n        self.hamlpy_loader = hamlpy_loader_class()\n    \n    def _test_assert_exception(self, template_name):\n        try:\n            self.hamlpy_loader.load_template_source(template_name)\n        except TemplateDoesNotExist:\n            self.assertTrue(True)\n        else:\n            self.assertTrue(False, '\\'%s\\' should not be loaded by the hamlpy tempalte loader.' % template_name)\n    \n    def test_file_not_in_dict(self):\n        # not_in_dict.txt doesn't exit, so we're expecting an exception\n        self._test_assert_exception('not_in_dict.hamlpy')\n    \n    def test_file_in_dict(self):\n        # in_dict.txt in in dict, but with an extension not supported by\n        # the loader, so we expect an exception\n        self._test_assert_exception('in_dict.txt')\n    \n    def test_file_should_load(self):\n        # loader_test.hamlpy is in the dict, so it should load fine\n        try:\n            self.hamlpy_loader.load_template_source('loader_test.hamlpy')\n        except TemplateDoesNotExist:\n            self.assertTrue(False, '\\'loader_test.hamlpy\\' should be loaded by the hamlpy tempalte loader, but it was not.')\n        else:\n            self.assertTrue(True)\n    \n    def test_file_different_extension(self):\n        # loader_test.hamlpy is in dict, but we're going to try\n        # to load loader_test.txt\n        # we expect an exception since the extension is not supported by\n        # the loader\n        self._test_assert_exception('loader_test.txt')\n"
  },
  {
    "path": "hamlpy/test/node_factory_test.py",
    "content": "from hamlpy import nodes\n\nclass TestNodeFactory():\n    \n    def test_creates_element_node_with_percent(self):\n        node = nodes.create_node('%div')\n        assert isinstance(node, nodes.ElementNode)\n        \n        node = nodes.create_node('   %html')\n        assert isinstance(node, nodes.ElementNode)\n        \n    def test_creates_element_node_with_dot(self):\n        node = nodes.create_node('.className')\n        assert isinstance(node, nodes.ElementNode)\n        \n        node = nodes.create_node('   .className')\n        assert isinstance(node, nodes.ElementNode)\n        \n    def test_creates_element_node_with_hash(self):\n        node = nodes.create_node('#idName')\n        assert isinstance(node, nodes.ElementNode)\n        \n        node = nodes.create_node('   #idName')\n        assert isinstance(node, nodes.ElementNode)\n    \n    def test_creates_html_comment_node_with_front_slash(self):\n        node = nodes.create_node('/ some Comment')\n        assert isinstance(node, nodes.CommentNode)\n\n        node = nodes.create_node('     / some Comment')\n        assert isinstance(node, nodes.CommentNode)\n        \n    def test_random_text_returns_haml_node(self):\n        node = nodes.create_node('just some random text')\n        assert isinstance(node, nodes.HamlNode)\n        \n        node = nodes.create_node('   more random text')\n        assert isinstance(node, nodes.HamlNode)\n    \n    def test_correct_symbol_creates_haml_comment(self):\n        node = nodes.create_node('-# This is a haml comment')\n        assert isinstance(node, nodes.HamlCommentNode)\n        \n    def test_equals_symbol_creates_variable_node(self):\n        node = nodes.create_node('= some.variable')\n        assert isinstance(node, nodes.VariableNode)\n    \n    def test_dash_symbol_creates_tag_node(self):\n        node = nodes.create_node('- for something in somethings')\n        assert isinstance(node, nodes.TagNode)\n    \n    def test_backslash_symbol_creates_tag_node(self):\n        node = nodes.create_node('\\\\= some.variable')\n        assert isinstance(node, nodes.HamlNode)\n        \n        node = nodes.create_node('    \\\\= some.variable')\n        assert isinstance(node, nodes.HamlNode)\n    \n    def test_python_creates_python_node(self):\n        node = nodes.create_node(':python')\n        assert isinstance(node, nodes.PythonFilterNode)\n    \n    def test_slash_with_if_creates_a_conditional_comment_node(self):\n        node = nodes.create_node('/[if IE 5]')\n        assert isinstance(node, nodes.ConditionalCommentNode)\n        \n"
  },
  {
    "path": "hamlpy/test/regression.py",
    "content": "# -*- coding: utf-8 -*-\nimport unittest\nfrom nose.tools import eq_, raises\nfrom hamlpy import hamlpy\n\nclass RegressionTest(unittest.TestCase):\n    # Regression test for Github Issue 92\n    def test_haml_comment_nodes_dont_post_render_children(self):\n        haml = '''\n        -# My comment\n            #my_div\n                my text\n        test\n        '''\n        html = \"test\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.strip())\n        \n    def test_whitespace_after_attribute_key(self):\n        haml = '%form{id : \"myform\"}'\n        html = \"<form id='myform'></form>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.strip())\n    \n    def test_for_newline_after_conditional_comment(self):\n        haml = '/[if lte IE 7]\\n\\ttest\\n#test'\n        html = \"<!--[if lte IE 7]>\\n\\ttest\\n<![endif]-->\\n<div id='test'></div>\"\n        hamlParser = hamlpy.Compiler()\n        result = hamlParser.process(haml)\n        eq_(html, result.strip())\n"
  },
  {
    "path": "hamlpy/test/template_compare_test.py",
    "content": "import codecs\nimport unittest\nfrom nose.tools import eq_\nfrom hamlpy import hamlpy\n\nclass TestTemplateCompare(unittest.TestCase):\n\n    def test_nuke_inner_whitespace(self):\n        self._compare_test_files('nukeInnerWhiteSpace')\n\n    def test_nuke_outer_whitespace(self):\n        self._compare_test_files('nukeOuterWhiteSpace')\n\n    def test_comparing_simple_templates(self):\n        self._compare_test_files('simple')\n        \n    def test_mixed_id_and_classes_using_dictionary(self):\n        self._compare_test_files('classIdMixtures')\n    \n    def test_self_closing_tags_close(self):\n        self._compare_test_files('selfClosingTags')\n        \n    def test_nested_html_comments(self):\n        self._compare_test_files('nestedComments')\n        \n    def test_haml_comments(self):\n        self._compare_test_files('hamlComments')\n        \n    def test_implicit_divs(self):\n        self._compare_test_files('implicitDivs')\n        \n    def test_django_combination_of_tags(self):\n        self._compare_test_files('djangoCombo')\n        \n    def test_self_closing_django(self):\n        self._compare_test_files('selfClosingDjango')\n        \n    def test_nested_django_tags(self):\n        self._compare_test_files('nestedDjangoTags')\n        \n    def test_filters(self):\n        self._compare_test_files('filters')\n    \n    def test_filters_markdown(self):\n        try:\n            import markdown\n            self._compare_test_files('filtersMarkdown')\n        except ImportError:\n            pass\n\n    def test_filters_pygments(self):\n        try:\n            import pygments\n            if pygments.__version__ == '1.6':\n                self._compare_test_files('filtersPygments16')\n            else:\n                self._compare_test_files('filtersPygments')\n        except ImportError:\n            pass\n\n    def test_nested_if_else_blocks(self):\n        self._compare_test_files('nestedIfElseBlocks')\n\n    def test_all_if_types(self):\n        self._compare_test_files('allIfTypesTest')\n\n    def test_multi_line_dict(self):\n        self._compare_test_files('multiLineDict')\n\n    def test_filter_multiline_ignore(self):\n        self._compare_test_files('filterMultilineIgnore')\n\n    def test_whitespace_preservation(self):\n        self._compare_test_files('whitespacePreservation')\n\n    def _print_diff(self, s1, s2):\n        if len(s1) > len(s2):\n            shorter = s2\n        else:\n            shorter = s1\n\n        line = 1\n        col = 1\n        \n        for i, _ in enumerate(shorter):\n            if len(shorter) <= i + 1:\n                print 'Ran out of characters to compare!'\n                print 'Actual len=%d' % len(s1)\n                print 'Expected len=%d' % len(s2)\n                break\n            if s1[i] != s2[i]:\n                print 'Difference begins at line', line, 'column', col\n                actual_line = s1.splitlines()[line - 1]\n                expected_line = s2.splitlines()[line - 1]\n                print 'HTML (actual, len=%2d)   : %s' % (len(actual_line), actual_line)\n                print 'HTML (expected, len=%2d) : %s' % (len(expected_line), expected_line)\n                print 'Character code (actual)  : %d (%s)' % (ord(s1[i]), s1[i])\n                print 'Character code (expected): %d (%s)' % (ord(s2[i]), s2[i])\n                break\n\n            if shorter[i] == '\\n':\n                line += 1\n                col = 1\n            else:\n                col += 1\n        else:\n            print \"No Difference Found\"\n\n    def _compare_test_files(self, name):\n        haml_lines = codecs.open('templates/' + name + '.hamlpy', encoding = 'utf-8').readlines()\n        html = open('templates/' + name + '.html').read()\n        \n        haml_compiler = hamlpy.Compiler()\n        parsed = haml_compiler.process_lines(haml_lines)\n\n        # Ignore line ending differences\n        parsed = parsed.replace('\\r', '')\n        html = html.replace('\\r', '')\n        \n        if parsed != html:\n            print '\\nHTML (actual): '\n            print '\\n'.join([\"%d. %s\" % (i + 1, l) for i, l in enumerate(parsed.split('\\n')) ])\n            self._print_diff(parsed, html)\n        eq_(parsed, html)\n        \nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "hamlpy/test/templates/allIfTypesTest.hamlpy",
    "content": "- if something\n  Cool\n- ifchanged something\n  Changed\n- ifequal something \"booya\"\n  Equal\n- ifnotequal something \"blamo\"\n  No Equal\n- ifchanged something\n  Changed\n- else\n  No Changed\n- ifequal something \"booya\"\n  Equal\n- else\n  No Equal\n- ifnotequal something \"blamo\"\n  No Equal\n- else\n  Equal"
  },
  {
    "path": "hamlpy/test/templates/allIfTypesTest.html",
    "content": "{% if something %}\n  Cool\n{% endif %}\n{% ifchanged something %}\n  Changed\n{% endifchanged %}\n{% ifequal something \"booya\" %}\n  Equal\n{% endifequal %}\n{% ifnotequal something \"blamo\" %}\n  No Equal\n{% endifnotequal %}\n{% ifchanged something %}\n  Changed\n{% else %}\n  No Changed\n{% endifchanged %}\n{% ifequal something \"booya\" %}\n  Equal\n{% else %}\n  No Equal\n{% endifequal %}\n{% ifnotequal something \"blamo\" %}\n  No Equal\n{% else %}\n  Equal\n{% endifnotequal %}\n"
  },
  {
    "path": "hamlpy/test/templates/classIdMixtures.hamlpy",
    "content": "%div#Article.article.entry{'id':'123', 'class':'true'}\n  Now this is interesting\n"
  },
  {
    "path": "hamlpy/test/templates/classIdMixtures.html",
    "content": "<div id='Article_123' class='article entry true'>\n  Now this is interesting\n</div>\n"
  },
  {
    "path": "hamlpy/test/templates/djangoCombo.hamlpy",
    "content": "- extends \"base_generic.html\"\n\n- block title\n  = section.title\n\n- block content\n  %h1= section.title\n\n  - for story in story_list\n    %h2\n      %a{'href':'{{ story.get_absolute_url }}'}\n        = story.headline|upper\n    %p= story.tease|truncatewords:\"100\"\n"
  },
  {
    "path": "hamlpy/test/templates/djangoCombo.html",
    "content": "{% extends \"base_generic.html\" %}\n\n{% block title %}\n  {{ section.title }}\n\n{% endblock %}\n{% block content %}\n  <h1>{{ section.title }}</h1>\n\n  {% for story in story_list %}\n    <h2>\n      <a href='{{ story.get_absolute_url }}'>\n        {{ story.headline|upper }}\n      </a>\n    </h2>\n    <p>{{ story.tease|truncatewords:\"100\" }}</p>\n  {% endfor %}\n{% endblock %}\n"
  },
  {
    "path": "hamlpy/test/templates/filterMultilineIgnore.hamlpy",
    "content": ".multilinetest1{id:'{{myId}}',\n\talt: \"{{nothing}}\"}\n:plain\n\tThese { { braces\n\n\tshould } not be interpreted as a multiline string\n\n:css\n\t.test {\n\t\tdisplay: inline;\n\t}\n:javascript\n\tThese {\n\tBraces should {\n\t\talso\n\t} be { ignored\n\t\t\n.multilinetest2{id:'{{myId}}',\n\tclass:'{{myClass}}',\n\talt: \"\"}\n/ The following is from hjonathan, issue #67\n%head\n  .blah\n    :javascript\n      $(document).ready(function(){\n        $(\"#form{{form.initial.id}}\").submit(form_submit);\n        //Double nesting\n        $(function() {\n            blahblahblah\n        });\n        \n        // Javascript comment\n      });\n  :javascript\n    $(document).ready(function(){\n      $(\"#form{{form.initial.id}}\").submit(form_submit);\n      // Javascript comment\n    });\n  :css\n    .someClass {\n      width: 100px;\n    }\n  :cdata\n    if (a < b && a < 0)\n    {\n      return 1;\n    }\n-# Regression from Culebron (Github issue #90)\n:javascript\n        (\n            {\n                a\n            }\n        );\n:javascript\n\n            {\n                a\n            }\n        )"
  },
  {
    "path": "hamlpy/test/templates/filterMultilineIgnore.html",
    "content": "<div id='{{myId}}' class='multilinetest1' alt='{{nothing}}'></div>\nThese { { braces\n\nshould } not be interpreted as a multiline string\n\n<style type='text/css'>\n/*<![CDATA[*/\n\t.test {\n\t\tdisplay: inline;\n\t}\n/*]]>*/\n</style>\n<script type='text/javascript'>\n// <![CDATA[\n\tThese {\n\tBraces should {\n\t\talso\n\t} be { ignored\n\n// ]]>\n</script>\n<div id='{{myId}}' class='multilinetest2 {{myClass}}' alt=''></div>\n<!-- The following is from hjonathan, issue #67 -->\n<head>\n  <div class='blah'>\n<script type='text/javascript'>\n// <![CDATA[\n      $(document).ready(function(){\n        $(\"#form{{form.initial.id}}\").submit(form_submit);\n        //Double nesting\n        $(function() {\n            blahblahblah\n        });\n\n        // Javascript comment\n      });\n// ]]>\n</script>\n  </div>\n<script type='text/javascript'>\n// <![CDATA[\n    $(document).ready(function(){\n      $(\"#form{{form.initial.id}}\").submit(form_submit);\n      // Javascript comment\n    });\n// ]]>\n</script>\n<style type='text/css'>\n/*<![CDATA[*/\n    .someClass {\n      width: 100px;\n    }\n/*]]>*/\n</style>\n  <![CDATA[\n    if (a < b && a < 0)\n    {\n      return 1;\n    }\n  ]]>\n</head>\n<script type='text/javascript'>\n// <![CDATA[\n        (\n            {\n                a\n            }\n        );\n// ]]>\n</script>\n<script type='text/javascript'>\n// <![CDATA[\n\n            {\n                a\n            }\n        )\n// ]]>\n</script>\n"
  },
  {
    "path": "hamlpy/test/templates/filters.hamlpy",
    "content": ":javascript\n  $(document).ready(function(){\n    $(\"#form{{form.initial.id}}\").submit(form_submit);\n    // Javascript comment\n  });\n:css\n  .someClass {\n    width: 100px;\n  }\n:cdata\n  if (a < b && a < 0)\n  {\n    return 1;\n  }\n:python\n  a=1\n  for i in range(5):\n    print a+i\n"
  },
  {
    "path": "hamlpy/test/templates/filters.html",
    "content": "<script type='text/javascript'>\n// <![CDATA[\n  $(document).ready(function(){\n    $(\"#form{{form.initial.id}}\").submit(form_submit);\n    // Javascript comment\n  });\n// ]]>\n</script>\n<style type='text/css'>\n/*<![CDATA[*/\n  .someClass {\n    width: 100px;\n  }\n/*]]>*/\n</style>\n<![CDATA[\n  if (a < b && a < 0)\n  {\n    return 1;\n  }\n]]>\n1\n2\n3\n4\n5\n"
  },
  {
    "path": "hamlpy/test/templates/filtersMarkdown.hamlpy",
    "content": ":markdown\n  hello\n  no paragraph\n\n  line break  \n  follow\n\n  New paragraph\n\n      code block\n"
  },
  {
    "path": "hamlpy/test/templates/filtersMarkdown.html",
    "content": "<p>hello\nno paragraph</p>\n<p>line break<br />\nfollow</p>\n<p>New paragraph</p>\n<pre><code>code block\n</code></pre>"
  },
  {
    "path": "hamlpy/test/templates/filtersPygments.hamlpy",
    "content": ":highlight\n    print \"hi\"\n\n    if x:\n        print \"y\":\n    else:\n        print \"z\":\n"
  },
  {
    "path": "hamlpy/test/templates/filtersPygments.html",
    "content": "\n<div class=\"highlight\"><pre><span class=\"n\">print</span> &quot;<span class=\"n\">hi</span>&quot;\n\n<span class=\"k\">if</span> <span class=\"n\">x</span><span class=\"p\">:</span>\n    <span class=\"n\">print</span> &quot;<span class=\"n\">y</span>&quot;<span class=\"p\">:</span>\n<span class=\"k\">else</span><span class=\"p\">:</span>\n    <span class=\"n\">print</span> &quot;<span class=\"n\">z</span>&quot;<span class=\"p\">:</span>\n</pre></div>\n"
  },
  {
    "path": "hamlpy/test/templates/filtersPygments16.hamlpy",
    "content": ":highlight\n    print \"hi\"\n\n    if x:\n        print \"y\":\n    else:\n        print \"z\":\n"
  },
  {
    "path": "hamlpy/test/templates/filtersPygments16.html",
    "content": "\n<div class=\"highlight\"><pre><span class=\"n\">print</span> <span class=\"s\">&quot;hi&quot;</span>\n\n<span class=\"k\">if</span> <span class=\"n\">x</span><span class=\"o\">:</span>\n    <span class=\"n\">print</span> <span class=\"s\">&quot;y&quot;</span><span class=\"o\">:</span>\n<span class=\"nl\">else:</span>\n    <span class=\"n\">print</span> <span class=\"s\">&quot;z&quot;</span><span class=\"o\">:</span>\n</pre></div>\n"
  },
  {
    "path": "hamlpy/test/templates/hamlComments.hamlpy",
    "content": "%div\n  %div\n    -# These comments won't show up\n    This will\n    -#\n      None of this\n      Inside of here will show \n      up.\n        Yikes!\n  %div More\n%div Hello\n"
  },
  {
    "path": "hamlpy/test/templates/hamlComments.html",
    "content": "<div>\n  <div>\n    This will\n  </div>\n  <div>More</div>\n</div>\n<div>Hello</div>\n"
  },
  {
    "path": "hamlpy/test/templates/implicitDivs.hamlpy",
    "content": ".articles\n  #article_1\n    .title.bold So happy\n    #content_1.content\n      Finally, I can use HAML again!"
  },
  {
    "path": "hamlpy/test/templates/implicitDivs.html",
    "content": "<div class='articles'>\n  <div id='article_1'>\n    <div class='title bold'>So happy</div>\n    <div id='content_1' class='content'>\n      Finally, I can use HAML again!\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "hamlpy/test/templates/multiLineDict.hamlpy",
    "content": "%div{'class': 'row'}\n  %img{'src': '/static/imgs/ibl_logo{{id}}.gif', \n       'alt': 'IBL Logo'}\n  %br\n  %img{'src': '/static/imgs/ibl_logo.gif', \n       'alt': 'IBL Logo{{id}}'}"
  },
  {
    "path": "hamlpy/test/templates/multiLineDict.html",
    "content": "<div class='row'>\n  <img src='/static/imgs/ibl_logo{{id}}.gif' alt='IBL Logo' />\n  <br />\n  <img src='/static/imgs/ibl_logo.gif' alt='IBL Logo{{id}}' />\n</div>\n"
  },
  {
    "path": "hamlpy/test/templates/nestedComments.hamlpy",
    "content": "/\n  %div.someClass\n    %div\n      None of this matters"
  },
  {
    "path": "hamlpy/test/templates/nestedComments.html",
    "content": "<!-- \n  <div class='someClass'>\n    <div>\n      None of this matters\n    </div>\n  </div>\n-->\n"
  },
  {
    "path": "hamlpy/test/templates/nestedDjangoTags.hamlpy",
    "content": "%ul\n  - for story in story_list\n    %li= story.text\n    - if story.author_list\n      - for author in story.author_list\n        .author= author\n    - else\n      .author Anonymous\n  - empty\n    .error No stories found"
  },
  {
    "path": "hamlpy/test/templates/nestedDjangoTags.html",
    "content": "<ul>\n  {% for story in story_list %}\n    <li>{{ story.text }}</li>\n    {% if story.author_list %}\n      {% for author in story.author_list %}\n        <div class='author'>{{ author }}</div>\n      {% endfor %}\n    {% else %}\n      <div class='author'>Anonymous</div>\n    {% endif %}\n  {% empty %}\n    <div class='error'>No stories found</div>\n  {% endfor %}\n</ul>\n"
  },
  {
    "path": "hamlpy/test/templates/nestedIfElseBlocks.hamlpy",
    "content": "- if condition\n  - if condition\n  - else\n- else"
  },
  {
    "path": "hamlpy/test/templates/nestedIfElseBlocks.html",
    "content": "{% if condition %}\n  {% if condition %}\n  {% else %}\n  {% endif %}\n{% else %}\n{% endif %}\n"
  },
  {
    "path": "hamlpy/test/templates/nukeInnerWhiteSpace.hamlpy",
    "content": "%p<  Foo\n%p<\n  - if something\n    %q\n      Foo\n%p<\n  = Foo\n%p\n  %q< Foo\n%p\n  %q{a: \"2\"}< Foo\n%p\n  %q<= FooBar\n%p\n  %q<\n    Foo\n    Bar\n%p\n  %q{a: \"2\"}<\n    Foo\n    Bar\n%p\n  %q<\n    %div\n      Foo\n      Bar\n%p\n  %q{a: \"2\"}<\n    %div\n      Foo\n      Bar\n\n-# Regression test\n%p\n  %q<= foo\n  %q{a: \"2\"}<\n    bar\n  %q{a: \"2\"}\n    bar\n-# Filters\n%p<\n    :plain\n      test1\n      test2\n%p<\n    :plain\n      blah\n        test3\n        test4\n%p<\n    :plain\n      test5\n      test6\n    :plain\n      test7\n    :plain\n      test8\n      test9"
  },
  {
    "path": "hamlpy/test/templates/nukeInnerWhiteSpace.html",
    "content": "<p>Foo</p>\n<p>{% if something %}\n    <q>\n      Foo\n    </q>\n  {% endif %}</p>\n<p>{{ Foo }}</p>\n<p>\n  <q>Foo</q>\n</p>\n<p>\n  <q a='2'>Foo</q>\n</p>\n<p>\n  <q>{{ FooBar }}</q>\n</p>\n<p>\n  <q>Foo\n    Bar</q>\n</p>\n<p>\n  <q a='2'>Foo\n    Bar</q>\n</p>\n<p>\n  <q><div>\n      Foo\n      Bar\n    </div></q>\n</p>\n<p>\n  <q a='2'><div>\n      Foo\n      Bar\n\n    </div></q>\n</p>\n<p>\n  <q>{{ foo }}</q>\n  <q a='2'>bar</q>\n  <q a='2'>\n    bar\n  </q>\n</p>\n<p>test1\ntest2</p>\n<p>blah\n  test3\n  test4</p>\n<p>test5\ntest6\ntest7\ntest8\ntest9</p>\n"
  },
  {
    "path": "hamlpy/test/templates/nukeOuterWhiteSpace.hamlpy",
    "content": "%ul#display-inline-block-example\n  %li Item one\n  %li> Item two\n  %li Item three\n%p\n  - if something\n    %q>\n      Foo\n%p\n  - sometag\n  %q>\n    Foo\n%p\n  /[test]\n    %q>\n      Foo\n%p\n  :javascript\n    test\n  %q>\n    blah\n-# Tests from Ruby HAML\n%p\n  %p\n    %q>\n      Foo\n%p\n  %p\n    %q{a: '2'}>\n      Foo\n%p\n  %p\n    %q> Foo\n%p\n  %p\n    %q{a: \"2\"}> Foo\n%p\n  %p\n    %q>\n      = Foo\n%p\n  %p\n    %q{a: \"2\"}>\n      = Foo\n%p\n  %p\n    %q>= Foo\n%p\n  %p\n    %q{a: \"2\"}>= Foo\n%p\n  %p\n    foo\n    %q>\n      Foo\n    bar\n%p\n  %p\n    foo\n    %q{a: 2}>\n      Foo\n    bar\n%p\n  %p\n    foo\n    %q> Foo\n    bar\n%p\n  %p\n    foo\n    %q{a: \"2\"}> Foo\n    bar\n%p\n  %p\n    foo\n    %q>\n      = Foo\n    bar\n%p\n  %p\n    foo\n    %q{a: \"2\"}>\n      = Foo\n    bar\n%p\n  %p\n    foo\n    %q>= Foo\n    bar\n%p\n  %p\n    foo\n    %q{a: \"2\"}>= Foo\n    bar\n%p\n  %p\n    foo\n    %q>\n      = FooBar\n    bar\n%p\n  %p\n    foo\n    %q{a: \"2\"}>\n      = FooBar\n    bar\n%p\n  %p\n    foo\n    %q>= FooBar\n    bar\n%p\n  %p\n    foo\n    %q{a: \"2\"}>= FooBar\n    bar\n%p\n  %p\n    %q>\n%p\n  %p\n    %q>/\n%p\n  %p\n    %q{a: \"2\"}>\n%p\n  %p\n    %q{a: \"2\"}>/"
  },
  {
    "path": "hamlpy/test/templates/nukeOuterWhiteSpace.html",
    "content": "<ul id='display-inline-block-example'>\n  <li>Item one</li><li>Item two</li><li>Item three</li>\n</ul>\n<p>\n  {% if something %}<q>\n      Foo\n    </q>{% endif %}\n</p>\n<p>\n  {% sometag %}<q>\n    Foo\n  </q></p>\n<p>\n<!--[test]><q>\n      Foo\n    </q><![endif]-->\n</p>\n<p>\n<script type='text/javascript'>\n// <![CDATA[\n    test\n// ]]>\n</script><q>\n    blah\n  </q></p>\n<p>\n  <p><q>\n      Foo\n    </q></p>\n</p>\n<p>\n  <p><q a='2'>\n      Foo\n    </q></p>\n</p>\n<p>\n  <p><q>Foo</q></p>\n</p>\n<p>\n  <p><q a='2'>Foo</q></p>\n</p>\n<p>\n  <p><q>\n      {{ Foo }}\n    </q></p>\n</p>\n<p>\n  <p><q a='2'>\n      {{ Foo }}\n    </q></p>\n</p>\n<p>\n  <p><q>{{ Foo }}</q></p>\n</p>\n<p>\n  <p><q a='2'>{{ Foo }}</q></p>\n</p>\n<p>\n  <p>\n    foo<q>\n      Foo\n    </q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q a='2'>\n      Foo\n    </q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q>Foo</q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q a='2'>Foo</q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q>\n      {{ Foo }}\n    </q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q a='2'>\n      {{ Foo }}\n    </q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q>{{ Foo }}</q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q a='2'>{{ Foo }}</q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q>\n      {{ FooBar }}\n    </q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q a='2'>\n      {{ FooBar }}\n    </q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q>{{ FooBar }}</q>bar\n  </p>\n</p>\n<p>\n  <p>\n    foo<q a='2'>{{ FooBar }}</q>bar\n  </p>\n</p>\n<p>\n  <p><q></q></p>\n</p>\n<p>\n  <p><q /></p>\n</p>\n<p>\n  <p><q a='2'></q></p>\n</p>\n<p>\n  <p><q a='2' /></p>\n</p>\n"
  },
  {
    "path": "hamlpy/test/templates/selfClosingDjango.hamlpy",
    "content": "%ul\n  - for story in story_list\n    %li= story.text\n- blocktrans with object.duration_as_time as dur\n  %span.jtimer.bigger {{ dur }}\n  remain\n"
  },
  {
    "path": "hamlpy/test/templates/selfClosingDjango.html",
    "content": "<ul>\n  {% for story in story_list %}\n    <li>{{ story.text }}</li>\n  {% endfor %}\n</ul>\n{% blocktrans with object.duration_as_time as dur %}\n  <span class='jtimer bigger'>{{ dur }}</span>\n  remain\n{% endblocktrans %}\n"
  },
  {
    "path": "hamlpy/test/templates/selfClosingTags.hamlpy",
    "content": "%div/\n%br/\n%br\n%meta{'content':'text/html'}\n%img\n%link\n%br\n%hr\n"
  },
  {
    "path": "hamlpy/test/templates/selfClosingTags.html",
    "content": "<div />\n<br />\n<br />\n<meta content='text/html' />\n<img />\n<link />\n<br />\n<hr />\n"
  },
  {
    "path": "hamlpy/test/templates/simple.hamlpy",
    "content": "%div \n  %div.someClass \n    Here we go\n    And more\n%div More\n"
  },
  {
    "path": "hamlpy/test/templates/simple.html",
    "content": "<div>\n  <div class='someClass'>\n    Here we go\n    And more\n  </div>\n</div>\n<div>More</div>\n"
  },
  {
    "path": "hamlpy/test/templates/whitespacePreservation.hamlpy",
    "content": "-# Test plaintext/elements\n%pre\n\n\n\t%div{class:'something'}\n\t\n\t\n\t\tSome text\n\t\t\n\t\tSome other text\n\t\t\n\t\t\n\t\tSome more text\n\n\n-# Test self-closing tag\n%input{type:'text'}\n\n\n-# Test inline element\n%div{class:'something'}= var\n\n\n-# Test Django tag\n- if something\n\t\n\tTest 1\n\t\n\t%div\n\t\n\t\n\t\tTest 2\n\n\n-# Test filters\n:plain\n\t\n\tSome text\n\tSome plain text\n\t\n\tSome more text\n\t\n\t\n\tOne more text\n\t\n:css\n\t\t\n\tSome text\n\tSome plain text\n\t\n\tSome more text\n\t\n\t\n\tOne more text\n\t\n:stylus\n\t\t\n\tSome text\n\tSome plain text\n\t\n\tSome more text\n\t\n\t\n\tOne more text\n\n:cdata\n\t\t\n\tSome text\n\tSome plain text\n\t\n\tSome more text\n\t\n\t\n\tOne more text\n\t\n:coffee\n\t\n\tSome text\n\tSome plain text\n\t\n\tSome more text\n\t\n\t\n\tOne more text\n\n:javascript\n\t\t\n\tSome text\n\tSome plain text\n\t\n\tSome more text\n\t\n\t\n\tOne more text\n\n-# Test inner whitespace removal\n\n%div<\n\t\n\tTest\n\t\n\tasd\n\n-# Test outer whitespace removal\n\t\n%p\n\n\t%li Item one\n\t\n\t%li> Item two\n\t\n\t%li Item three\n\t\n%p\n\n\t%li>\n\t\tItem one\n\n%p\n\n\t%li> Item one\n\t\n\t\n\t%li Item two\n\t\n\t%li Item three\n\n%input\n%input>\n%input"
  },
  {
    "path": "hamlpy/test/templates/whitespacePreservation.html",
    "content": "<pre>\n\n\n\t<div class='something'>\n\n\n\t\tSome text\n\n\t\tSome other text\n\n\n\t\tSome more text\n\n\n\t</div>\n</pre>\n<input type='text' />\n\n\n<div class='something'>{{ var }}</div>\n\n\n{% if something %}\n\n\tTest 1\n\n\t<div>\n\n\n\t\tTest 2\n\n\n\t</div>\n{% endif %}\n\nSome text\nSome plain text\n\nSome more text\n\n\nOne more text\n\n<style type='text/css'>\n/*<![CDATA[*/\n\n\tSome text\n\tSome plain text\n\n\tSome more text\n\n\n\tOne more text\n\n/*]]>*/\n</style>\n<style type='text/stylus'>\n/*<![CDATA[*/\n\nSome text\nSome plain text\n\nSome more text\n\n\nOne more text\n\n/*]]>*/\n</style>\n<![CDATA[\n\n\tSome text\n\tSome plain text\n\n\tSome more text\n\n\n\tOne more text\n\n]]>\n<script type='text/coffeescript'>\n#<![CDATA[\n\n\tSome text\n\tSome plain text\n\n\tSome more text\n\n\n\tOne more text\n\n#]]>\n</script>\n<script type='text/javascript'>\n// <![CDATA[\n\n\tSome text\n\tSome plain text\n\n\tSome more text\n\n\n\tOne more text\n\n// ]]>\n</script>\n\n<div>Test\n\n\tasd</div>\n\n<p>\n\n\t<li>Item one</li><li>Item two</li><li>Item three</li>\n\n</p>\n<p><li>\n\t\tItem one\n\n\t</li></p>\n<p><li>Item one</li><li>Item two</li>\n\n\t<li>Item three</li>\n\n</p>\n<input /><input /><input />\n"
  },
  {
    "path": "hamlpy/test/test_elements.py",
    "content": "from nose.tools import eq_\n\nfrom hamlpy.elements import Element\n\nclass TestElement(object):\n\n        def test_attribute_value_not_quoted_when_looks_like_key(self):\n            sut = Element('')\n            s1 = sut._parse_attribute_dictionary('''{name:\"viewport\", content:\"width:device-width, initial-scale:1, minimum-scale:1, maximum-scale:1\"}''')\n            eq_(s1['content'], 'width:device-width, initial-scale:1, minimum-scale:1, maximum-scale:1')\n            eq_(s1['name'], 'viewport')\n\n            sut = Element('')\n            s1 = sut._parse_attribute_dictionary('''{style:\"a:x, b:'y', c:1, e:3\"}''')\n            eq_(s1['style'], \"a:x, b:'y', c:1, e:3\")\n\n            sut = Element('')\n            s1 = sut._parse_attribute_dictionary('''{style:\"a:x, b:'y', c:1, d:\\\\\"dk\\\\\", e:3\"}''')\n            eq_(s1['style'], '''a:x, b:'y', c:1, d:\"dk\", e:3''')\n\n            sut = Element('')\n            s1 = sut._parse_attribute_dictionary('''{style:'a:x, b:\\\\'y\\\\', c:1, d:\"dk\", e:3'}''')\n            eq_(s1['style'], '''a:x, b:'y', c:1, d:\"dk\", e:3''')\n\n        def test_dashes_work_in_attribute_quotes(self):\n            sut = Element('')\n            s1 = sut._parse_attribute_dictionary('''{\"data-url\":\"something\", \"class\":\"blah\"}''')\n            eq_(s1['data-url'],'something')\n            eq_(s1['class'], 'blah')\n\n            s1 = sut._parse_attribute_dictionary('''{data-url:\"something\", class:\"blah\"}''')\n            eq_(s1['data-url'],'something')\n            eq_(s1['class'], 'blah')\n\n        def test_escape_quotes_except_django_tags(self):\n            sut = Element('')\n\n            s1 = sut._escape_attribute_quotes('''{% url 'blah' %}''')\n            eq_(s1,'''{% url 'blah' %}''')\n\n            s2 = sut._escape_attribute_quotes('''blah's blah''s {% url 'blah' %} blah's blah''s''')\n            eq_(s2,r\"blah\\'s blah\\'\\'s {% url 'blah' %} blah\\'s blah\\'\\'s\")\n\n        def test_attributes_parse(self):\n            sut = Element('')\n\n            s1 = sut._parse_attribute_dictionary('''{a:'something',\"b\":None,'c':2}''')\n            eq_(s1['a'],'something')\n            eq_(s1['b'],None)\n            eq_(s1['c'],2)\n\n            eq_(sut.attributes, \"a='something' c='2' b\")\n\n        def test_pulls_tag_name_off_front(self):\n            sut = Element('%div.class')\n            eq_(sut.tag, 'div')\n            \n        def test_default_tag_is_div(self):\n            sut = Element('.class#id')\n            eq_(sut.tag, 'div')\n            \n        def test_parses_id(self):\n            sut = Element('%div#someId.someClass')\n            eq_(sut.id, 'someId')\n            \n            sut = Element('#someId.someClass')\n            eq_(sut.id, 'someId')\n            \n        def test_no_id_gives_empty_string(self):\n            sut = Element('%div.someClass')\n            eq_(sut.id, '')\n        \n        def test_parses_class(self):\n            sut = Element('%div#someId.someClass')\n            eq_(sut.classes, 'someClass')\n            \n        def test_properly_parses_multiple_classes(self):\n            sut = Element('%div#someId.someClass.anotherClass')\n            eq_(sut.classes, 'someClass anotherClass')\n            \n        def test_no_class_gives_empty_string(self):\n            sut = Element('%div#someId')\n            eq_(sut.classes, '')\n            \n        def test_attribute_dictionary_properly_parses(self):\n            sut = Element(\"%html{'xmlns':'http://www.w3.org/1999/xhtml', 'xml:lang':'en', 'lang':'en'}\")\n            assert \"xmlns='http://www.w3.org/1999/xhtml'\" in sut.attributes\n            assert \"xml:lang='en'\" in sut.attributes\n            assert \"lang='en'\" in sut.attributes\n\n        def test_id_and_class_dont_go_in_attributes(self):\n            sut = Element(\"%div{'class':'hello', 'id':'hi'}\")\n            assert 'class=' not in sut.attributes\n            assert 'id=' not in sut.attributes\n            \n        def test_attribute_merges_classes_properly(self):\n            sut = Element(\"%div.someClass.anotherClass{'class':'hello'}\")\n            assert 'someClass' in sut.classes\n            assert 'anotherClass' in sut.classes\n            assert 'hello' in sut.classes\n            \n        def test_attribute_merges_ids_properly(self):\n            sut = Element(\"%div#someId{'id':'hello'}\")\n            eq_(sut.id, 'someId_hello')\n            \n        def test_can_use_arrays_for_id_in_attributes(self):\n            sut = Element(\"%div#someId{'id':['more', 'andMore']}\")\n            eq_(sut.id, 'someId_more_andMore')\n        \n        def test_self_closes_a_self_closing_tag(self):\n            sut = Element(r\"%br\")\n            assert sut.self_close\n            \n        def test_does_not_close_a_non_self_closing_tag(self):\n            sut = Element(\"%div\")\n            assert sut.self_close == False\n            \n        def test_can_close_a_non_self_closing_tag(self):\n            sut = Element(\"%div/\")\n            assert sut.self_close\n            \n        def test_properly_detects_django_tag(self):\n            sut = Element(\"%div= $someVariable\")\n            assert sut.django_variable\n            \n        def test_knows_when_its_not_django_tag(self):\n            sut = Element(\"%div Some Text\")\n            assert sut.django_variable == False\n            \n        def test_grabs_inline_tag_content(self):\n            sut = Element(\"%div Some Text\")\n            eq_(sut.inline_content, 'Some Text')\n            \n        def test_multiline_attributes(self):\n            sut = Element(\"\"\"%link{'rel': 'stylesheet', 'type': 'text/css',\n                'href': '/long/url/to/stylesheet/resource.css'}\"\"\")\n            assert \"href='/long/url/to/stylesheet/resource.css'\" in sut.attributes\n            assert \"type='text/css'\" in sut.attributes\n            assert \"rel='stylesheet'\" in sut.attributes\n"
  },
  {
    "path": "readme.md",
    "content": "# HamlPy\n\nHamlPy (pronounced \"haml pie\") is a tool for Django developers who want to use a Haml like syntax for their templates.\nHamlPy is not a template engine in itself but simply a compiler which will convert HamlPy files into templates that Django can understand.\n\n\nBut wait, what is Haml?  Haml is an incredible template engine written in Ruby used a lot in the Rails community.  You can read more about it [here](http://www.haml-lang.com \"Haml Home\").\n\n## Installing\n\n### Stable release\n\nThe latest stable version of HamlPy can be installed using [setuptools](http://pypi.python.org/pypi/setuptools/) `easy_install hamlpy` or  [pip](http://pypi.python.org/pypi/pip/) (`pip install hamlpy`)\n\n### Development\n\nThe latest development version can be installed directly from GitHub:\n\n    pip install https://github.com/jessemiller/HamlPy/tarball/master\n\n## Syntax\n\nAlmost all of the XHTML syntax of Haml is preserved.  \n\n\t#profile\n\t\t.left.column\n\t\t\t#date 2010/02/18\n\t\t\t#address Toronto, ON\n\t\t.right.column\n\t\t\t#bio Jesse Miller\n\t\t\t\nturns into..\n\n\t<div id='profile'>\n\t\t<div class='left column'>\n\t\t\t<div id='date'>2010/02/18</div>\n\t\t\t<div id='address'>Toronto, ON</div>\n\t\t</div>\n\t\t<div class='right column'>\n\t\t\t<div id='bio'>Jesse Miller</div>\n\t\t</div>\n\t</div>\n\t\n\nThe main difference is instead of interpreting Ruby, or even Python we instead can create Django Tags and Variables\n\n\t%ul#athletes\n\t\t- for athlete in athlete_list\n\t\t\t%li.athlete{'id': 'athlete_{{ athlete.pk }}'}= athlete.name\n\nturns into..\n\n\t<ul id='athletes'>\n\t\t{% for athlete in athlete_list %}\n\t\t\t<li class='athlete' id='athlete_{{ athlete.pk }}'>{{ athlete.name }}</li>\n\t\t{% endfor %}\n\t</ul>\n\n## Usage\n\n### Option 1: Template loader\n\nThe template loader was originally written by [Chris Hartjes](https://github.com/chartjes) under the name 'djaml'. This project has now been merged into the HamlPy codebase.\n\nAdd the HamlPy template loaders to the Django template loaders:\n\n    TEMPLATE_LOADERS = (\n\t    'hamlpy.template.loaders.HamlPyFilesystemLoader',\n\t    'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',   \n        ...\n    )\n\nIf you don't put the HamlPy template loader first, then the standard Django template loaders will try to process\nit first. Make sure your templates have a `.haml` or `.hamlpy` extension, and put them wherever you've told Django\nto expect to find templates (TEMPLATE_DIRS).\n\n#### Template caching\n\nFor caching, just add `django.template.loaders.cached.Loader` to your TEMPLATE_LOADERS:\n\n\tTEMPLATE_LOADERS = (\n\t    ('django.template.loaders.cached.Loader', (\n\t\t    'hamlpy.template.loaders.HamlPyFilesystemLoader',\n\t\t    'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',\n\t\t    ...\n\t    )),   \n\t)\n\n#### Settings\n\nFollowing values in Django settings affect haml processing:\n\n  * `HAMLPY_ATTR_WRAPPER` -- The character that should wrap element attributes. This defaults to ' (an apostrophe).\n\n### Option 2: Watcher \n\nHamlPy 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:\n\n\n        usage: hamlpy-watcher [-h] [-v] [-i EXT [EXT ...]] [-ext EXT] [-r S]\n                            [--tag TAG] [--attr-wrapper {\",'}]\n                            input_dir [output_dir]\n\n        positional arguments:\n        input_dir             Folder to watch\n        output_dir            Destination folder\n\n        optional arguments:\n        -h, --help            show this help message and exit\n        -v, --verbose         Display verbose output\n        -i EXT [EXT ...], --input-extension EXT [EXT ...]\n                                The file extensions to look for\n        -ext EXT, --extension EXT\n                                The output file extension. Default is .html\n        -r S, --refresh S     Refresh interval for files. Default is 3 seconds\n        --tag TAG             Add self closing tag. eg. --tag macro:endmacro\n        --attr-wrapper {\",'}  The character that should wrap element attributes.\n                                This defaults to ' (an apostrophe).\n        --jinja               Makes the necessary changes to be used with Jinja2\n\nOr to simply convert a file and output the result to your console:\n\n\thamlpy inputFile.haml\n\t\nOr you can have it dump to a file:\n\n\thamlpy inputFile.haml outputFile.html\n\nOptionally, `--attr-wrapper` can be specified:\n\n    hamlpy inputFile.haml --attr-wrapper='\"'\n\nUsing the `--jinja` compatibility option adds macro and call tags, and changes the `empty` node in the `for` tag to `else`.\n\nFor HamlPy developers, the `-d` switch can be used with `hamlpy` to debug the internal tree structure.\n\t\n### Create message files for translation\n\nThere is a very simple solution.\n\n\tdjango-admin.py makemessages --settings=<project.settings> -a\n\t\nWhere:\n\n  * project.settings -- Django configuration file where  module \"hamlpy\" is configured properly.\n\t\n## Reference\n\nCheck out the [reference.md](http://github.com/jessemiller/HamlPy/blob/master/reference.md \"HamlPy Reference\") file for a complete reference and more examples.\n\n## Status\n\nHamlPy currently:\n\n- has no configuration file.  which it should for a few reasons, like turning off what is autoescaped for example\n- does not support some of the filters yet\n\n## Contributing\n\nVery 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\n\n    nosetests *.py\n"
  },
  {
    "path": "reference.md",
    "content": "# HamlPy Reference\n\n# Table of Contents\n\n- [Plain Text](#plain-text)\n- [Doctype](#doctype)\n- [HTML Elements](#html-elements)\n\t- [Element Name: %](#element-name-)\n\t- [Attributes: {}](#attributes-)\n\t\t- [Attributes without values (Boolean attributes)](#attributes-without-values-boolean-attributes)\n\t\t- ['class' and 'id' attributes](#class-and-id-attributes)\n\t- [Class and ID: . and #](#class-and-id--and-)\n\t\t- [Implicit div elements](#implicit-div-elements)\n\t- [Self-Closing Tags: /](#self-closing-tags-)\n- [Comments](#comments)\n\t- [HTML Comments /](#html-comments-)\n\t- [Conditional Comments /[]](#conditional-comments-)\n\t- [HamlPy Comments: -#](#hamlpy-comments--)\n- [Django Specific Elements](#django-specific-elements)\n\t- [Django Variables: =](#django-variables-)\n\t- [Inline Django Variables: ={...}](#inline-django-variables-)\n\t- [Django Tags: -](#django-tags--)\n\t\t- [Tags within attributes:](#tags-within-attributes)\n\t- [Whitespace removal](#whitespace-removal)\n- [Filters](#filters)\n\t- [:plain](#plain)\n\t- [:javascript](#javascript)\n\t- [:coffeescript or :coffee](#coffeescript-or-coffee)\n\t- [:cdata](#cdata)\n\t- [:css](#css)\n\t- [:stylus](#stylus)\n\t- [:markdown](#markdown)\n\t- [:highlight](#highlight)\n\t- [:python](#python)\n\n## Plain Text\n\nAny line that is not interpreted as something else will be taken as plain text and outputted unmodified.  For example:\n\n\t%gee\n\t\t%whiz\n\t\t\tWow this is cool!\n\t\t\t\nis compiled to:\n\n\t<gee>\n\t\t<whiz>\n\t\t\tWow this is cool!\n\t\t</whiz>\n\t</gee>\n\n## Doctype\n\nYou can specify a specific doctype after the !!! The following doctypes are supported:\n\n* `!!!`: XHTML 1.0 Transitional\n* `!!! Strict`: XHTML 1.0 Strict\n* `!!! Frameset`: XHTML 1.0 Frameset\n* `!!! 5`: XHTML 5\n* `!!! 1.1`: XHTML 1.1\n* `!!! XML`: XML prolog\n\n## HTML Elements\n\n### Element Name: %\n\nThe percent character placed at the beginning of the line will then be followed by the name of the element, then optionally modifiers (see below), a space, and text to be rendered inside the element.  It creates an element in the form of <element></element>.  For example:\n\n\t%one\n\t\t%two\n\t\t\t%three Hey there\n\t\t\t\nis compiled to:\n\n\t<one>\n\t\t<two>\n\t\t\t<three>Hey there</three>\n\t\t</two>\n\t</one>\n\nAny string is a valid element name and an opening and closing tag will automatically be generated.\n\n### Attributes: {}\n\nBrackets represent a Python dictionary that is used for specifying the attributes of an element.  The dictionary is placed after the tag is defined.  For example:\n\n\t%html{'xmlns':'http://www.w3.org/1999/xhtml', 'xml:lang':'en', 'lang':'en'}\n\t\nis compiled to:\n\n\t<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'></html>\n\nLong attribute dictionaries can be separated into multiple lines:\n\n    %script{'type': 'text/javascript', 'charset': 'utf-8', \n            'href': '/long/url/to/javascript/resource.js'}\n\n#### Attributes without values (Boolean attributes)\n\nAttributes without values can be specified using Python's ```None``` keyword (without quotes). For example:\n\n\t%input{'type':'checkbox', value:'Test', checked: None}\n\nis compiled to:\n\n\t<input type=\"checkbox\" value=\"Test\" checked />\n\n\n#### 'class' and 'id' attributes\n\nThe 'class' and 'id' attributes can also be specified as a Python tuple whose elements will be joined together.  A 'class' tuple will be joined with \" \" and an 'id' tuple is joined with \"_\".  For example:\n\n\t%div{'id': ('article', '3'), 'class': ('newest', 'urgent')} Content\n\t\nis compiled to:\n\n\t<div id='article_3' class='newest urgent'>Content</div>\n\t\n### Class and ID: . and # \n\nThe period and pound sign are borrowed from CSS.  They are used as shortcuts to specify the class and id attributes of an element, respectively.  Multiple class names can be specified by chaining class names together with periods.  They are placed immediately after a tag and before an attribute dictionary.  For example:\n\n\t%div#things\n\t\t%span#rice Chicken Fried\n\t\t%p.beans{'food':'true'} The magical fruit\n\t\t%h1#id.class.otherclass La La La\n\t\nis compiled to:\n\n\t<div id='things'>\n\t\t<span id='rice'>Chiken Fried</span>\n\t\t<p class='beans' food='true'>The magical fruit</p>\n\t\t<h1 id='id' class='class otherclass'>La La La</h1>\n\t</div>\n\t\nAnd,\n\n\t%div#content\n\t\t%div.articles\n\t\t\t%div.article.title Doogie Howser Comes Out\n\t\t\t%div.article.date 2006-11-05\n\t\t\t%div.article.entry\n\t\t\t\tNeil Patrick Harris would like to dispel any rumors that he is straight\n\t\t\t\t\nis compiled to:\n\n\t<div id='content'>\n\t\t<div class='articles'>\n\t\t\t<div class='article title'>Doogie Howser Comes Out</div>\n\t\t\t<div class='article date'>2006-11-05</div>\n\t\t\t<div class='article entry'>\n\t\t\t\tNeil Patrick Harris would like to dispel any rumors that he is straight\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\nThese shortcuts can be combined with the attribute dictionary and they will be combined as if they were all put inside a tuple.  For example:\n\n\t%div#Article.article.entry{'id':'1', 'class':'visible'} Booyaka\n\t\nis equivalent to:\n\t\n\t%div{'id':('Article','1'), 'class':('article','entry','visible')} Booyaka\n\t\nand would compile to:\n\n\t<div id='Article_1' class='article entry visible'>Booyaka</div>\n\t\nYou can also use more pythonic array structures in the dictionary, like so:\n\n    %div{'id':['Article','1'], 'class':['article','entry','visible']} Booyaka\n\t\n#### Implicit div elements\n\nBecause divs are used so often, they are the default element.  If you only define a class and/or id using `.` or `#` then the %div will be implied.  For example:\n\n\t#collection\n\t\t.item\n\t\t\t.description What a cool item!\n\t\t\t\nwill compile to:\n\n\t<div id='collection'>\n\t\t<div class='item'>\n\t\t\t<div class='description'>What a cool item!</div>\n\t\t</div>\n\t</div>\n\t\n### Self-Closing Tags: /\n\nThe forward slash character, when placed at the end of a tag definition, causes the tag to be self-closed.  For example:\n\n\t%br/\n\t%meta{'http-equiv':'Content-Type', 'content':'text/html'}/\n\t\nwill compile to:\n\n\t<br />\n\t<meta http-quiv='Content-Type' content='text/html' />\n\t\nSome tags are automatically closed, as long as they have no content.  `meta, img, link, script, br` and `hr` tags are automatically closed.  For example:\n\n\t%br\n\t%meta{'http-equiv':'Content-Type', 'content':'text/html'}\n\t\nwill compile to:\n\n\t<br />\n\t<meta http-quiv='Content-Type' content='text/html' />\n\t\n## Comments\n\nThere are two types of comments supported:  those that show up in the HTML and those that don't.\n\n### HTML Comments /\n\nThe forward slash character, when placed at the beginning of a line, wraps all the text after it in an HTML comment.  For example:\n\n\t%peanutbutterjelly\n\t\t/ This is the peanutbutterjelly element\n\t\tI like sandwiches!\n\t\t\nis compiled to:\n\n\t<peanutbutterjelly>\n\t\t<!-- This is the peanutbutterjelly element -->\n\t\tI like sandwiches!\n\t</peanutbutterjelly>\n\t\nThe forward slash can also wrap indented sections of code.  For example:\n\n\t/\n\t\t%p This doesn't render\n\t\t%div\n\t\t\t%h1 Because it's commented out!\n\t\t\t\nis compiled to:\n\n\t<!--\n\t\t<p>This doesn't render</p>\n\t\t<div>\n\t\t\t<h1>Because it's commented out!</h1>\n\t\t</div>\n\t-->\n\t\n### Conditional Comments /[]\n\nYou can use [Internet Explorer conditional comments](http://www.quirksmode.org/css/condcom.html) by enclosing the condition in square brackets after the /. For example:\n\n    /[if IE]\n        %h1 Get a better browser\n    \nis compiled to:\n\n    <!--[if IE]>\n        <h1>Get a better browser</h1>\n    <![endif]-->\n\t\n### HamlPy Comments: -# \n\nThe hyphen followed immediately by the pound sign signifies a silent comment.  Any text following this isn't rendered during compilation at all.  For example:\n\n\t%p foo\n\t-# Some comment\n\t%p bar\n\t\nis compiled to:\n\n\t<p>foo</p>\n\t<p>bar</p>\n\t\n## Django Specific Elements\n\nThe key difference in HamlPy from Haml is the support for Django elements.  The syntax for ruby evaluation is borrowed from Haml and instead outputs Django tags and variables.\n\n### Django Variables: =\n\nA line starting with an equal sign followed by a space and then content is evaluated as a Django variable.  For example:\n\n\t.article\n\t\t.preview\n\t\t\t= story.teaser\n\t\t\t\nis compiled to:\n\n\t<div class='article'>\n\t\t<div class='preview'>\n\t\t\t{{ story.teaser }}\n\t\t</div>\n\t</div>\n\t\nA Django variable can also be used as content for any HTML element by placing an equals sign as the last character before the space and content.  For example:\n\n\t%h2\n\t\t%a{'href':'stories/1'}= story.teaser\n\t\t\nis compiled to:\n\n\t<h2>\n\t\t<a href='stories/1'>{{ story.teaser }}</a>\n\t</h2>\n\n### Inline Django Variables: ={...}\n\t\nYou can also use inline variables by surrounding the variable name with curly braces. For example:\n\n\tHello ={name}, how are you today?\n\nis compiled to\n\n\tHello {{ name }}, how are you today?\n\nInline variables can also be used in an element's attribute values. For example:\n\n\t%a{'title':'Hello ={name}, how are you?'} Hello\n\nis compiled to:\n\n\t<a title='Hello {{ name }}, how are you?'>Hello</a>\n\nInline variables can be escaped by placing a `\\` before them. For example:\n\n\tHello \\={name}\n\nis compiled to\n\n\tHello ={name}\n\nThe Ruby style (`#{...}` rather than `={...}`) is also supported and the two can be used interchangeably.\n\n\n\n\n### Django Tags: -\n\nThe hypen character at the start of the line followed by a space and a Django tag will be inserted as a Django tag.  For example:\n\n\t- block content\n\t\t%h1= section.title\n\t\n\t\t- for dog in dog_list\n\t\t\t%h2\n\t\t\t\t= dog.name\n\t\nis compiled to:\n\n\t{% block content %}\n\t\t<h1>{{ section.title }}</h1>\n\t\t\n\t\t{% for dog in dog_list %}\n\t\t\t<h2>\n\t\t\t\t{{ dog.name }}\n\t\t\t</h2>\n\t\t{% endfor %}\n\t{% endblock %}\n\t\n\t\nNotice that block, for, if and else, as well as ifequal, ifnotequal, ifchanged and 'with' are all automatically closed.  Using endfor, endif, endifequal, endifnotequal, endifchanged or endblock will throw an exception.\n\n#### Tags within attributes:\n\nThis is not yet supported: `%div{'attr':\"- firstof var1 var2 var3\"}` will not insert the `{% ... %}`.\n\nThe workaround is to insert actual django template tag code into the haml. For example:\n\n    %a{'href': \"{% url socialauth_begin 'github' %}\"} Login with Github\n\nis compiled to:\n\n    <a href=\"{% url socialauth_begin 'github' %}\">Login with Github</a>\n\n\n### Whitespace removal\n\nSometimes we want to remove whitespace inside or around an element, usually to fix the spacing problem with inline-block elements (see \"The Enormous Drawback\" section of [this article](http://robertnyman.com/2010/02/24/css-display-inline-block-why-it-rocks-and-why-it-sucks/) for more details).\n\nTo remove leading and trailing spaces **inside** a node (\"inner whitespace removal\"), use the `<` character after an element. For example, this:\n\n\t%div\n\t\t%pre<\n\t\t\t= Foo\n\nis compiled to:\n\n\t<div>\n\t  <pre>{{ Foo }}</pre>\n\t</div>\n\nTo remove leading and trailing spaces **around** a node (\"outer whitespace removal\"), use the `>` character after an element. For example, this:\n\n\t%li Item one\n\t%li> Item two\n\t%li Item three\n\nis compiled to:\n\n\t<li>Item one</li><li>Item two</li><li>Item three</li>\n\n## Filters\n\n### :plain\n\nDoes not parse the filtered text. This is useful for large blocks of text without HTML tags, when you don’t want lines starting with . or - to be parsed.\n\n### :javascript\n\nSurrounds the filtered text with &lt;script type=\"text/javascript\"&gt; and CDATA tags. Useful for including inline Javascript.\n\n### :coffeescript or :coffee\n\nSurrounds the filtered text with &lt;script type=\"text/coffeescript\"&gt; and CDATA tags. Useful for including inline Coffeescript.\n\n### :cdata\n\nSurrounds the filtered text with CDATA tags.\n\n### :css\n\nSurrounds the filtered text with &lt;style type=\"text/css\"&gt; and CDATA tags. Useful for including inline CSS.\n\n### :stylus\n\nSurrounds the filtered text with &lt;style type=\"text/stylus\"&gt; and CDATA tags. Useful for including inline Stylus.\n\n### :markdown\n\nConverts the filter text from Markdown to HTML, using the Python [Markdown library](http://freewisdom.org/projects/python-markdown/).\n\n### :highlight\n\nThis will output the filtered text with syntax highlighting using [Pygments](http://pygments.org).\n\nFor syntax highlighting to work correctly, you will also need to generate or include a Pygments CSS file. See\nthe section [\"Generating styles\"](http://pygments.org/docs/cmdline/#generating-styles) in the Pygments\ndocumentation for more information.\n\n### :python\n\nExecute the filtered text as python and output the result in the file. For example:\n\n\t:python\n\t\tfor i in range(0, 5): \n\t\t\tprint \"<p>item %s</p>\" % i\n\nis compiled to:\n\n\t<p>item 0</p>\n\t<p>item 1</p>\n\t<p>item 2</p>\n\t<p>item 3</p>\n\t<p>item 4</p>\n\n"
  },
  {
    "path": "setup.py",
    "content": "from setuptools import setup\n\n# Note to Jesse - only push sdist to PyPi, bdist seems to always break pip installer\nsetup(name='hamlpy',\n      version = '0.82.2',\n      download_url = 'git@github.com:jessemiller/HamlPy.git',\n      packages = ['hamlpy', 'hamlpy.template'],\n      author = 'Jesse Miller',\n      author_email = 'millerjesse@gmail.com',\n      description = 'HAML like syntax for Django templates',\n      keywords = 'haml django converter',\n      url = 'http://github.com/jessemiller/HamlPy',\n      license = 'MIT',\n      install_requires = [\n      ],\n      entry_points = {\n          'console_scripts' : ['hamlpy = hamlpy.hamlpy:convert_files',\n                               'hamlpy-watcher = hamlpy.hamlpy_watcher:watch_folder']\n      }\n    )\n"
  },
  {
    "path": "watch_me.rb",
    "content": "watch('.*\\.(py|hamlpy|html)') { |md|  system(\"cd hamlpy/test;nosetests --with-sneazr\") }"
  }
]