Adapter
difficile
Registrazione zcml
Ciò che si vuole ottenere è adattare oggetti che implementano una certa interfaccia dando loro delle annotazioni. In keywordannotator si registra un adapter per oggetti che implementano l'interfaccia IKeywordMatch. Questo adapter dovrebbe fornire per questi oggetti una nuova interfaccia IKeywordBasedAnnotations, che è solo un'interfaccia marker (o etichetta). Questo adapter può essere creato richiamando la classe KeywordBasedAnnotations in events.py. Si registra quell'adapter nel file configure.zcml:
<adapter
for=".interfaces.IKeywordMatch"
provides=".interfaces.IKeywordBasedAnnotations"
factory=".events.KeywordBasedAnnotations"
/>
In quadapter si agisce in modo simile:
<adapter
for=".interfaces.IMaudio"
provides=".interfaces.IAudioAnnotations"
factory=".events.AudioAnnotations"
/>
Ciò significa che l'adapter può essere creato richiamando la classe AudioAnnotations nel file events.py di quadapter. Questo adapter fornisce l'interfaccia IAudioAnnotations per oggetti che implementano già l'interfaccia IMaudio.
IAudioAnnotations non è un'interfaccia marker ma un'interfaccia "normale". Nel file interfaces.py di quadapter si è stabilito che ogno oggetto che richiede di implementare l'interfaccia IAudioAnnotations dovrebbe avere gli attributi completeURL e partURL:
class IAudioAnnotations(Interface):
"""Provide access to the audio annotations of an IMaudio object.
"""
completeURL = schema.URI(title=u'URL to complete audio content')
partURL = schema.URI(title=u'URL to a part of the audio content')
A questo punto si potrebbe essere giunti alla conclusione che Zope 3 utilizza molte interfacce. È così!
Codice di un adapter
Sono stati registrati due adapter. Come appare ora il codice? In keywordannotator:
class KeywordBasedAnnotations(object):
...
def __init__(self, context):
self.context = context
annotations = IAnnotations(self.context)
self._metadata = annotations.get(self._anno_key, None)
if self._metadata is None:
self._metadata = PersistentDict()
annotations[self._anno_key] = self._metadata
La funzione __init__ è la factory; in altre parole, è la funzione che crea un oggetto KeywordBasedAnnotations basato su un altro oggetto che viene passato attraverso il parametro 'context'. A questo punto per la prima volta compare realmente una annotazione. In questa linea:
annotations = IAnnotations(self.context)
Qui l'oggetto context è adattato all'interfaccia IAnnotations e l'oggetto racchiuso o adattato viene immagazzinato nella variabile delle annotazioni. Quella variabile è fondamentalmente un dizionario python che per ora non contiene probabilmente nessun valore. Le altre linee si assicurano che sia disponibile ora in quell'oggetto una struttura di base per immagazzinare annotazioni.
Ora nel codice di adapter in quadapter:
class AudioAnnotations(KeywordBasedAnnotations):
...
def __get_completeURL(self):
return self._metadata.get(COMP_ANNO)
def __set_completeURL(self, url):
self._metadata[COMP_ANNO] = url
completeURL = property(__get_completeURL, __set_completeURL)
Questa classe subclassa la classe KeywordBasedAnnotations da keywordannotator, in questo modo eredita la funzione vista prima. Ma le righe in questo codice eseguono proprio ciò che costituisce il motivo primario per cui si è iniziato questo progetto: aggiungono la proprietà completeURL, in cui immagazzinare il link alla funzione completa della mia chiesa. Questo link è memorizzato nella proprietà self._metadata, che è un'annotazione a quest'oggetto.
La stessa cosa avviene (con una porzione di codice che qui non viene mostrata perché praticamente uguale a quella sopra) per la proprietà partURL, in cui si può ora immagazzinare un link ad una parte della predica o in termini ragionevoli: il sermone.
