[Z3-checkins] r5103 - in z3/Five: . trunk trunk/demo trunk/demo/FiveDemo trunk/demo/FiveViewsDemo trunk/demo/FiveViewsDemo/www trunk/doc trunk/tests trunk/tests/products trunk/tests/products/FiveTest

faassen at codespeak.net faassen at codespeak.net
Wed Jun 16 14:54:01 MEST 2004


Author: faassen
Date: Wed Jun 16 14:54:00 2004
New Revision: 5103

Added:
   z3/Five/
   z3/Five/trunk/
   z3/Five/trunk/BSD.txt
   z3/Five/trunk/INSTALL.txt
   z3/Five/trunk/LICENSES.txt
   z3/Five/trunk/README.txt
   z3/Five/trunk/ZopePublicLicense.txt
   z3/Five/trunk/__init__.py
   z3/Five/trunk/api.py
   z3/Five/trunk/browser.py
   z3/Five/trunk/demo/
   z3/Five/trunk/demo/FiveDemo/
   z3/Five/trunk/demo/FiveDemo/__init__.py
   z3/Five/trunk/demo/FiveDemo/classes.py
   z3/Five/trunk/demo/FiveDemo/configure.zcml
   z3/Five/trunk/demo/FiveDemo/interfaces.py
   z3/Five/trunk/demo/FiveViewsDemo/
   z3/Five/trunk/demo/FiveViewsDemo/README.txt
   z3/Five/trunk/demo/FiveViewsDemo/__init__.py
   z3/Five/trunk/demo/FiveViewsDemo/browser.py
   z3/Five/trunk/demo/FiveViewsDemo/configure.zcml
   z3/Five/trunk/demo/FiveViewsDemo/helpers.py
   z3/Five/trunk/demo/FiveViewsDemo/interfaces.py
   z3/Five/trunk/demo/FiveViewsDemo/simplecontent.py
   z3/Five/trunk/demo/FiveViewsDemo/www/
   z3/Five/trunk/demo/FiveViewsDemo/www/simpleContentAdd.zpt
   z3/Five/trunk/demo/README.txt
   z3/Five/trunk/doc/
   z3/Five/trunk/doc/five.mgp
   z3/Five/trunk/five.zcml
   z3/Five/trunk/fiveconfigure.py
   z3/Five/trunk/fivedirectives.py
   z3/Five/trunk/interfaces.py
   z3/Five/trunk/meta.zcml
   z3/Five/trunk/metaconfigure.py
   z3/Five/trunk/metadirectives.py
   z3/Five/trunk/monkey.py
   z3/Five/trunk/provideinterface.py
   z3/Five/trunk/services.zcml
   z3/Five/trunk/svn-commit.tmp
   z3/Five/trunk/tests/
   z3/Five/trunk/tests/README.txt
   z3/Five/trunk/tests/framework.py
   z3/Five/trunk/tests/products/
   z3/Five/trunk/tests/products/FiveTest/
   z3/Five/trunk/tests/products/FiveTest/__init__.py
   z3/Five/trunk/tests/products/FiveTest/classes.py
   z3/Five/trunk/tests/products/FiveTest/configure.zcml
   z3/Five/trunk/tests/products/FiveTest/interfaces.py
   z3/Five/trunk/tests/test_five.py
   z3/Five/trunk/viewable.py
   z3/Five/trunk/viewattribute.py
   z3/Five/trunk/zcml.py
Log:
Initial import of Five. This is a cvs export of cvs.infrae.com/Five.


Added: z3/Five/trunk/BSD.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/BSD.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,30 @@
+$Revision: 1.1 $
+Copyright (c) 2004 Infrae. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+   
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+
+  3. Neither the name of Infrae nor the names of its contributors may
+     be used to endorse or promote products derived from this software
+     without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INFRAE OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: z3/Five/trunk/INSTALL.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/INSTALL.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,24 @@
+How to install Five
+-------------------
+
+Installing Five is relatively straightforward. 
+
+* You need a Zope 2.7 instance.
+
+* You also need an installation of Zope 3. Later on we may produce a
+  Five-specific distribution of the Zope 3 components that are needed,
+  but for now just use Zope 3. You can install it by typing 'make'.
+
+* You need to make your Zope 2.7 instance aware of Zope 3 it can
+  import packages from it. To do this, go to the etc/zope.conf of your
+  Zope 2.7 instance and add a ``path`` entry to your Zope 3's ``src``
+  directory, i.e.::
+
+  path /path/to/Zope3/src
+
+* Next, install the Five product into your Zope 2.7 instance as a
+  product and restart Zope. Five should now be installed.
+
+* You can also install ``demo/FiveDemo`` and
+  ``demo/FiveViewsDemo``. For more about what these demos, see
+  ``README.txt``.

Added: z3/Five/trunk/LICENSES.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/LICENSES.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,22 @@
+Part of this software is derived from Zope 3. These parts are licensed under
+the Zope Public License, contained ZopePublicLicense.txt.
+
+The parts directly derived from Zope 3 source code are marked by the
+following block.
+
+"""
+Copyright (c) 2001, 2002, 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.
+"""
+
+The rest of the software falls under the BSD license and is copyright
+Infrae. This license is listed in BSD.txt.
+
+

Added: z3/Five/trunk/README.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/README.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,253 @@
+Introduction
+------------
+
+"It was the dawn of the third age of Zope. The Five project was a dream
+given form. Its goal: to use Zope 3 technologies in Zope 2.7 by
+creating a Zope 2 product where Zope 3 and Zope 2 could work out their
+differences peacefully." -- Babylon 5, creatively quoted
+
+"The Law of Fives states simply that: ALL THINGS HAPPEN IN FIVES, OR
+ARE DIVISIBLE BY OR ARE MULTIPLES OF FIVE, OR ARE SOMEHOW DIRECTLY OR
+INDIRECTLY RELATED TO FIVE.
+
+THE LAW OF FIVES IS NEVER WRONG." -- Principia Discordia
+
+How to install Five
+-------------------
+
+See ``INSTALL.txt``.
+
+How to use Five
+---------------
+
+Five is only useful on the Python (Product) level, not from within the
+Zope Management Interface. 
+
+Adapters
+--------
+
+The immediate thing that Five brings to do the table are
+adapters. This section goes through some demo code to explain how
+everything is tied together. ``demo/FiveDemo`` is a demo Product you
+can install and examine that has all the presented here together.
+
+Zope 3 adapters depend on Zope 3 interfaces. To create a Zope 3
+interface you need to subclass it from
+``zope.interface.Interface``. Here is an example::
+
+  from zope.interface import Interface
+
+  class IMyInterface(Interface):
+      """This is a Zope 3 interface.
+      """
+      def someMethod():
+          """This method does amazing stuff.
+          """
+
+Now to make some class declare that it implements this interface, you
+need to use the ``implements()`` function in the class::
+
+  from zope.interface import implements
+  from interfaces import IMyInterface
+
+  class MyClass:
+      implements(IMyInterface)
+
+      def someMethod(self):
+           return "I am alive! Alive!"
+
+For an explanation of the relation of Zope 3 interfaces to Zope 2
+interfaces, see below.
+
+Now let's set up the interface that we are adapting to::
+
+  class INewInterface(Interface):
+      """The interface we adapt to.
+      """
+
+      def anotherMethod():
+          """This method does more stuff.
+          """
+
+Next we'll work on the class that implements the adapter. The
+requirement to make a class that is an adapter is very simple; you
+only need to take a context object as the constructor. The context
+object is the object being adapted. An example::
+
+  from zope.interface import implements
+  from interfaces import INewInterface
+
+  class MyAdapter:
+      implements(INewInterface)
+ 
+      def __init__(self, context):
+          self.context = context
+
+      def anotherMethod(self):
+          return "We have adapted: %s" % self.context.someMethod()
+
+Next, we hook it all up using zcml. If the classes are in a module
+called ``classes.py`` and the interfaces in a module called
+``interfaces.py``, we can declare ``MyAdapter`` to be an adapter for
+``IMyInterface`` to ``INewInterface`` like this (in a file called
+``configure.zcml``)::
+
+  <configure xmlns="http://namespaces.zope.org/zope">
+
+    <adapter 
+      for=".interfaces.IMyInterface"
+      provides=".interfaces.INewInterface"
+      factory=".classes.MyAdapter" /> 
+    
+  </configure>
+
+The next step is to read ``configure.zcml`` so Zope can find these
+declarations. Do this by placing the following in the ``__init__.py``
+of your Zope product::
+
+  from Products.Five import zcml
+  import Products
+   
+  def initialize(context):
+      zcml.process('configure.zcml', package=Products.FiveDemo)        
+ 
+Any class that implements ``INewInterface`` can now be adapted to
+``INewInterface``, like this::
+
+  from zope.component import getAdapter
+  from classes import MyClass
+  from interfaces import INewInterface
+
+  object = MyClass()
+  adapted = getAdapter(object, INewInterface)
+  print adapted.anotherMethod()
+
+A shortcut for ``getAdapter()`` is to call the interface directly,
+like this::
+
+  adapted = INewInterface(object)
+
+Views in Five
+-------------
+
+This section will give a brief introduction on how to use the five
+view system. ``demo/FiveViewsDemo`` is a demo Product you can install
+and examine that has all the presented here tied together, please consult
+it for more details.
+
+Five enables you to create views for your own objects, or even built-in
+Zope objects, as long as two things are the case:
+
+* The object provides an Zope 3 interface, typically through its class.
+
+* The object (typically its class) is made viewable.
+
+Typically you give your classes an interface using the ``implements``
+directive in the class body::
+
+  class MyClass:
+      implements(ISomeInterface)
+
+For existing objects that you cannot modify this is not
+possible. Instead, we provide a ZCML directive to accomplish this. As
+an example, to make Zope's ``Folder`` (and all its subclasses)
+implement ``IFolder`` (an interface you defined), you can do the
+following in ZCML::
+
+  <five:implements class="OFS.Folder.Folder" 
+                   interface=".interfaces.IFolder" />
+
+``five`` in this case refers to the XML namespace for Five,
+``http://namespace.zope.org/five``.
+
+To make an object viewable through Five your object needs to mix in
+``Viewable``, which can be imported from Products.Five.api. For
+instance::
+
+  from Products.Five.api import Viewable
+
+  class MyClass(OFS.SimpleItem.Item, Viewable):
+      implements(ISomeInterface)
+
+For existing Zope objects, this is not easily possible. We've provided
+another ZCML directive however to take care of that. To continue our
+example, to make Zope's ``Folder`` viewable through Five, you need to
+declare this in ZCML as well:
+
+  <five:viewable class="OFS.Folder.Folder"/>
+
+This makes Folder look up Zope 3 views first, and then if they cannot be
+found, fall back on the regular Zope 2 views. This allows the ZMI to work
+still, but new views can be added on the fly.
+
+Note that at the point of writing it is only possible to make an object
+viewable through ZCML if this object does not already provide its own
+``__bobo_traverse__`` method.
+
+Views in Five are simple classes. The only requirements for a Five
+view class are:
+
+  * They need an ``__init__()`` that take a context and a request
+    attribute. Typically this comes from a base class, such as
+    ``FiveView``.
+
+  * They need to be initialized with the Zope 2 security system, as
+    otherwise you cannot use the view. 
+
+  * This also means they need to be part of the Zope 2 acquisition
+    system, as this is a requirement for Zope 2 security to
+    function. The ``BrowserView`` base class, available from
+    ``Products.Five.api``, already inherits from
+    ``Acquisition.Explicit`` to make this be the case. Acquisition is
+    explicit so no attributes can be acquired by accident.
+
+An example of a simple view::
+ 
+  from Products.Five.api import BrowserView
+
+  class SimpleFolderView(BrowserView):
+      security = ClassSecurityInfo()
+
+      security.declarePublic('eagle')
+      def eagle(self):
+          """Test
+          """
+          return "The eagle has landed: %s" % self.context.objectIds()
+
+  InitializeClass(SimpleFolderView)
+
+Note that it is not a good idea to give a view class its own
+``index_html``, as this confuses Five's view lookup machinery.
+
+As you can see, the class is initialized with the Zope 2 security
+system. This view uses methods in Python, but you can also use other
+Zope 2 mechanisms such as ``PageTemplateFile``.
+
+Finally, we need to hook up the pages through ZCML::
+
+  <five:page 
+    for=".interfaces.IFolder"
+    class=".browser.SimpleFolderView"
+    attribute="eagle"
+    name="eagle.txt"
+    />
+
+Interfaces in Zope 2 versus Zope 3
+----------------------------------
+
+Zope 2 has used the ``__implements__`` class attribute for interface
+declarations.  Zope 2 cannot detect Zope 3 interfaces and the
+Zope 3 machinery cannot detect Zope 2 interfaces. This is a good
+thing, as Zope 2 has no way to deal with Zope 3 interfaces, and Zope 3
+cannot comprehend Zope 2 interfaces. It also means you can safely
+these interface declarations in a class. It's a rare case where you
+need this though; you're better off just switching to ``implements()``
+for your application if you are using Five. 
+
+Switching from Zope 2 interfaces to Zope 3 interfaces is easy -- just
+make your interfaces inherit from ``zope.interface.Interface`` instead
+of ``Interface.Interface`` (or ``Interface.Base``). This should get
+you going and your application may very well still work. Later on, you
+will also have to change calls to ``isImplementedBy`` and such in your
+application to ``providedBy``, as ``isImplementedBy`` has been
+deprecated (you'll see the DeprecationWarnings in your log).

Added: z3/Five/trunk/ZopePublicLicense.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/ZopePublicLicense.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,59 @@
+Zope Public License (ZPL) Version 2.0
+-----------------------------------------------
+
+This software is Copyright (c) Zope Corporation (tm) and
+Contributors. All rights reserved.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the above
+   copyright notice, this list of conditions, and the following
+   disclaimer.
+
+2. Redistributions in binary form must reproduce the above
+   copyright notice, this list of conditions, and the following
+   disclaimer in the documentation and/or other materials
+   provided with the distribution.
+
+3. The name Zope Corporation (tm) must not be used to
+   endorse or promote products derived from this software
+   without prior written permission from Zope Corporation.
+
+4. The right to distribute this software or to use it for
+   any purpose does not give you the right to use Servicemarks
+   (sm) or Trademarks (tm) of Zope Corporation. Use of them is
+   covered in a separate agreement (see
+   http://www.zope.com/Marks).
+
+5. If any files are modified, you must cause the modified
+   files to carry prominent notices stating that you changed
+   the files and the date of any change.
+
+Disclaimer
+
+  THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
+  AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+  NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.
+
+
+This software consists of contributions made by Zope
+Corporation and many individuals on behalf of Zope
+Corporation.  Specific attributions are listed in the
+accompanying credits file.

Added: z3/Five/trunk/__init__.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/__init__.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,5 @@
+import Acquisition
+import monkey
+
+# trigger monkey patches
+monkey.monkeyPatch()

Added: z3/Five/trunk/api.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/api.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,2 @@
+from browser import BrowserView
+from viewable import Viewable

Added: z3/Five/trunk/browser.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/browser.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,22 @@
+import Acquisition
+from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass
+
+class BrowserView(Acquisition.Explicit):
+    security = ClassSecurityInfo()
+    
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    # XXX do not create any methods on the subclass called index_html,
+    # as this makes Zope 2 traverse into that first!
+    
+    def __call__(self, *args, **kw):
+        attr = self.__page_attribute__
+        if attr == '__call__':
+            raise AttributeError("__call__")
+        meth = getattr(self, attr)
+        return meth(*args, **kw)
+    
+InitializeClass(BrowserView)

Added: z3/Five/trunk/demo/FiveDemo/__init__.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveDemo/__init__.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,19 @@
+from Products.Five import zcml
+import Products
+
+def initialize(context):
+    zcml.process('configure.zcml', package=Products.FiveDemo)
+
+    # after everything is configured, we can use adapters
+    
+    from zope.component import getAdapter
+    from classes import MyClass
+    from interfaces import INewInterface
+    
+    object = MyClass()
+    adapted = getAdapter(object, INewInterface)
+    print adapted.anotherMethod()
+
+    # shortcut
+    adapted = INewInterface(object)
+    print adapted.anotherMethod()

Added: z3/Five/trunk/demo/FiveDemo/classes.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveDemo/classes.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,17 @@
+from zope.interface import implements
+from interfaces import IMyInterface, INewInterface
+
+class MyClass:
+    implements(IMyInterface)
+
+    def someMethod(self):
+        return "I am alive! Alive!"
+    
+class MyAdapter:
+    implements(INewInterface)
+  
+    def __init__(self, context):
+        self.context = context
+        
+    def anotherMethod(self):
+        return "We have adapted: %s" % self.context.someMethod()

Added: z3/Five/trunk/demo/FiveDemo/configure.zcml
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveDemo/configure.zcml	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,8 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+  <adapter 
+    for=".interfaces.IMyInterface"
+    provides=".interfaces.INewInterface"
+    factory=".classes.MyAdapter" /> 
+    
+</configure>

Added: z3/Five/trunk/demo/FiveDemo/interfaces.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveDemo/interfaces.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,16 @@
+from zope.interface import Interface
+
+class IMyInterface(Interface):
+    """This is a Zope 3 interface.
+    """
+    def someMethod():
+        """This method does amazing stuff.
+        """
+
+class INewInterface(Interface):
+    """The interface we adapt to.
+    """
+
+    def anotherMethod():
+        """This method does more stuff.
+        """

Added: z3/Five/trunk/demo/FiveViewsDemo/README.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/README.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,8 @@
+Demo code of the Five view architecture.
+
+To this this, try adding a 'SimpleContent' object as 'test', and then do:
+
+http://myzope/test/eagle.txt
+
+This will show the registered view for eagle.txt, which is an attribute on
+FiveViewsDemo.browser.SimpleContentView.

Added: z3/Five/trunk/demo/FiveViewsDemo/__init__.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/__init__.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,13 @@
+# this a demo of Five views
+from Products.Five import zcml
+import Products
+import simplecontent
+
+def initialize(context):
+    zcml.process('configure.zcml', package=Products.FiveViewsDemo)
+
+    context.registerClass(
+        simplecontent.SimpleContent,
+        constructors = (simplecontent.manage_addSimpleContentForm,
+                        simplecontent.manage_addSimpleContent),
+        )

Added: z3/Five/trunk/demo/FiveViewsDemo/browser.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/browser.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,31 @@
+from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass
+from Products.Five.api import BrowserView
+
+class SimpleContentView(BrowserView):
+    """More docstring. Please Zope"""
+    security = ClassSecurityInfo()
+
+    security.declareProtected('View Management Screens', 'eagle')
+    def eagle(self):
+        """Docstring"""
+        return "The eagle has landed"
+    
+InitializeClass(SimpleContentView)
+
+class SimpleFolderView(BrowserView):
+    security = ClassSecurityInfo()
+
+    security.declarePublic('eagle')
+    def eagle(self):
+        """Test
+        """
+        return "The eagle has landed: %s" % self.context.objectIds()
+
+    security.declareProtected('View management screens', 'mydefault')
+    def mydefault(self):
+        """Test
+        """
+        return "This is default view for %s" % self.context.absolute_url()
+    
+InitializeClass(SimpleFolderView)

Added: z3/Five/trunk/demo/FiveViewsDemo/configure.zcml
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/configure.zcml	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,27 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:five="http://namespaces.zope.org/five">
+
+  <five:page 
+    for=".interfaces.ISimpleContent"
+    class=".browser.SimpleContentView"
+    attribute="eagle"
+    name="eagle.txt"
+    />
+
+  <five:implements
+    class="OFS.Folder.Folder"
+    interface=".interfaces.IFolder"
+    />
+
+  <five:viewable
+    class="OFS.Folder.Folder" 
+    />
+
+  <five:page
+    for=".interfaces.IFolder"
+    class=".browser.SimpleFolderView"
+    attribute="eagle"
+    name="eagle.txt"
+    />
+  
+</configure>

Added: z3/Five/trunk/demo/FiveViewsDemo/helpers.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/helpers.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,16 @@
+import urllib
+
+def add_and_edit(self, id, REQUEST):
+    """Helper function to point to the object's management screen if
+    'Add and Edit' button is pressed.
+    id -- id of the object we just added
+    """
+    if REQUEST is None:
+        return
+    try:
+        u = self.DestinationURL()
+    except:
+        u = REQUEST['URL1']
+    if REQUEST.has_key('submit_edit'):
+        u = "%s/%s" % (u, urllib.quote(id))
+    REQUEST.RESPONSE.redirect(u+'/manage_main')

Added: z3/Five/trunk/demo/FiveViewsDemo/interfaces.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/interfaces.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,9 @@
+from zope.interface import Interface
+
+class ISimpleContent(Interface):
+    def mymethod():
+        """This is just a sample method.
+        """
+
+class IFolder(Interface):
+    pass

Added: z3/Five/trunk/demo/FiveViewsDemo/simplecontent.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/simplecontent.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,35 @@
+from OFS.SimpleItem import SimpleItem
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from helpers import add_and_edit
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.Five.api import Viewable
+from zope.interface import implements
+from interfaces import ISimpleContent
+
+class SimpleContent(SimpleItem, Viewable):
+
+    implements(ISimpleContent)
+    
+    meta_type = 'SimpleContent'
+    security = ClassSecurityInfo()
+
+    def __init__(self, id, title):
+        self.id = id
+        self.title = title
+        
+    security.declarePublic('mymethod')
+    def mymethod(self):
+        return "Hello world"
+
+InitializeClass(SimpleContent)
+
+manage_addSimpleContentForm = PageTemplateFile(
+    "www/simpleContentAdd", globals(),
+    __name__ = 'manage_addSimpleContentForm')
+
+def manage_addSimpleContent(self, id, title, REQUEST=None):
+    """Add the simple content."""
+    id = self._setObject(id, SimpleContent(id, title))
+    add_and_edit(self, id, REQUEST)
+    return ''

Added: z3/Five/trunk/demo/FiveViewsDemo/www/simpleContentAdd.zpt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/FiveViewsDemo/www/simpleContentAdd.zpt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,47 @@
+<h1 tal:replace="structure here/manage_page_header">Header</h1>
+
+<h2 tal:define="form_title string:Add Silva SidebarService"
+    tal:replace="structure here/manage_form_title">Form Title</h2>
+
+<p class="form-help">
+Add Simple Content
+</p>
+
+<form action="manage_addSimpleContent" method="post">
+<table cellspacing="0" cellpadding="2" border="0">
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Id
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="id" size="40" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Title
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="title" size="40" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    </td>
+    <td align="left" valign="top">
+    <div class="form-element">
+    <input class="form-element" type="submit" name="submit_add" 
+     value=" Add " /> 
+    <input class="form-element" type="submit" name="submit_edit" 
+     value=" Add and Edit " />
+    </div>
+    </td>
+  </tr>
+</table>
+</form>
+
+<h1 tal:replace="structure here/manage_page_footer">Footer</h1>

Added: z3/Five/trunk/demo/README.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/demo/README.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,3 @@
+This directory contains a demo product, called FiveDemo, that
+demonstrates the use of Five.
+

Added: z3/Five/trunk/doc/five.mgp
==============================================================================
--- (empty file)
+++ z3/Five/trunk/doc/five.mgp	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,127 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%deffont "standard" xfont "helvetica-medium-r"
+%deffont "thick" xfont "helvetica-bold-r"
+%deffont "typewriter" xfont "courier-medium-r"
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Default settings per each line numbers.
+%%
+%default 1 area 90 90, leftfill, size 2, fore "gray20", back "white", font "standard", hgap 0
+%default 2 size 7, vgap 10, prefix " ", ccolor "blue"
+%default 3 size 2, bar "gray70", vgap 10
+%default 4 size 5, fore "gray20", vgap 30, prefix " ", font "standard"
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Default settings that are applied to TAB-indented lines.
+%%
+%tab 1 size 5, vgap 40, prefix "  ", icon box "red" 50
+%tab 2 size 4, vgap 40, prefix "      ", icon arc "yellow" 50
+%tab 3 size 3, vgap 40, prefix "            ", icon delta3 "white" 40
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%page
+
+Five - Zope 3 in Zope 2
+
+
+
+
+%center
+Martijn Faassen, Infrae
+faassen at infrae.com
+
+%page
+
+Motto
+
+
+It was the dawn of the third age of Zope. The Five project was a dream given form. Its goal: to use Zope 3 technologies in Zope 2.7 by creating a Zope 2 product where Zope 3 and Zope 2 could work out their differences peacefully. 
+
+(Babylon 5 season 1 intro, creatively quoted)
+
+%page
+
+Motto 2
+
+
+The Law of Fives states simply that: ALL THINGS HAPPEN IN FIVES, OR ARE DIVISIBLE BY OR ARE MULTIPLES OF FIVE, OR ARE SOMEHOW DIRECTLY OR INDIRECTLY RELATED TO FIVE.
+
+THE LAW OF FIVES IS NEVER WRONG. 
+
+(Principia Discordia)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%page
+
+The problem
+
+
+	We're using Zope 2 in production
+
+	Zope 2 is showing its age
+
+	Zope 3 has better ways to do things
+
+	But can't just switch, we have customers!
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%page
+
+Benefits of using Zope 3 in Zope 2
+
+
+	Able to use Zope 3 technologies right away
+
+	Don't reinvent the wheel/APIs
+
+	Better prepared for Zope 3 transition
+
+	Evolution, not revolution
+
+	Convergence, not divergence
+
+%page
+
+What works now?
+
+
+	Interfaces (zope.interface)
+
+	Schema (zope.schema)
+
+	ZCML (zope.configuration)
+
+	Adapters (zope.component)
+
+	Views, including layers, skins (zope.component)
+
+%page
+
+Brief demo
+
+
+	Show ZCML, adapters and views in action
+ 
+%page
+
+Next?
+
+
+	Utilities (global ones should work)
+
+	Forms
+
+	Views (improve the current system)
+
+	Who knows?
+
+%page
+
+Plans
+
+
+	Relicense from BSD to generic ZPL 2.1
+
+	Move from CVS at Infrae into SVN at codespeak.net
+
+	Convergence; join us!
+

Added: z3/Five/trunk/five.zcml
==============================================================================
--- (empty file)
+++ z3/Five/trunk/five.zcml	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,10 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+           xmlns:five="http://namespaces.zope.org/five">
+  
+  <include file="meta.zcml" />
+  <include file="services.zcml" />
+
+  <five:implements class="ZPublisher.HTTPRequest.HTTPRequest"
+                   interface="zope.publisher.interfaces.browser.IBrowserRequest" />
+
+</configure>

Added: z3/Five/trunk/fiveconfigure.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/fiveconfigure.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,143 @@
+"""Five specific directives.
+"""
+import os
+from zope.interface import classImplements, Interface
+from zope.component import getService, getGlobalService,\
+     ComponentLookupError
+from zope.configuration.exceptions import ConfigurationError
+from zope.component.servicenames import Adapters, Presentation
+from zope.publisher.interfaces.browser import IBrowserRequest
+from provideinterface import provideInterface
+from viewattribute import ViewAttribute
+from viewable import Viewable
+
+#def handler(serviceName, methodName, *args, **kwargs):
+#    method=getattr(getService(serviceName), methodName)
+#    method(*args, **kwargs)
+
+def handler(serviceName, methodName, *args, **kwargs):
+    method=getattr(getGlobalService(serviceName), methodName)
+    method(*args, **kwargs)
+
+def page(_context, name, for_,
+         layer='default', template=None, class_=None,
+         attribute='__call__', menu=None, title=None, 
+         ):
+
+    try:
+        s = getGlobalService(Presentation)
+    except ComponentLookupError, err:
+        pass
+
+    if not (class_ or template):
+        raise ConfigurationError("Must specify a class or template")
+
+    if attribute != '__call__':
+        if template:
+            raise ConfigurationError(
+                "Attribute and template cannot be used together.")
+
+        if not class_:
+            raise ConfigurationError(
+                "A class must be provided if attribute is used")
+
+    if template:
+        template = os.path.abspath(str(_context.path(template)))
+        if not os.path.isfile(template):
+            raise ConfigurationError("No such file", template)
+
+    if class_:
+        if attribute != '__call__':
+            if not hasattr(class_, attribute):
+                raise ConfigurationError(
+                    "The provided class doesn't have the specified attribute "
+                    )
+        if template:
+            # class and template
+            new_class = SimpleViewClass(
+                template, bases=(class_, ))
+        else:
+            #if not hasattr(class_, 'browserDefault'):
+            #    cdict = {
+            #        'browserDefault':
+            #        lambda self, request: (getattr(self, attribute), ())
+            #        }
+            #else:
+            #    cdict = {}
+                
+            #cdict['__page_attribute__'] = attribute
+            class_.__page_attribute__ = attribute
+            new_class = class_
+
+    else:
+        # template
+        new_class = SimpleViewClass(template)
+
+    _handle_for(_context, for_)
+
+    _context.action(
+        discriminator = ('view', for_, name, IBrowserRequest, layer),
+        callable = handler,
+        args = (Presentation, 'provideAdapter',
+                IBrowserRequest, new_class, name, [for_], Interface, layer,
+                _context.info),
+        )
+
+def _handle_for(_context, for_):
+    if for_ is not None:
+        _context.action(
+            discriminator = None,
+            callable = provideInterface,
+            args = ('', for_)
+            )        
+
+def implements(_context, class_, interface):
+    for interface in interface:
+        _context.action(
+            discriminator = None,
+            callable = classImplements,
+            args = (class_, interface)
+            )
+        _context.action(
+            discriminator = None,
+            callable = provideInterface,
+            args = (interface.__module__ + '.' + interface.getName(),
+                    interface)
+            )
+
+def classViewable(class_):
+    if hasattr(class_, '__bobo_traverse__'):
+        raise TypeError("__bobo_traverse already__ exists on %s" % class_)
+    setattr(class_, '__bobo_traverse__', Viewable.__bobo_traverse__)
+
+def viewable(_context, class_):
+    _context.action(
+        discriminator = (class_,),
+        callable = classViewable,
+        args = (class_,)
+        )
+        
+def layer(_context, name):
+
+    _context.action(
+        discriminator = ('layer', name),
+        callable = handler,
+        args = (Presentation, 'defineLayer', name, _context.info)
+        )
+
+def skin(_context, name, layers):
+    if ',' in layers:
+        raise TypeError("Commas are not allowed in layer names.")
+
+    _context.action(
+        discriminator = ('skin', name),
+        callable = handler,
+        args = (Presentation, 'defineSkin', name, layers, _context.info)
+        )
+
+def defaultSkin(_context, name):
+    _context.action(
+        discriminator = 'defaultSkin',
+        callable = handler,
+        args = (Presentation, 'setDefaultSkin', name, _context.info)
+        )

Added: z3/Five/trunk/fivedirectives.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/fivedirectives.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,160 @@
+from zope.interface import Interface
+from zope.configuration.fields import GlobalObject, Tokens,\
+     PythonIdentifier, MessageID
+from zope.schema import TextLine, Id
+
+class IBasicViewInformation(Interface):
+    """
+    This is the basic information for all views.
+    """
+    
+    for_ = Tokens(
+        title=u"Specifications of the objects to be viewed",
+        description=u"""This should be a list of interfaces or classes
+        """,
+        required=True,
+        value_type=GlobalObject(missing_value=object())
+        )
+
+    class_ = GlobalObject(
+        title=u"Class",
+        description=u"A class that provides attributes used by the view.",
+        required=False
+        )
+
+    layer = TextLine(
+        title=u"The layer the view is in.",
+        description=u"""
+        A skin is composed of layers. It is common to put skin
+        specific views in a layer named after the skin. If the 'layer'
+        attribute is not supplied, it defaults to 'default'.""",
+        required=False
+        )
+
+class IPagesDirective(IBasicViewInformation):
+    """
+    Define multiple pages without repeating all of the parameters.
+
+    The pages directive allows multiple page views to be defined
+    without repeating the 'for', 'permission', 'class', 'layer',
+    'allowed_attributes', and 'allowed_interface' attributes.
+    """
+
+    for_ = GlobalObject(
+        title=u"The interface this view is for.",
+        required=False
+        )
+
+class IPagesPageSubdirective(Interface):
+    """
+    Subdirective to IPagesDirective
+    """
+
+    name = TextLine(
+        title=u"The name of the page (view)",
+        description=u"""
+        The name shows up in URLs/paths. For example 'foo' or
+        'foo.html'. This attribute is required unless you use the
+        subdirective 'page' to create sub views. If you do not have
+        sub pages, it is common to use an extension for the view name
+        such as '.html'. If you do have sub pages and you want to
+        provide a view name, you shouldn't use extensions.""",
+        required=True
+        )
+
+    template = TextLine(
+        title=u"The name of a page template.",
+        description=u"""
+        Refers to a file containing a page template (must end in
+        extension '.pt').""",
+        required=False
+        )
+
+    attribute = PythonIdentifier(
+        title=u"The name of an attribute to publish.",
+        description=u"""
+        This is used to publish an attribute provided by a class,
+        instead of a template.
+
+        This is the attribute, usually a method, to be published as
+        the page (view).  The default is "__call__".""",
+        required=False
+        )
+
+    title = MessageID(
+        title=u"The browser menu label for the page (view)",
+        description=u"""
+        This attribute must be supplied if a menu attribute is
+        supplied.""",
+        required=False
+        )
+
+class IPageDirective(IPagesDirective, IPagesPageSubdirective):
+    """
+    The page directive is used to create views that provide a single
+    url or page.
+
+    The page directive creates a new view class from a given template
+    and/or class and registers it.
+    """
+
+class IImplementsDirective(Interface):
+    """State that a class implements something.
+    """
+    class_ = GlobalObject(
+        title=u"Class",
+        required=True
+        )
+
+    interface = Tokens(
+        title=u"One or more interfaces",
+        required=True,
+        value_type=GlobalObject()
+        )
+
+class IViewableDirective(Interface):
+    """State that a class can be viewed.
+    """
+    class_ = GlobalObject(
+        title=u"Class",
+        required=True
+        )
+    
+class ILayerDirective(Interface):
+    """
+    Register a layer
+    """
+
+    name = TextLine(
+        title=u"Layer name",
+        description=u"Layer name",
+        required=True
+        )
+
+class ISkinDirective(Interface):
+    """
+    Register a skin
+    """
+
+    name = TextLine(
+        title=u"Skin name",
+        description=u"Skin name",
+        required=True
+        )
+
+    layers = Tokens(
+        title=u"The layers it consists of.",
+        required=True,
+        value_type=TextLine()
+        )
+
+class IDefaultSkinDirective(Interface):
+    """
+    Register a skin
+    """
+
+    name = TextLine(
+        title=u"Default skin name",
+        description=u"Default skin name",
+        required=True
+        )

Added: z3/Five/trunk/interfaces.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/interfaces.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,3 @@
+from zope.interface import Interface
+
+# nothing in here for now

Added: z3/Five/trunk/meta.zcml
==============================================================================
--- (empty file)
+++ z3/Five/trunk/meta.zcml	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,80 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta">
+
+  <meta:directives namespace="http://namespaces.zope.org/zope">
+
+    <meta:directive
+        name="interface"
+        schema=".metadirectives.IInterfaceDirective"
+        handler=".metaconfigure.interface"
+        />
+
+    <meta:directive
+        name="adapter"
+        schema=".metadirectives.IAdapterDirective"
+        handler=".metaconfigure.adapter"
+        />
+
+    <meta:directive
+        name="utility"
+        schema=".metadirectives.IUtilityDirective"
+        handler=".metaconfigure.utility"
+        />
+
+    <meta:directive
+        name="serviceType"
+        schema=".metadirectives.IServiceTypeDirective"
+        handler=".metaconfigure.serviceType"
+        />
+                                                                                
+    <meta:directive
+        name="service"
+        schema=".metadirectives.IServiceDirective"
+        handler=".metaconfigure.service"
+        />
+
+  </meta:directives>
+
+  <meta:directives namespace="http://namespaces.zope.org/five">
+    
+    <meta:directive
+        name="page"
+        schema=".fivedirectives.IPageDirective"
+        handler=".fiveconfigure.page"
+        />
+ 
+    <meta:directive
+       name="layer"
+       schema=".fivedirectives.ILayerDirective"
+       handler=".fiveconfigure.layer"
+       />
+
+     <meta:directive
+       name="skin"
+       schema=".fivedirectives.ISkinDirective"
+       handler=".fiveconfigure.skin"
+       />
+
+     <meta:directive
+       name="defaultSkin"
+       schema=".fivedirectives.IDefaultSkinDirective"
+       handler=".fiveconfigure.defaultSkin"
+       />
+
+    <!-- specific to Five -->
+    <meta:directive
+       name="implements"
+       schema=".fivedirectives.IImplementsDirective"
+       handler=".fiveconfigure.implements"
+       />
+
+    <meta:directive
+       name="viewable"
+       schema=".fivedirectives.IViewableDirective"
+       handler=".fiveconfigure.viewable"
+       />
+
+  </meta:directives>
+
+</configure>

Added: z3/Five/trunk/metaconfigure.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/metaconfigure.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,128 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Generic Components ZCML Handlers
+
+$Id: metaconfigure.py,v 1.5 2004/06/02 08:44:01 faassen Exp $
+"""
+from zope.component import getService, getServices
+from zope.component.servicenames import Adapters
+from provideinterface import provideInterface
+
+def handler(serviceName, methodName, *args, **kwargs):
+    method=getattr(getService(serviceName), methodName)
+    method(*args, **kwargs)
+
+def managerHandler(methodName, *args, **kwargs):
+    method=getattr(getServices(), methodName)
+    method(*args, **kwargs)
+
+def serviceType(_context, id, interface):
+    _context.action(
+        discriminator = ('serviceType', id),
+        callable = managerHandler,
+        args = ('defineService', id, interface),
+        )
+
+    if interface.__name__ not in ['IUtilityService']:
+        _context.action(
+            discriminator = None,
+             callable = provideInterface,
+             args = (interface.__module__+'.'+interface.getName(),
+                     interface)
+             )
+
+def provideService(serviceType, component, permission):
+    # XXX this can probably be eliminated and provideService can be used
+    # directly
+    service_manager = getServices()
+    service_manager.provideService(serviceType, component)
+
+def service(_context, serviceType, component=None, permission=None,
+            factory=None):
+    if factory:
+        if component:
+            raise TypeError("Can't specify factory and component.")
+
+        component = factory()
+
+    _context.action(
+        discriminator = ('service', serviceType),
+        callable = provideService,
+        args = (serviceType, component, permission),
+        )
+
+def interface(_context, interface, type=None):
+    _context.action(
+        discriminator = None,
+        callable = provideInterface,
+        args = ('', interface, type)
+        )
+
+def adapter(_context, factory, provides, for_, permission=None, name=''):
+    for_ = tuple(for_)
+
+    # Generate a single factory from multiple factories:
+    factories = factory
+    if len(factories) == 1:
+        factory = factories[0]
+    elif len(factories) < 1:
+        raise ValueError("No factory specified")
+    elif len(factories) > 1 and len(for_) != 1:
+        raise ValueError("Can't use multiple factories and multiple for")
+    else:
+        def factory(ob):
+            for f in factories:
+                ob = f(ob)
+            return ob
+        # Store the original factory for documentation
+        factory.factory = factories[0]
+
+    _context.action(
+        discriminator = ('adapter', for_, provides, name),
+        callable = handler,
+        args = (Adapters, 'register',
+                for_, provides, name, factory, _context.info),
+        )
+    _context.action(
+        discriminator = None,
+        callable = provideInterface,
+        args = ('', provides)
+               )
+    if for_:
+        for iface in for_:
+            if iface is not None:
+                _context.action(
+                    discriminator = None,
+                    callable = provideInterface,
+                    args = ('', iface)
+                    )
+
+def utility(_context, provides, component=None, factory=None,
+            permission=None, name=''):
+    if factory:
+        if component:
+            raise TypeError("Can't specify factory and component.")
+        component = factory()
+
+    _context.action(
+        discriminator = ('utility', provides, name),
+        callable = handler,
+        args = ('Utilities', 'provideUtility',
+                provides, component, name),
+        )
+    _context.action(
+        discriminator = None,
+        callable = provideInterface,
+        args = (provides.__module__ + '.' + provides.getName(), provides)
+               )

Added: z3/Five/trunk/metadirectives.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/metadirectives.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,120 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""
+$Id: metadirectives.py,v 1.2 2004/05/18 13:58:57 faassen Exp $
+"""
+from zope.interface import Interface
+from zope.configuration.fields import GlobalObject, Tokens, \
+     PythonIdentifier, MessageID
+from zope.schema import TextLine, Id
+
+class IBasicComponentInformation(Interface):
+
+    component = GlobalObject(
+        title=u"Component to be used",
+        required=False
+        )
+
+    factory = GlobalObject(
+        title=u"Factory",
+        required=False
+        )
+
+class IServiceTypeDirective(Interface):
+                                                           
+    id = TextLine(
+        title=u"ID of the service type",
+        required=True
+        )
+ 
+    interface = GlobalObject(
+        title=u"Interface of the service type",
+        required=True
+        )
+ 
+class IServiceDirective(IBasicComponentInformation):
+    """
+    Register a service
+    """
+ 
+    serviceType = TextLine(
+        title=u"ID of service type",
+        required=True
+        )
+
+class IInterfaceDirective(Interface):
+    """
+    Define an interface
+    """
+    
+    interface = GlobalObject(
+        title=u"Interface",
+        required=True
+        )
+
+    type = GlobalObject(
+        title=u"Interface type",
+        required=False
+        )
+
+class IAdapterDirective(Interface):
+    """
+    Register an adapter
+    """
+
+    factory = Tokens(
+        title=u"Adapter factory/factories",
+        description=u"""A list of factories (usually just one) that create the
+        adapter instance.""",
+        required=True,
+        value_type=GlobalObject()
+        )
+
+    provides = GlobalObject(
+        title=u"Interface the component provides",
+        description=u"""This attribute specifes the interface the adapter
+        instance must provide.""",
+        required=True
+        )
+
+    for_ = Tokens(
+        title=u"Specifications to be adapted",
+        description=u"""This should be a list of interfaces or classes
+        """,
+        required=True,
+        value_type=GlobalObject(missing_value=object())
+        )
+
+    name = TextLine(
+        title=u"Name",
+        description=u"""Adapters can have names. This attribute allows you to
+        specify the name for this adapter.""",
+        required=False
+        )
+
+class IUtilityDirective(IBasicComponentInformation):
+    """
+    Register a utility
+    """
+
+    provides = GlobalObject(
+        title=u"Interface the component provides",
+        required=True
+        )
+
+    name = TextLine(
+        title=u"Name",
+        required=False
+        )
+

Added: z3/Five/trunk/monkey.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/monkey.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,19 @@
+
+def monkeyPatch():
+    """Trigger all monkey patches needed to make Five work.
+    
+    This adjusts Zope 2 classes to make them work with Zope 3.
+
+    Monkey patches are kept to a minimum level.
+    """
+    
+    from ZPublisher.HTTPRequest import HTTPRequest
+    
+    def getPresentationSkin(self):
+        return getattr(self, '_presentation_skin', None)
+
+    def setPresentationSkin(self, skin):
+        self._presentation_skin = skin
+        
+    HTTPRequest.getPresentationSkin = getPresentationSkin
+    HTTPRequest.setPresentationSkin = setPresentationSkin

Added: z3/Five/trunk/provideinterface.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/provideinterface.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+from zope.component import getService, servicenames
+from zope.interface import directlyProvides
+from zope.interface.interfaces import IInterface
+from types import ClassType
+
+def provideInterface(id, interface, iface_type=None):
+    """register Interface with utility service
+    """
+    if not id:
+        id = "%s.%s" % (interface.__module__, interface.__name__)
+
+    if not IInterface.providedBy(interface):
+        if not isinstance(interface, (type, ClassType)):
+            raise TypeError(id, "is not an interface or class")
+        return
+
+    if iface_type is not None:
+        if not iface_type.extends(IInterface):
+            raise TypeError(iface_type, "is not an interface type")
+        directlyProvides(interface, iface_type)
+    else:
+        iface_type = IInterface
+        
+    utilityService = getService(servicenames.Utilities)
+    utilityService.provideUtility(iface_type, interface, name=id)

Added: z3/Five/trunk/services.zcml
==============================================================================
--- (empty file)
+++ z3/Five/trunk/services.zcml	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,27 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+  <serviceType
+      id="Utilities"
+      interface="zope.component.interfaces.IUtilityService" />
+   
+  <service
+      serviceType="Utilities"
+      factory="zope.component.utility.GlobalUtilityService" />
+   
+  <serviceType
+      id="Adapters"
+      interface="zope.component.interfaces.IAdapterService" />
+   
+  <service
+      serviceType="Adapters"
+      factory="zope.component.adapter.GlobalAdapterService" />
+
+  <serviceType
+      id="Presentation"
+      interface="zope.component.interfaces.IPresentationService" />
+  
+  <service
+      serviceType="Presentation"
+      factory="zope.component.presentation.GlobalPresentationService" />
+ 
+</configure>

Added: z3/Five/trunk/svn-commit.tmp
==============================================================================
--- (empty file)
+++ z3/Five/trunk/svn-commit.tmp	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,4 @@
+Initial import of Five, taken from Infrae CVS at cvs.infrae.com/Five
+--This line, and those below, will be ignored--
+
+A    .

Added: z3/Five/trunk/tests/README.txt
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/README.txt	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,28 @@
+How to run the tests:
+
+The tests need all products in the tests/products subdirectory installed
+in your Zope instance's Products directory. On unixy systems, this can
+be most simply done by a symlink::
+
+  cd myinstance/Products
+  ln -s Five/tests/products/FiveTest .
+
+and so on for each product in tests/products.
+
+The tests also require ZopeTestCase to be installed. ZopeTestCase can
+be downloaded from here:
+
+http://zope.org/Members/shh/ZopeTestCase
+
+it needs to be installed in your Zope software's lib/python/Testing
+directory.
+
+Finally, to run the tests you need to set the following environment
+variables:
+
+  export INSTANCE_HOME=/path/to/instance
+  export SOFTWARE_HOME=/path/to/software/lib/python
+
+Then you should be able to run the tests by typing:
+
+  python2.3 test_five.py

Added: z3/Five/trunk/tests/framework.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/framework.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# ZopeTestCase 
+#
+# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
+#
+# This version of framework.py will use the SOFTWARE_HOME
+# environment variable to locate Zope and the Testing package.
+#
+# If the tests are run in an INSTANCE_HOME installation of Zope,
+# Products.__path__ and sys.path with be adjusted to include the
+# instance's Products and lib/python directories respectively.
+#
+# If you explicitly set INSTANCE_HOME prior to running the tests,
+# auto-detection is disabled and the specified path will be used 
+# instead.
+#
+# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
+# will be adjusted to use it.
+#
+# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup 
+# is assumed, and you can attach to a running ZEO server (via the 
+# instance's custom_zodb.py).
+#
+##############################################################################
+#
+# The following code should be at the top of every test module:
+#
+# import os, sys
+# if __name__ == '__main__':
+#     execfile(os.path.join(sys.path[0], 'framework.py'))
+#
+# ...and the following at the bottom:
+#
+# if __name__ == '__main__':
+#     framework()
+#
+##############################################################################
+
+__version__ = '0.2.3'
+
+# Save start state
+#
+__SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '')
+__INSTANCE_HOME = os.environ.get('INSTANCE_HOME', '')
+
+if __SOFTWARE_HOME.endswith(os.sep):
+    __SOFTWARE_HOME = os.path.dirname(__SOFTWARE_HOME)
+
+if __INSTANCE_HOME.endswith(os.sep):
+    __INSTANCE_HOME = os.path.dirname(__INSTANCE_HOME)
+
+# Find and import the Testing package
+#
+if not sys.modules.has_key('Testing'):
+    p0 = sys.path[0]
+    if p0 and __name__ == '__main__':
+        os.chdir(p0)
+        p0 = ''
+    s = __SOFTWARE_HOME
+    p = d = s and s or os.getcwd()
+    while d:
+        if os.path.isdir(os.path.join(p, 'Testing')):
+            zope_home = os.path.dirname(os.path.dirname(p))
+            sys.path[:1] = [p0, p, zope_home]
+            break
+        p, d = s and ('','') or os.path.split(p)
+    else:
+        print 'Unable to locate Testing package.',
+        print 'You might need to set SOFTWARE_HOME.'
+        sys.exit(1)
+
+import Testing, unittest
+execfile(os.path.join(os.path.dirname(Testing.__file__), 'common.py'))
+
+# Include ZopeTestCase support
+#
+if 1:   # Create a new scope
+
+    p = os.path.join(os.path.dirname(Testing.__file__), 'ZopeTestCase')
+
+    if not os.path.isdir(p):
+        print 'Unable to locate ZopeTestCase package.',
+        print 'You might need to install ZopeTestCase.'
+        sys.exit(1)
+
+    ztc_common = 'ztc_common.py'
+    ztc_common_global = os.path.join(p, ztc_common) 
+
+    f = 0
+    if os.path.exists(ztc_common_global):
+        execfile(ztc_common_global)
+        f = 1
+    if os.path.exists(ztc_common):
+        execfile(ztc_common)
+        f = 1
+
+    if not f:
+        print 'Unable to locate %s.' % ztc_common
+        sys.exit(1)
+
+# Debug
+#
+print 'SOFTWARE_HOME: %s' % os.environ.get('SOFTWARE_HOME', 'Not set')
+print 'INSTANCE_HOME: %s' % os.environ.get('INSTANCE_HOME', 'Not set')
+sys.stdout.flush()
+

Added: z3/Five/trunk/tests/products/FiveTest/__init__.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/products/FiveTest/__init__.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,6 @@
+from Products.Five import zcml
+import Products
+
+def initialize(context):
+    zcml.process('configure.zcml', package=Products.FiveTest)
+

Added: z3/Five/trunk/tests/products/FiveTest/classes.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/products/FiveTest/classes.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,17 @@
+from zope.interface import implements
+from interfaces import IAdaptable, IAdapted
+
+class Adaptable:
+    implements(IAdaptable)
+
+    def method(self):
+        return "The method"
+    
+class Adapter:
+    implements(IAdapted)
+  
+    def __init__(self, context):
+        self.context = context
+        
+    def adaptedMethod(self):
+        return "Adapted: %s" % self.context.method()

Added: z3/Five/trunk/tests/products/FiveTest/configure.zcml
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/products/FiveTest/configure.zcml	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,8 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+  <adapter 
+    for=".interfaces.IAdaptable"
+    provides=".interfaces.IAdapted"
+    factory=".classes.Adapter" /> 
+    
+</configure>

Added: z3/Five/trunk/tests/products/FiveTest/interfaces.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/products/FiveTest/interfaces.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,17 @@
+from zope.interface import Interface
+
+class IAdaptable(Interface):
+    """This is a Zope 3 interface.
+    """
+    def method(self):
+        """This method will be adapted
+        """
+        
+class IAdapted(Interface):
+    """The interface we adapt to.
+    """
+
+    def adaptedMethod(self):
+        """A method to adapt.
+        """
+

Added: z3/Five/trunk/tests/test_five.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/test_five.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,45 @@
+import os, sys
+
+if __name__ == '__main__':
+    execfile(os.path.join(sys.path[0], 'framework.py'))
+
+# XXX hack but no other way to initialize options apparently
+from Zope.Startup.run import configure
+configure('../../../etc/zope.conf')
+
+from Testing import ZopeTestCase
+
+ZopeTestCase.installProduct('Five')
+ZopeTestCase.installProduct('FiveTest')
+
+from zope.component import getAdapter
+from Products.FiveTest.classes import Adaptable
+from Products.FiveTest.interfaces import IAdapted
+
+class FiveTestCase(ZopeTestCase.ZopeTestCase):
+    def beforeSetUp(self):
+        self.root = self._app()
+
+    def test_adapters(self):
+        obj = Adaptable()
+        adapted = getAdapter(obj, IAdapted)
+        self.assertEquals(
+            "Adapted: The method",
+            adapted.adaptedMethod())
+
+    def test_adapters2(self):
+        obj = Adaptable()
+        adapted = IAdapted(obj)
+        self.assertEquals(
+            "Adapted: The method",
+            adapted.adaptedMethod())
+        
+    
+if __name__ == '__main__':
+    framework()
+else:
+    import unittest
+    def test_suite():
+        suite = unittest.TestSuite()
+        suite.addTest(unittest.makeSuite(FiveTestCase))
+        return suite

Added: z3/Five/trunk/viewable.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/viewable.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,42 @@
+from zope.component import getView, ComponentLookupError
+from zope.interface import implements
+from zope.publisher.interfaces.browser import IBrowserRequest
+
+class FakeRequest:
+    implements(IBrowserRequest)
+    
+    def getPresentationSkin(self):
+        return None
+    
+class Viewable:
+    """A mixin to make an object viewable using the Zope 3 system.
+    """
+    def __bobo_traverse__(self, REQUEST, name):
+        try:
+            if not IBrowserRequest.providedBy(REQUEST):
+                REQUEST = FakeRequest()
+            try:
+                return getView(self, name, REQUEST).__of__(self)
+            except ComponentLookupError:
+                pass
+            try:
+                return getattr(self, name)
+            except AttributeError:
+                pass
+            try:
+                return self[name]
+            except (AttributeError, KeyError):
+                pass
+            method = REQUEST.get('REQUEST_METHOD', 'GET')
+            if not method in ('GET', 'POST'):
+                return NullResource(self, name, REQUEST).__of__(self)
+
+            # Waaa. See Application.py
+            try:
+                REQUEST.RESPONSE.notFoundError("%sn%s" % (name, method))
+            except AttributeError:
+                raise KeyError, name
+        except:
+            import traceback
+            traceback.print_exc()
+            raise

Added: z3/Five/trunk/viewattribute.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/viewattribute.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,49 @@
+import Acquisition
+from AccessControl import getSecurityManager
+from zExceptions import Unauthorized
+
+from zope.component import getView
+
+class FiveViewError(Exception):
+    pass
+
+class ViewAttribute(Acquisition.Explicit):
+ 
+    def __init__(self, view_type):
+        self._view_type = view_type
+        
+    def index_html(self):
+        """Default method on view
+        """
+        # need this info to do security checks, so can't delegate to
+        # __getitem__
+        obj = self.aq_parent
+        view = getView(obj, self._view_type, self.aq_acquire('REQUEST'))
+        view = view.__of__(obj)
+        method_on_view = getattr(view, 'index_html', None)
+        if method_on_view is None:
+            raise FiveViewError, "No default view (index_html)"
+        security_manager = getSecurityManager()
+        if not security_manager.validate(method_on_view, obj, 'index_html',
+                                         method_on_view):
+            raise Unauthorized        
+        return method_on_view()
+     
+    def __getitem__(self, name):
+        """Get correct method on view
+        """
+        # get the object we are viewing
+        obj = self.aq_parent
+        # look up the view
+        view = getView(obj, self._view_type, self.aq_acquire('REQUEST'))
+        # wrap it in the right acquisition context for security
+        view = view.__of__(obj)
+        # look up method
+        method_on_view = getattr(view, name, None)
+        
+        if method_on_view is None:
+            # we do not accept calling unknown methods
+            raise FiveViewError, "Unknown view method: %s" % name 
+        
+        # let the ZPublisher do the calling, its security kicks in
+        return method_on_view

Added: z3/Five/trunk/zcml.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/zcml.py	Wed Jun 16 14:54:00 2004
@@ -0,0 +1,25 @@
+from zope.configuration import xmlconfig
+import Products
+
+_initialized = False
+_global_context = None
+def initialize(execute=True):
+    """This gets called once to initialize ZCML enough.
+    """
+    global _initialized, _global_context
+    if _initialized:
+        return _global_context
+    _global_context = xmlconfig.file('five.zcml', package=Products.Five)
+    _initialized = True
+    return _global_context
+
+def process(file, execute=True, package=None):
+    """Process a ZCML file.
+
+    Note that this can be called multiple times, unlike in Zope 3. This
+    is needed because in Zope 2 we don't (yet) have a master ZCML file
+    which can include all the others.
+    """
+    context = initialize()
+    return xmlconfig.file(file, context=context, execute=execute,
+                          package=package)


More information about the z3-checkins mailing list