[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