Warning: long and winding posting ahead. It's a really important
issue, though.
It took some time for me to realize that the fix I committed for bug
617 [1] had some unintended effects, and we'll need to fix macro
handler lookup again for 1.7, and possibly 1.6.4.
[1]
http://helma.org/bugs/show_bug.cgi?id=617
The problem is that the fix was intended to only change macro handler
lookup in the parent objects of the this-object, but in fact it also
affects the this-object itself. Thus, in helma 1.6.3 and svn trunk, a
macro handler only resolves to the this-object if the handler name is
either "this" or the exact prototype name of the this-object.
Inherited prototypes are not resolved to the this-object, which broke
at least a few places in Gobi, and probably other apps to.
So one more effort is needed to fix this problem deeply, and in the
process define macro handler resolution (behavior has always been
foggy, to say the least).
I start with describing the old (pre-1.6.3) behavior, then the current
(1.6.3/trunk) behavior, and then what options we have to get
consistent and predictable behavior in the future.
In releases propr to 1.6.3, macro handlers were always resolved
against the this-object and all parent objects of the this object,
including inherited prototype names in the process. Only then did the
code check res.handlers for registered macro handlers (pre-populated
with the objects in the request path).
The (undocumented) rationale for this behavior was that it should be
possible to (temporarily) override res.handlers when calling a macro
on an object not in the request path, and have it behave like it was
in the request path (including its parent objects).
As I said, the behaviour in 1.6.3 and svn trunk is to only resolve
against the this-object and its parents if the prototype name matches
exactly, which is a kind of weird middle-of-the-road behaviour. It
takes something of the old "implicit-this-object-as-handler" idea but
only implements it half-ways. I don't think it's a solution we should
stick with.
Finally, the options we have for fixing this.
The first one, which I'll call the raw-and-simple solution, is to drop
the implicit-this-object-as-handler idea altogether and only resolve
this-macros against the this-object, everything else against
res.handlers. This would be simple and transparent behaviour. The
downside of this solution would be that existing applications would
have to be rewritten (replacing prototype names with "this" where
skins are invoked on objects not in the request path). It would also
make it harder to expose the parent objects of the this-object to
skins where this is really required. I don't think this would be the
case too often.
The second, which I'll call the multi-layered approach, is to break up
the macro resolver process further: First resolve against the this-
object, taking into consideration its inherited prototype names. Than
resolve against res.handlers, which by default contains the request
path keyed by prototype names. Finally, resolve against the this-
objects's parent chain, again including inherited prototype names.
This would make the algorithm a bit more complex, but it would
probably be more intuitive and natural, and would require less changes
to existing code than the raw-and simple solution.
In case we choose the raw-and-simple solution we could also find some
tricks to make it simpler to temporarily override res.handlers with
the this-object's parent path. One idea is to add a boolean argument
to the renderSkin* methods that indicates whether the this-object's
parent chain should override res.handlers: moo.renderSkin("foo",
params, true); would then resolve macros against moo and its parent
objects before checking res.handlers.
If you followed me through here: thanks and congratulations! I suggest
we may talk about this on the #helma IRC channel today. I'm online and
waiting for your comments and suggestions.
Hannes