## DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE# Version 2, December 2004## Copyright (C) 2004 Sam Hocevar# 14 rue de Plaisance, 75014 Paris, France# Everyone is permitted to copy and distribute verbatim or modified# copies of this license document, and changing it is allowed as long# as the name is changed.## DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION## 0. You just DO WHAT THE FUCK YOU WANT TO.### This is a template language.# It's a bit different from the others you may encounter, however, in that you have to parse your template manually.# This is a bit of an odd concept for some used to working with more complex template systems at first, but let me explain.## The current syntax is {[block_open]} {{variable}} {[/block_close]}.# Let's say we have a file called foo.plnr that looks like so:## {[block]}# {{variable}}# {[/block]}# {{variable}}## In the code, we'd process this with the following:## from planar import *# tpl = Template('foo.plnr')## for i in range(0, 10):# tpl.block.assign('variable', i)# tpl.block.parse()## tpl.assign('variable', 'outside of the block scope')# tpl.parse()## print tpl## Essentially, you're responsible for parsing it all yourself. There's no logic in the template at all.# Planar is designed to be used as a very thin layer on top of your application.#__all__ = ['Template']MODE_VAR = -1MODE_BLOCK_CONTENTS = -2MODE_BLOCK_OPEN = -3MODE_BLOCK_CLOSE = -4legal = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'class WhatTheShitAreYouDoingException(Exception): passclass MalformedTemplateException(WhatTheShitAreYouDoingException): passclass Block: """This is the basic class for handling blocks. It provides the following functions: from_string(content) - Creates a block out of an already-processed string. You should not use this. assign(var[, value]) - Assigns a value to a variable. var can be a dictionary of var: value pairs. parse([flush_children]) - Parse the block one time. If flush_children is true, the children will not be flushed (this is typically an undesirable action). flush() - Clear the internal buffer of parsed outputs. render() - Return a string representation of the block.""" flush_children = '' def __str__(self): return self.render() def __init__(self, block_id, content = False): self.block_id = block_id self.content = '' self.compiled = None self.fcmd = None self.output = [] self.vars = {} if content: self.from_string(content) def from_string(self, content): self.content = content self.compiled = compile("'''" + content + "'''", '<string>', 'eval') self.fcmd = compile(self.flush_children, '<string>', 'exec') def assign(self, var, val = False): if type(var) == dict: for k in var: self.vars[k] = str(var[k]) elif val or (type(val) != bool and not val): self.vars[str(var)] = str(val) else: return False def parse(self, flush_children = True): try: self.output.append(eval(self.compiled)) except KeyError: raise WhatTheShitAreYouDoingException, "You're missing a variable when you try to parse block '%s'" % self.block_id if flush_children: eval(self.fcmd) def flush(self): self.output = [] def render(self): return "".join(self.output)## somebody is going to have my head for this#def Template(tplfile): """This function parses a file for blocks and variables. This is probably all that you'll want to use here.""" b_id = [] b_cont = [] id = '' mode = False offset = 0 c = p = False o = '' f = open(tplfile) root = Block('root') while c != '': p = c c = f.read(1) if not mode: if c == '{': mode = True id = '' else: o += c else: if mode <= MODE_BLOCK_OPEN: if not c in legal + '/]': o += '{' if mode == MODE_VAR: o += '{' elif mode == MODE_BLOCK_OPEN: o += '[' elif mode == MODE_BLOCK_CLOSE: o += '[/' o += id + c mode = False continue elif c == ']': if mode == MODE_BLOCK_CLOSE: if b_id[len(b_id)-1] == id: # block close exec('root.' + '.'.join(b_id) + ".from_string('''" + o.replace("'", "\\'") + "''')") s = b_id.pop() o = b_cont.pop() o += "''' + self." + id + ".render() + '''" if len(b_id) > 0: exec('root.' + '.'.join(b_id) + '.flush_children += "self.' + s + '.flush(); "') elif len(b_id) == 0: exec('root.flush_children += "self.' + s + '.flush(); "') else: raise MalformedTemplateException, "Blocks '%s' and '%s' are interleaved." % (b_id[len(b_id)-1], id) else: # block open b_id.append(id) try: eval('root.' + '.'.join(b_id)) raise MalformedTemplateException, "Block %s was previously defined in context %s." % (id, '.'.join(b_id[:len(b_id)-1])) except SyntaxError: raise MalformedTemplateException, "Malformed token '%s'" % id except AttributeError: exec('root.' + '.'.join(b_id) + '= Block("' + '.'.join(b_id) + '")') b_cont.append(o) o = '' id = '' mode = True elif c == '/': if id != '': raise MalformedTemplateException, "Malformed token '%s'" % id else: mode = MODE_BLOCK_CLOSE else: id += c elif mode == MODE_VAR: if not c in legal + '}': raise MalformedTemplateException, "Unclosed or malformed token '%s'" % id elif c == '}': o += "''' + self.vars['" + id + "'] + '''" id = '' mode = True else: id += c elif c == '{': mode = MODE_VAR elif c == '[': mode = MODE_BLOCK_OPEN else: if c == '}': if id != '': raise MalformedTemplateException, "Unclosed token '%s'" % id if p == '{': o += p + c mode = False if mode == MODE_BLOCK_OPEN: mode = MODE_BLOCK_CONTENTS else: mode = False root.from_string(o) return root