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)
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)
def reset(self): self.depth = 0 self.html = StringIO() self.trim_next = False self.globals = { '_haml': self }
def reset(self): self.depth = 0 self.html = StringIO() self.trim_next = False self.globals = {'_haml': self}