Placeholders can get far more complicated than that. This example shows what
kind of code the various NameMapper features produce. The formulas are
taken from Cheetah's test suite, in the
Cheetah.Tests.SyntaxAndOutput.Placeholders
class.
1 placeholder: $aStr 2 placeholders: $aStr $anInt 2 placeholders, back-to-back: $aStr$anInt 1 placeholder enclosed in {}: ${aStr} 1 escaped placeholder: \$var func placeholder - with (): $aFunc() func placeholder - with (int): $aFunc(1234) func placeholder - with (string): $aFunc('aoeu') func placeholder - with ('''\nstring'\n'''): $aFunc('''\naoeu'\n''') func placeholder - with (string*int): $aFunc('aoeu'*2) func placeholder - with (int*float): $aFunc(2*2.0) Python builtin values: $None $True $False func placeholder - with ($arg=float): $aFunc($arg=4.0) deeply nested argstring: $aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) ): function with None: $aFunc(None) autocalling: $aFunc! $aFunc(). nested autocalling: $aFunc($aFunc). list subscription: $aList[0] list slicing: $aList[:2] list slicing and subcription combined: $aList[:2][0] dict - NameMapper style: $aDict.one dict - Python style: $aDict['one'] dict combined with autocalled string method: $aDict.one.upper dict combined with string method: $aDict.one.upper() nested dict - NameMapper style: $aDict.nestedDict.two nested dict - Python style: $aDict['nestedDict']['two'] nested dict - alternating style: $aDict['nestedDict'].two nested dict - NameMapper style + method: $aDict.nestedDict.two.upper nested dict - alternating style + method: $aDict['nestedDict'].two.upper nested dict - NameMapper style + method + slice: $aDict.nestedDict.two.upper[:4] nested dict - Python style, variable key: $aDict[$anObj.meth('nestedDict')].two object method: $anObj.meth1 object method + complex slice: $anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ] very complex slice: $( anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ] )
We'll need a big program to set up the placeholder values. Here it is:
#!/usr/bin/env python from ComplexExample import ComplexExample try: # Python >= 2.2.1 True, False except NameError: # Older Python True, False = (1==1), (1==0) class DummyClass: _called = False def __str__(self): return 'object' def meth(self, arg="arff"): return str(arg) def meth1(self, arg="doo"): return arg def meth2(self, arg1="a1", arg2="a2"): return str(arg1) + str(arg2) def callIt(self, arg=1234): self._called = True self._callArg = arg def dummyFunc(arg="Scooby"): return arg defaultTestNameSpace = { 'aStr':'blarg', 'anInt':1, 'aFloat':1.5, 'aList': ['item0','item1','item2'], 'aDict': {'one':'item1', 'two':'item2', 'nestedDict':{1:'nestedItem1', 'two':'nestedItem2' }, 'nestedFunc':dummyFunc, }, 'aFunc': dummyFunc, 'anObj': DummyClass(), 'aMeth': DummyClass().meth1, } print ComplexExample( searchList=[defaultTestNameSpace] )
Here's the output:
1 placeholder: blarg 2 placeholders: blarg 1 2 placeholders, back-to-back: blarg1 1 placeholder enclosed in {}: blarg 1 escaped placeholder: $var func placeholder - with (): Scooby func placeholder - with (int): 1234 func placeholder - with (string): aoeu func placeholder - with ('''\nstring'\n'''): aoeu' func placeholder - with (string*int): aoeuaoeu func placeholder - with (int*float): 4.0 Python builtin values: 1 0 func placeholder - with ($arg=float): 4.0 deeply nested argstring: 1: function with None: autocalling: Scooby! Scooby. nested autocalling: Scooby. list subscription: item0 list slicing: ['item0', 'item1'] list slicing and subcription combined: item0 dict - NameMapper style: item1 dict - Python style: item1 dict combined with autocalled string method: ITEM1 dict combined with string method: ITEM1 nested dict - NameMapper style: nestedItem2 nested dict - Python style: nestedItem2 nested dict - alternating style: nestedItem2 nested dict - NameMapper style + method: NESTEDITEM2 nested dict - alternating style + method: NESTEDITEM2 nested dict - NameMapper style + method + slice: NEST nested dict - Python style, variable key: nestedItem2 object method: doo object method + complex slice: do very complex slice: do
And here - tada! - is the generated module.
To save space, I've included only the lines containing the write
calls.
The rest of the module is the same as in the first example, chapter
2.1. I've split some of the lines to make them fit on
the page.
1 write('1 placeholder: ') 2 write(filter(VFS(SL,"aStr",1))) # generated from '$aStr' at line 1, col 16. 3 write('\n2 placeholders: ') 4 write(filter(VFS(SL,"aStr",1))) # generated from '$aStr' at line 2, col 17. 5 write(' ') 6 write(filter(VFS(SL,"anInt",1))) # generated from '$anInt' at line 2, col 23. 7 write('\n2 placeholders, back-to-back: ') 8 write(filter(VFS(SL,"aStr",1))) # generated from '$aStr' at line 3, col 31. 9 write(filter(VFS(SL,"anInt",1))) # generated from '$anInt' at line 3, col 36. 10 write('\n1 placeholder enclosed in {}: ') 11 write(filter(VFS(SL,"aStr",1))) # generated from '${aStr}' at line 4, # col 31. 12 write('\n1 escaped placeholder: $var\nfunc placeholder - with (): ') 13 write(filter(VFS(SL,"aFunc",0)())) # generated from '$aFunc()' at line 6, # col 29. 14 write('\nfunc placeholder - with (int): ') 15 write(filter(VFS(SL,"aFunc",0)(1234))) # generated from '$aFunc(1234)' at # line 7, col 32. 16 write('\nfunc placeholder - with (string): ') 17 write(filter(VFS(SL,"aFunc",0)('aoeu'))) # generated from "$aFunc('aoeu')" # at line 8, col 35. 18 write("\nfunc placeholder - with ('''\\nstring'\\n'''): ") 19 write(filter(VFS(SL,"aFunc",0)('''\naoeu'\n'''))) # generated from # "$aFunc('''\\naoeu'\\n''')" at line 9, col 46. 20 write('\nfunc placeholder - with (string*int): ') 21 write(filter(VFS(SL,"aFunc",0)('aoeu'*2))) # generated from # "$aFunc('aoeu'*2)" at line 10, col 39. 22 write('\nfunc placeholder - with (int*float): ') 23 write(filter(VFS(SL,"aFunc",0)(2*2.0))) # generated from '$aFunc(2*2.0)' # at line 11, col 38. 24 write('\nPython builtin values: ') 25 write(filter(None)) # generated from '$None' at line 12, col 24. 26 write(' ') 27 write(filter(True)) # generated from '$True' at line 12, col 30. 28 write(' ') 29 write(filter(False)) # generated from '$False' at line 12, col 36. 30 write('\nfunc placeholder - with ($arg=float): ') 31 write(filter(VFS(SL,"aFunc",0)(arg=4.0))) # generated from # '$aFunc($arg=4.0)' at line 13, col 40. 32 write('\ndeeply nested argstring: ') 33 write(filter(VFS(SL,"aFunc",0)( arg = VFS(SL,"aMeth",0)( arg = VFS(SL,"aFunc",0)( 1 ) ) ))) # generated from '$aFunc( $arg = $aMeth( $arg = $aFunc( 1 ) ) )' # at line 14, col 26. 34 write(':\nfunction with None: ') 35 write(filter(VFS(SL,"aFunc",0)(None))) # generated from '$aFunc(None)' at # line 15, col 21. 36 write('\nautocalling: ') 37 write(filter(VFS(SL,"aFunc",1))) # generated from '$aFunc' at line 16, # col 14. 38 write('! ') 39 write(filter(VFS(SL,"aFunc",0)())) # generated from '$aFunc()' at line 16, # col 22.
40 write('.\nnested autocalling: ') 41 write(filter(VFS(SL,"aFunc",0)(VFS(SL,"aFunc",1)))) # generated from # '$aFunc($aFunc)' at line 17, col 21. 42 write('.\nlist subscription: ') 43 write(filter(VFS(SL,"aList",1)[0])) # generated from '$aList[0]' at line # 18, col 20. 44 write('\nlist slicing: ') 45 write(filter(VFS(SL,"aList",1)[:2])) # generated from '$aList[:2]' at # line 19, col 15. 46 write('\nlist slicing and subcription combined: ') 47 write(filter(VFS(SL,"aList",1)[:2][0])) # generated from '$aList[:2][0]' # at line 20, col 40. 48 write('\ndict - NameMapper style: ') 49 write(filter(VFS(SL,"aDict.one",1))) # generated from '$aDict.one' at line # 21, col 26. 50 write('\ndict - Python style: ') 51 write(filter(VFS(SL,"aDict",1)['one'])) # generated from "$aDict['one']" # at line 22, col 22. 52 write('\ndict combined with autocalled string method: ') 53 write(filter(VFS(SL,"aDict.one.upper",1))) # generated from # '$aDict.one.upper' at line 23, col 46. 54 write('\ndict combined with string method: ') 55 write(filter(VFN(VFS(SL,"aDict.one",1),"upper",0)())) # generated from # '$aDict.one.upper()' at line 24, col 35. 56 write('\nnested dict - NameMapper style: ') 57 write(filter(VFS(SL,"aDict.nestedDict.two",1))) # generated from # '$aDict.nestedDict.two' at line 25, col 33. 58 write('\nnested dict - Python style: ') 59 write(filter(VFS(SL,"aDict",1)['nestedDict']['two'])) # generated from # "$aDict['nestedDict']['two']" at line 26, col 29. 60 write('\nnested dict - alternating style: ') 61 write(filter(VFN(VFS(SL,"aDict",1)['nestedDict'],"two",1))) # generated # from "$aDict['nestedDict'].two" at line 27, col 34. 62 write('\nnested dict - NameMapper style + method: ') 63 write(filter(VFS(SL,"aDict.nestedDict.two.upper",1))) # generated from # '$aDict.nestedDict.two.upper' at line 28, col 42. 64 write('\nnested dict - alternating style + method: ') 65 write(filter(VFN(VFS(SL,"aDict",1)['nestedDict'],"two.upper",1))) # generated from "$aDict['nestedDict'].two.upper" at line 29, col 43. 66 write('\nnested dict - NameMapper style + method + slice: ')
67 write(filter(VFN(VFS(SL,"aDict.nestedDict.two",1),"upper",1)[:4])) # generated from '$aDict.nestedDict.two.upper[:4]' at line 30, col 50. 68 write('\nnested dict - Python style, variable key: ') 69 write(filter(VFN(VFS(SL,"aDict",1) [VFN(VFS(SL,"anObj",1),"meth",0)('nestedDict')],"two",1))) # generated from "$aDict[$anObj.meth('nestedDict')].two" at line 31, # col 43. 70 write('\nobject method: ') 71 write(filter(VFS(SL,"anObj.meth1",1))) # generated from '$anObj.meth1' at # line 32, col 16. 72 write('\nobject method + complex slice: ') 73 write(filter(VFN(VFS(SL,"anObj",1),"meth1",1) [0: ((4/4*2)*2)/VFN(VFS(SL,"anObj",1),"meth1",0)(2) ])) # generated from '$anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ]' # at line 33, col 32. 74 write('\nvery complex slice: ') 75 write(filter(VFN(VFS(SL,"anObj",1),"meth1",1) [0: ((4/4*2)*2)/VFN(VFS(SL,"anObj",1),"meth1",0)(2) ] )) # generated from '$( anObj.meth1[0: ((4/4*2)*2)/$anObj.meth1(2) ] )' # at line 34, col 21. 76 write('\n')
For each placeholder lookup, the the innermost level of nesting is a VFS
call, which looks up the first (leftmost) placeholder component in the
searchList. This is wrapped by zero or more VFN
calls, which perform
Universal Dotted Notation lookup on the next dotted component of the
placeholder, looking for an attribute or key by that name within the previous
object (not in the searchList). Autocalling is performed by VFS
and
VFN
: that's the reason for their third argument.
Explicit function/method arguments, subscripts and keys (which are all expressions) are left unchanged, besides expanding any embedded $placeholders in them. This means they must result in valid Python expressions, following the standard Python quoting rules.
Built-in Python values (None
, True
and False
) are
converted to filter(None)
, etc. They use normal Python variable
lookup rather than VFS
. (Cheetah emulates True
and False
using global variables for Python < 2.2.1, when they weren't builtins yet.)