[Zope-CVS] SVN: book/trunk/smileyutility/ global and local smiley utility.

Stephan Richter srichter at cosmos.phy.tufts.edu
Sat Aug 21 14:16:50 EDT 2004


Log message for revision 27213:
  global and local smiley utility.
  


Changed:
  A   book/trunk/smileyutility/
  A   book/trunk/smileyutility/__init__.py
  A   book/trunk/smileyutility/browser.py
  A   book/trunk/smileyutility/configure.zcml
  A   book/trunk/smileyutility/globaltheme.py
  A   book/trunk/smileyutility/interfaces.py
  A   book/trunk/smileyutility/localtheme.py
  A   book/trunk/smileyutility/meta.zcml
  A   book/trunk/smileyutility/metaconfigure.py
  A   book/trunk/smileyutility/metadirectives.py
  A   book/trunk/smileyutility/overview.pt
  A   book/trunk/smileyutility/smileys/
  A   book/trunk/smileyutility/smileys/plain/
  A   book/trunk/smileyutility/smileys/plain/biggrin.png
  A   book/trunk/smileyutility/smileys/plain/confused.png
  A   book/trunk/smileyutility/smileys/plain/cool.png
  A   book/trunk/smileyutility/smileys/plain/oh.png
  A   book/trunk/smileyutility/smileys/plain/sad.png
  A   book/trunk/smileyutility/smileys/plain/smile.png
  A   book/trunk/smileyutility/smileys/plain/tongue.png
  A   book/trunk/smileyutility/smileys/plain/wink.png
  A   book/trunk/smileyutility/smileys/yazoo/
  A   book/trunk/smileyutility/smileys/yazoo/biggrin.png
  A   book/trunk/smileyutility/smileys/yazoo/confused.png
  A   book/trunk/smileyutility/smileys/yazoo/cool.png
  A   book/trunk/smileyutility/smileys/yazoo/oh.png
  A   book/trunk/smileyutility/smileys/yazoo/sad.png
  A   book/trunk/smileyutility/smileys/yazoo/smile.png
  A   book/trunk/smileyutility/smileys/yazoo/tongue.png
  A   book/trunk/smileyutility/smileys/yazoo/wink.png
  A   book/trunk/smileyutility/tests/
  A   book/trunk/smileyutility/tests/__init__.py
  A   book/trunk/smileyutility/tests/smiley.zcml
  A   book/trunk/smileyutility/tests/test_directives.py
  A   book/trunk/smileyutility/tests/test_doc.py


-=-
Added: book/trunk/smileyutility/__init__.py
===================================================================
--- book/trunk/smileyutility/__init__.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/__init__.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,97 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Smiley Themes
+
+Here is an example:
+
+  First we need to prepare the system by creating and registering some themes.
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> from zope.app.tests import ztapi
+  
+  >>> import globaltheme
+  
+  >>> theme = globaltheme.GlobalSmileyTheme()
+  >>> theme.provideSmiley(':-)', '++resource++plain__smile.png')
+  >>> theme.provideSmiley(';-)', '++resource++plain__wink.png')
+  >>> ztapi.provideUtility(ISmileyTheme, theme, 'plain')
+  >>> globaltheme.declareDefaultSmileyTheme('plain')
+
+  >>> theme = globaltheme.GlobalSmileyTheme()
+  >>> theme.provideSmiley(':-]', '++resource++square__smile.png')
+  >>> theme.provideSmiley(';-]', '++resource++square__wink.png')
+  >>> ztapi.provideUtility(ISmileyTheme, theme, 'square')
+
+  Now we can test the API calls.
+
+  >>> getSmiley(':-)', TestRequest(), 'plain')
+  '/++resource++plain__smile.png'
+  >>> getSmiley(':-)', TestRequest())
+  '/++resource++plain__smile.png'
+  >>> getSmiley(':-)', TestRequest(), 'square')
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: 'Smiley not found.'
+  >>> getSmiley(':-]', TestRequest())
+  Traceback (most recent call last):
+  ...
+  ComponentLookupError: 'Smiley not found.'
+
+  >>> querySmiley(':-)', TestRequest(), 'plain')
+  '/++resource++plain__smile.png'
+  >>> querySmiley(':-)', TestRequest())
+  '/++resource++plain__smile.png'
+  >>> querySmiley(':-)', TestRequest(), 'square') is None
+  True
+  >>> querySmiley(':-]', TestRequest()) is None
+  True
+
+  >>> themes = getSmileyThemes()
+  >>> themes.sort()
+  >>> themes
+  [u'plain', u'square']
+
+  >>> map = getSmileysMapping(TestRequest(), 'plain')
+  >>> map = map.items()
+  >>> map.sort()
+  >>> import pprint
+  >>> pprint.pprint(map)
+  [(':-)', '/++resource++plain__smile.png'),
+   (';-)', '/++resource++plain__wink.png')]
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.app import zapi
+
+from interfaces import ISmileyTheme
+
+def getSmiley(text, request, theme='default'):
+    theme = zapi.getUtility(ISmileyTheme, theme)
+    return theme.getSmiley(text, request)
+
+def querySmiley(text, request, theme='default', default=None):
+    theme = zapi.queryUtility(ISmileyTheme, theme)
+    if theme is None:
+        return default
+    return theme.querySmiley(text, request, default)
+
+def getSmileyThemes():
+    return [name for name, util in zapi.getUtilitiesFor(ISmileyTheme)
+            if name != 'default']
+
+def getSmileysMapping(request, theme='default'):
+    theme = zapi.getUtility(ISmileyTheme, theme)
+    return theme.getSmileysMapping(request)

Added: book/trunk/smileyutility/browser.py
===================================================================
--- book/trunk/smileyutility/browser.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/browser.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,33 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Local Smiley Theme Browser components
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+from zope.app import zapi
+
+from localtheme import queryNextTheme, getURL
+
+class Overview(object):
+
+    def getLocalSmileys(self):
+        return [{'text': name, 'url': getURL(smiley, self.request)}
+                for name, smiley in self.context.items()]
+    
+    def getAcquiredSmileys(self):
+        theme = queryNextTheme(self.context, zapi.name(self.context))
+        map = theme.getSmileysMapping(self.request)
+        return [{'text': name, 'url': path} for name, path in map.items()
+                if name not in self.context]

Added: book/trunk/smileyutility/configure.zcml
===================================================================
--- book/trunk/smileyutility/configure.zcml	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/configure.zcml	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,119 @@
+<configure 
+    xmlns:zope="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    xmlns="http://namespaces.zope.org/smiley"
+    i18n_domain="smileyutility">
+
+  <theme name="plain">
+    <smiley text=":D"  file="./smileys/plain/biggrin.png"/>
+    <smiley text=":-D" file="./smileys/plain/biggrin.png"/>
+    <smiley text=":/"  file="./smileys/plain/confused.png"/>
+    <smiley text=":-/" file="./smileys/plain/confused.png"/>
+    <smiley text="8)"  file="./smileys/plain/cool.png"/>
+    <smiley text="8-)" file="./smileys/plain/cool.png"/>
+    <smiley text=":o"  file="./smileys/plain/oh.png"/>
+    <smiley text=":-o" file="./smileys/plain/oh.png"/>
+    <smiley text=":("  file="./smileys/plain/sad.png"/>
+    <smiley text=":-(" file="./smileys/plain/sad.png"/>
+    <smiley text=":)"  file="./smileys/plain/smile.png"/>
+    <smiley text=":-)" file="./smileys/plain/smile.png"/>
+    <smiley text=":P"  file="./smileys/plain/tongue.png"/>
+    <smiley text=":-P" file="./smileys/plain/tongue.png"/>
+    <smiley text=";)"  file="./smileys/plain/wink.png"/>
+    <smiley text=";-)" file="./smileys/plain/wink.png"/>
+  </theme>             
+                       
+  <theme name="yazoo"> 
+    <smiley text=":D"  file="./smileys/yazoo/biggrin.png"/>
+    <smiley text=":-D" file="./smileys/yazoo/biggrin.png"/>
+    <smiley text=":/"  file="./smileys/yazoo/confused.png"/>
+    <smiley text=":-/" file="./smileys/yazoo/confused.png"/>
+    <smiley text="8)"  file="./smileys/yazoo/cool.png"/>
+    <smiley text="8-)" file="./smileys/yazoo/cool.png"/>
+    <smiley text=":o"  file="./smileys/yazoo/oh.png"/>
+    <smiley text=":-o" file="./smileys/yazoo/oh.png"/>
+    <smiley text=":("  file="./smileys/yazoo/sad.png"/>
+    <smiley text=":-(" file="./smileys/yazoo/sad.png"/>
+    <smiley text=":)"  file="./smileys/yazoo/smile.png"/>
+    <smiley text=":-)" file="./smileys/yazoo/smile.png"/>
+    <smiley text=":P"  file="./smileys/yazoo/tongue.png"/>
+    <smiley text=":-P" file="./smileys/yazoo/tongue.png"/>
+    <smiley text=";)"  file="./smileys/yazoo/wink.png"/>
+    <smiley text=";-)" file="./smileys/yazoo/wink.png"/>
+  </theme>
+
+  <defaultTheme name="plain" />
+
+
+  <zope:content class=".localtheme.SmileyTheme">  
+    <zope:factory
+        id="book.smileyutility.SmileyTheme"
+        title="Smiley Theme"
+        description="A Smiley Theme"
+        />
+    <zope:implements
+        interface="zope.app.utility.interfaces.ILocalUtility" 
+        />
+    <zope:implements
+        interface="zope.app.container.interfaces.IContentContainer" 
+        />
+    <zope:implements
+        interface="zope.app.annotation.interfaces.IAttributeAnnotatable" 
+        />
+    <zope:allow
+        interface="zope.app.container.interfaces.IReadContainer"
+        />
+    <zope:require
+        permission="zope.ManageServices"
+        interface="zope.app.container.interfaces.IWriteContainer"
+        />
+    <zope:require
+        permission="zope.ManageServices"
+        interface=".interfaces.ISmileyTheme"
+        set_schema=".interfaces.ISmileyTheme"
+        />
+  </zope:content>
+
+  <zope:content class=".localtheme.Smiley">
+    <zope:require
+        like_class="zope.app.file.image.Image"
+        />
+  </zope:content>
+
+  <browser:tool
+      interface=".interfaces.ISmileyTheme"
+      title="Smiley Themes"
+      description="Smiley Themes allow you to convert text-based to icon-based
+      smileys."
+      />
+
+  <browser:addMenuItem
+      class=".localtheme.Smiley"
+      title="Smiley"
+      description="A Smiley"
+      permission="zope.ManageServices"
+      />
+
+  <browser:addMenuItem
+      class=".localtheme.SmileyTheme"
+      title="Smiley Theme"
+      description="A Smiley Theme"
+      permission="zope.ManageServices"
+      />
+
+  <browser:containerViews
+      for=".localtheme.SmileyTheme"
+      index="book.messageboard.View"
+      contents="zope.ManageServices"
+      add="zope.ManageServices"
+      />
+
+  <browser:page
+      name="overview.html"
+      menu="zmi_views" title="Overview"
+      for=".localtheme.SmileyTheme"
+      permission="zope.ManageServices"
+      class=".browser.Overview"
+      template="overview.pt" />
+
+</configure>

Added: book/trunk/smileyutility/globaltheme.py
===================================================================
--- book/trunk/smileyutility/globaltheme.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/globaltheme.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,111 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Global Smiley Theme Implementation
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+from zope.component.exceptions import ComponentLookupError
+from zope.interface import implements
+
+from zope.app import zapi
+from zope.app.traversing.interfaces import IContainmentRoot
+
+from interfaces import ISmileyTheme, IGlobalSmileyTheme
+
+class Root(object):
+    implements(IContainmentRoot)
+
+def getRootURL(request):
+    return str(zapi.getView(Root(), 'absolute_url', request))
+
+
+class GlobalSmileyTheme(object):
+    """A filesystem based smiley theme.
+
+    Let's make sure that the global theme implementation actually fulfills the
+    `ISmileyTheme` API.
+
+    >>> from zope.interface.verify import verifyClass
+    >>> verifyClass(IGlobalSmileyTheme, GlobalSmileyTheme)
+    True
+
+    Initialize the theme and add a couple of smileys.
+
+    >>> theme = GlobalSmileyTheme()
+    >>> theme.provideSmiley(':-)', '++resource++plain__smile.png')
+    >>> theme.provideSmiley(';-)', '++resource++plain__wink.png')
+
+    Let's try to get a smiley out of the registry.
+
+    >>> from zope.publisher.browser import TestRequest
+
+    >>> theme.getSmiley(':-)', TestRequest())
+    '/++resource++plain__smile.png'
+    >>> theme.getSmiley(':-(', TestRequest())
+    Traceback (most recent call last):
+    ...
+    ComponentLookupError: 'Smiley not found.'
+    >>> theme.querySmiley(';-)', TestRequest())
+    '/++resource++plain__wink.png'
+    >>> theme.querySmiley(';-(', TestRequest()) is None
+    True
+
+    And finally we's like to get a dictionary of all smileys. 
+    
+    >>> map = theme.getSmileysMapping(TestRequest())
+    >>> len(map)
+    2
+    >>> map[':-)']
+    '/++resource++plain__smile.png'
+    >>> map[';-)']
+    '/++resource++plain__wink.png'
+    """
+    implements(IGlobalSmileyTheme)
+
+    def __init__(self):
+        self.__smileys = {}
+
+    def getSmiley(self, text, request):
+        "See book.smileyutility.interfaces.ISmileyTheme"
+        smiley = self.querySmiley(text, request)
+        if smiley is None:
+            raise ComponentLookupError, 'Smiley not found.'
+        return smiley
+
+    def querySmiley(self, text, request, default=None):
+        "See book.smileyutility.interfaces.ISmileyTheme"
+        if self.__smileys.get(text) is None:
+            return default
+        return getRootURL(request) + '/' + self.__smileys[text]
+
+    def getSmileysMapping(self, request):
+        "See book.smileyutility.interfaces.ISmileyTheme"
+        smileys = self.__smileys.copy()
+        root_url = getRootURL(request)
+        for name, smiley in smileys.items():
+            smileys[name] = root_url + '/' + smiley
+        return smileys
+
+    def provideSmiley(self, text, smiley_path):
+        "See book.smileyutility.interfaces.IGlobalSmileyTheme"
+        self.__smileys[text] = smiley_path
+
+
+def declareDefaultSmileyTheme(name):
+    """Declare the default smiley theme."""
+    utilities = zapi.getService(zapi.servicenames.Utilities)
+    theme = zapi.getUtility(ISmileyTheme, name)
+    # register the utility simply without a name
+    utilities.provideUtility(ISmileyTheme, theme, 'default')

Added: book/trunk/smileyutility/interfaces.py
===================================================================
--- book/trunk/smileyutility/interfaces.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/interfaces.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,73 @@
+##############################################################################
+#
+# Copyright (c) 2003, 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Smiley Utility interfaces
+
+$Id$
+"""
+from zope.interface import Interface
+from zope.schema import Field
+
+from zope.app.container.constraints import ContainerTypesConstraint
+from zope.app.container.constraints import ItemTypePrecondition
+from zope.app.container.interfaces import IContained, IContainer
+from zope.app.file.interfaces import IImage
+
+
+class ISmileyTheme(Interface):
+    """A theme is a collection of smileys having a stylistic theme.
+
+    Themes are intened to be implemented as named utilities, which will be
+    available via a local smiley service.
+    """
+
+    def getSmiley(text, request):
+        """Returns a smiley for the given text and theme.
+
+        If no smiley was found, a ComponentLookupError should be raised.
+        """
+
+    def querySmiley(text, request, default=None):
+        """Returns a smiley for the given text and theme.
+
+        If no smiley was found, the default value is returned.
+        """
+
+    def getSmileysMapping(request):
+        """Return a mapping of text to URL.
+
+        This is incredibly useful when actually attempting to substitute the
+        smiley texts with a URL.
+        """
+
+
+class IGlobalSmileyTheme(ISmileyTheme):
+    """A global smiley theme that also allows managament of smileys."""
+
+    def provideSmiley(text, smiley_path):
+        """Provide a smiley for the utility."""
+
+
+class ISmiley(IImage):
+    """A smiley is just a glorified image"""
+    __parent__ = Field(
+        constraint = ContainerTypesConstraint(ISmileyTheme))
+
+
+class ILocalSmileyTheme(ISmileyTheme, IContainer):
+    """A local smiley themes that manages its smileys via the container API"""
+
+    def __setitem__(name, object):
+        """Add a IMessage object."""
+
+    __setitem__.precondition = ItemTypePrecondition(ISmiley)

Added: book/trunk/smileyutility/localtheme.py
===================================================================
--- book/trunk/smileyutility/localtheme.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/localtheme.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,173 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Local Smiley Theme Implementation
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+from zope.component.exceptions import ComponentLookupError
+from zope.interface import implements
+
+from zope.app import zapi
+from zope.app.container.btree import BTreeContainer
+from zope.app.component.localservice import getNextService
+from zope.app.file.image import Image
+
+from interfaces import ISmileyTheme, ISmiley, ILocalSmileyTheme
+
+class Smiley(Image):
+    implements(ISmiley)
+
+class SmileyTheme(BTreeContainer):
+    """A local smiley theme implementation.
+
+    >>> import os
+    >>> from zope.app.tests import setup
+    >>> from zope.app.utility.utility import LocalUtilityService
+    >>> import book.smileyutility
+    >>> site = setup.placefulSetUp()
+    >>> rootFolder = setup.buildSampleFolderTree()
+
+    Setup a simple function to add local smileys to a theme.
+
+    >>> def addSmiley(theme, text, filename):
+    ...     base_dir = os.path.dirname(book.smileyutility.__file__)
+    ...     filename = os.path.join(base_dir, filename)
+    ...     theme[text] = Smiley(open(filename, 'r'))
+
+    Create components in root folder
+
+    >>> site = setup.createServiceManager(rootFolder)
+    >>> utils = setup.addService(site, zapi.servicenames.Utilities,
+    ...                         LocalUtilityService())
+    >>> theme = SmileyTheme()
+    >>> addSmiley(theme, ':)',  'smileys/plain/smile.png')
+    >>> addSmiley(theme, ':(',  'smileys/plain/sad.png')
+    >>> util = setup.addUtility(site, 'plain', ISmileyTheme, theme)
+
+    Create components in `folder1`
+
+    >>> site = setup.createServiceManager(rootFolder['folder1'])
+    >>> utils = setup.addService(site, zapi.servicenames.Utilities,
+    ...                          LocalUtilityService())
+    >>> theme = SmileyTheme() 
+    >>> addSmiley(theme, ':)',  'smileys/plain/biggrin.png')
+    >>> addSmiley(theme, '8)',  'smileys/plain/cool.png')
+    >>> util = setup.addUtility(site, 'plain', ISmileyTheme, theme)
+
+    Now test the single smiley accessor methods
+
+    >>> from zope.publisher.browser import TestRequest
+    >>> from zope.app.component.localservice import setSite
+    >>> from book.smileyutility import getSmiley, querySmiley
+
+    >>> setSite(rootFolder)
+    >>> getSmiley(':)', TestRequest(), 'plain')
+    'http://127.0.0.1/++etc++site/default/plain/%3A%29'
+    >>> getSmiley(':(', TestRequest(), 'plain')
+    'http://127.0.0.1/++etc++site/default/plain/%3A%28'
+    >>> getSmiley('8)', TestRequest(), 'plain')
+    Traceback (most recent call last):
+    ...
+    ComponentLookupError: '8)'
+    >>> querySmiley('8)', TestRequest(), 'plain', 'nothing')
+    'nothing'
+
+    >>> setSite(rootFolder['folder1'])
+    >>> getSmiley(':)', TestRequest(), 'plain')
+    'http://127.0.0.1/folder1/++etc++site/default/plain/%3A%29'
+    >>> getSmiley(':(', TestRequest(), 'plain')
+    'http://127.0.0.1/++etc++site/default/plain/%3A%28'
+    >>> getSmiley('8)', TestRequest(), 'plain')
+    'http://127.0.0.1/folder1/++etc++site/default/plain/8%29'
+    >>> getSmiley(':|', TestRequest(), 'plain')
+    Traceback (most recent call last):
+    ...
+    ComponentLookupError: ':|'
+    >>> querySmiley(':|', TestRequest(), 'plain', 'nothing')
+    'nothing'
+    
+    Let's now test the `getSmileysMapping()` method. To do that we create a
+    small helper method that helps us compare dictionaries.
+
+    >>> from pprint import pprint
+    >>> from book.smileyutility import getSmileysMapping
+    >>> def output(dict):
+    ...     items = dict.items()
+    ...     items.sort()
+    ...     pprint(items)
+
+    >>> setSite(rootFolder)
+    >>> output(getSmileysMapping(TestRequest(), 'plain'))
+    [(u':(', 'http://127.0.0.1/++etc++site/default/plain/%3A%28'),
+     (u':)', 'http://127.0.0.1/++etc++site/default/plain/%3A%29')]
+
+    >>> setSite(rootFolder['folder1'])
+    >>> output(getSmileysMapping(TestRequest(), 'plain'))
+    [(u'8)', 'http://127.0.0.1/folder1/++etc++site/default/plain/8%29'),
+     (u':(', 'http://127.0.0.1/++etc++site/default/plain/%3A%28'),
+     (u':)', 'http://127.0.0.1/folder1/++etc++site/default/plain/%3A%29')]
+    >>> getSmileysMapping(TestRequest(), 'foobar')
+    Traceback (most recent call last):
+    ...
+    ComponentLookupError: \
+(<InterfaceClass book.smileyutility.interfaces.ISmileyTheme>, 'foobar')
+
+    >>> setup.placefulTearDown()
+    """
+    implements(ILocalSmileyTheme)
+
+    def getSmiley(self, text, request):
+        "See book.smileyutility.interfaces.ISmileyTheme"
+        if text not in self:
+            theme = queryNextTheme(self, zapi.name(self))
+            if theme is None:
+                raise ComponentLookupError(text)
+            else:
+                return theme.getSmiley(text, request)
+        return getURL(self[text], request)
+        
+    def querySmiley(self, text, request, default=None):
+        "See book.smileyutility.interfaces.ISmileyTheme"
+        if text not in self:
+            theme = queryNextTheme(self, zapi.name(self))
+            if theme is None:
+                return default
+            else:
+                return theme.querySmiley(text, request, default)
+        return getURL(self[text], request)
+
+    def getSmileysMapping(self, request):
+        "See book.smileyutility.interfaces.ISmileyTheme"
+        theme = queryNextTheme(self, zapi.name(self))
+        if theme is None:
+            smileys = {}
+        else:
+            smileys = theme.getSmileysMapping(request)
+
+        for name, smiley in self.items():
+            smileys[name] = getURL(smiley, request)
+
+        return smileys
+
+
+def queryNextTheme(context, name, default=None):
+    """Get the next theme higher up."""
+    utilities = getNextService(context, zapi.servicenames.Utilities)
+    return utilities.queryUtility(ISmileyTheme, name, default)
+
+def getURL(smiley, request):
+    """Get the URL of the smiley."""
+    url = zapi.getView(smiley, 'absolute_url', request=request)
+    return url()

Added: book/trunk/smileyutility/meta.zcml
===================================================================
--- book/trunk/smileyutility/meta.zcml	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/meta.zcml	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,28 @@
+<configure xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/smiley">
+
+    <meta:complexDirective
+        name="theme"
+        schema=".metadirectives.IThemeDirective"
+        handler=".metaconfigure.theme">
+
+      <meta:subdirective
+          name="smiley"
+          schema=".metadirectives.ISmileySubdirective" />
+
+    </meta:complexDirective>
+
+    <meta:directive
+        name="smiley"
+        schema=".metadirectives.ISmileyDirective"
+        handler=".metaconfigure.smiley" />
+
+    <meta:directive
+        name="defaultTheme"
+        schema=".metadirectives.IDefaultThemeDirective"
+        handler=".metaconfigure.defaultTheme" />
+
+  </meta:directives>
+
+</configure>

Added: book/trunk/smileyutility/metaconfigure.py
===================================================================
--- book/trunk/smileyutility/metaconfigure.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/metaconfigure.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Smiley Configuration code
+
+$Id: metaconfigure.py,v 1.1 2003/08/22 21:27:33 srichter Exp $
+"""
+import os
+
+from zope.app import zapi
+from zope.app.component.metaconfigure import utility
+from zope.app.publisher.browser.resourcemeta import resource
+
+from interfaces import ISmileyTheme
+from globaltheme import GlobalSmileyTheme, declareDefaultSmileyTheme
+
+__registered_resources = []
+
+def registerSmiley(text, path, theme):
+    theme = zapi.queryUtility(ISmileyTheme, theme)
+    theme.provideSmiley(text, path)
+
+
+class theme(object):
+
+    def __init__(self, _context, name):
+        self.name = name
+        utility(_context, ISmileyTheme,
+                factory=GlobalSmileyTheme, name=name)
+
+    def smiley(self, _context, text, file):
+        return smiley(_context, text, file, self.name)
+
+    def __call__(self):
+        return
+
+
+def smiley(_context, text, file, theme):
+
+    name = theme + '__' + os.path.split(file)[1]
+    path = '/++resource++' + name
+
+    if name not in __registered_resources:
+        resource(_context, name, image=file)
+        __registered_resources.append(name)
+
+    _context.action(
+        discriminator = ('smiley', theme, text),
+        callable = registerSmiley,
+        args = (text, path, theme),
+        )
+
+
+def defaultTheme(_context, name=None):
+    _context.action(
+        discriminator = ('smiley', 'defaultTheme',),
+        callable = declareDefaultSmileyTheme,
+        args = (name,),
+        )
+

Added: book/trunk/smileyutility/metadirectives.py
===================================================================
--- book/trunk/smileyutility/metadirectives.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/metadirectives.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,56 @@
+##############################################################################
+#
+# Copyright (c) 2003, 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Smiley Configuration interfaces
+
+$Id: metadirectives.py,v 1.1 2003/08/22 21:27:33 srichter Exp $
+"""
+from zope.interface import Interface
+from zope.configuration.fields import Path
+from zope.schema import TextLine
+
+class IThemeDirective(Interface):
+    """Define a new theme."""
+    
+    name = TextLine(
+        title=u"Theme Name",
+        description=u"The name of the theme.",
+        default=None,
+        required=False)
+
+class ISmileySubdirective(Interface):
+    """This directive adds a new smiley using the theme information of the
+    complex smileys directive."""
+
+    text = TextLine(
+        title=u"Smiley Text",
+        description=u"The text that represents the smiley, i.e. ':-)'",
+        required=True)
+
+    file = Path(
+        title=u"Image file",
+        description=u"Path to the image that represents the smiley.",
+        required=True)
+
+class ISmileyDirective(ISmileySubdirective):
+    """This is a standalone directive registering a smiley for a certain
+    theme."""
+
+    theme = TextLine(
+        title=u"Theme",
+        description=u"The theme the smiley belongs to.",
+        default=None,
+        required=False)
+
+class IDefaultThemeDirective(IThemeDirective):
+    """Specify the default theme."""

Added: book/trunk/smileyutility/overview.pt
===================================================================
--- book/trunk/smileyutility/overview.pt	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/overview.pt	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,27 @@
+<html metal:use-macro="views/standard_macros/view">
+<head>
+  <title metal:fill-slot="title" 
+         i18n:translate="">Smiley Theme</title>
+</head>
+<body>
+<div metal:fill-slot="body">
+
+  <h2 i18n:translate="">Local Smileys</h2> 
+  <ul>
+    <li tal:repeat="smiley view/getLocalSmileys">
+    <b tal:content="smiley/text"/> &#8594;
+    <img src="" tal:attributes="src smiley/url"/>
+    </li>          
+  </ul>
+
+  <h2 i18n:translate="">Acquired Smileys</h2>
+  <ul>
+    <li tal:repeat="smiley view/getAcquiredSmileys">
+    <b tal:content="smiley/text"/> &#8594;
+    <img src="" tal:attributes="src smiley/url"/>
+    </li>          
+  </ul>
+
+</div>
+</body>
+</html>

Added: book/trunk/smileyutility/smileys/plain/biggrin.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/biggrin.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/plain/confused.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/confused.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/plain/cool.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/cool.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/plain/oh.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/oh.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/plain/sad.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/sad.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/plain/smile.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/smile.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/plain/tongue.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/tongue.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/plain/wink.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/plain/wink.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/biggrin.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/biggrin.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/confused.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/confused.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/cool.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/cool.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/oh.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/oh.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/sad.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/sad.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/smile.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/smile.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/tongue.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/tongue.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/smileys/yazoo/wink.png
===================================================================
(Binary files differ)


Property changes on: book/trunk/smileyutility/smileys/yazoo/wink.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: book/trunk/smileyutility/tests/__init__.py
===================================================================

Added: book/trunk/smileyutility/tests/smiley.zcml
===================================================================
--- book/trunk/smileyutility/tests/smiley.zcml	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/tests/smiley.zcml	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,21 @@
+<configure 
+    xmlns:zope="http://namespaces.zope.org/zope"
+    xmlns="http://namespaces.zope.org/smiley">
+
+  <zope:include package="book.smileyutility" file="meta.zcml" />
+
+  <theme name="yazoo">
+    <smiley text=":(" file="../smileys/yazoo/sad.png"/>
+    <smiley text=":)" file="../smileys/yazoo/smile.png"/>
+  </theme>
+
+  <theme name="plain" />
+
+  <smiley
+      theme="plain"
+      text=":("
+      file="../smileys/yazoo/sad.png"/>
+
+  <defaultTheme name="plain" />
+
+</configure>

Added: book/trunk/smileyutility/tests/test_directives.py
===================================================================
--- book/trunk/smileyutility/tests/test_directives.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/tests/test_directives.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,58 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test the workflow ZCML namespace directives.
+
+$Id: test_directives.py,v 1.1 2003/08/22 21:27:36 srichter Exp $
+"""
+import unittest
+
+from zope.app import zapi
+from zope.app.tests.placelesssetup import PlacelessSetup
+from zope.configuration import xmlconfig
+
+from book.smileyutility import tests 
+from book.smileyutility.interfaces import ISmileyTheme
+
+class DirectivesTest(PlacelessSetup, unittest.TestCase):
+
+    def setUp(self):
+        super(DirectivesTest, self).setUp()
+        self.context = xmlconfig.file("smiley.zcml", tests)
+
+    def test_SmileyDirectives(self):
+        self.assertEqual(
+            zapi.getUtility(ISmileyTheme,
+                            'default')._GlobalSmileyTheme__smileys,
+            {u':(': u'/++resource++plain__sad.png'})
+        self.assertEqual(
+            zapi.getUtility(ISmileyTheme,
+                            'plain')._GlobalSmileyTheme__smileys,
+            {u':(': u'/++resource++plain__sad.png'})
+        self.assertEqual(
+            zapi.getUtility(ISmileyTheme,
+                            'yazoo')._GlobalSmileyTheme__smileys,
+            {u':)': u'/++resource++yazoo__smile.png',
+             u':(': u'/++resource++yazoo__sad.png'})
+
+    def test_defaultTheme(self):
+        self.assertEqual(zapi.getUtility(ISmileyTheme, 'default'),
+                         zapi.getUtility(ISmileyTheme, 'plain'))
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(DirectivesTest),
+        ))
+
+if __name__ == '__main__':
+    unittest.main()

Added: book/trunk/smileyutility/tests/test_doc.py
===================================================================
--- book/trunk/smileyutility/tests/test_doc.py	2004-08-21 18:16:23 UTC (rev 27212)
+++ book/trunk/smileyutility/tests/test_doc.py	2004-08-21 18:16:50 UTC (rev 27213)
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test the workflow ZCML namespace directives.
+
+$Id: test_globalservice.py,v 1.1 2003/08/22 21:27:36 srichter Exp $
+"""
+import unittest
+
+from zope.interface import Interface
+from zope.testing.doctestunit import DocTestSuite
+
+from zope.app.tests import ztapi, placelesssetup
+
+class AbsoluteURL:
+    def __init__(self, context, request):
+        pass
+    def __str__(self):
+        return ''
+
+def setUp():
+    placelesssetup.setUp()
+    ztapi.browserView(Interface, 'absolute_url', AbsoluteURL)
+
+
+def test_suite():
+    return unittest.TestSuite((
+        DocTestSuite('book.smileyutility',
+                     setUp=setUp, tearDown=placelesssetup.tearDown),
+        DocTestSuite('book.smileyutility.globaltheme',
+                     setUp=setUp, tearDown=placelesssetup.tearDown),
+        DocTestSuite('book.smileyutility.localtheme'),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')



More information about the Zope-CVS mailing list