[Zope-dev] AttributeError validate using the Visitor pattern

Itai Tavor itai@optusnet.com.au
Mon, 19 Feb 2001 11:33:10 +1100


Hi David,

You posted your questions 3 days ago, so maybe you found a solution 
by now... but this might still be useful to you.

I just implemented a visitor similar to yours, with a few changes. It 
involves the following objects: Order and OrderLineItem. I created a 
Folder named 'displayItemVisitor' in Order containing:

Order.displayItemsVisitor.displayItem (Python Script):
     <params>item</params>
     return item.accept(container, _)

Order.displayItemsVisitor.visitLineItem (DTML Method):
     <td>&dtml-qty;</td>
     <td class="price"><dtml-var "getRetailAmount(qty, 
in_basket_date)" fmt=dollars-and-cents></td>

The 'accept' method of OrderLineItem is:
     <params>visitor, _</params>
     return visitor.visitLineItem(container, _)

And the whole thing gets used in the DTML method that displays an order, using:
     <dtml-in line_items>
       <dtml-var "displayItemsVisitor.displayItem(_['sequence-item'], _)">
     </dtml-in>

Interesting points:

- I'm passing _ explicitly instead of relying on binding. I vaguely 
recall reading something about a problem binding the namespace. It 
might be fixed in the latest Python Scripts, I haven't tried the CVS 
version yet.

- visitLineItem is called in the context of an OrderLineItem, so no 
<dtml-with item> is needed.

- If you wanted the visitor to implement looping over the items 
(which is how the GoF do it) you could easily make something like:

     Order.displayItemsVisitor.displayItems (DTML Method):
         <dtml-in line_items>
           <tr>
             <dtml-var "_['sequence-item'].accept(container, _)">
           </tr>
         </dtml-in>

BTW, I never thought of using a visitor for this until you brought it 
up, so thanks! What I really like about it is that the same 'accept' 
method can be used by multiple visitors, each one implementing a 
different view of the object. So I can have displayItemsVisitor, 
displayItemsCompactVisitor, and displayItemsEditableVisitor, all 
calling item.accept(), and I avoid polluting my OrderLineItem class 
with multiple view methods. OTOH, it requires adding public access 
methods to OrderLineItem, because a view method in OrderLineItem can 
do <dtml-var price>, while the visitor must do <dtml-var 
"getPrice()">. Oh well, there's always a price to pay ;-)

HTH, Itai

R. David Murray wrote:

>OK, having helped me figure out how to work around the bug in accessing
>ZPatterns objects from a catalog, I've got a new challenge for you all.
>
>Now that I've got my list of objects, I want to generate a web page displaying
>them.  The page has the structure of a series of table rows.  Inside each
>row data about a single object is displayed, using a common format but
>with certain differences depending on the type of object.  To implement this,
>I am trying to use the Visitor pattern from the Gang of Four book.
>
>So, I have a Folder displayItemList.  This folder contains (at the moment)
>three methods: displayTable, visitAuthor, and visitBook.  displayTable
>generates the html for the outer table, down to the <tr></tr> tags.
>Between those tags, it calls <dtml-var "accept(me)">, where me is
>this() for the displayTable method, and accept is a pythonscript method
>defined on each of the object type's Specialist.  Each accept method
>is of the form:
>
>return visitor.visitBook(None,_,item=context)
>
>with _ bound to namespace on the bindings tab and 'visitor' being listed
>in the arguments line.
>
>visitBook begins with the line:
>
><dtml-with item>
>
>Trying to display my list, I get an AttributeError on 'validate', and
>ZDebug flags the 'with' line as the error location.  validate
>appears nowhere in my code, so from all I can figure from a certain
>amount of inspection of the source, Zope is looking for this method
>on the DTMLMethod and not finding it.
>
>ZDebug says the namespace stack consists of a single entry, which looks like
>the DTMLMethod itself (visitBook, presumably).  Seems to me the namespace
>stack should be deeper than that.
>
>I've been poking at this for a couple hours now without making any more
>progress, so I'm going to quit for the day and come back to it tomorrow.
>If anybody has any bright ideas, or sees something obvious I'm doing wrong,
>please clue me in.  Thanks!
>
>By the way, I also tried making accept be visitor.visitBook(context,_),
>but that produced the same error and ZDebug could only point to the
>call to accept as the error location.
>
>--RDM
-- 
--
Itai Tavor                      -- "Je sautille, donc je suis."    --
itai@optusnet.com.au            --               - Kermit the Frog --
--                                                                 --
-- "If you haven't got your health, you haven't got anything"      --