你的第一个Zope3应用
panjy
你的第一个Zope3应用
是的!我们打算开始创建一个Zope3应用,一个在线书签。我们的应用将显示到网站的链接和每条链接的描述。
那么,在开始一个Zope3项目前,你得做何准备呢?哦!很抱歉!我没法一言以蔽之,你最好先学习并实践XP(极限编程,一种轻量级的软件开发过程) http://en.wikipedia.org/wiki/Extreme_programming 。总之,在你初步设计之后,就将编写接口。让我们期待Python 3.0 会让它变得容易些吧!然后开始编写单元测试,至此你的想法已非常具体!最后编写正式代码。当你一个接一个的实现接口并通过单元测试,你会拥有(前所未有的)满足感! 我已经在这里给出了BookMarker应用的源代码:boom.tar.bz2
我们的代码将放在$HOME/myzope/lib/python/boom目录中
首先创建一个interfaces.py的文件,我们将在该文件内保存所有接口。后面我们将在单元测试的强力支持下,一个接一个的实现这些接口。
接口
下面就是我们的interfaces.py:
from zope.interface import Interface
from zope.schema import Text, TextLine, Field
from zope.app.container.constraints import ContainerTypesConstraint
from zope.app.container.constraints import ItemTypePrecondition
from zope.app.container.interfaces import IContained, IContainer
class IMark(Interface):
"""这是书签对象."""
url = TextLine(
title=u"URL/Link",
description=u"URL of the website",
default=u"http://www.zope.org",
required=True)
description = Text(
title=u"Description",
description=u"Description of the website",
default=u"",
required=False)
class IBookMarker(IContainer):
"""这是所有书签对象的容器."""
name = TextLine(
title=u"Name of BookMarker",
description=u"A name for BookMarker",
default=u"",
required=True)
def __setitem__(name, obj):
pass
__setitem__.precondition = ItemTypePrecondition(IMark)
class IMarkContained(IContained):
"""一条书签只能包含在一个BookMarker容器中"""
__parent__ = Field(
constraint = ContainerTypesConstraint(IBookMarker))
我们的第一个接口IMark有两个属性,一个是站点的URL,另一个是它的描述。请注意,IMark不是一个类,尽管我们使用了Python的类定义。IMark继承自Interface,因此是个接口。第二个是一个容器接口,它是一个扩展的Icontainer接口。我们可以使用这个容器接口来保存我们的数据(IMark实现的实例)。我们将IMark的所有对象放到IBookMarker的一个容器对象里。我们连同IMarkContained(作为一个约束接口)一起来实现IMark。所以IMark对象只能包含在IBookMarker对象中。
单元测试
现在创建tests.py文件,输入下列语句:
import unittest
from zope.testing.doctestunit import DocTestSuite
from zope.app.container.tests.test_icontainer import TestSampleContainer
from boom.bookmarker import BookMarker, Mark
class BookMarkerContainerTest(TestSampleContainer):
def makeBookMarkerObject(self):
return BookMarker()
def test_suite():
return unittest.TestSuite((
DocTestSuite('boom.bookmarker'),
unittest.makeSuite(BookMarkerContainerTest),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
实际上我们在这里并没有编写任何的单元测试,不过它会自动对我们的文档进行测试
然后运行单元测试:
$ cd $HOME/myzope/lib $ ../bin/test -vpu --dir boom
正式编码
现在让我们继续去实现(bookmarker.py):
__docformat__ = 'restructuredtext'
from zope.interface import implements
from zope.app.container.btree import BTreeContainer
from zope.app.container.contained import Contained
from boom.interfaces import IMark, IMarkContained, IBookMarker
class Mark(Contained):
"""IMark的实现
确认`Mark` 实现了`IMark` 接口::
>>> from zope.interface.verify import verifyClass
>>> verifyClass(IMark, Mark)
True
确认`Mark` 实现了`IMarkContained`接口:
>>> from zope.interface.verify import verifyClass
>>> verifyClass(IMarkContained, Mark)
True
一个检查Mark的链接地址的示例::
>>> mk = Mark()
>>> mk.url
u'http://www.zope.org'
>>> mk.url = u'http://www.python.org'
>>> mk.url
u'http://www.python.org'
检查Mark描述信息的示例::
>>> mk = Mark()
>>> mk.description
u''
>>> mk.description = u'Zope Project Web Site'
>>> mk.description
u'Zope Project Web Site'
"""
implements(IMark, IMarkContained)
url = u"http://www.zope.org"
description = u""
class BookMarker(BTreeContainer):
"""使用B-Tree容器来实现IBookMarker接口
确认`BookMarker` 实现了`IBookMarker` 接口::
>>> from zope.interface.verify import verifyClass
>>> verifyClass(IBookMarker, BookMarker)
True
改变书签名字的示例::
>>> bm = BookMarker()
>>> bm.name
u''
>>> bm.name = u'MyBookMarker'
>>> bm.name
u'MyBookMarker'
"""
implements(IBookMarker)
name = u""
我们已经在实现的同时也编写了Doctests,该Doctests是同例子一起的,所以这种实现方式我们称之为事例驱动单元测试
配置
现在编写配置(保存在configure.zcml文件中):
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<interface
interface=".interfaces.IBookMarker"
type="zope.app.content.interfaces.IContentType"
/>
<content class=".bookmarker.BookMarker">
<implements
interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
/>
<implements
interface="zope.app.container.interfaces.IContentContainer"
/>
<factory
id="boom.bookmarker.BookMarker"
description="Book Marker"
/>
<require
permission="zope.ManageContent"
interface=".interfaces.IBookMarker"
/>
<require
permission="zope.ManageContent"
set_schema=".interfaces.IBookMarker"
/>
</content>
<interface
interface=".interfaces.IMark"
type="zope.app.content.interfaces.IContentType"
/>
<content class=".bookmarker.Mark">
<implements
interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
/>
<factory
id="boom.bookmarker.Mark"
description="A book mark."
/>
<require
permission="zope.ManageContent"
interface=".interfaces.IMark"/>
<require
permission="zope.ManageContent"
set_schema=".interfaces.IMark"
/>
</content>
<browser:addform
label="Add Book Marker"
name="AddBookMarker.html"
schema="boom.interfaces.IBookMarker"
content_factory="boom.bookmarker.BookMarker"
fields="name"
permission="zope.ManageContent"
/>
<browser:addMenuItem
class=".bookmarker.BookMarker"
title="Book Marker"
permission="zope.ManageContent"
view="AddBookMarker.html"
/>
<browser:editform
schema="boom.interfaces.IBookMarker"
for="boom.interfaces.IBookMarker"
label="Change Book Marker"
name="edit.html"
permission="zope.ManageContent"
menu="zmi_views" title="Edit"
/>
<browser:containerViews
for="boom.interfaces.IBookMarker"
index="zope.View"
contents="zope.View"
add="zope.ManageContent"
/>
<browser:addform
label="Add Mark"
name="AddMark.html"
schema="boom.interfaces.IMark"
content_factory="boom.bookmarker.Mark"
fields="url description"
permission="zope.ManageContent"
/>
<browser:addMenuItem
class="boom.bookmarker.Mark"
title="Mark"
description="URL of Website"
permission="zope.ManageContent"
view="AddMark.html"
/>
<browser:editform
schema="boom.interfaces.IMark"
for="boom.interfaces.IMark"
label="Change Mark"
fields="url description"
name="edit.html"
permission="zope.ManageContent"
menu="zmi_views" title="Edit"
/>
<browser:page
name="marks.html"
for="boom.interfaces.IBookMarker"
class=".browser.BookMarks"
template="marks.pt"
permission="zope.Public"
menu="zmi_views"
title="Marks"
/>
</configure>
它能不言自明(即能够自我解释,XML之类的标记语言都有这个特点)吗?“不...!”好吧,我们将稍后简单的谈谈Zope Configuration Markup Language(ZCML,Zope配置标记语言)。实际上,如果你对ZCML熟悉的话,你会发现这个配置不止是不言自明,它将带给你的是对整个应用的总体思路。现在你可能在想,这并不Pythonic嘛 Sad ,嗨!再想想!
开始运行吧
最后一步就是要让我们的应用运行起来,在文件$HOME/myzope/etc/package-icludes/boom-configure.zcml中插入下列行:
<include package="boom"/>
现在你已经注册了你的包。
重新启动Zope,然后打开你的浏览器,添加一个BookMarker和一些书签。
现在,你不想让你的书签排列得更好点吗?先暂时休息一下,之后我们将为书签创建一个视图。
