summaryrefslogtreecommitdiff
path: root/docs/users_guide_2_src/13a_precompiledTemplateModules.txt
blob: 5b0f978577ab5ee4f0605647f9162868affcb759 (plain)
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
A look inside precompiled template modules
==========================================

..
    :label: howWorks.pyTrivia

When debugging a template, it's useful to compile it with "cheetah compile"
and then inspect the resulting Python module.  This will often clear up whether
Cheetah misinterpreted your intent.  You can do this even if you don't intend to
use the precompiled templates in production.  It's also a good way to learn how
Cheetah works.  Simply make a throwaway template definition containing only one
placeholder or directive, compile it with "cheetah compile", and see what
Python code Cheetah generated.

However, precompiled template modules can be a bit cryptic to read unless you
have a bit of background information.  Let's look at an example.  Put the
following into /tmp/x.tmpl (or any other file) and run "cheetah compile" on
it::

    The number is $Test.unittest.main.
    #set mood = "lucky"
    I'm feeling $lucky.

Open the resulting /tmp/x.py in your favorite text editor.  You'll see a class
with the same name as the module::

    class x(Template):

This template class contains a method ``.respond()``::

    def respond(self, trans=None):
        ## CHEETAH: main method generated for this template
        if (not trans and not self._CHEETAH__isBuffering and 
            not callable(self.transaction)):
            trans = self.transaction # is None unless self.awake() was called
        if not trans:
            trans = DummyTransaction()
            _dummyTrans = True
        else: _dummyTrans = False
        write = trans.response().write
        SL = self._CHEETAH__searchList
        _filter = self._CHEETAH__currentFilter
        
        ########################################
        ## START - generated method body

        
        write('The number is ')
        _v = VFFSL(SL,"Test.unittest.main",True) 
        # '$Test.unittest.main' on line 1, col 15
        if _v is not None: write(_filter(_v, rawExpr='$Test.unittest.main')) 
        # from line 1, col 15.
        write('.\n')
        mood = "lucky"
        write("I'm feeling ")
        _v = VFFSL(SL,"lucky",True) # '$lucky' on line 3, col 13
        if _v is not None: write(_filter(_v, rawExpr='$lucky')) 
        # from line 3, col 13.
        write('.\n') 
        
        ########################################
        ## END - generated method body
        
        return _dummyTrans and trans.response().getvalue() or ""

This becomes clearer when we scroll up to see some important imports and
global variables::

    from Cheetah.Template import Template
    from Cheetah.DummyTransaction import DummyTransaction
    from Cheetah.NameMapper import NotFound, valueFromFrameOrSearchList
    VFFSL=valueFromFrameOrSearchList
    __CHEETAH_version__ = '2.0rc6'
    __CHEETAH_src__ = 'x.tmpl'

The actual code will differ slightly depending on your Cheetah version.  Also,
we've split some long lines to make this page printer-friendly.  

Placeholder lookup is handled by ``VFFSL``, which is really the
``Cheetah.NameMapper.valueFromFrameOrSearchList`` function or its equivalent
in Cheetah/_namemapper.c.  

``trans`` and ``write()`` are Webware compatibility features.  Normally 
``trans`` is not specified and Cheetah creates a ``DummyTransaction``
instance.  ``write()`` is a shortcut for ``trans.response().write()``,
which concatenates the output to an internal buffer.  The method returns
the result: ``trans.response().getvalue()``.  You might assume from 
``.getvalue()`` that Cheetah uses ``StringIO`` internally, but you'd be wrong.
Cheetah *used* to use ``StringIO`` but now it uses a list and ``str.join()``.
The ``.getvalue()`` name is retained for backward compatibility.

If this template is part of a Webware site and the user enters its URL, Webware
calls ``.respond()`` with a live Webware transaction.  In this case,
``write()`` writes the output directly to Webware's output stream.  (Or to
a Webware buffer, but that's not our concern.)  There's nothing to return
because the output has already been written, so the method returns the empty
string.  That way if it accidentally gets concatenated to the output, no harm
will be done.

You can write your own transaction class to support non-Webware output 
streaming, but Cheetah currently comes with no examples of this.  Ask on
the mailing list if you need help with it.

Global variables and class attributes defined by Cheetah have a 
``_CHEETAH_`` prefix.  Instance attributes defined by Cheetah have a
``__CHEETAH__`` prefix (two trailing underscores).  You should normally
never write to these but you can read them if desired; many are
self-explanatory.  One such attribute is ``._CHEETAH__searchList``.  This
is the actual search List ``VFFSL()`` will consult for placeholder lookups.