Dear Sam,
here is a copy of my cheetahPages file to look at.  To use it in a
servlet I usually write my servlets like this:

from cheetahPages import cheetahPage

class servlet(cheetahPage):
    def writeTemplate(self):
        self.write(self.cheetahTemplate('template.html').render())


My cheetahPages files does a couple of things for me.  First it creates
a cheetahTemplate object which takes care pasisng the correct
searchList to the template, which is usually passed to render as an
argument.    The cheetahPage class does all the real work.  It takes a
template (which can be named anything you want, I always use .html
instead of the conventional .tmpl because Dreamweaver deals with it
easier) and compiles the template into a compiled template and loads
the template.  If the template is already compiled, it checks the date
of the compiled template against template file and recompiles if needed
(this is a little weak, because my original code, commented out, was
compiling too often), and reloads the compiled template if needed. 
Like I said this is only one way to use cheetah, but it really works
well for me.  You'll notice the templateRoot function.  This returns
the relative location of the templates folder (assumed to be the same
as the servlet if it si not overwritten).  If templateRoot is present
it looks there for the template files, this helps keep all my templates
in one nice little package again separate from my servlets.  Hope this
helps.

Jose


> -------- Original Message --------
> Subject: Re: [Webware-discuss] several questions about webware
> From: "Sam Nilsson" <[EMAIL PROTECTED]>
> Date: Mon, January 31, 2005 12:24 am
> To: "jose" <[EMAIL PROTECTED]>
>
> jose wrote:
> > I find that this keeps my presentation code
> > nicely separated from my program code, and keeps the templates very clean.
> > I would be happy to share my cheetahPage with anyone if there is interest.
> >
> > Jose
>
> Hi Jose,
>
> I would appreciate taking a look at your cheetahPage!
>
> - Sam Nilsson
from WebKit.Page import Page
from Cheetah.CheetahWrapper import CheetahWrapper
import os, re, time


__Version__ = 1.1
__Author__ = 'Jose Galvez, MD'

class cheetahTemplate:
    '''
    Cheetah Template object
    
    The purpose of this class to represent a cheetah template.  Once the
    template is created the object has a single method, render which takes
    as an optional argument the searchList and returns the rendered html
    
    This class it very tightly inigrated with cheetahPage
    
    @author: Jose Galvez
    '''
    def __init__(self, base, mod):
        '''
        cheetahTemplate constructor
        
        @param base: The parent or base object, used as the base searchList
        @param mod: The compiled cheetah module as returned by cheetahPage._loadTemplate
        '''
        self.base = base
        self.modName = mod.__name__.split('.').pop()
        self.mod = getattr(mod, self.modName)
        
    def render(self, searchList=False):
        '''
        The only exposed method that a template may have
        
        @param searchList: Optional paramiter, the searchList is used by cheetah
        to find varaibles for substitution
        
        @return: rendered html as string
        '''
        tmpl = self.mod()
        # now deal with the search list
        # did we supply a search list? if so deal with it, if not pass
        # an empty one
        if not searchList:
            searchList = []
        else:
            if type(searchList) == tuple:
                searchList = list(searchList)
            elif type(searchList) == dict:
                searchList = [searchList]
            elif type(searchList) == str:
                raise 'Can not pass a string as a searchList, try using Vars() to accomplish this'
        searchList.append(self.base)
            
        # searchList manipulation to move the various parts around
        # so that they are searched in the correct order
        
        # dump original searchList into a holding pen using pop to emply
        # out the searchList
        orgSl = [] 
        for i in range(len(tmpl.searchList())):
            orgSl.append(tmpl.searchList().pop(0))
        
        # add our own stuff the searchList
        tmpl.searchList().extend(searchList)
        # add the original searchList to the end of the list
        tmpl.searchList().extend(orgSl)
        
        # end searchList manipulation
        
        #return the compiled template
        return tmpl.respond()

class cheetahPage(Page):
    '''
    site page for cheetah templates
    
        1. compileTemplate(string)
            compile the template if it has changed since the last time 
            it was compiled and return a cheetahTemplate object
            
        2. Important to note that basetemplates are not reloaded very
        effeciantly, this is a limitation of webware not cheetah
    '''
    
    def __init__(self):
        Page.__init__(self)
        # Init the cheetah cache object
        self.dependancyCheck = re.compile('#from (.*) import (?P<dependancy>.*)')
        self.cheetahCache = {}
        self.reloadList = []
        
    def _respond(self, transaction):
        """
        Handles actions if an _action_ field is defined, otherwise
        invokes writeHTML().
        Invoked by both respondToGet() and respondToPost().
        """
        req = transaction.request()
        # Check for actions
        for action in self.actions():
            # note the added new action do_ taken form java stuff
            if ((req.queryString().find('do_%s' % action) != -1) or 
            (req.queryString().find('action_%s' % action) != -1) or 
            (req.queryString().find('_action_%s' % action) != -1)):
                if self._actionSet().has_key(action):
                    self.handleAction(action)
                    return
            elif req.hasField('do_%s' % action):
                if self._actionSet().has_key(action):
                    self.handleAction(action)
                    return
            elif req.hasField('_action_%s' % action) or \
               req.field('_action_', None) == action or \
               (req.hasField('_action_%s.x' % action) and \
                req.hasField('_action_%s.y' % action)):
                if self._actionSet().has_key(action):
                    self.handleAction(action)
                    return
        
        self.writeHTML()
        
    def hr(self, length = 90):
        '''
        writes a line on a web page set at 90%
        xhtml complient now
        '''
        self.writeln('<hr width="%s" />' % (str(length) + '%',))
    
    def br(self):
        '''
        writes a <BR> tag
        xhtml complient now
        '''
        self.writeln('<BR />')

    def preAction(self, actionName):
        '''
        preAction is not needed any longer
        '''
        pass
        
    def postAction(self, actionName):
        '''
        postAction is not needed any longer
        '''
        pass

    def writeHTML(self):
        '''
        divert the writeHTML from writeContent to writeTemplate
        my personal choice this can easily be changed back to 
        something else or removed entilry
        '''
        self.writeTemplate()
    
    def writeTemplate(self):
        '''
        default page content, this methode needs to be overwritten 
        to produce the default page content
        '''
        self.writeln('Sorry this page does not have any default Content')

    def templateRoot(self):
        '''
        Defines the template root for a site if you need to
        this is generally done best in a "site.py" page for
        general importation
        If not overwritten it will be assumed that the template root
        is at the same level as the servlet.

        Return string template root, this should be either a relative location to
        the servlets, or an absolute location
        '''
        return 0
    
    def cheetahTemplate(self, template, g=False):
        '''
            1. compiles a tempalte and returns a compiled template object
        
            2. optionally provide the global namespace otherwise an error will
            be generated
        '''
        self._compileTemplate(template)
        modName = os.path.splitext(template)[0]
        mod = self._loadTemplate(modName, g=g)
        chT = cheetahTemplate(self, mod)
        return chT
    
    def _loadTemplate(self, template, g=False):
        '''
        Loads a given module as well as handeling whether the template
        modules needs to be reloaded
        
        @param tempalte: name of the compiled template
        @type template: string
        
        @parm g: globals - Globals must be passed to the function to ensure that the
        template is loaded into the correct namespace
        @type g: globals dict
        '''
        
        if not g:
            # lets try to make up my own globals variable, this might break in 
            # the next version of python, if so I'll have to figure something else out
            try:
                g = {'__name__':self.__module__}
            except:
                raise 'You must pass globals() to the loadTemplate function for it to work'
                
        if self.templateRoot():
            mod =  __import__(self.templateRoot()+'.'+template, g, {}, [template])
        else:
            mod =  __import__(template, g, {}, [template])
        self._reloadTemplate(mod)
        return mod
    
    def _templatePath(self, t):
        '''
        internal method used by template to get and deal with
        template root paths
        uses templateRoot to define template locations if defined
        
        @param t: template file
        @type: string
        
        @return: fullTemplatePath - full path to template file
        @return: templateName  -  name of compiled template
        '''
        # First get cheetah root
        if self.templateRoot():
            # Template paths must be relative to the servlet 
            # using them otherwise return an error

            # first lets figure out what the real location of the template root is
            chRoot = self.serverSidePath(self.templateRoot())
            if not os.path.exists(chRoot):
                # the relative path does not exsist
                raise 'Sorry the path %s does not exsist' % chRoot
            fullTemplatePath = os.path.join(chRoot, t)
        else:
            fullTemplatePath = self.serverSidePath(t)
        templateName, templateExt = os.path.splitext(t)
        return fullTemplatePath, templateName, templateExt[1:]
        
    def _reloadTemplate(self, mod):
        '''
        reloads a compiled template if it marked for reloading
        '''
        reload(mod)
        modName = mod.__name__.split('.').pop()
        if modName in self.reloadList:
            self.reloadList.remove(modName)
            reload(mod)
    
    def _compileTemplate(self, t):
        '''
        compiles the given template into a compiled template
        Only compiles template if it has changed otherise it leaves it along
        
        @param t: template
        @type t: string
        '''
        # compile only if we need too
        fullTemplatePath, templateName, templateExt = self._templatePath(t)
        fullCompiledTemplatePath = os.path.splitext(fullTemplatePath)[0]+'.py'
        mtime = os.path.getmtime(fullTemplatePath)
        cachedMtime = self.cheetahCache.get(templateName, False)
        fullCompiledTemplatePathExists = os.path.exists(fullCompiledTemplatePath)
        
        if ((fullCompiledTemplatePathExists) and (not cachedMtime) and (not self.application().server().config()['AutoReload'])):
            # if the compiled template exsits and we just don't have a record of it in our
            # cheetahCache, then don't worry assuming AutoReload is set to 0, just add it, this assums that the compiled 
            # tempalte is actaully the correct one, if this is not correct delete it
            # and let the system rebuild it form scratch
            
            self.cheetahCache[templateName] = mtime
            
        elif ((mtime != cachedMtime) or (not fullCompiledTemplatePathExists)):
            # check to make sure __init__ exsists
            if not os.path.exists(os.path.join(os.path.dirname(fullTemplatePath), '__init__.py')):
                initFile = file(os.path.join(os.path.dirname(fullTemplatePath), '__init__.py'), 'w')
                initFile.write('# __init__ #')
                initFile.close()
                
            # open template and see if there any any dependancies that we need to compile first
            tmpl = file(fullTemplatePath)
            tLn = tmpl.readline()
            while tLn[0] == '#':  # for l in range(10): #read only first 10 line
                #tLn = tmpl.readline()
                dependanceCheck = self.dependancyCheck.match(tLn)
                if dependanceCheck:
                    dependancy = dependanceCheck.groupdict().get('dependancy', False)
                    if dependancy:
                        # we may be loading something that we don't have to compile
                        try:
                            self._compileTemplate(dependancy+'.'+templateExt)
                        except:
                            # nothing to do I just don't want an error to be raised
                            pass
                tLn = tmpl.readline()
            tmpl.close()
            
                
            # insert the mtime into the template cache
            self.cheetahCache[templateName] = mtime
            
            # insert the template in to the reload variable
            self.reloadList.append(templateName)
            
            baseTemplateDir = os.path.dirname(fullTemplatePath)
            
            cheetahOptions = ['cheetahPage',
                                  'compile',
                                  '--idir', baseTemplateDir,
                                  '--odir', baseTemplateDir,
                                  '--iext', templateExt,
                                  '--nobackup',
                                  templateName]
            # actually compile the template
            CheetahWrapper().main(cheetahOptions)
    

Reply via email to