[Zope] - The beginning of darkness...

Evan Gibson egibson@connect.com.au
Fri, 22 Jan 1999 18:03:53 +1100


I have started down the path to evil...

Mr Bailey made a small dtml object that let us input dates and to call the
dtml while passing in the names we wanted on the objects we went:

<!--#with "_.namespace(varname='start')"-->
  <!--#var date_input-->
<!--#/with-->

This returns us start_year, start_month and start_day. This was very good.

The requirement of using the #with tag was very bad. It looks ugly and
messy. What I _wanted_ was to type:

<!--#var date_input varname='start'-->

and then later on add default values:

<!--#var date_input varname='start' year="1999"-->


With any further keywords being passed into the namespace so the DTML can
find them. This looks neat and makes DTML components useable more like
functions. There is namespace contamination in that you can't use anything
your tag would normally (so don't expect "fmt" to be anything other than 
the format command of dtml!) but I think it's safe enough.

So I started to delve into the not so hidden, but not so looked at code of
DocumentTemplate with the aim of implementing a var2 tag as a test.

I copied DT_Var.py to DT_Var2.py, had DT_Strings.py import it, no problem.

Looking through DT_Var2 I noticed that the main problem is parse_params from 
DT_Utils.py which raises errors on non-valid keywords.
I changed it to, instead, collect and return the invalid keywords if there
are any. If not it returns the normal result. This shouldn't break anything
unless someone was relying on the failure mode.

It doesn't work. 

<!--#var2 date_input--> returns an "Invalid Attribute Name" error on
date_input itself. I put some debug info in to test it, but just kept
getting the same error and not my modified error message, even though I
stopped and started the server. It was as if it was using the old
parse_params even though var2 was being noticed as a valid tag and var2
doesn't even _import_ parse_params and was calling parse_params2.
Very strange.

So, anyone have any ideas why?


Smile. It's been fun messing around in the guts of it all...


--------------------------

def parse_params2(text,
                 result=None,
                 otherparams=None,
                 tag='',
                 unparmre=regex.compile(
                     '\([\0- ]*\([^\0- =\"]+\)\)'),
                 qunparmre=regex.compile(
                     '\([\0- ]*\("[^"]*"\)\)'),
                 parmre=regex.compile(
                     '\([\0- ]*\([^\0- =\"]+\)=\([^\0- =\"]+\)\)'),
                 qparmre=regex.compile(
                     '\([\0- ]*\([^\0- =\"]+\)="\([^"]*\)\"\)'),
                 **parms):

    result=result or {}
    otherparams=otherparams or {}

    if parmre.match(text) >= 0:
        name=lower(parmre.group(2))
        value=parmre.group(3)
        l=len(parmre.group(1))
    elif qparmre.match(text) >= 0:
        name=lower(qparmre.group(2))
        value=qparmre.group(3)
        l=len(qparmre.group(1))
    elif unparmre.match(text) >= 0:
        name=unparmre.group(2)
        l=len(unparmre.group(1))
        if result:
            if parms.has_key(name):
                if parms[name] is None: raise ParseError, (
                    'Attribute %s requires a value' % name, tag)
                result[name]=parms[name]
            else: raise ParseError, (
                'Invalid attribute name, "%s" result:%s' % (name,`result`) , tag)
        else:
            result['']=name
        return apply(parse_params,(text[l:],result),parms)
    elif qunparmre.match(text) >= 0:
        name=qunparmre.group(2)
        l=len(qunparmre.group(1))
        if result: raise ParseError, (
            'Invalid attribute name, "%s" result:%s' % (name,`result`) , tag)
        else: result['']=name
        return apply(parse_params,(text[l:],result),parms)
    else:
        if not text or not strip(text): return result
        raise ParseError, ('invalid parameter: "%s"' % text, tag)
   
    if result.has_key(name):
        p=parms[name]
        if type(p) is not ListType or p:
            raise ParseError, (
                'Duplicate values for attribute "%s"' % name, tag)

    if not parms.has_key(name):
        otherparams[name]=value
        #raise ParseError, (
        #    'Invalid attribute name, "%s"' % name, tag)
    else:
        result[name]=value

    text=strip(text[l:])
    if text: return apply(parse_params,(text,result,otherparams),parms)
    else:
        if otherparams:
                return (result,otherparams)
        else:
                return result


--------------------------

And these are the changes to class Var in DT_Var to make it Var2:


    def __init__(self, args, fmt='s'):
        args = parse_params2(args, name='', lower=1, upper=1, expr='',
                            capitalize=1, spacify=1, null='', fmt='s',
                            size=0, etc='...', thousands_commas=1,
                            html_quote=1, url_quote=1, sql_quote=1,
                            newline_to_br=1)

	self.newnamespace = {}

        if type(args) == type(()) and length(args) == 2:
                self.newnamespace = args[1]
                args = args[0]

        self.args=args

        self.modifiers=tuple(
            map(lambda t: t[1],
                filter(lambda m, args=args, used=args.has_key:
                       used(m[0]) and args[m[0]],
                       modifiers)))

        name, expr = name_param(args,'var',1)

        self.__name__, self.expr = name, expr
        self.fmt = fmt

        if len(args)==1 and fmt=='s':
            if expr is None: expr=name
            else: expr=expr.eval
            self.simple_form=expr,


    def render(self, md):
        md.update(self.newnamespace)

{  and then the rest of the old render... }



--
  Evan ~ThunderFoot~ Gibson    ~ nihil mutatem, omni deletum ~
      May the machines watch over you with loving grace.