is a very simple templating-system. the goals of this 'system' were - easy to use and to learn cheetah and yaptu for example was much to complex to install and learn and did a lot of things i didnt need. - easy to change. blender is going to be used and serviced by python newbies. there is absolutely no chance to have something like complex regexes, evaluation or automatically including the namespaces and the like. - much cooler name than 'yaptu' ;-)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | import types
class Blender:
"""blends values into the given pattern.replace
if neither values nor pattern are defined a default
pattern is being created that prints the values of
the instance in the format [name1: value1, name2 = value2, ...]
"""
def __init__(self, pattern = None, values = None,
startToken = "${", endToken = "}"):
"""initializes the instance with defaultvalues.
that is the start and the end token
"""
self.BlendPattern = pattern
self.BlendValues = values
self.StartToken = startToken
self.EndToken = endToken
def blend(self, values = None, pattern = None):
"""blends the values into the given pattern"""
values = self.getValues(values)
pattern = self.getPattern(pattern, values)
for name in values.keys():
id = self.getTokenName(name)
value = values[name]
pattern = pattern.replace(id, str(value))
return pattern
def getValues(self, values):
""" returns the dictionary of values.
if no values are supplied this
instance is returned as a dictionary."""
if values == None:
if self.BlendValues == None:
values = self.__dict__
else:
values = self.BlendValues
if type(values) != types.DictionaryType:
values = values.__dict__
return values
def getBasePattern(self, values):
"""returns a pattern in the format
[name1: value1, name2: value2, ...]
excluding the instance-attributes of this class
"""
names = values.keys()
names.sort()
result = "["
for name in names:
if name not in ["BlendPattern",
"BlendValues",
"StartToken",
"EndToken"]:
result += name + ": " + self.getTokenName(name) + ", "
return result[0:-2] + "]"
def getPattern(self, pattern, values):
"""returns a pattern for this instance. if no pattern is defined
returns a default-pattern.
"""
if pattern == None:
if self.BlendPattern == None:
pattern = self.getBasePattern(values)
else:
pattern = self.BlendPattern
return pattern
def getTokenName(self, name):
"""returns the tokenname bound by the start and end token.
"""
return self.StartToken + name + self.EndToken
def __str__(self):
return self.blend()
class Person(Blender):
def __init__(self, name, lastName):
Blender.__init__(self)
self.Name = name
self.LastName = lastName
class User(Person):
def __init__(self, id, name, lastName):
Person.__init__(self, name, lastName)
self.ID = id
class Login(Blender):
def __init__(self):
Blender.__init__(self)
self.BlendPattern = """
Hello ${Name} ${LastName}!
Your Userid is: ${ID}.
You are logged into domain ${Domain}.
"""
class UserQuery(Blender):
def __init__(self, values):
pattern = """
SELECT *
FROM User
WHERE
id = ${ID} AND
domain like '${Domain}'
"""
Blender.__init__(self, pattern, values)
if __name__ == "__main__":
p = Person("Robert", "Kuzelj")
print p
u = User("007", "Robert", "Kuzelj")
print u
login = Login()
login.Name = "Robert"
login.LastName = "Kuzelj"
login.ID = 7
login.Domain = "python.org"
print login
sql = "SELECT * from User WHERE id=:{ID} AND domain like ':{Domain}'"
print Blender(sql, {"Domain": "python.org", "ID": "007"}, ":{", "}")
print UserQuery(login)
|
this class was mainly motivated due the fact, that i had a lot of small and medium value-classes i needed to trace. the output was meant to be easy to digest (sometimes the need arose to process the output) and the layout was meant to be easyly changed.
the second force that made me do it (except for the usual suspects ) was the need to have a simple variable replacement-system for dynamic sql-statements.
since my code had to be serviced by relativly new python/OO people i decided not to use cheetah or any other templatingsystem. cause every lib a looked at was - either hard to install - hard to learn - almost everytime hard to change (say impossible) - did stuff i did not need (complex regexes) - or did all the things above i am convinced that it is ideally suited to peoble with modest python knowhow beginning to explore the dynamic nature of python.
EXTENSIONS one thing i was thinkink about was to make blender even more 'declarative' by using the docstring of the declaring class.
something similar to this would then be possible
class UserQuery(Blender): """ SELECT * FROM User WHERE id = ${ID} AND domain like '${Domain}' """
no definition of an constructor no calling of baseconstrutors... on the other hand this would make the inner workings of blender harder to grasp and simplicity was one of the major goals.
advantage over % ? I'm not seeing the advantage over python's own % operator. If you used %( and )s for the "start and end tokens", the % operator will easily interpolate in a dictionary of replacements.
gives
and it's already available in all python programs.
oops,
this was defenitly a case of rtfm on my side. didnt know, that this is possible.
so the only advantage might be to have a automatic representation of an object (not very much i admit)
ciao robertj