Package: collective.beancounter
Author:seletzDate:2007-11-14Revision:53844AbstractThis package scratches an itch of mine in providing a very simple viewlet
which displays the percentage a content is filled by an user.setup stuff>>> class Mock(object):
...    def __init__(self, **kw): self.__sict__.update(kw)BlurbFirst we define an interface to be used to mark bean-countable content:>>> from zope import interface
>>> class IBeanContable(interface.Interface):
...     """ a content which is bean countable """The counting itself is very simple and done by an adapter. We simply count
which fields in thedefaultschemata are filled. We there count only
the writable fields. From that we calculate a percentage.Lets define a interface for that functionality:>>> class IBeanCounter(interface.Interface):
...     percentage = interface.Attribute(u"The percentage filled")Now lets create some content class to test our stuff:>>> _ = self.folder.invokeFactory("Document", "doc")
>>> doc = self.folder.get(_)Count the fields which are in thedefaultschemata and are rewd/write:>>> len([f for f in doc.Schema().fields() if f.schemata=="default" and f.mode =="rw"])
4Ok, now how many of them are filled?:>>> l = [f for f in doc.Schema().fields() if f.schemata=="default" and f.mode =="rw"]
>>> [f.getName() for f in l if f.get(doc)]
['id']Ok, fair enough. Now lets do the opposite:>>> [f.getName() for f in l if not f.get(doc)]
['title', 'description', 'text']Ok, thats enough. Lets wrap it up.ImplementationWe have an adapter:>>> from collective.beancounter.adapter import ATBeanCounter
>>> ct = ATBeanCounter(doc)
>>> print ct.percentage
25.0Fill out completely:>>> doc.update( title="muha", text="haha", description="desc")
>>> ct = ATBeanCounter(doc)
>>> print ct.percentage
100.0Yay.Field filterYou may provide an adapter to specify a filter to decide which
fields you consider to be “countable”:>>> from collective.beancounter.interfaces import IBeanCounterFieldFilterWe provide adefault adapter for AT objects:>>> from collective.beancounter.adapter import ATFieldFilterThat adapter provides a filter which filters out fields which:are not user settableare not in the “default” schemataare not in the special plone field blacklistare not boolean fields (these are true or false, i.e. always “filled”)>>> IBeanCounterFieldFilter(doc)
<collective.beancounter.adapter.ATFieldFilter object at ...>Lets test that:>>> from collective.beancounter.adapter import countable_fields
>>> sorted([f.getName() for f in countable_fields(doc)])
['description', 'id', 'text', 'title']Ok, that filters nothing, which is fine. Now lets provide an adapter
which does filter out the “title”,”id” and “description” fields:>>> from zope import component
>>> from Products.Archetypes.interfaces import IBaseObject
>>> class TestFilter(object):
...     component.adapts(IBaseObject)
...     interface.implements(IBeanCounterFieldFilter)
...     def __init__(self,context): self.context = context
...     def __call__(self, field):
...         return field.getName() not in "title id description".split()
>>> component.provideAdapter(TestFilter)We should now get our adapter:>>> IBeanCounterFieldFilter(doc)
<TestFilter object at ...>We should now get ALL fields but the ones we filtered out:>>> set("title id description".split()) & set([f.getName() for f in countable_fields(doc)])
set([])vim: set ft=rst tw=75 nocin nosi ai sw=4 ts=4 expandtab: