Created PlowPlate, the successor to Plow2. Inserted docstrings. Reformatted
indentation to all spaces. Changed names of methods and attributes to
lowercaseUppercase convention and made all attributes private (under protest).
'block' now refers to the block body and 'blockName' to the block name,
but the block() method remains the same. extract() method renamed to
findBlock(). unknowns_hook() renamed to valueForUnknownKey().
Implemented valueForKey()--it just looks up the value in the UserDict.
Passes the plowtest.py test suite.
Available for your downloading pleasure at
On Tue, Apr 24, 2001 at 05:58:38PM -0400, Chuck Esterbrook wrote:
> def setValueForKeyFunc(self, func):
> self._valueForKeyFunc = func
> def valueForKey(self, key, default=NoDefault):
> Returns the value for the given key. If the key does not exist,
> default is returned if specified or an exception is thrown.
> This method relies on "valueForKey" look up function that has
> been previously set via setValueForKeyFunc.
> return self._valueForKeyFunc(key, default)
What is the purpose of _valueForKeyFunc? If somebody wants to change the
implementation, they can override the method or use a mixin.
Did not implement the 'default' argument. If the key is not found,
valueForUnknownKey(self, key) is called. The caller should be setting
every value in the template, anyway, and explicitly setting it to "" if
that is what is desired.
> Once you do this, do you even need to inherit from UserDict?
I like having one official dictionary where all the plug-in values are
explicitly set. Thus, if you know your template has 9 keys, you can
quickly verify that 9 values are being set, and what they're being set to.
Although I can see the point of NamedValueAccess also. I implemented
valueForKey, so that a subclass can override it for NameValueAccess.
(Although it would also have to override the constructor to specify
> Methods like distribution(self) are not
> obvious to me.
unknowns() I added because Sasa needed it. placeholders() is useful for
debugging -- to quickly get a list of all the keys a template needs.
distribution() I threw in just for trivia information.
> ** I think class 'Plow' should be renamed to 'Template'.
That would conflict with an ultra-generic term and other
Renamed to PlowPlate. Is that better? Then all our templating classes
can be named *Plate.
Unsure what to do about 'path'. I am loth to add prependPath(),
appendPath(), removeOnePathElement(), etc., when list assignment
works so well. But an application should have only one set of
paths, which it can specify in a subclass. Or the application can
always pass absolute pathnames.
> ** The placeholder and block patterns should also be features of the Plow
> instance. If not set, then they are taken from the module. e.g.,
Good point. Will do later.
Ugh (using a method when attribute assignment will do), but not worth
> ** I think we might as well make the left and right delimiters REs to begin
> with as well, although I don't know if that point is important or not.
Perhaps we can do this later. valueForUnknownKey at least requires the literal
Perhaps they should be set as a triplet:
def setPlaceholderPolicy(placeholderRE, left, right):
with the understanding that placeholderRE must match the placeholder *and its
delimeters* but not the escaped form, and 'left' and 'right' are used only
to reconstruct the placeholder-with-delimeters and not for parsing.
> ** What exactly is clear_rows() for?
Nothing important. See below for its purpose. '_rows' is a private
attribute I don't want the caller to know about.
> Actually the whole "row" thing eludes me a bit.
It's only for objects which are for-blocks. Normally you parse by
calling str(p) which calls p.sub(), which returns the result without
modifying anything. However, in a for-block, you need to generate the
rows one by one and you need to store them someplace. Voila the
row() method and '_rows'.
str(p) checks '_rows' to see if it's empty. If it is, you get the
normal behavior. But if not, it concatenates the list of rows and
returns that instead, and doesn't call sub().
Thus, why you may want a clear_rows() method. Say you want to reuse
the same template but with a different page of row data. Or say you've
already called row() and now you want to convert the object back into
a normal template (so that __str__ will start calling sub() again).
> ** There is test code in both Plow2.py and plowtest.py. Is the first no
> longer relevant? Maybe it can be axed.
Yes, I meant to remove it.
> ** I recommend pyunit for regression tests.
> I wouldn't use it at this point, primarily because of lack of doc strings.
> I don't know if I'm unique in that regard, but if the interface isn't clear
> and the doc strings aren't there, I have a hard time working up to using
> something in my production work. I guess that even reflects in my review,
> because if I had tried harder, I'm sure I could have gotten to the bottom
> of rows, distribution() etc. I just think it's so much easier if the author
> can throw a few plain English, non-implementation-ridden statements my way.
Did you read the README, or what made the README unclear? I moved the
explanations and usage examples from the module docstring to the README
because you or somebody suggested it. As for not enough documentation,
I was afraid of the opposite, that there was too much documentation and
people wouldn't want to read it all, since the README does get pretty detailed
(so I thought).
I'll be out of town tonight through Monday, so I won't be able to work
on it much more till next week.
-Mike (Iron) Orr, iron@... (if mail problems: mso@...)
http://mso.oz.net/ English * Esperanto * Russkiy * Deutsch * Espan~ol