===========================
 at convenience directives
===========================

fieldevents provides a couple of directives for handling non-invasive
setup of fieldevent behavior.

wicked:decorate-at-field --

    Monecorates fieldevent 

wicked:atschema-fields-implement

at field decorator directive
============================

Nothing too fancy here, we just want to monkey patch our render and
store methods inplace of a field's::

    >>> from cStringIO import StringIO
    >>> out = StringIO()
    >>> class DummyATField(object):
    ...     def get(self, instance, **kw):
    ...         value = self.value
    ...         return value
    ...     def set(self, instance, value, **kw):
    ...         self.value = value

so we'll register a storage subscriber so we can log the value when
it's stored

    >>> @adapter(DummyATField, wicked.fieldevent.IFieldStorageEvent)
    ... @implementer(IFieldValueSetter)
    ... def log_store(field, event):
    ...     print >> out, "%s" %(event.value) 

    >>> provideSubscriptionAdapter(log_store)

decorate_at_field does the work here: it can be run to register with a
context or just immediately do registrations(zcml=False). 

It will add our class to the classes to be cleaned up later::

    >>> decorate_at_field(fieldclass=DummyATField, zcml=False)
    >>> from meta import _fieldclass_monkies
    >>> DummyATField in _fieldclass_monkies
    True

It also swaps the existing get and set methods for 'render' and 'store'::

    >>> DummyATField.__original_get
    <unbound method DummyATField.get>

    >>> DummyATField.__original_set
    <unbound method DummyATField.set>

    >>> DummyATField.get
    <unbound method DummyATField.render>

    >>> DummyATField.set
    <unbound method DummyATField.store>

Now when we instantiate a field instance, calling get and set should
do exactly as before, since the old getter and setter have been
registered as part of adapters::

    >>> instance = object()    
    >>> field = DummyATField()
    >>> field.set(instance, 'HOWDY', foo='bar')
    >>> print out.getvalue()
    HOWDY...
    
    >>> print field.get(instance, foo='bar')
    HOWDY

atschema-fields-implement directive
===================================

We'll create some mock objects to simulate a schema in module space.

    >>> class IMarker(Interface):
    ...     """a marker interface"""

    >>> atschema = dict(text=DummyATField(),
    ...                 description=DummyATField(),
    ...                 other=DummyATField())

"schemafields_provide" will apply (via alsoProvides) the interface to
all the fields specified by in the said schema. Field names must be
correct, or errors will raise.

Here we mark "text" and "other"::

    >>> from wicked.fieldevent import meta
    >>> meta.schemafields_provide(IMarker, atschema, ['text', 'other'])
    >>> IMarker.providedBy(atschema['text'])
    True

    >>> IMarker.providedBy(atschema['other'])
    True

but descriptions is not marked::
    
    >>> IMarker.providedBy(atschema['description'])
    False

if run with the cleanUp flag, "schemafields_provide" will remove the
interfaces rather than apply them.  The cleanup function
"cleanup_schemafields_provide" utilizes this and the global var
"_schemafields_marked" to cleanup the fields::

see the currently marked fields::

    >>> meta._schemafields_marked
    [(<InterfaceClass...IMarker>, {...}, ['text', 'other'])]

running it again should not add more fields to clean up::

    >>> meta.schemafields_provide(IMarker, atschema, ['text', 'other'])
    >>> meta._schemafields_marked
    [(<InterfaceClass...IMarker>, {...}, ['text', 'other'])]

    >>> len(meta._schemafields_marked)
    1

do cleanup::

    >>> cleanup_schemafields_provide()
    >>> meta._schemafields_marked
    []

check to make sure fields are clean::

    >>> IMarker.providedBy(atschema['text'])
    False

    >>> IMarker.providedBy(atschema['other'])
    False
    
    >>> IMarker.providedBy(atschema['description'])
    False

finally, "schemafields_implement" provides the zope.configuration
compatible wrapper.  The only other wrinkle is that the implemented
interface is provided(if zcml=True) ::

    >>> class AT(object):
    ...     schema = atschema

    >>> meta.schemafields_implement(_context=None, atclass=AT(), implements=IMarker, fields=['text', 'other'], zcml=False)

the interfaces are now set as before::

    >>> IMarker.providedBy(atschema['text'])
    True

    >>> IMarker.providedBy(atschema['other'])
    True

    >>> IMarker.providedBy(atschema['description'])
    False

The clean  call by the test does the unregistering for this...
