loops/helpers.txt
helmutm 273a05a5d1 Make typeInterface field available for type concepts
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1131 fd906abe-77d9-0310-91a1-e0d9ade77398
2006-03-20 08:39:02 +00:00

231 lines
6.9 KiB
Text
Executable file

===============================================================
loops - Linked Objects for Organization and Processing Services
===============================================================
This file documents and tests a bunch of facilities that support the
loops framework, mostly provided by sub-packages of the cybertools
package.
($Id$)
Let's first do some basic imports
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
>>> site = placefulSetUp(True)
>>> from zope.app import zapi
>>> from zope.app.tests import ztapi
>>> from zope.interface import Interface
>>> from zope.publisher.browser import TestRequest
and setup a simple loops site with its manager objects,
>>> from loops import Loops
>>> site['loops'] = Loops()
>>> loopsRoot = site['loops']
>>> from loops.concept import ConceptManager, Concept
>>> loopsRoot['concepts'] = ConceptManager()
>>> concepts = loopsRoot['concepts']
>>> from loops.resource import ResourceManager, Document, MediaAsset
>>> loopsRoot['resources'] = ResourceManager()
>>> resources = loopsRoot['resources']
some concepts,
>>> cc1 = Concept(u'Zope')
>>> concepts['cc1'] = cc1
>>> cc1.title
u'Zope'
>>> cc2 = Concept(u'Zope 3')
>>> concepts['cc2'] = cc2
>>> cc2.title
u'Zope 3'
and resources:
>>> doc1 = Document(u'Zope Info')
>>> resources['doc1'] = doc1
>>> doc1.title
u'Zope Info'
>>> img1 = MediaAsset(u'An Image')
>>> resources['img1'] = img1
Finally, we also need a relation registry:
>>> from cybertools.relation.interfaces import IRelationRegistry
>>> from cybertools.relation.registry import DummyRelationRegistry
>>> from zope.app.testing import ztapi
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry())
Type management with typology
=============================
The type of an object may be determined by adapting it to the IType
interface. The loops framework provides an adapter (LoopsType) for this
purpose:
>>> from cybertools.typology.interfaces import IType
>>> from loops.interfaces import IConcept
>>> from loops.type import ConceptType
>>> ztapi.provideAdapter(IConcept, IType, ConceptType)
>>> cc1_type = IType(cc1)
As we have not yet associated a type with one of our content objects we get
>>> cc1_type.typeProvider is None
True
>>> cc1_type.title
u'Unknown Type'
>>> cc1_type.token
'.unknown'
So we create two special concepts: one ('hasType') as the predicate signifying
a type relation, and the other ('type') as the one and only type concept:
>>> concepts['hasType'] = Concept(u'has type')
>>> concepts['type'] = Concept(u'Type')
>>> typeObject = concepts['type']
Assigning a type to a concept is a core functionality of concepts as
concept types are themselves concepts; and we assign the type object to
itself (as it in fact is of type 'type'):
>>> typeObject.conceptType = typeObject
So let's check the type of the type object:
>>> type_type = IType(typeObject)
>>> type_type.typeProvider is typeObject
True
>>> type_type.title
u'Type'
>>> type_type.token
'.loops/concepts/type'
>>> type_type.tokenForSearch
'loops:concept:type'
>>> type_type.qualifiers
('concept',)
Now we register another type ('topic') and assign it to cc1:
>>> concepts['topic'] = Concept(u'Topic')
>>> topic = concepts['topic']
>>> topic.conceptType = typeObject
>>> cc1.conceptType = topic
Note: as these kind of usually short-living adapters makes heavy use of
lazy properties, one should always get a new adapter:
>>> topic_type = IType(topic)
>>> cc1_type = IType(cc1)
>>> topic_type == type_type
True
>>> cc1_type == topic_type
False
>>> cc1_type.typeProvider == topic
True
>>> topic_type.qualifiers
('concept',)
>>> topic_type.defaultContainer
<loops.concept.ConceptManager object ...>
>>> topic_type.factory
<class 'loops.concept.Concept'>
Now let's have a look at resources.
>>> from loops.interfaces import IResource
>>> from loops.type import ResourceType
>>> ztapi.provideAdapter(IResource, IType, ResourceType)
>>> doc1_type = IType(doc1)
>>> doc1_type.title
u'Document'
>>> doc1_type.token
'loops.resource.Document'
>>> doc1_type.tokenForSearch
'loops:resource:document'
>>> doc1_type.qualifiers
('resource',)
>>> doc1_type.defaultContainer
<loops.resource.ResourceManager object ...>
>>> doc1_type.factory
<class 'loops.resource.Document'>
>>> img1_type = IType(img1)
>>> img1_type.title
u'Media Asset'
Can we find out somehow which types are available? This is the time to look
for a type manager. This could be a utility; but in the loops package it
is again an adapter, now for the loops root object. Nevertheless one can
get a type manager from all loops objects, always with the same context:
>>> from cybertools.typology.interfaces import ITypeManager
>>> from loops.interfaces import ILoopsObject
>>> from loops.type import LoopsTypeManager
>>> ztapi.provideAdapter(ILoopsObject, ITypeManager, LoopsTypeManager)
>>> typeManager = ITypeManager(loopsRoot)
>>> typeManager.context == ITypeManager(cc1).context == loopsRoot
True
>>> types = typeManager.types
>>> sorted(t.token for t in types)
['.loops/concepts/topic', '.loops/concepts/type',
'loops.resource.Document', 'loops.resource.MediaAsset']
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
True
The listTypes() method allows us to select types that fulfill a certain
condition:
>>> types = typeManager.listTypes(include=('concept',))
>>> sorted(t.token for t in types)
['.loops/concepts/topic', '.loops/concepts/type']
>>> types = typeManager.listTypes(exclude=('concept',))
>>> sorted(t.token for t in types)
['loops.resource.Document', 'loops.resource.MediaAsset']
Type-based interfaces and adapters
----------------------------------
>>> from loops.interfaces import ITypeConcept
>>> from loops.type import TypeConcept
>>> ztapi.provideAdapter(IConcept, ITypeConcept, TypeConcept)
A type has an optional typeInterface attribute that objects of this type
will be adaptable to. The default for this is None:
>>> cc1_type.typeInterface
>>> cc1_type.typeInterface is None
True
For concept objects that provide types (type providers) the value of
the typeInterface attribute is the ITypeConcept interface:
>>> topic_type.typeInterface is ITypeConcept
True
We now want to have a topic (i.e. a concept that has topic as its
conceptType and thus topic_type as its type) to be adaptable to ITopic.
This is done by assigning this interface to topic_type.typeProvider,
i.e. the 'topic' concept, via an adapter:
>>> class ITopic(Interface): pass
>>> from zope.interface import implements
>>> class Topic(object):
... implements(ITopic)
... def __init__(self, context): pass
>>> ztapi.provideAdapter(IConcept, ITopic, Topic)
>>> ITypeConcept(topic).typeInterface = ITopic
>>> cc1.conceptType = topic
>>> cc1_type = IType(cc1)
>>> cc1Adapter = cc1_type.typeInterface(cc1)
>>> ITopic.providedBy(cc1Adapter)
True