[Checkins] SVN: zope.schema/branches/roger-sources/src/zope/schema/sources.txt Implemented different variations of ISource tests

Roger Ineichen roger at projekt01.ch
Sat Aug 30 09:16:43 EDT 2008


Log message for revision 90615:
  Implemented different variations of ISource tests
  - Source as named adapter
  - Source as named context binder
  - Source as component
  - Source as context binder

Changed:
  U   zope.schema/branches/roger-sources/src/zope/schema/sources.txt

-=-
Modified: zope.schema/branches/roger-sources/src/zope/schema/sources.txt
===================================================================
--- zope.schema/branches/roger-sources/src/zope/schema/sources.txt	2008-08-30 13:07:01 UTC (rev 90614)
+++ zope.schema/branches/roger-sources/src/zope/schema/sources.txt	2008-08-30 13:16:43 UTC (rev 90615)
@@ -9,9 +9,9 @@
   This can return any kind of object it wants. It doesn't have to care
   for browser representation, encoding, ...
 
-- A way to map a value from the iterable to something that can be used
-  for form *values* - this is called a token. A token is commonly a
-  (unique) 7bit representation of the value.
+- A way to map a value from the source (iterable) to something that can be used
+  for form *values* - this is called a token. A token is commonly a unique
+  7bit representation of the value.
 
 - A way to map a value to something that can be displayed to the user -
   this is called a title
@@ -35,10 +35,10 @@
 
 Create a source for all odd numbers.
 
-    >>> from zope import interface
+    >>> import zope.interface
     >>> from zope.schema.interfaces import ISource, IContextSourceBinder
     >>> class MySource(object):
-    ...     interface.implements(ISource)
+    ...     zope.interface.implements(ISource)
     ...     divisor = 2
     ...     def __contains__(self, value):
     ...         return bool(value % self.divisor)
@@ -48,8 +48,8 @@
     >>> 2 in my_source
     False
 
-    >>> from zope.schema import Choice
-    >>> choice = Choice(__name__='number', source=my_source)
+    >>> import zope.schema
+    >>> choice = zope.schema.Choice(__name__='number', source=my_source)
     >>> bound = choice.bind(object())
     >>> bound.vocabulary
     <...MySource...>
@@ -63,15 +63,238 @@
     ...     source = MySource()
     ...     source.divisor = context.divisor
     ...     return source
-    >>> interface.directlyProvides(my_binder, IContextSourceBinder)
+    >>> zope.interface.directlyProvides(my_binder, IContextSourceBinder)
 
     >>> class Context(object):
     ...     divisor = 3
 
-    >>> choice = Choice(__name__='number', source=my_binder)
+    >>> choice = zope.schema.Choice(__name__='number', source=my_binder)
     >>> bound = choice.bind(Context())
     Binder was called.
     >>> bound.vocabulary
     <...MySource...>
     >>> bound.vocabulary.divisor
     3
+
+
+==========
+Variations
+==========
+
+There are several ways to make a source component available. The following 
+tests will show the different options we have to implement and use sources.
+
+Let's define a generic context providing some test values for the next couple 
+tests:
+
+    >>> class Context(object):
+    ...     values = [4, 5, 6]
+    >>> context = Context()
+
+We also need to setup the vocabulary register:
+
+   >>> vr = zope.schema.vocabulary.getVocabularyRegistry()
+
+
+Source as named adapter
+-----------------------
+
+This example shows how to implement a ISource component as a named adapter.
+The source is registered as a named adapter providing ISource and the name
+is used in the IChoice field. The choice field will adapt the source within the
+field context if we bind the field to the context.
+
+    >>> class NamedSource(object):
+    ...     zope.interface.implements(ISource)
+    ... 
+    ...     values = [1, 2, 3]
+    ... 
+    ...     def __init__(self, context):
+    ...         self.context = context
+    ... 
+    ...     def __contains__(self, value):
+    ...         return value in self.values
+
+Register the named source in our vocabulary registry:
+
+   >>> vr.register('Named Source', NamedSource)
+
+We can use such a source within a IChoice field like:
+
+    >>> field = zope.schema.Choice(
+    ...     source='Named Source')
+
+Without bind the context to the field, the source doesn't work because of it's
+half ready initialization:
+
+   >>> field.vocabulary is None
+   True
+
+   >>> field.vocabularyName
+   'Named Source'
+
+This source must get bound the context:
+
+  >>> boundField = field.bind(context)
+  >>> boundField
+  <zope.schema._field.Choice object at ...>
+
+Now, the bound field provides a working source:
+
+   >>> 1 in boundField.vocabulary
+   True
+
+   >>> 42 in boundField.vocabulary
+   False
+
+
+Source as named context binder
+------------------------------
+
+The following source, registered as named source, uses the vocabulary
+registry as named adapter storage. The IChoice uses the vocabulary name as
+a key for lookup the source and will adapt the given field context if we bind
+the field to the context.
+
+    >>> class NamedContextBinderSource(object):
+    ...     zope.interface.implements(ISource, IContextSourceBinder)
+    ... 
+    ...     def __init__(self, context):
+    ...         self.context = context
+    ...
+    ...     def __contains__(self, value):
+    ...         return value in self.context.values
+
+Register the named source in our vocabulary registry:
+
+    >>> vr.register('Named Context Binder Source',  NamedContextBinderSource)
+
+We can use such a source within a IChoice field like:
+
+    >>> field = zope.schema.Choice(
+    ...     source='Named Context Binder Source')
+
+Without bind the context to the field, the source doesn't work because of it's
+half ready initialization:
+
+    >>> field.vocabulary is None
+    True
+
+    >>> field.vocabularyName
+    'Named Context Binder Source'
+
+This source must get bound the context:
+
+    >>> boundField = field.bind(context)
+    >>> boundField
+    <zope.schema._field.Choice object at ...>
+
+Now we can check our source:
+
+    >>> 4 in boundField.vocabulary
+    True
+
+    >>> 42 in boundField.vocabulary
+    False
+
+
+Source as component
+-------------------
+
+This simple source works out of the box and doesn't need to get adapted. The
+source will not be served from the vocabulary registry. The source get assinged
+as a instance of the fields source argument. This means the source will work 
+without to bind the field to the context.
+
+    >>> class SimpleSource(object):
+    ...     zope.interface.implements(ISource)
+    ...
+    ...     values = [1, 2, 3]
+    ... 
+    ...     def __contains__(self, value):
+    ...         return value in self.values
+
+    >>> simpleSource = SimpleSource()
+
+We can use such a source within a IChoice field like:
+
+    >>> field = zope.schema.Choice(
+    ...     source=simpleSource)
+
+This source can be used without to bind the context to the field:
+
+    >>> 1 in field.vocabulary
+    True
+
+    >>> 42 in field.vocabulary
+    False
+
+If we bind the context to the field:
+
+    >>> boundField = field.bind(context)
+    >>> boundField
+    <zope.schema._field.Choice object at ...>
+
+We still get the same result as before:
+
+    >>> 1 in boundField.vocabulary
+    True
+
+    >>> 42 in boundField.vocabulary
+    False
+
+
+Source as context binder
+------------------------
+
+This source implementation provides a context source binder and will be
+served as named adapter from the vocabulary registry. The source context binder
+name is used in the fields source argument. The choice field will adapt the 
+source within the field context if we bind the field to the context.
+
+    >>> class ContextBinderSource(object):
+    ...     zope.interface.implements(ISource, IContextSourceBinder)
+    ... 
+    ...     context = None
+    ... 
+    ...     def __call__(self, context):
+    ...         self.context = context
+    ...         return self
+    ...
+    ...     def __contains__(self, value):
+    ...         return value in self.context.values
+
+We can use such a source within a IChoice field like:
+
+    >>> field = zope.schema.Choice(
+    ...     source=ContextBinderSource())
+
+Without bind the context to the field, the source doesn't work because of it's
+missing adaption:
+
+    >>> field.vocabulary
+    <ContextBinderSource object at ...>
+
+    >>> field.vocabulary.context is None
+    True
+
+    >>> field.vocabularyName is None
+    True
+
+The field must bind the source to the field:
+
+    >>> boundField = field.bind(context)
+    >>> boundField
+    <zope.schema._field.Choice object at ...>
+
+Now we can check our source:
+
+    >>> 4 in boundField.vocabulary
+    True
+
+    >>> 42 in boundField.vocabulary
+    False
+
+Reset the vocabulary registry:
+
+    >>> zope.schema.vocabulary._clear()



More information about the Checkins mailing list