[Grok-dev] Re: Grok nomenclature

Martin Aspeli optilude at gmx.net
Wed Apr 30 17:48:00 EDT 2008


Martijn Faassen wrote:
> Martin Aspeli wrote:
> [snip]
>> The point is that we need a convention that's (a) visually appealing (b) 
>> clear and (c) consistent, so that we don't end up with 100 different 
>> ways of doing the same thing, making it hard to figure out what 
>> components actually get registered when you work with a complex package 
>> with potentially dozens of grokked things.
> 
> I think we should investigate a way to signal that we want 
> auto-registration for existing classes (that you now register using ZCML).
> 
> That is, if you say:
> 
> from plone.app.portlets.portlets import base
> 
> class MyPortletAssignment(base.Assignment):
>      pass
> 
> nothing happens. You register using ZCML or not at all; Grok won't care.
> 
> If you say:
> 
> import grok
> from plone.app.portlets.portelts import base
> 
> class MyPortletAssignment(base.Assignment):
>      grok.grokked()
> 
> It'll be grokked (if a grokker was registered for base.Assignment of 
> course). 'grok.grokked()' just adds the IGrokked interface to these 
> classes. You then are supposed to use directives where needed.

There's a slight problem with that, in that if you did implements() as 
well, it may override, but I'm sure this could be worked around.

How about:

  class MyPortletAssignment(base.Assignment):
      grok.as('plone.portlet')

This would look up a named grokker called 'plone.portlet' that would be 
able to grok this type of class. I would also make it possible to 
parameterise this, so e.g.:

  class MyPortletAssignment(base.Assignment):
      grok.as('plone.portlet', name='my_assignment', for_=IFoo)

In pseudo-code, grok.as() would be:

  def as(_grokker_name, **kwargs):
      grokker = getUtility(IGrokker, name=_grokker_name)
      context = sys._getframe(1)
      grokker.grok(context, **kwargs)

This is a fairly fundamental shift, though. :)

> These directives can be defined by grok. In this case the semantics of 
> these directives should be the same, or very similar, to the semantics 
> of the directives as used in Grok ('grok.context()' should not suddenly 
> be used to set the view name, say).

Sure. However, as soon as I needed another descriptor (to set the 
portlet manager, say), I'd need to venture outside the grok namespace, 
since I couldn't invent grok.portlet_manager('foo') easily. More on this 
below.

> Sometimes you need domain-specific directives. Let's imagine you need a 
> 'pipeline' directive (purely imaginary), and this is entirely portlet 
> specific. Then you'd do:
> 
> import grok
> from plone.app.portlets.portlets import base
> 
> class MyPortletAssignment(base.Assignment):
>      grok.grokked()
>      base.pipeline("Whatever")

Right - in the grok.as() example above, I actually imagined descriptors 
moving to named parameters to the grok.as() function. To someone not 
familiar with the details of what is Grok what isn't Grok, the 
distinction between grok.* and base.* would be fairly arbitrary.

However, I think you make a good point about treating these as 
domain-specific extensions with their own namespace below.

> It should be clear to the reader of the code that this is a class-level 
> directive - there's nothing else it could be doing, and people should be 
> able to recognize class directives as they're well familiar with 
> zope.interface.implements().

True, it's less of a problem than the base-class case.

> This will allow domain-specific extensions to the Grok language to be in 
> their own namespace, and there won't be an explosion of classes, one for 
> non-grok and one for grok, where this is not necessary. If ZCML can 
> register it, one should be able to register it with Grok too.

That's a very good point - I agree with this meme very much, actually.

Of course, in some cases, it makes sense to have a Grokish base class. 
For portlets, for example, we're actually condensing three classes to 
one with Grokish behaviour and may want to make that explicit.

> The requirements for extensions to the Grok domain specific language:
> 
> * avoid there being a "ZCML class" and a "Grok class". No explosion of 
> base classes. Of course if there's no base class at all yet for the ZCML 
> case we are fine.

+1

> * clearly signal to the reader of the code that things are being grokked.

+1

> * don't expand the 'grok.' namespace. What's in there is defined by Grok 
> (and five.grok follows that). Separate namespaces are a good thing, and 
> monkey-patching import namespaces is bad.

+1

> * there being a way to evolve an application from the use of ZCML to the 
> use of Grok, without changing everything at once.

+1

> * reuse grok directives where it makes sense

+1

> * introduce new directives where that makes sense, and import the 
> directives from the same place as the base classes. I think these things 
> should be semantically near.

+0.5 - I think this is clear when it comes to directives, certainly. For 
other things (base classes - are there other primitives we need to 
consider?), conventions may be useful.

> If this means that you end up importing directives and base classes from 
> 10 different modules in a package, I think it's time to start 
> refactoring the package and consolidating the places you need to import 
> from into one.

True. I imagine us having convenience imports in places, certainly.

Cheers,
Martin

-- 
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book



More information about the Grok-dev mailing list