예제 #1
0
파일: haml.py 프로젝트: kroo/pyhaml
class Engine(object):

    optparser = OptionParser(version=__version__)

    optparser.add_option('-i', '--filename',
        help='file to render',
        dest='filename')

    optparser.add_option('-d', '--debug',
        help='display debugging information',
        action='store_true',
        dest='debug',
        default=False)

    optparser.add_option('-w', '--attr_wrapper',
        help='attribute wrapper character',
        type='choice',
        choices=['"',"'"],
        dest='attr_wrapper',
        default='"')

    optparser.add_option('-f', '--format',
        help='(html5|html4|xhtml)',
        type='choice',
        choices=['html5', 'html4', 'xhtml'],
        default='html5',
        dest='format')

    optparser.add_option('-e', '--escape_html',
        help='sanitize values by default',
        action='store_true',
        dest='escape_html',
        default=True)

    optparser.add_option('-b', '--batch',
        help='batch compile haml files',
        action='store_true',
        dest='batch',
        default=False)

    optparser.add_option('-s', '--suppress_eval',
        help='suppress script evaluation',
        action='store_true',
        dest='suppress_eval',
        default=False)

    optparser.add_option('-p', '--preserve',
        help='preserve whitespace tags',
        action='append',
        type='str',
        dest='preserve',
        default=['pre', 'textarea'])

    optparser.add_option('-a', '--autoclose',
        help='autoclose tags',
        action='append',
        type='str',
        dest='autoclose',
        default=[
            'meta',
            'img',
            'input',
            'link',
            'br',
            'hr',
            'area',
            'param',
            'col',
            'base',
        ])

    optparser.add_option('-x', '--fail_fast',
      help='Raise an exception immediately on Lex or Parse error.',
      action='store_true',
      dest='fail_fast',
      default=False)


    def __init__(self):
        self._cache = Cache()
        self.haml_line_cache = {}
        self.parser = yacc.yacc(
            module=parser,
            write_tables=0,
            debug=0)
        self.lexer = lex.lex(module=lexer)

    def reset(self):
        self.depth = 0
        self.html = StringIO()
        self.trim_next = False
        self.globals = { '_haml': self }

    def setops(self, *args, **kwargs):
        """
Sets options for the Haml engine.  Options should be given as keyword arguments.
        """
        (self.op, _) = Engine.optparser.parse_args([])
        for (k,v) in kwargs.items():
            opt = Engine.optparser.get_option('--' + k)
            if opt:
                self.op.__dict__[k] = opt.check_value(k,v)

    def _modulename(self, path):
      """ensure no . characters exist in path, as these have meaning in g3"""
      return path.replace(".", "-dot-")

    def find_module(self, fullname):
        if not fullname.startswith("//"):
          dir = os.path.dirname(self.op.filename)
        else:
          dir = os.curdir
          fullname = fullname[2:]
        path = os.path.join(dir, '%s.haml' % fullname)
        if os.path.exists(path):
            return Loader(self, path)
        raise ImportError, "could not find file at path %s" % path

    def load_module(self, fullname, path, loader):
        code = self.cache(path)
        fullname = self._modulename(fullname)
        mod = imp.new_module(fullname)
        mod = sys.modules.setdefault(fullname, mod)
        mod.__file__ = path
        mod.__loader__ = loader
        mod.__dict__.update(self.globals)
        ex(code, mod.__dict__)
        return mod

    def imp(self, fullname):
        finder = Finder(self)
        loader = finder.find_module(fullname)
        if loader:
            return loader.load_module(fullname)
        return None

    def entab(self):
        self.depth += 1

    def detab(self):
        self.depth -= 1

    def trim(self):
        self.trim_next = True

    def indent(self, indent):
        if not self.trim_next:
            self.write('\n')
            if indent:
                self.write('  ' * self.depth)
        self.trim_next = False

    def write(self, *args):
        for arg in args:
            arg = arg.encode("ascii", "xmlcharrefreplace")
            self.html.write(arg)

    def escape(self, string):
        return cgi.escape(string, True)

    def preserve_whitespace(self, string):
        return string.replace('\n', '
')

    def attrs(self, id, klass, a):
        a = dict((k,v) for k,v in a.items() if v != None)
        if id:
            a['id'] = id + '_' + a.get('id','') if 'id' in a else id
        if klass:
            a['class'] = (klass + ' ' + a.get('class','')).strip()
        w = self.op.attr_wrapper
        for k,v in a.items():
            if v is None or v is False: continue
            if v is True: v = k # for things like checked=checked
            v = unicode(v).replace(w, {'"':'"', "'":'''}[w])
            self.write(' %s=%s%s%s' % (k,w,v,w))

    def compile(self, s, filename="<string>"):
        """
Compile a HAML string, returning a Python code object that can be exec'd.
Optional filename parameter specifies the name of the file containing the HAML
code, which helps give better error messages.
        """
        self.parser.__dict__.update({
            'depth': 0,
            'src': [],
            'last_obj': None,
            'debug': self.op.debug,
            'op': self.op,
            'to_close': [],
            'preserve': 0,
            'lineno': 1,
        })

        self.lexer.begin('INITIAL')
        self.lexer.__dict__.update({
            'depth': 0,
            'type': None,
            'length': None,
            'block': None,
            'lineno': 1,
        })

        try:
            self.parser.parse(s, lexer=self.lexer, debug=self.op.debug, tracking=True)
        except HamlParserException, ex:
            lineno, haml_line, msg = ex
            if type(haml_line) == int:
                #interpret haml_line as character position to get the line
                haml_line = get_lines_in_position_range(self.lexer.lexdata,
                    haml_line, haml_line)
            raise HamlException, "Parse error in file %r: %s at line %d:\n%s\n%s" % \
(filename, msg, lineno, haml_line, traceback.format_exc())
        #add a line too the beginning of the Python source indicating which
        #Haml file this is.  This can be accessed later for getting descriptive
        #error messages.
        lines = ["HAML_file_name = %r" % filename]
        #haml_lines maps Python lines to Haml (line number, code) pairs.
        haml_lines = [(0, "<no line 0>"), (0, "<HAML setup>")]
        for call in self.parser.src:
            line = str(call)
            lines.append(line)
            haml_line = call.haml.posinfo
            #append once for every Python line this Haml call turned into
            for i in range(1 + line.count('\n')):
                haml_lines.append(haml_line)
        self.haml_line_cache[filename] = haml_lines
        src = '\n'.join(lines) + '\n'
        try:
            #important for file to be "<haml>" so execute() can detect Haml
            #code in tracebacks
            return code.compile_command(src, "<haml>", "exec")
        except SyntaxError:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            haml_line_number, haml_line = self.get_haml_line_info(filename,
exc_value.lineno, exc_value.text)
            #change the syntax error message to show the Haml code
            message = traceback.format_exception_only(exc_type, exc_value)
            #message[0] was originally 'File "<pythonfile>", line <pythonline>'
            message[0] = '  File "%s", line %d\n' % (filename, haml_line_number)
            #message[1] was originally the python line with the syntax error
            message[1] = '    %s\n  Python:\n%s' % (haml_line, message[1])
            raise HamlException, ''.join(message)
예제 #2
0
class Engine(object):

    optparser = OptionParser(version=__version__)

    optparser.add_option('-i',
                         '--filename',
                         help='file to render',
                         dest='filename')

    optparser.add_option('-d',
                         '--debug',
                         help='display debugging information',
                         action='store_true',
                         dest='debug',
                         default=False)

    optparser.add_option('-w',
                         '--attr_wrapper',
                         help='attribute wrapper character',
                         type='choice',
                         choices=['"', "'"],
                         dest='attr_wrapper',
                         default='"')

    optparser.add_option('-f',
                         '--format',
                         help='(html5|html4|xhtml)',
                         type='choice',
                         choices=['html5', 'html4', 'xhtml'],
                         default='html5',
                         dest='format')

    optparser.add_option('-e',
                         '--escape_html',
                         help='sanitize values by default',
                         action='store_true',
                         dest='escape_html',
                         default=True)

    optparser.add_option('-b',
                         '--batch',
                         help='batch compile haml files',
                         action='store_true',
                         dest='batch',
                         default=False)

    optparser.add_option('-s',
                         '--suppress_eval',
                         help='suppress script evaluation',
                         action='store_true',
                         dest='suppress_eval',
                         default=False)

    optparser.add_option('-p',
                         '--preserve',
                         help='preserve whitespace tags',
                         action='append',
                         type='str',
                         dest='preserve',
                         default=['pre', 'textarea'])

    optparser.add_option('-a',
                         '--autoclose',
                         help='autoclose tags',
                         action='append',
                         type='str',
                         dest='autoclose',
                         default=[
                             'meta',
                             'img',
                             'input',
                             'link',
                             'br',
                             'hr',
                             'area',
                             'param',
                             'col',
                             'base',
                         ])

    optparser.add_option(
        '-x',
        '--fail_fast',
        help='Raise an exception immediately on Lex or Parse error.',
        action='store_true',
        dest='fail_fast',
        default=False)

    def __init__(self):
        self._cache = Cache()
        self.haml_line_cache = {}
        self.parser = yacc.yacc(module=parser, write_tables=0, debug=0)
        self.lexer = lex.lex(module=lexer)

    def reset(self):
        self.depth = 0
        self.html = StringIO()
        self.trim_next = False
        self.globals = {'_haml': self}

    def setops(self, *args, **kwargs):
        """
Sets options for the Haml engine.  Options should be given as keyword arguments.
        """
        (self.op, _) = Engine.optparser.parse_args([])
        for (k, v) in kwargs.items():
            opt = Engine.optparser.get_option('--' + k)
            if opt:
                self.op.__dict__[k] = opt.check_value(k, v)

    def _modulename(self, path):
        """ensure no . characters exist in path, as these have meaning in g3"""
        return path.replace(".", "-dot-")

    def find_module(self, fullname):
        if not fullname.startswith("//"):
            dir = os.path.dirname(self.op.filename)
        else:
            dir = os.curdir
            fullname = fullname[2:]
        path = os.path.join(dir, '%s.haml' % fullname)
        if os.path.exists(path):
            return Loader(self, path)
        raise ImportError, "could not find file at path %s" % path

    def load_module(self, fullname, path, loader):
        code = self.cache(path)
        fullname = self._modulename(fullname)
        mod = imp.new_module(fullname)
        mod = sys.modules.setdefault(fullname, mod)
        mod.__file__ = path
        mod.__loader__ = loader
        mod.__dict__.update(self.globals)
        ex(code, mod.__dict__)
        return mod

    def imp(self, fullname):
        finder = Finder(self)
        loader = finder.find_module(fullname)
        if loader:
            return loader.load_module(fullname)
        return None

    def entab(self):
        self.depth += 1

    def detab(self):
        self.depth -= 1

    def trim(self):
        self.trim_next = True

    def indent(self, indent):
        if not self.trim_next:
            self.write('\n')
            if indent:
                self.write('  ' * self.depth)
        self.trim_next = False

    def write(self, *args):
        for arg in args:
            arg = arg.encode("ascii", "xmlcharrefreplace")
            self.html.write(arg)

    def escape(self, string):
        return cgi.escape(string, True)

    def preserve_whitespace(self, string):
        return string.replace('\n', '&#x000A;')

    def attrs(self, id, klass, a):
        a = dict((k, v) for k, v in a.items() if v != None)
        if id:
            a['id'] = id + '_' + a.get('id', '') if 'id' in a else id
        if klass:
            a['class'] = (klass + ' ' + a.get('class', '')).strip()
        w = self.op.attr_wrapper
        for k, v in a.items():
            if v is None or v is False: continue
            if v is True: v = k  # for things like checked=checked
            v = unicode(v).replace(w, {'"': '&quot;', "'": '&#39;'}[w])
            self.write(' %s=%s%s%s' % (k, w, v, w))

    def compile(self, s, filename="<string>"):
        """
Compile a HAML string, returning a Python code object that can be exec'd.
Optional filename parameter specifies the name of the file containing the HAML
code, which helps give better error messages.
        """
        self.parser.__dict__.update({
            'depth': 0,
            'src': [],
            'last_obj': None,
            'debug': self.op.debug,
            'op': self.op,
            'to_close': [],
            'preserve': 0,
            'lineno': 1,
        })

        self.lexer.begin('INITIAL')
        self.lexer.__dict__.update({
            'depth': 0,
            'type': None,
            'length': None,
            'block': None,
            'lineno': 1,
        })

        try:
            self.parser.parse(s,
                              lexer=self.lexer,
                              debug=self.op.debug,
                              tracking=True)
        except HamlParserException, ex:
            lineno, haml_line, msg = ex
            if type(haml_line) == int:
                #interpret haml_line as character position to get the line
                haml_line = get_lines_in_position_range(
                    self.lexer.lexdata, haml_line, haml_line)
            raise HamlException, "Parse error in file %r: %s at line %d:\n%s\n%s" % \
(filename, msg, lineno, haml_line, traceback.format_exc())
        #add a line too the beginning of the Python source indicating which
        #Haml file this is.  This can be accessed later for getting descriptive
        #error messages.
        lines = ["HAML_file_name = %r" % filename]
        #haml_lines maps Python lines to Haml (line number, code) pairs.
        haml_lines = [(0, "<no line 0>"), (0, "<HAML setup>")]
        for call in self.parser.src:
            line = str(call)
            lines.append(line)
            haml_line = call.haml.posinfo
            #append once for every Python line this Haml call turned into
            for i in range(1 + line.count('\n')):
                haml_lines.append(haml_line)
        self.haml_line_cache[filename] = haml_lines
        src = '\n'.join(lines) + '\n'
        try:
            #important for file to be "<haml>" so execute() can detect Haml
            #code in tracebacks
            return code.compile_command(src, "<haml>", "exec")
        except SyntaxError:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            haml_line_number, haml_line = self.get_haml_line_info(
                filename, exc_value.lineno, exc_value.text)
            #change the syntax error message to show the Haml code
            message = traceback.format_exception_only(exc_type, exc_value)
            #message[0] was originally 'File "<pythonfile>", line <pythonline>'
            message[0] = '  File "%s", line %d\n' % (filename,
                                                     haml_line_number)
            #message[1] was originally the python line with the syntax error
            message[1] = '    %s\n  Python:\n%s' % (haml_line, message[1])
            raise HamlException, ''.join(message)
예제 #3
0
파일: haml.py 프로젝트: kroo/pyhaml
 def reset(self):
     self.depth = 0
     self.html = StringIO()
     self.trim_next = False
     self.globals = { '_haml': self }
예제 #4
0
 def reset(self):
     self.depth = 0
     self.html = StringIO()
     self.trim_next = False
     self.globals = {'_haml': self}