And you get that without having to write any custom supporting code for your template: no creating of a view method, inheriting from some base class, relying on acquisition, nothing.

This is implemented as a named adapter under the hood. In the example above, the datetime (context/modified) is the context, the name is "dateutils", and "long"/"short" are methods called on the adapter. Here's what the implementation might look like:

Note that while any permission should theoretically work, we've found that for unknown reasons we have to use zope2.Public. This should hopefully not be a security hole because the invocation will always happen in a template that is otherwise protected, but caveat emptor.

Note that when you add a new method, you have to add the attribute in zcml, or you'll get a traversal error.

Alternatively, you can create a new interface to represent your new functions, implement that interface, and then your zcml is as follows;

And I'll finish with a caveat. There are times when creating your own tales functions makes a lot of sense. There are more times when it doesn't. Only use this abstraction when you have a great many unrelated templates that share the same basic logic. Great candidates are general-purpose "utility" functions.