TALES path expression adapters

Status: IsProposal

Author

JimFulton

Problem

See NamespacesInTemplates.

This proposal is based on an email thread:

http://mail.zope.org/pipermail/zope3-dev/2003-February/005626.html

The gist of the problem is:

  • Content objects don't provide any standard API.
  • In general, interesting standard APIs? are provided by adapters in Zope 3.
  • We need easy access to these APIs? in ZPT. We want to do so conveniently.

The above proposal proposed:

  • A syntax for accessing registered adapters in TALES path expressions:
           path/adaptername:name
    

    where

    • path is some path expression,
    • adaptername is a name registered somehow
    • name is some name that we traverse to
  • A declaration mechanism for associating XML namespaces with adapter names.

The proposal had two problems:

  1. The proposed syntax doesn't make much sense as a way to access adapters. It separates the adapter from the thing being adapted. It also requires a second name that might not be needed.

    The proposal was motivated by XML namespaces. An adapter was thought of as a namespace qualifier.

  2. The proposal didn't specify how adapters would actually get registered.

The proposal has been partly implemented. The syntax is supported by a rather complex ZCML registration system.

It should be noted that, while it is desirable to be able to define adapter names within a template, it also needs to be possible to predefine names as part of a system configuration.

Finally, a similar mechanism has been created by Evan Simpson on a Zope 2 branch:

http://mail.zope.org/pipermail/zpt/2003-August/004902.html

Proposal

I suggest that rather than thinking of this in terms of namespaces, it is better to think about this in terms of adapters. This suggests a different syntax and points the way to some possible registration mechanisms.

After much discussion on the mailing list, http://mail.zope.org/pipermail/zope3-dev/2004-May/010975.html , and much discussion on IRC, I think we are narrowing down on a syntax of the form:

    ob/##adaptername

where "#" might be replaced with some other character.

The reasons for this syntax are:

  • After much discussion, it was mostly felt that a simple traversal operator of some sort, was best. That is, a syntax of the form: name1 operator name2.
  • Many people feel that the operator should be a decorated "/" to emphasize that this is a special form of traversal. Many other people think the "/" just adds noise.
  • We already have: ob/@@name means get the view named "name" for ob. It makes a lot of sense to use a very similar syntax for looking up adapters.

I fear we won't be able to pick a syntax that everyone likes. :( Garrett Smith put it very well on IRC: "Funny...this topic is like a couple trying to pick out the interior color of their new car". :)

Adapters could be specified in two ways:

  1. Using simple names (same rules as Python identifiers)
  2. Using dotted names.

If a dotted name is used, then we treat the dotted name as a global identifier, grab the global and call it with the object being adapted. So:

     tal:content="x/y*foo.bar.baz/z"

would be approximately equivalent to:

     tal:content="python: modules['foo.bar'].baz(x.y).z"

If a simple name is used, then we have to look up the name in some sort of registry. I suggest that, in Zope 3, when a simple name is used, we get a named adapter of the object to IPathAdapter. So, to register foo.bar.baz from the example above, we'd use the following zcml:

     <adapter name="baz" factory="foo.bar.baz" 
              provides="zope.app.traversing.interfaces.IPathAdapter"
              ... />

We'd like to be able to define names to be used by a template in the template itself. We will folow the approach used in Evan's proposal and define a TAL adapter namespace for defining adapters. To define an adapter, just use a tal:define with an adapter namespace qualifier:

     tal:define="adapter baz modules/foo.bar/baz"

Adapter definitions will apply to the element in which they are given.

We will add an "adapter" path traversal namespace. This means that you will be able to use paths of the form: ob/++adapter++adaptername in any Zope 3 path, where "adaptername" is either the name of an IPathAdapter adapter or a dotted name. Note, however that because this mechanism is independent of ZPT, ZPT-defined adapters will not be able to be used.

Current status

The adapter path namespace has been partially implemented. You can use it to access named IPathAdapter adapters. You can't use dotted names yet. (There are some security issues that need to be addressed before sotted names can be supported.)

The existing short syntax: ob/adaptername: is still implemented. It hs been updated to use named IPathAdapter adapters.

I would like to settle on a syntax of the form: ob/##adaptername, where # is some character. It is to late to agree on and implement a new short syntax for Zope X3.0.

Other syntaxs considered and rejected

Steve Alexander has suggested the following syntax:

    object:adaptername

which gets an adapter with the given name for the object. I think that this makes a lot more sense. The only problem with this, IMO, is that the colon screams namespace. I think a different character would be better. I think that other syntaxes are worth considering. Some possibilities include using some other character:

    object*adaptername

I'm not wed to '*':

    object~adaptername

or:

    object->adaptername

which was rejected because some tools incorrectly think it's invalid to have a > in an XML attribute.

or, possibly, a "cast" notation:

    (adaptername)object

One disadvantage I see with the cast notation is that it's a bit jarring in:

a/b/(adapter)c/d

as the adapter is applied to a/b/c. The order just doesn't seem quite right.

Many people sugested:

    adapter(object)

which has the problem that it suggests a generalized call mechanism:

  • We don't want a generalized call system, at least not now.
  • A generalizd call system wouldn't serve our needs very well, as we want to be able to register adapter names in zcml and a generalized call system would look for names in the zpt variable namespaces.

Note that all of these options allow multiple adaptation:

    object*adapter1*adapter2

    (adapter2)(adapter1)object

which would mean, adapt object with adapter1 and adapt the result with adapter2.



( 97 subscribers )