[Checkins] SVN: zope3book/trunk/source/ Add few more chapter outlines
Baiju M
baiju.m.mail at gmail.com
Fri Feb 20 14:10:15 EST 2009
Log message for revision 96847:
Add few more chapter outlines
Changed:
D zope3book/trunk/source/InstallingZope3.rst
D zope3book/trunk/source/Preface.rst
A zope3book/trunk/source/browser-pages.rst
A zope3book/trunk/source/browser-resouces.rst
A zope3book/trunk/source/component-architecture.rst
U zope3book/trunk/source/conf.py
A zope3book/trunk/source/content-components.rst
A zope3book/trunk/source/development-tools.rst
A zope3book/trunk/source/getting-started.rst
U zope3book/trunk/source/index.rst
A zope3book/trunk/source/interfaces.rst
A zope3book/trunk/source/introduction.rst
A zope3book/trunk/source/skinning.rst
A zope3book/trunk/source/testing.rst
-=-
Deleted: zope3book/trunk/source/InstallingZope3.rst
===================================================================
--- zope3book/trunk/source/InstallingZope3.rst 2009-02-20 17:55:43 UTC (rev 96846)
+++ zope3book/trunk/source/InstallingZope3.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -1,394 +0,0 @@
-Installing Zope 3
------------------
-
-
-Difficulty
-::::::::::
-
-Newcomer
-
-
-Skilla
-::::::
-
-- You should know how to use the command line of your operating system.
- (For Windows releases, the Installer is provided.)
-- You need to know how to successfully install the latest version of
- Python on your system.
-
-
-Problem/Task
-::::::::::::
-
-Before you can develop anything for Zope 3, you should, of course, install
-it.
-
-
-Solution
-::::::::
-
-
-Zope 3 Installation Requirements
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Zope 3 usually requires the latest stable Python version. For the Zope X3
-3.0.0 release, this is Python 2.3.4 or better. Note that you should always
-use the latest bug-fix release. Zope 3 does not require you to install or
-activate any special packages; the stock Python is fine. This has the great
-advantage that you can use a pre-packaged Python distribution (for example
-RPM, deb, Windows Installer) for your favorite operating system.
-
-Note: While distutils is part of the standard Python distribution, packagers
-often treat it as a separate installation package. In order to install Zope
-3, your Python must have distutils installed as well.
-
-The only catch is that Zope 3's C modules must be compiled with the same C
-compiler as Python. For example, if you install the standard Python
-distribution on Windows, which is compiled with Visual C++ 7, you cannot
-compile Zope 3's modules with Cygwin. However, this problem is not as bad as
-it seems. The Zope 3 binary distributions are always compiled with the same
-compiler as the standard Python distribution for the operating system.
-Furthermore, if you want to compile everything yourself, you are likely to
-use only one compiler anyway.
-
-On Unix/Linux your best bet is `gcc`_. All Zope 3 developers are using
-`gcc`_, so it will always be supported. Furthermore, all Linux Python
-distribution packages are compiled using `gcc`_. In Windows, the standard
-Python distribution is compiled using Visual C++ 7, as mentioned previously.
-Therefore the Zope 3 binary Windows release is also compiled with that
-compiler. However, people have also successfully used `gcc`_ by using
-Cygwin, which comes with Python. Finally, you can run Zope 3 on MacOS X as
-well. All you need are `gcc`_ and the `make` program. With these, both
-Python and Zope 3 compile just fine.
-
-Python is available at the Python Web site ( `www.python.org`_).
-
-
-Installing Zope from SVN
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-In order to check out Zope 3 from SVN, you need to have a SVN client
-installed on your system. If you do not have a SVN account, you can use the
-anonymous user to check out a sandbox:
-
-
-1 svn co svn://svn.zope.org/repos/main/Zope3/trunk Zope3
-
-After the checkout is complete, you enter the Zope 3 directory:
-
-
-1 cd Zope3
-
-From there you run `make` (so you need to have `make` installed, and it
-should be available for all mentioned environments). If your Python
-executable is not called `python2.3`_ and/or your Python binary is not in
-the path, you need to edit the first line of the `Makefile`_ file to contain
-the correct path to the Python binary. Then you just run make, which
-builds/compiles Zope 3:
-
-
-1 make
-
-Next you copy `sampleprincipals.zcml`_ to `principals.zcml`_ and add a user
-with manager rights, as follows:
-
-
-1 <principal
-2 id="zope.userid" title="User Name Title"
-3 login="username" password="passwd" />
-4
-5 <grant role="zope.Manager" principal="zope.userid" />
-
-In the preceding code block, note the following:
-
-- Line 2: Notice that you do not need `zope.`_ as part of your
- principal ID, but the ID must contain at least one dot ( `.`_), because
- that signals a valid ID.
-- Line 3: The login and password strings can be any random value, but
- they must be correctly encoded for XML.
-- Line 5: If you do not use the default security policy, you might not
- be able to use this `zope:grant`_ directive because it might not support
- roles. However, if you use the plain Zope 3 checkout, roles are available
- by default.
-
-During development, you often do not want to worry about security. In such a
-case you can simply give `anybody`_ the `Manager`_ role:
-
-
-1 <grant role="zope.Manager" principal="zope.anybody" />
-
-The fundamental application server configuration can be found in
-`zope.conf`_. If `zope.conf`_ is not available, `zope.conf.in`_ is used
-instead. In this file you can define the types and ports of the servers you
-would like to activate, setup the ZODB storage type and specify logging
-options. The configuration file is very well documented, and making the
-desired changes should be easy.
-
-Now you are ready to start Zope 3 for the first time:
-
-
-1 ./bin/runzope
-
-The following output text should appear::
-
- ------
- 2003-06-02T20:09:13 INFO PublisherHTTPServer zope.server.http (HTTP)
- started.
- Hostname: localhost
- Port: 8080
- ------
- 2003-06-02T20:09:13 INFO PublisherFTPServer zope.server.ftp started.
- Hostname: localhost
- Port: 8021
- ------
- 2003-06-02T20:09:13 INFO root Startup time: 5.447 sec real, 5.190 sec
- CPU
-
-After Zope comes up, you can test the servers by typing the following URL in
-your browser: `http://localhost:8080/`_. You can test FTP by using
-`ftp://username@localhost:8021/`_. Even WebDAV is available using
-`webdav://localhost:8080/`_ in Konqueror or your favorite WebDAV client.
-
-An XML-RPC server is also built in to Zope by default, but most objects do
-not support any XML-RPC methods, so you cannot test it right away. Chapter
-"??" provides detailed instructions on how to use the XML-RPC server.
-
-
-Installing the Source Distribution
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-e following sections describe how to use the source TAR ball to compile and
-install a Zope 3 distribution.
-
-
-Unpacking the Package
-:::::::::::::::::::::
-
-The latest release of Zope 3 can be found at
-`www.zope.org/Products/ZopeX3`_. First, you need to download the latest Zope
-3 release by clicking the file that is available for all platforms, i.e.
-`ZopeX3-VERSION.tgz`_. You can use `tar`_ or WinZip to extract the archive,
-like this:
-
-
-1 tar xzf ZopeX3-3.0.0.tgz
-
-
-Building Zope
-:::::::::::::
-
-For Zope 3 releases, distributation makers provided the well-known
-`configure`_/ `make` procedure. So you can start the configuration process
-by using the following after you have entered the newly created directory:
-
-
-1 ./configure
-
-If you want to place the binaries of the distribution somewhere other than
-`/usr/local/ZopeX3-VERSION`_, you can specify the `-prefix`_ option as
-usual. Also, if you have Python installed at a non-standard location, you can
-specify the Python executable by using `-with-python`_. A full configuration
-statement could look like this:
-
-
-1 ./configure --prefix=/opt/Zope3 --with-
- python=/opt/puython2.3/bin/python2.3
-
-The following output is immediately returned:
-
-
-1 Configuring Zope X3 installation
-2
-3 Using Python interpreter at /opt/puython2.3/bin/python2.3
-
-Now that the source has been configured, you can build it by using `make`.
-After you enter the `make` command, the following line is returned:
-
-
-1 /opt/python2.3/bin/python2.3 install.py -q build
-
-The hard drive is busy for several minutes, compiling the source. When the
-command line returns, you can run the tests by using the following:
-
-
-1 make check
-
-Here, both the unit and functional tests are executed. For each executed
-test, you have one dot on the screen. The check takes between 5 and 10
-minutes depending on the speed and free cycles on your computer. The final
-output should look as follows::
-
-
- Python2.3 install.py -q build
- Python2.3 test.py -v
- Running UNIT tests at level 1
- Running UNIT tests from
- /path/to/ZopeX3-VERSION/build/lib.linux-i686-2.3
- [some 4000+ dots]
- ----------------------------------------------------------------------
- Ran 3896 tests in 696.647s
-
- OK
-
-The exact number of tests run depends on the version of Zope, the operating
-system, and the host platform. If the last line displays `OK`_, you know
-that all tests passed. After you have verified the check, you can install the
-distribution as follows:
-
-
-1 make install
-
-Note: You have to have the correct permissions to create the installation
-directory and copy the files into it. Thus, it might be useful to become root
-to execute the command.
-
-
-Creating a Zope Instance
-::::::::::::::::::::::::
-
-When the installation is complete, Zope is available in the directory you
-specified in `-prefix`_ or under `/usr/local/ZopeX3-VERSION`_. However,
-Zope will not yet run, because you have not created an instance yet. You use
-instances when you want to host several Zope-based sites, using the same base
-software configuration.
-
-Creating a new instance is easy. You enter the Zope 3 installation directory
-and enter the following command:
-
-
-1 /bin/mkzopeinstance -u username:password -d path/to/instance
-
-This creates a Zope 3 instance in `path/to/instance`_. A user who has the
-login `username`_ and password `password`_ is created for you, and the
-`zope.manager`_ role is assigned to it. All the configuration for the created
-instance are available in the `path/to/instance/etc`_ directory. You need to
-review all the information in there to ensure that it fits your needs.
-
-
-Running Zope
-::::::::::::
-
-You execute Zope by calling
-
-
-1 ./bin/runzope
-
-from the instance directory. The startup output will be equal to that of the
-source Zope SVN installation.
-
-You are all done now! When the server is up and running, you can test it via
-you favorite browser, as described earlier in this chapter.
-
-
-Installing the Source Distribution in Windows Without Using make
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Installing the source distribution on Windows is possible even without
-`make`. However, you need a supported C compiler to build the package. If
-you do not have a C compiler or Cygwin installed, you can use the Windows
-Installer to install Zope 3. (See the next section for more details.)
-
-Before installing Zope 3, you need to install Python 2.3.4 or higher. On
-Windows NT/2000/XP the extension `.py`_ is automatically associated with the
-Python executable, so you do not need to specify the Python executable when
-running a script.
-
-After you unpack the distribution, you enter the directory. You build the
-software by using this:
-
-
-1 install.py -q build
-
-When the build process is complete, you can run the tests with this:
-
-
-1 test.py -v
-
-This should give you the same output as under Unix/Linux. After the tests are
-verified, you install the distribution by using the following command:
-
-
-1 install.py -q install
-
-You have now completed the installation of Zope 3. Now you can follow the
-final steps in the previous section to create an instance and start up Zope.
-
-Note: When you install Zope 3 in Windows without using `make`, it's really
-hard to uninstall it later, because you have to manually delete files and
-directories from various locations, including your Python's `Lib/site-
-packages"` and `Scripts` directories. You also have to completely remove
-the `zopeskel` directory. If you use Windows Installer instead, an
-uninstallation program is provided and registered in the Control Panel's
-Add/Remove Programs applet.
-
-
-Installing the Binary Distribution of Zope
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Currently binary releases of Zope are available only for Windows. These
-releases assume that you have the standard Windows Python release installed.
-The Windows binary release is an executable that automatically executes
-Windows Installer. The first task is to make sure that you have the correct
-Python version installed. Zope X3.0 is released to work with Python 2.3.
-Thus, you need to install the latest Python 2.3 bug fix release. You can get
-the Windows binary installer at `www.python.org/download/`_.
-
-If you already have a previous version of Zope X3, you need to remove it by
-using Add/Remove Programs from the Control Panel. Then you can install the
-Zope X3.0 release, which you can find at `dev.zope.org/Zope3/Downloads`_.
-After you download it, you simply execute the installer and follow its
-instructions.
-
-When the install is complete, you need to open a Windows command prompt and
-change to the root Python 2.3 directory, usually `C:\python23`. Then you
-execute the instance creation script using this:
-
-
-1 .\python .\Scripts\mkzopeinstance -u username:password -d
- c:\path\to\instance
-
-This completes the installation. You can now run Zope 3 by using this:
-
-
-1 .\python c:\path\to\instance\bin\runzope
-
-The instance's `bin`_ directory also contains some other useful scripts,
-such as the test runner.
-
-You can later use the Control Panel's Add/Remove Programs applet to uninstall
-Zope 3 again.
-
-.. _gcc: gcc
-.. _www.python.org: www.python.org
-.. _python2.3: python2.3
-.. _Makefile: Makefile
-.. _sampleprincipals.zcml: sample_principals.zcml
-.. _principals.zcml: principals.zcml
-.. _zope.: zope.
-.. _.: .
-.. _zope:grant: zope:grant
-.. _anybody: anybody
-.. _Manager: Manager
-.. _zope.conf: zope.conf
-.. _zope.conf.in: zope.conf.in
-.. _http://localhost:8080/: http://localhost:8080/
-.. _ftp://username@localhost:8021/: ftp://username@localhost:8021/
-.. _webdav://localhost:8080/: webdav://localhost:8080/
-.. _www.zope.org/Products/ZopeX3: www.zope.org/Products/ZopeX3
-.. _ZopeX3-VERSION.tgz: ZopeX3-VERSION.tgz
-.. _tar: tar
-.. _configure: configure
-.. _/usr/local/ZopeX3-VERSION: /usr/local/ZopeX3-VERSION
-.. _-prefix: --prefix
-.. _-with-python: --with-python
-.. _OK: OK
-.. _path/to/instance: path/to/instance
-.. _username: username
-.. _password: password
-.. _zope.manager: zope.manager
-.. _path/to/instance/etc: path/to/instance/etc
-.. _.py: .py
-.. _www.python.org/download/: www.python.org/download/
-.. _dev.zope.org/Zope3/Downloads: dev.zope.org/Zope3/Downloads
-.. _python23: c:\python23\
-.. _bin: bin
Deleted: zope3book/trunk/source/Preface.rst
===================================================================
--- zope3book/trunk/source/Preface.rst 2009-02-20 17:55:43 UTC (rev 96846)
+++ zope3book/trunk/source/Preface.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -1,202 +0,0 @@
-Preface
--------
-
-.. note:: This is the preface of the original book. We need to
- create another preface for the new version.
-
-The preface will be a brief introduction into Zope 3 and its capabilities as
-well as into Python , the programming language Zope is written in.
-
-What is Zope?
-~~~~~~~~~~~~~
-
-What is Zope? While this sounds like a simple question that should be
-answered in a line or two, I often find myself in situations where I am
-unable to simple say: "It is an Open-Source Application Server." or "It is a
-Content Management System.". Both of these descriptions are true, but they
-are really putting a limit on Zope that simply does not exist. So before I
-will give my definition of Zope, let's collect some of the solutions Zope has
-been used for. As mentioned above, many people use Zope as a Content
-Management System, which are usually Web-based (browser managed) systems.
-Basically the users can manage the content of a page through a set of Web
-forms, workflows and editing tools. However, there is an entirely different
-CMS genre, for which Zope also has been used. Other companies, such as
-struktur AG, used Zope successfully to interface with the XML Database Tamino
-(from software AG). The second common use is Zope as a Web-Application
-server, where it is used to build Web-based applications, such as online
-shops or project management tools. Of course, Zope is also suitable for
-regular Web sites.
-
-And yet, there is a usage that we neglected so far. Zope can also be used as
-a reliable backend server managing the logistics of a company's operations.
-In fact, bluedynamics.com in Austria built a logistic software based on Zope
-2 ZClasses and a relational database that was able to handle hundreds of
-thousands transactions each day from taking credit card information and
-billing the customer up to ordering the products from the warehouse using
-XML-RPC. In my opinion this is the true strength of Zope, since it allows not
-only Web-familiar protocols to talk to, but also any other network protocol
-you can imagine. Zope 3, with its component architecture, accelerates even
-more in this area, since third party products can be easily plugged in or
-even replace some of the defaults. For example the Twisted framework can
-replace all of ZServer (the Zope Server components).
-
-Now that we have seen some of the common and uncommon uses of Zope it might
-be possible to formulate a more formal definition of Zope, just in case you
-are being asked at one point. Zope is an application and backend server
-framework that allows developers to quickly implement protocols, build
-applications (usually Web-based) and function as glue among other net-enabled
-services.
-
-Before Zope was developed, Zope Corporation was reviewing many possible
-programming languages to develop the framework, such as Java, C/C++, Perl and
-Python. After extensive research they found that only Python would give them
-the competitive advantage in comparison to the other large framework
-providers, such as IBM, BEA and others.
-
-
-Powerful Python
-~~~~~~~~~~~~~~~
-
-Python is a high-level object-oriented scripting language producing - by
-design - clean code through mandatory indentation. While Perl is also an
-interpreted scripting language, it lacks the cleanness and object-orientation
-of Python. Java, on the other hand, provides a nice object-oriented approach,
-but fails to provide powerful tools to build applications in a quick manner.
-So it is not surprising that Python is used in a wide variety of real world
-situations, like NASA, which uses Python to interpret their simulation data
-and connect various small C/C++ programs. Also, Mailman, the well-known
-mailing list manager, is being developed using Python. On the other hand, you
-have academics that use this easy-to-learn language for their introductory
-programming courses.
-
-Since Python is such an integral part of the understanding of Zope, you
-should know it well. If you are looking for some introductory documentation,
-you should start with the tutorial that is available directly from the Python
-homepage `http://www.python.org/doc/current/tut/tut.html`_. Also, there are a
-wide variety of books published by almost every publisher.
-
-
-In the beginning there was...
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Every time I am being asked to give a presentation or write a survey-like
-article about Zope, I feel the need to tell a little bit about its history,
-not only because it is a classic Open-Source story, but also because it gives
-some background on why the software behaves the way it does. So it should
-definitely not be missing here.
-
-Before Zope was born, Zope Corporation (which was originally named Digital
-Creations) developed and distributed originally three separate products
-called Bobo, Principia and Aqueduct. Bobo was an object publisher written in
-Python, which allowed one to publish objects as pages on the web. It also
-served as object database and object request broker (ORB), converting URLs
-into object paths. Most of this base was implemented by Jim Fulton in 1996
-after giving a frustrating Python CGI tutorial at the International Python
-Conference. Even though Bobo was licensed under some sort of "free" license,
-it was not totally Open-Source and Principia was the commercial big brother.
-
-In 1998, Hadar Pedhazur, a well-known venture capitalist, convinced Digital
-Creations to open up their commercial products and publish them as Open
-Source under the name Zope. Zope stands for the "Z Object Publishing
-Environment". The first Zope release was 1.7 in December 1998. Paul Everitt,
-former CEO, and all the other people at Zope Corporation converted from a
-product company into a successful consultant firm. Alone the story how Zope
-Corporation went from a proprietary, product-based to a service-based company
-is very interesting, but is up to someone else to tell.
-
-In the summer of 1999, Zope Corporation published version 2.0, which will be
-the base for the stable release until Zope 3.0 will outdate it in the next
-few years. Zope gained a lot of popularity with the 2.x series; it is now
-included in all major Linux distributions and many books have been written
-about it. Originally I was going to write this book on the Zope 2.x API, but
-with the beginning of the Zope 3.x development in late 2001, it seemed much
-more useful to do the documentation right this time and write an API book
-parallel to the development itself. In fact when these lines were originally
-written, there was no Zope Management Interface , and the initial security
-had just been recently implemented.
-
-
-Zope 3 Components
-~~~~~~~~~~~~~~~~~
-
-Zope 3 will make use of many of the latest and hottest development patterns
-and technologies, and that with "a twist" as Jim Fulton likes to describe it.
-But Zope 3 also reuses some of the parts that were developed for previous
-versions. Users will be glad to find that Acquisition (but in a very
-different form) is available again as well as Zope Page Templates and the
-Document Template Markup Language - DTML (even though with less emphasis).
-Also, there is the consensus of a Zope Management Interface in Zope 3 again,
-but is completely developed from scratch in a modular fashion so that
-components cannot be only reused, but the entire GUI can be altered as
-desired.
-
-But not only DTML, ZPT and Aquidition received a new face in Zope 3; external
-data handling has been also totally reworked to make external data play
-better together with the internal persistence framework, so that the system
-can take advantage of transactions, and event channels. Furthermore, the
-various external data sources are now handled much more generically and are
-therefore more transparent to the developer. But which external data sources
-are supported? By default Zope 3 comes with a database adaptor for Gadfly ,
-but additional adapters for PostGreSQL and other databases already exist and
-many others will follow. Data sources that support XML-RPC, like the very
-scalable XML database Tamino, could also be seamlessly inserted. However, any
-other imaginable data source can be connected to Zope by developing a couple
-of Python modules, as described in various chapters.
-
-During the last five years (the age of Zope 2) not only Zope was developed
-and improved, but also many third party products were written by members of
-the very active Zope community for their everyday need. These products range
-from Hot Fixes, Database Adaptors and Zope objects to a wide range of end
-user software, such as e-commerce, content management and e-learning systems.
-However, some of these products turned out to be generically very useful to a
-wide variety of people; actually, they are so useful, that they were
-incorporated into the Zope 3 core. The prime examples are the two
-internationalization and localization tools Localizer (by Juan David Iba?ez
-Palomar) and ZBabel (by me), whose existence shaped the implementation of the
-internationalization and localization support Zope 3 significantly. Another
-great product that made it into the Zope 3 core was originally written by
-Martijn Faassen and is called Formulator. Formulator allows the developer to
-define fields (representing some meta-data of a piece of content) that
-represent data on the one side and HTML fields on the other. One can then
-combine fields to a form and have it displayed on the Web. The second great
-feature Formulator came with was the Validator, which validated user-entered
-data on the server side. Formulator's concepts were modularized into schemas
-and forms/widgets and incorporated in Zope 3.
-
-Altogether, the framework is much cleaner now (and more pythonic) and
-features that failed to make it into the Zope 2 core were incorporated.
-
-
-Goals of this book
-~~~~~~~~~~~~~~~~~~
-
-The main target audience for this book are developers that would like to
-develop on the Zope 3 framework itself; these are referred to as Zope
-developers in this book. But also Python programmers will find many of the
-chapters interesting, since they introduce concepts that could be used in
-other Python applications as well. Python programmers could also use this
-book as an introduction to Zope.
-
-In general the chapters have been arranged in a way so that the Zope 3
-structure itself could be easily understood. The book starts out by getting
-you setup, so that you can evaluate and develop with Zope 3. The second part
-of the book consists of chapters that are meant as introductions to various
-important concepts of Zope 3. If you are a hands-on developer like me, you
-might want to skip this part until you have done some development. The third
-and fourth part are the heart of the book, since a new content component with
-many features is developed over a course of 12 chapters. Once you understand
-how to develop content components, part five has a set of chapters that
-introduce other components that might be important for your projects. The
-fifth part is intended for people that wish to use Zope technologies outside
-of Zope 3. The emphasis on testing is one of the most important philosophical
-transitions the Zope 3 development team has undergone. Thus the last chapter
-is dedicated to various ways to write tests.
-
-Last but not least this book should encourage you to start helping us to
-develop Zope 3. This could be in the form of enhancing the Zope 3 core itself
-or by developing third party products, reaching from new content objects to
-entire applications, such as an e-commerce system. This book covers all the
-modules and packages required for you to start developing.
-
-.. _http://www.python.org/doc/current/tut/tut.html:
- http://www.python.org/doc/current/tut/tut.html
Added: zope3book/trunk/source/browser-pages.rst
===================================================================
--- zope3book/trunk/source/browser-pages.rst (rev 0)
+++ zope3book/trunk/source/browser-pages.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,61 @@
+Browser Pages
+=============
+
+In the last chapter we have seen how to use resources HTML. The
+resource HTML will be only available on site-level with the `\@\@`
+prefix.
+
+Browser page (or more generically views) are representations for
+particular objects/components.
+
+If you have a template like this (helloworld.pt)::
+
+ Hello, World !
+
+Here is how to register a page for IFolder interface::
+
+ <browser:page
+ name="helloworld.html"
+ for="zope.app.folder.interfaces.IFolder"
+ template="helloworld.pt"
+ permission="zope.Public"
+ />
+
+
+View components
+---------------
+
+While templates display data view components are preparing data.
+View components convert data to output formats also prepare related
+data (meta-data). Then, create TAL-friendly object structures (dicts
+and lists). View components know about: component for which the
+representation is created (context) and request object holding all
+`output media` information (request)
+
+
+Implementation
+~~~~~~~~~~~~~~
+
+Normally view components are added inside `browser` package inside
+your main package. The organization of the browser code is really up
+to you and the above examples are just the most basic rules of thumb.
+
+Here is simple view defined::
+
+ from zope.publisher.browser import BrowserPage
+ from zope.app.folder import interfaces
+
+ class HelloWorld(BrowserPage):
+
+ def subFolderIds(self):
+ for name, subobj in self.context.items():
+ if interfaces.IFolder.providedBy(subobj):
+ yield name
+
+Since methods and attributes of the view component are directly used
+by the template, they should return simple iterable objects
+(e.g. lists, tuples, generators) or mappings (e.g. dicts).
+
+
+View components - integration
+-----------------------------
Added: zope3book/trunk/source/browser-resouces.rst
===================================================================
--- zope3book/trunk/source/browser-resouces.rst (rev 0)
+++ zope3book/trunk/source/browser-resouces.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,149 @@
+Browser Resources
+=================
+
+
+File Resource
+-------------
+
+Certain presentation, like images and style sheets are not associated
+with any other component, so that one cannot create a view. To solve
+this problem, resources were developed, which are presentation
+components that do not require any context. This mini-chapter will
+demonstrate how resources are created and registered with Zope 3.
+
+The first goal is to register a simple plain-text file called
+`resource.txt` as a browser resource. The first step is to create
+this file anywhere you wish on the filesystem, and adding the
+following content::
+
+ Hello, I am a Zope 3 Resource Component!
+
+Now just register the resource in a ZCML configuration file using the
+`browser` resource directive::
+
+ <browser:resource
+ name="resource.txt"
+ file="resource.txt"
+ layer="default"
+ />
+
+Line 2: This is the name under which the resource will be known in
+Zope.
+
+Line 3: The file attribute specifies the path to the resource on the
+filessytem. The current working directory ('.') is always the
+directory the configuration file is located. So in the example
+above, the file `resource.txt` is located in the same folder as the
+configuration file is.
+
+Line 4: The optional layer attribute specifies the layer the resource
+is added to. By default, the default layer is selected.
+
+Once you hook up the configuration file to the main configuration
+path and restart Zope 3, you should be able to access the resource
+now via a Browser using `http://localhost:8080/@@/resource.txt`. The
+`@@/` in the URL tells the traversal mechanism that the following
+object is a resource.
+
+
+Image resource
+--------------
+
+If you have an image resource, you might want to use different
+configuration. Create a simple image called img.png and register it
+as follows::
+
+ <browser:resource
+ name="img.png"
+ image="img.png"
+ permission="zope.ManageContent"
+ />
+
+Line 3: As you can see, instead of the `file` attribute we use the
+`image` one. Internally this will create an `Image` object, which is
+able to detect the content type and returns it correctly. There is a
+third possible attribute named `template`. If specified, a Page
+Template that is executed when the resource is called. Note that
+only one of `file`, `image`, or `template` attributes can be
+specified inside a resource directive.
+
+Line 4: A final optional attribute is the ''permission'' one must
+have to view the resource. To demonstrate the security, I set the
+permission required for viewing the image to `zope.ManageContent`, so
+that you must log in as an administrator/- manager to be able to view
+it. The default of the attribute is `zope.Public` so that everyone
+can see the resource.
+
+
+Directory resource
+------------------
+
+If you have many resource files to register, it can be very tedious
+to write a single directive for every resource. For this purpose the
+`resourceDirectory` is provided, with which you can simply declare an
+entire directory, including its content as resources. Thereby the
+filenames of the files are reused as the names for the resource
+available. Assuming you put your two previous resources in a
+directory called resource, then you can use the following::
+
+ <browser:resourceDirectory
+ name="resources"
+ directory="../resource"
+ />
+
+The image will then be publically available under the URL:
+`http://localhost:8080/@@/resources/img.png`
+
+The `DirectoryResource` object uses a simple resource type
+recognition. It looks at the filename extensions to discover the
+type. For page templates, currently the extensions ''pt'', ''zpt''
+and ''html'' are registered and for an image ''gif'', ''png'' and
+''jpg''. All other extensions are converted to file resources. Note
+that it is not necessary to have a list of all image types, since
+only Browser-displayable images must be recognized.
+
+
+ZRT resource
+------------
+
+When working locally, you may be storing your image resources in a
+directory. If you have a subfolder called `images` with an image
+`logo.png`. And you have a template, so here is the HTML to insert
+the logo::
+
+ <img src="./images/logo.png" />
+
+Now you can see that the template locally works.
+
+If you view the HTML via Zope, you can see that it is broken.
+
+Now, let's try to register the logo with the system like this::
+
+ <resource
+ name="logo.png"
+ file="images/logo.png"
+ />
+
+Now try again, after restarting Zope 3, you can see that it is still
+broken!. So, relative path is not correct.
+
+Zope Resource Templates (ZRT) allows for locally working resources to
+work with Zope 3 as well. It will rewrite text segments in a
+resource. It is a 3rd party package developed by Stephan Richter for
+Lovely Systems. The package is available from here:
+`http://pypi.python.org/pypi/z3c.zrtresource`
+
+To use the zrt-resource add the following lines to the page
+template::
+
+ <!--
+ /* zrt-replace: "./images/logo.png" \
+ tal"string:${context/++resource++logo.png}" */
+ -->
+
+Then convert HTML resource registration to::
+
+ <zrt-resource
+ name="helloworld.html"
+ file="helloworld.html"
+ />
Added: zope3book/trunk/source/component-architecture.rst
===================================================================
--- zope3book/trunk/source/component-architecture.rst (rev 0)
+++ zope3book/trunk/source/component-architecture.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,407 @@
+Component Architecture
+======================
+
+`Zope Component Architecture (ZCA)` is a framework for supporting
+component based design and programming. It is very well suited to
+developing large Python software systems. The ZCA is not specific to
+the Zope web application server: it can be used for developing any
+Python application.
+
+The ZCA is all about using Python objects effectively. Components
+are reusable objects with introspectable interfaces. A component
+provides an interface implemented in a class, or any other callable
+object. It doesn't matter how the component is implemented, the
+important part is that it comply with its interface contracts. Using
+ZCA, you can spread the complexity of systems over multiple
+cooperating components. It helps you to create two basic kinds of
+components: `adapter` and `utility`.
+
+There are two core packages related to the ZCA:
+
+* `zope.interface` is used to define the interface of a component.
+
+* `zope.component` deals with registration and retrieval of
+ components.
+
+Remember, the ZCA is not about the components themselves, rather it
+is about creating, registering, and retrieving components. Remember
+also, an `adapter` is a normal Python class (or a factory in general)
+and `utility` is a normal Python callable object.
+
+The ZCA framework is developed as part of the Zope 3 project. As
+noted earlier, it is a pure Python framework, so it can be used in any
+kind of Python application. Currently both Zope 3 and Zope 2 projects
+use this framework extensively. There are many other projects
+including non-web applications using it.
+
+Installation
+------------
+
+Using `zc.buildout` with `zc.recipe.egg` recipe you can create Python
+interpreter with specified Python eggs. First you can create a
+directory and initialize Buildout::
+
+ $ mkdir explore-zope.component
+ $ cd explore-zope.component
+ $ echo "#Buildout configuration" > buildout.cfg
+ $ svn co svn://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap
+ $ ~/usr/bin/python2.4 bootstrap/bootstrap.py
+
+Now modify the `buildout.cfg` like this::
+
+ [buildout]
+ parts = py
+
+ [py]
+ recipe = zc.recipe.egg
+ eggs = zope.component
+ interpreter = mypython
+
+Now run `buildout` script inside `bin` directory. This will download
+zope.component and its dependency eggs and install it. Now you can
+access the interpreter created by the Buildout recipe like this::
+
+ $ ./bin/buildout
+ $ ./bin/mypython
+ >>> import zope.component
+
+Adapters
+--------
+
+
+Implementation
+~~~~~~~~~~~~~~
+
+This section will describe adapters in detail. Zope component
+architecture, as you noted, helps to effectively use Python objects.
+Adapter components are one of the basic components used by Zope
+component architecture for effectively using Python objects. Adapter
+components are Python objects, but with well defined interface.
+
+To declare a class is an adapter use `adapts` function defined in
+`zope.component` package. Here is a new `FrontDeskNG` adapter with
+explicit interface declaration::
+
+ >>> from zope.interface import implements
+ >>> from zope.component import adapts
+
+ >>> class FrontDeskNG(object):
+ ...
+ ... implements(IDesk)
+ ... adapts(IGuest)
+ ...
+ ... def __init__(self, guest):
+ ... self.guest = guest
+ ...
+ ... def register(self):
+ ... guest = self.guest
+ ... next_id = get_next_id()
+ ... bookings_db[next_id] = {
+ ... 'name': guest.name,
+ ... 'place': guest.place,
+ ... 'phone': guest.phone
+ ... }
+
+What you defined here is an `adapter` for `IDesk`, which adapts
+`IGuest` object. The `IDesk` interface is implemented by
+`FrontDeskNG` class. So, an instance of this class will provide
+`IDesk` interface.
+
+::
+
+ >>> class Guest(object):
+ ...
+ ... implements(IGuest)
+ ...
+ ... def __init__(self, name, place):
+ ... self.name = name
+ ... self.place = place
+
+ >>> jack = Guest("Jack", "Bangalore")
+ >>> jack_frontdesk = FrontDeskNG(jack)
+
+ >>> IDesk.providedBy(jack_frontdesk)
+ True
+
+The `FrontDeskNG` is just one adapter you created, you can also
+create other adapters which handles guest registration differently.
+
+
+Registration
+~~~~~~~~~~~~
+
+To use this adapter component, you have to register this in a
+component registry also known as site manager. A site manager
+normally resides in a site. A site and site manager will be more
+important when developing a Zope 3 application. For now you only
+required to bother about global site and global site manager ( or
+component registry). A global site manager will be in memory, but a
+local site manager is persistent.
+
+To register your component, first get the global site manager::
+
+ >>> from zope.component import getGlobalSiteManager
+ >>> gsm = getGlobalSiteManager()
+ >>> gsm.registerAdapter(FrontDeskNG,
+ ... (IGuest,), IDesk, 'ng')
+
+To get the global site manager, you have to call
+`getGlobalSiteManager` function available in `zope.component`
+package. In fact, the global site manager is available as an
+attribute (`globalSiteManager`) of `zope.component` package. So, you
+can directly use `zope.component.globalSiteManager` attribute. To
+register the adapter in component, as you can see above, use
+`registerAdapter` method of component registry. The first argument
+should be your adapter class/factory. The second argument is a tuple
+of `adaptee` objects, i.e, the object which you are adapting. In
+this example, you are adapting only `IGuest` object. The third
+argument is the interface implemented by the adapter component. The
+fourth argument is optional, that is the name of the particular
+adapter. Since you gave a name for this adapter, this is a `named
+adapter`. If name is not given, it will default to an empty string
+('').
+
+In the above registration, you have given the adaptee interface and
+interface to be provided by the adapter. Since you have already
+given these details in adapter implementation, it is not required to
+specify again. In fact, you could have done the registration like
+this::
+
+ >>> gsm.registerAdapter(FrontDeskNG, name='ng')
+
+There are some old API to do the registration, which you should
+avoid. The old API functions starts with `provide`, eg:
+`provideAdapter`, `provideUtility` etc. While developing a Zope 3
+application you can use Zope configuration markup language (ZCML) for
+registration of components. In Zope 3, local components (persistent
+components) can be registered from Zope Management Interface (ZMI) or
+you can do it programmatically also.
+
+You registered `FrontDeskNG` with a name `ng`. Similarly you can
+register other adapters with different names. If a component is
+registered without name, it will default to an empty string.
+
+
+Querying adapter
+~~~~~~~~~~~~~~~~
+
+Retrieving registered components from component registry is achieved
+through two functions available in `zope.component` package. One of
+them is `getAdapter` and the other is `queryAdapter`. Both functions
+accepts same arguments. The `getAdapter` will raise
+`ComponentLookupError` if component lookup fails on the other hand
+queryAdapter will return `None`.
+
+You can import the methods like this::
+
+ >>> from zope.component import getAdapter
+ >>> from zope.component import queryAdapter
+
+In the previous section you have registered a component for guest
+object (adaptee) which provides `IDesk` interface with name as `ng`.
+In the first section of this chapter, you have created a guest object
+named `jack`.
+
+This is how you can retrieve a component which adapts the interface
+of jack object (`IGuest`) and provides `IDesk` interface also
+with name as `ng`. Here both `getAdapter` and
+`queryAdapter` works similarly::
+
+ >>> getAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS
+ <FrontDeskNG object at ...>
+ >>> queryAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS
+ <FrontDeskNG object at ...>
+
+As you can see, the first argument should be adaptee then, the
+interface which should be provided by component and last the name of
+adapter component.
+
+If you try to lookup the component with an name not used for
+registration but for same adaptee and interface, the lookup will fail.
+Here is how the two methods works in such a case::
+
+ >>> getAdapter(jack, IDesk, 'not-exists') #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: ...
+ >>> reg = queryAdapter(jack,
+ ... IDesk, 'not-exists') #doctest: +ELLIPSIS
+ >>> reg is None
+ True
+
+As you can see above, `getAdapter` raised a
+`ComponentLookupError` exception, but `queryAdapter`
+returned `None` when lookup failed.
+
+The third argument, the name of registration, is optional. If the
+third argument is not given it will default to empty string ('').
+Since there is no component registered with an empty string,
+`getAdapter` will raise `ComponentLookupError`. Similarly
+`queryAdapter` will return `None`, see yourself how it
+works::
+
+ >>> getAdapter(jack, IDesk) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: ...
+ >>> reg = queryAdapter(jack, IDesk) #doctest: +ELLIPSIS
+ >>> reg is None
+ True
+
+In this section you have learned how to register a simple adapter and
+how to retrieve it from component registry. These kind of adapters is
+called single adapter, because it adapts only one adaptee. If an
+adapter adapts more that one adaptee, then it is called multi adapter.
+
+
+Retrieving adapter using interface
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Adapters can be directly retrieved using interfaces, but it will only
+work for non-named single adapters. The first argument is the adaptee
+and the second argument is a keyword argument. If adapter lookup
+fails, second argument will be returned.
+
+::
+
+ >>> IDesk(jack, alternate='default-output')
+ 'default-output'
+
+ Keyword name can be omitted:
+
+ >>> IDesk(jack, 'default-output')
+ 'default-output'
+
+ If second argument is not given, it will raise `TypeError`:
+
+ >>> IDesk(jack) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt',
+ <Guest object at ...>,
+ <InterfaceClass __builtin__.IDesk>)
+
+ Here `FrontDeskNG` is registered without name:
+
+ >>> gsm.registerAdapter(FrontDeskNG)
+
+ Now the adapter lookup should succeed:
+
+ >>> IDesk(jack, 'default-output') #doctest: +ELLIPSIS
+ <FrontDeskNG object at ...>
+
+For simple cases, you may use interface to get adapter components.
+
+
+Utility
+-------
+
+Now you know the concept of interface, adapter and component registry.
+Sometimes it would be useful to register an object which is not
+adapting anything. Database connection, XML parser, object returning
+unique Ids etc. are examples of these kinds of objects. These kind of
+components provided by the ZCA are called `utility` components.
+
+Utilities are just objects that provide an interface and that are
+looked up by an interface and a name. This approach creates a global
+registry by which instances can be registered and accessed by
+different parts of your application, with no need to pass the
+instances around as parameters.
+
+You need not to register all component instances like this. Only
+register components which you want to make replaceable.
+
+
+Simple utility
+~~~~~~~~~~~~~~
+
+A utility can be registered with a name or without a name. A utility
+registered with a name is called named utility, which you will see in
+the next section. Before implementing the utility, as usual, define
+its interface. Here is a `greeter` interface::
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface import implements
+
+ >>> class IGreeter(Interface):
+ ...
+ ... def greet(name):
+ ... """Say hello"""
+
+Like an adapter a utility may have more than one implementation. Here
+is a possible implementation of the above interface::
+
+ >>> class Greeter(object):
+ ...
+ ... implements(IGreeter)
+ ...
+ ... def greet(self, name):
+ ... return "Hello " + name
+
+The actual utility will be an instance of this class. To use this
+utility, you have to register it, later you can query it using the ZCA
+API. You can register an instance of this class (`utility`) using
+`registerUtility`::
+
+ >>> from zope.component import getGlobalSiteManager
+ >>> gsm = getGlobalSiteManager()
+
+ >>> greet = Greeter()
+ >>> gsm.registerUtility(greet, IGreeter)
+
+In this example you registered the utility as providing the `IGreeter`
+interface. You can look the interface up with either `queryUtility`
+or `getUtility`::
+
+ >>> from zope.component import queryUtility
+ >>> from zope.component import getUtility
+
+ >>> queryUtility(IGreeter).greet('Jack')
+ 'Hello Jack'
+
+ >>> getUtility(IGreeter).greet('Jack')
+ 'Hello Jack'
+
+As you can see, adapters are normally classes, but utilities are
+normally instances of classes. Only once you are creating the
+instance of a utility class, but adapter instances are dynamically
+created whenever you query for it.
+
+
+Named utility
+~~~~~~~~~~~~~
+
+When registering a utility component, like adapter, you can use a
+name. As mentioned in the previous section, a utility registered with
+a particular name is called named utility.
+
+This is how you can register the `greeter` utility with a name::
+
+ >>> greet = Greeter()
+ >>> gsm.registerUtility(greet, IGreeter, 'new')
+
+In this example you registered the utility with a name as providing
+the `IGreeter` interface. You can look up the interface with either
+`queryUtility` or `getUtility`::
+
+ >>> from zope.component import queryUtility
+ >>> from zope.component import getUtility
+
+ >>> queryUtility(IGreeter, 'new').greet('Jill')
+ 'Hello Jill'
+
+ >>> getUtility(IGreeter, 'new').greet('Jill')
+ 'Hello Jill'
+
+As you can see here, while querying you have to use the `name` as
+second argument.
+
+Calling `getUtility` function without a name (second argument) is
+equivalent to calling with an empty string as the name. Because, the
+default value for second (keyword) argument is an empty string.
+Then, component lookup mechanism will try to find the component with
+name as empty string, and it will fail. When component lookup fails
+it will raise `ComponentLookupError` exception. Remember, it will
+not return some random component registered with some other name.
+The adapter look up functions, `getAdapter` and `queryAdapter` also
+works similarly.
Modified: zope3book/trunk/source/conf.py
===================================================================
--- zope3book/trunk/source/conf.py 2009-02-20 17:55:43 UTC (rev 96846)
+++ zope3book/trunk/source/conf.py 2009-02-20 19:10:14 UTC (rev 96847)
@@ -49,9 +49,9 @@
# built documents.
#
# The short X.Y version.
-version = '3.5'
+version = '3.4'
# The full version, including alpha/beta/rc tags.
-release = '3.5dev'
+release = '3.4.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -153,7 +153,7 @@
#html_file_suffix = ''
# Output file base name for HTML help builder.
-htmlhelp_basename = 'ZopeDevelopersGuidedoc'
+htmlhelp_basename = 'Zope3DevelopersBook'
# Options for LaTeX output
@@ -169,7 +169,7 @@
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
('index', 'Zope3DevelopersBook.tex', ur"Zope 3 Developer's Book",
- ur'Zope Community', 'manual'),
+ ur'Zope Community', 'manual', 1),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -188,3 +188,9 @@
# If false, no module index is generated.
#latex_use_modindex = True
+# Additional stuff for the LaTeX preamble.
+
+latex_elements = {
+ 'fontpkg': '\\usepackage{palatino}'
+}
+
Added: zope3book/trunk/source/content-components.rst
===================================================================
--- zope3book/trunk/source/content-components.rst (rev 0)
+++ zope3book/trunk/source/content-components.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,520 @@
+Content Components
+==================
+
+Introduction
+------------
+
+See this example::
+
+ >>> from zope import interface
+
+ >>> class IPerson(interface.Interface):
+ ... name = interface.Attribute("Name")
+ >>> class Person(object):
+ ... interface.implements(IPerson)
+ ... name = None
+ >>> jack = Person()
+ >>> jack.name = "Jack"
+
+Here `jack` is a content component. So a content component is nothing but an
+object which provides a particular interface. As said in the previous chapter,
+use ``zope.schema`` to define fields of interface. The above interface can be
+declared like this::
+
+ >>> from zope import interface
+ >>> from zope import schema
+
+ >>> class IPerson(interface.Interface):
+ ... name = schema.TextLine(
+ ... title=u"Name",
+ ... description=u"Name of person",
+ ... default=u"",
+ ... required=True)
+
+If you are developing an enterprise application content will be the most
+important thing you have to organize first. To learn Zope 3 application
+development with content components, this chapter introduce a simple
+ticket/issue collector application.
+
+First look at the user stories, this book will implement these stories in
+coming chapters.
+
+ 1. Individual small ticket collector for each project. Many collectors can
+ be added to one running zope.
+
+ 2. Any number of tickets can be added to one collector.
+
+ 3. Each ticket will be added with a description and one initial comment.
+
+ 4. Additional comments can be added to tickets.
+
+This chapter starts a simple implementation of ticket collector.
+
+As stated above, our goal is to develop a fully functional, though not
+great-looking, web-based ticket collector application. The root object will be
+the ``Collector``, which can contain ``Ticket`` objects from various users.
+Since you want to allow people to respond to various tickets, you have to allow
+tickets to contain replies, which are ``Comment`` objects.
+
+That means you have two container-based components: The ``Collector`` contains
+only tickets and can be added to any Folder or container that wishes to be able
+to contain it. To make the ticket collector more interesting, it also has a
+description, which briefly introduces the subject/theme of the discussions
+hosted. ``Tickets``, on the other hand should be only contained by ticket
+collector. They will each have a summary and a description. And last
+``Comment`` should be only contained by tickets.
+
+This setup should contain all the essential things that you need to make the
+object usable. Later on you will associate a lot of other meta-data with these
+components to integrate them even better into Zope 3 and add additional
+functionality.
+
+The most convenient place to put your package is ``$HOME/myzope/lib/python``.
+To create that package, add a directory using::
+
+ $ cd $HOME/myzope/lib/python/
+ $ mkdir collector
+
+on GNU/Linux.
+
+To make this directory a package, place an empty __init__.py file in the new
+directory. In GNU/Linux you can do something like::
+
+ $ echo "# Make it a Python package" >> collector/__init__.py
+
+but you can of course also just use a text editor and save a file of this name.
+Just make sure that there is valid Python code in the file. The file should at
+least contain some whitespace, since empty files confuse some archive programs.
+
+From now on you are only going to work inside this ``collector`` package, which
+should be located at ``$HOME/myzope/lib/python/collector``.
+
+
+Interfaces
+----------
+
+The very first step of the coding process is always to define your interfaces,
+which represent your external API. You should be aware that software that is
+built on top of your packages expect the interfaces to behave exactly the way
+you specify them. This is often less of an issue for attributes and arguments
+of a method, but often enough developers forget to specify what the expected
+return value of a method or function is or which exceptions it can raise or
+catch.
+
+Interfaces are commonly stored in an ``interfaces`` module or package. Since
+our package is not that big, you are going to use a file-based module; therefore
+start editing a file called ``interfaces.py`` in your favorite editor.
+
+In this initial step of our application, you are only interested in defining one
+interface for the ticket collector itself and one for a single ticket, which
+are listed below (add these to the file ``interfaces.py``)::
+
+ from zope.interface import Interface
+ from zope.schema import Text, TextLine, Field
+
+ from zope.app.container.constraints import containers, contains
+ from zope.app.container.interfaces import IContained, IContainer
+
+ class IComment(Interface):
+ """Comment for Ticket"""
+
+ body = Text(
+ title=u"Additional Comment",
+ description=u"Body of the Comment.",
+ default=u"",
+ required=True)
+
+ class ITicket(IContainer):
+ """A ticket object."""
+
+ summary = TextLine(
+ title=u"Summary",
+ description=u"Short summary",
+ default=u"",
+ required=True)
+
+ description = Text(
+ title=u"Description",
+ description=u"Full description",
+ default=u"",
+ required=False)
+
+ contains('.IComment')
+
+ class ICollector(IContainer):
+ """Collector the base object. It can only
+ contains ITicket objects."""
+
+ contains('.ITicket')
+
+ description = Text(
+ title=u"Description",
+ description=u"A description of the collector.",
+ default=u"",
+ required=False)
+
+
+ class ITicketContained(IContained):
+ """Interface that specifies the type of objects that can contain
+ tickets. So a ticket can only contain in a collector."""
+
+ containers(ICollector)
+
+ class ICommentContained(IContained):
+ """Interface that specifies the type of objects that can contain
+ comments. So a comment can only contain in a ticket."""
+
+ containers(ITicket)
+
+If you want a hierarchy of comments, the ``IComment`` and ``ICommentContained``
+can be changed like this::
+
+ class IComment(Interface):
+ """Comment for Ticket"""
+
+ body = Text(
+ title=u"Additional Comment",
+ description=u"Body of the Comment.",
+ default=u"",
+ required=True)
+
+ contains('.IComment')
+
+ class ICommentContained(IContained):
+ """Interface that specifies the type of objects that can contain
+ comments. So a comment can contain in a ticket or a comment itself."""
+
+ containers(ITicket, IComment)
+
+See the ``IComment`` interface calls ``contains`` function with ``.IComment``
+as argument. And in ``ICommentContained`` interface, ``IComment`` is also
+added. But for simplicity these interfaces are not used in this chapter.
+
+
+Unit tests
+----------
+
+Unit testing is explained in another chapter_ . Here you can see some
+boiler-plate code which helps to run the doctest based unittests which you will
+write later. Since `Collector` and `Ticket` objects are containers, this code
+also run common tests for containers. By convention write all unit test files
+under `tests` directory. But doctest files are placed in the package directory
+itself.
+
+.. _chapter: /ZopeGuideUnitTesting
+
+First create ``tests/test_collector.py``::
+
+ import unittest
+ from zope.testing.doctestunit import DocTestSuite
+
+ from zope.app.container.tests.test_icontainer import TestSampleContainer
+
+ from collector.ticketcollector import Collector
+
+
+ class Test(TestSampleContainer):
+
+ def makeTestObject(self):
+ return Collector()
+
+ def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('collector.ticketcollector'),
+ unittest.makeSuite(Test),
+ ))
+
+ if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
+
+Then ``tests/test_ticket.py``::
+
+ import unittest
+ from zope.testing.doctestunit import DocTestSuite
+
+ from zope.app.container.tests.test_icontainer import TestSampleContainer
+
+ from collector.ticket import Ticket
+
+
+ class Test(TestSampleContainer):
+
+ def makeTestObject(self):
+ return Ticket()
+
+ def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('collector.ticket'),
+ unittest.makeSuite(Test),
+ ))
+
+ if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
+``tests/test_comment.py``::
+
+ import unittest
+ from zope.testing.doctestunit import DocTestSuite
+
+ def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('collector.comment'),
+ ))
+
+ if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
+To run the unit test::
+
+ $ cd $HOME/myzope/etc
+ $ ../bin/test -vpu --dir collector
+
+Of course now all tests should fail. In next section you will write doctests
+along with implemetation.
+
+
+Implementation
+--------------
+
+As you can see in the unit test module, collector is going to be implemented in
+``ticketcollector.py``. A base class, ``BTreeContainer`` is used to implement
+the container. This will make the implementation easier.
+
+Here is the ``ticketcollector.py``::
+
+ from zope.interface import implements
+ from zope.app.container.btree import BTreeContainer
+
+ from interfaces import ICollector
+
+ class Collector(BTreeContainer):
+ """A simple implementation of a collector using B-Tree Containers.
+
+ Make sure that the ``Collector`` implements the ``ICollector``
+ interface::
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(ICollector, Collector)
+ True
+
+ Here is an example of changing the description of the collector::
+
+ >>> collector = Collector()
+ >>> collector.description
+ u''
+ >>> collector.description = u'Ticket Collector Description'
+ >>> collector.description
+ u'Ticket Collector Description'
+ """
+
+ implements(ICollector)
+
+ description = u''
+
+
+Similarly ``ticket.py``::
+
+ from zope.interface import implements
+ from zope.interface import classProvides
+ from zope.app.container.btree import BTreeContainer
+ from zope.app.container.contained import Contained
+
+ from interfaces import ITicket, ITicketContained
+
+ class Ticket(BTreeContainer, Contained):
+ """A simple implementation of a ticket using B-Tree Containers.
+
+ Make sure that the ``Ticket`` implements the ``ITicket`` interface::
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(ITicket, Ticket)
+ True
+
+ Here is an example of changing the summary and description of the ticket::
+
+ >>> ticket = Ticket()
+ >>> ticket.summary
+ u''
+ >>> ticket.description
+ u''
+ >>> ticket.summary = u'Ticket Summary'
+ >>> ticket.description = u'Ticket Description'
+ >>> ticket.summary
+ u'Ticket Summary'
+ >>> ticket.description
+ u'Ticket Description'
+ """
+
+ implements(ITicket, ITicketContained)
+
+ summary = u''
+ description = u''
+
+Then `comment.py`::
+
+ from zope.interface import implements
+
+ from interfaces import IComment
+ from interfaces import ICommentContained
+ from zope.app.container.contained import Contained
+
+ class Comment(Contained):
+ """A simple implementation of a comment.
+
+ Make sure that the ``Comment`` implements the ``IComment`` interface::
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(IComment, Comment)
+ True
+
+ Here is an example of changing the body of the comment::
+
+ >>> comment = Comment()
+ >>> comment.body
+ u''
+ >>> comment.body = u'Comment Body'
+ >>> comment.body
+ u'Comment Body'
+ """
+
+ implements(IComment, ICommentContained)
+
+ body = u""
+
+
+Registration
+------------
+
+You have written interfaces and its implementations, now how to bind this with
+Zope 3 framework. You can use use Zope Configuration Markup Language (ZCML)
+based configuration file for this.
+
+This is our configure.zcml::
+
+ <configure
+ xmlns="http://namespaces.zope.org/zope"
+ i18n_domain="collector">
+
+ <interface
+ interface=".interfaces.ICollector"
+ type="zope.app.content.interfaces.IContentType"
+ />
+
+ <class class=".ticketcollector.Collector">
+ <implements
+ interface="zope.annotation.interfaces.IAttributeAnnotatable"
+ />
+ <implements
+ interface="zope.app.container.interfaces.IContentContainer"
+ />
+ <require
+ permission="zope.ManageContent"
+ set_schema=".interfaces.ICollector"
+ />
+ <require
+ permission="zope.ManageContent"
+ interface=".interfaces.ICollector"
+ />
+ </class>
+
+ <interface
+ interface=".interfaces.ITicket"
+ type="zope.app.content.interfaces.IContentType"
+ />
+
+ <class class=".ticket.Ticket">
+ <implements
+ interface="zope.annotation.interfaces.IAttributeAnnotatable"
+ />
+ <implements
+ interface="zope.app.container.interfaces.IContentContainer"
+ />
+ <require
+ permission="zope.ManageContent"
+ set_schema=".interfaces.ITicket"
+ />
+ <require
+ permission="zope.ManageContent"
+ interface=".interfaces.ITicket"
+ />
+ </class>
+
+ <interface
+ interface=".interfaces.IComment"
+ type="zope.app.content.interfaces.IContentType"
+ />
+
+ <class class=".comment.Comment">
+ <implements
+ interface="zope.annotation.interfaces.IAttributeAnnotatable"
+ />
+ <require
+ permission="zope.ManageContent"
+ set_schema=".interfaces.IComment"
+ />
+ <require
+ permission="zope.ManageContent"
+ interface=".interfaces.IComment"
+ />
+ </class>
+
+ <include package=".browser" />
+
+ </configure>
+
+
+Running application
+-------------------
+
+Before running the applcation create one view for ``Collector``.
+
+Create a `browser` directory and under that, a new `configure.zcml`
+file::
+
+ <configure
+ xmlns="http://namespaces.zope.org/browser">
+
+ <addMenuItem
+ class="collector.ticketcollector.Collector"
+ title="Collector"
+ description="A Collector"
+ permission="zope.ManageContent"
+ />
+
+ </configure>
+
+The ``class`` attribute specifies the module path for the class, a leading dot
+means to make the import relative to the package containing the ZCML file.
+Therefore in this case Zope will import the collector.ticketcollector module,
+then import "Collector" from that module.
+
+The ``title`` attribute provides the title to display in the add menu.
+
+The ``permission`` attribute is used to describe what permission is required
+for a person to be able to add one of these objects. The
+``zope.ManageContent`` permission means that the user can add, remove, and
+modify content (the "admin" user you created while making the instance is one
+such user).
+
+You have to tell Zope to read our ZCML file, and the easiest way to do that is
+to put a "slug" in the $HOME/myzope/etc/package-includes/ directory. A
+``slug`` is a ZCML file that just includes another file. Here's what our slug
+should look like (save it as "collector-configure.zcml")::
+
+ <include package="collector" />
+
+Now if you start Zope back up, you can go to the ZMI and add our content type by
+clicking on "Add Collector" and entering a name for our object; name it
+"MyCollector".
+
+Now restart Zope and visit http://localhost:8080 . You can add collector from
+menu.
+
+
+Views
+-----
+
+
+Functional testing
+------------------
Added: zope3book/trunk/source/development-tools.rst
===================================================================
--- zope3book/trunk/source/development-tools.rst (rev 0)
+++ zope3book/trunk/source/development-tools.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,194 @@
+Development Tools
+=================
+
+Before going to the details about how to develop a web application
+using Python and Zope components, we should familiarize some
+essential tools like Python eggs, setuptools and buildouts. If you
+are already familiar with these you may skip this chapter.
+
+
+Eggs
+----
+
+Eggs are Python's new distribution format managed using `setuptool`
+package http://peak.telecommunity.com/DevCenter/PythonEggs .
+
+To install an egg, you can use easy_install program
+http://peak.telecommunity.com/DevCenter/EasyInstall .
+
+An easy way to automate the installtion would be to use
+easy_setup.py program.
+
+::
+
+ $ wget -c http://peak.telecommunity.com/dist/ez_setup.py
+ $ python easy_setup.py
+
+
+Buildout
+--------
+
+The Buildout project provides support for creating applications,
+especially Python applications. It provides tools for assembling
+applications from multiple parts, Python or otherwise. An
+application may actually contain multiple programs, processes, and
+configuration settings.
+
+The word `buildout` refers to a description of a set of parts and the
+software to create and assemble them. It is often used informally to
+refer to an installed system based on a buildout definition. For
+example, if we are creating an application named `Foo``, then `the
+Foo buildout` is the collection of configuration and
+application-specific software that allows an instance of the
+application to be created. We may refer to such an instance of the
+application informally as `a Foo buildout`.
+
+Buildout provides support for creating, assembling and deploying
+applications, especially Python applications. You can build
+applications using Buildout recipes. Recipes are Python programs
+which follows a pattern to build various parts of an application.
+For example, a recipe will install Python eggs and another one will
+install test runner etc. Applications can be assembled from multiple
+parts with different configurations. A part can be a Python egg or
+any other program. We have already seen how to use buildout to setup
+a Zope~3 application in the getting started chapter.
+
+Buildout recipes
+----------------
+
+Buildout recipes are distributed in egg formats. Some examples of
+recipes are:
+
+* zc.recipe.egg -- The egg recipe installes one or more eggs, with
+ their dependencies. It installs their console-script entry points
+ with the needed eggs included in their paths.
+
+* zc.recipe.testrunner -- The testrunner recipe creates a test runner
+ script for one or more eggs.
+
+* zc.recipe.zope3recipes -- Recipes for creating Zope 3 instances
+ with distinguishing features:
+
+ - Don't use a skeleton
+
+ - Separates application and instance definition
+
+ - Don't support package-includes
+
+
+* zc.recipe.filestorage -- The filestorage recipe sets up a ZODB file
+ storage for use in a Zope 3 instance creayed by the `zope3recipes`
+ recipe.
+
+
+Using a recipe
+~~~~~~~~~~~~~~
+
+The procedure for using a recipe is common for almost all recipes.
+You can create buildouts with parts controlled recipes. Suppose you
+want to experiment with one package, say, `zope.component`, you can
+use `zc.recipe.egg` for installing it in buildout. The
+`zc.recipe.egg` will also provide an interpreter with the egg
+installed in the path. First you can create a directory and
+initialize Buildout:
+
+::
+
+ $ mkdir explore-zope.component
+ $ cd explore-zope.component
+ $ echo "#Buildout configuration" > buildout.cfg
+ $ svn co svn://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap
+ $ ~/usr/bin/python2.4 bootstrap/bootstrap.py
+
+Now modify the buildout.cfg like this::
+
+ [buildout]
+ parts = py
+
+ [py]
+ recipe = zc.recipe.egg
+ interpreter = mypython
+ eggs = zope.component
+
+Now run `buildout` script inside `bin` directory. This will download
+zope.component and its dependency eggs and install it. Now you can
+access the interpreter created by the Buildout recipe like this::
+
+ $ ./bin/buildout
+ $ ./bin/mypython
+ >>> import zope.component
+
+
+Developing a package
+--------------------
+
+The initial steps are not different from the above exmaple::
+
+ $ mkdir hello
+ $ cd hello
+ $ echo "#Buildout configuration" > buildout.cfg
+ $ svn co svn://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap
+ $ ~/usr/bin/python2.4 bootstrap/bootstrap.py
+
+Our application is a simple hello world package. First we will
+create an `src` directory to place our package. Inside the `src`
+directory, you can create the `hello` Python package. You can create
+the `src` and the `hello` package like this::
+
+ $ mkdir src
+ $ mkdir src/hello
+ $ echo "#Python package" > src/hello/__init__.py
+
+
+Now create a file named `say.py` inside the `hello` package with this
+code::
+
+ def say_hello():
+ print "Hello"
+
+To start building our package you have to create a `setup.py` file.
+The `setup.py` should have the minimum details as given below::
+
+ from setuptools import setup, find_packages
+
+ setup(
+ name='hello',
+ version='0.1',
+
+ packages=find_packages('src'),
+ package_dir={'': 'src'},
+
+ install_requires=['setuptools',
+ ],
+ entry_points = {'console_scripts':
+ ['print_hello = hello.say:say_hello']},
+ include_package_data=True,
+ zip_safe=False,
+ )
+
+Modify `buildout.cfg` as given below::
+
+ [buildout]
+ develop = .
+ parts = py
+
+ [py]
+ recipe = zc.recipe.egg
+ scripts = print_hello
+ eggs = hello
+
+Now run `buildout` script inside `bin` directory. Now you
+can run the `print_hello` script.
+
+::
+
+ $ ./bin/buildout
+ $ ./bin/print_hello
+ Hello
+
+
+Summary
+-------
+
+This chapter provided a brief introduction to eggs. Later we found
+how to use buildout tool for developing application.
Copied: zope3book/trunk/source/getting-started.rst (from rev 96811, zope3book/trunk/source/InstallingZope3.rst)
===================================================================
--- zope3book/trunk/source/getting-started.rst (rev 0)
+++ zope3book/trunk/source/getting-started.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,431 @@
+Getting Started
+===============
+
+Introduction
+------------
+
+This chapter cover the details of setting up an isolated working
+environment for web application development using Python and Zope
+components. As the first step, you will be required to install
+Python. Then, a basic understanding of Buildout, the build system
+used to set up development sandbox is required. More details about
+Buildout is given in the next chapter. Buildout will take care of
+download and installion of all the dependency packages. To create a
+project code base, you need to provide the minimal meta-data required
+for your project like name, version etc. These details can be given
+in `setup.py` and other configuration details in `buildout.cfg`.
+
+
+Python installation
+-------------------
+
+The Zope community has always recommended using a custom built Python
+for development and deployment. Both Python 2.4 and 2.5 should work
+for Zope 3.4 KGS packages. As of now, the author reccomend using
+Python 2.5 for any new project.
+
+
+GNU/Linux
+~~~~~~~~~
+
+To install Python, you will be required to install gcc, g++ and other
+development tools in your system. A typical installation of Python can
+be done like this:
+
+::
+
+ $ wget -c http://www.python.org/ftp/python/2.4.5/Python-2.4.5.tar.bz2
+ $ tar jxvf Python-2.4.5.tar.bz2
+ $ cd Python-2.4.5
+ $ ./configure --prefix=/home/guest/usr
+ $ make
+ $ make install
+
+As given above, you can provide an option, ``--prefix`` to install
+Python in a particular location. The above steps install Python
+inside ``/home/guest/usr`` directory.
+
+After installation, you can invoke the Python interpreter like this::
+
+ $ ~/usr/bin/python2.4
+ >>> print "Hello, world!"
+ Hello, world!
+
+.. note::
+
+ If you are not getting old statements in Python interactive prompt
+ when using up-arrow key, try installing libreadline development
+ libraries (Hint: apt-cache search libreadline). After installing
+ this library, you should install Python again. You also will be
+ required to install zlib (Hint: apt-cache search zlib compression
+ library) to properly install Zope 3.
+
+
+MS Windows
+~~~~~~~~~~
+
+Python provide binaries for MS Windows. You can use the MSI
+installer package from python.org
+
+
+Buildout
+--------
+
+Introduction
+~~~~~~~~~~~~
+
+We are going to use a build tool called Buildout for developing Zope
+3 applications from multiple parts. Buildout will give you an
+isolated working environment for developing applications. The
+Buildout package, named `zc.buildout` is available for download from
+PyPI. This section briefly goes through the usage of Buildout for
+developing applications.
+
+Buildout has a `boostrap.py` script for initializing a buildout based
+project for development or deployment. It will download and install
+`zc.buildout`, `setuptools` and other dependency modules in a
+specified directory. Once bootstrapped it will create a buildout
+executable script inside `bin` directory at the top of your project
+source. The default configuration for each project is `buildout.cfg`
+file at the top of your project source. Whenever you run the
+buildout command it will look into the default configuration file and
+will do actions based on it. Normally, the configuration file and
+boostrap script will be bundled with the project source itself.
+Other than the default configuration file along with the project
+source, you may also create a system wide default configuration file
+at `~/.buildout/default.cfg` .
+
+Buildout creator Jim Fulton recommend a custom built clean Python
+installation, i.e., there should not be any Python modules installed
+in your site-packages (ideally, a fresh Python installation). When you
+boostrap your project using Buildout's boostrap.py script, it will
+download and install all necessary packages in a specified directory.
+So, for an ideal project you only required a custom built clean Python
+and the project source with proper Buildout configuration and
+bootstrap script along with the source package.
+
+
+Buildout configuration
+~~~~~~~~~~~~~~~~~~~~~~
+
+These days, most of the Python packages are available in egg_ format.
+Buildout will download and install the eggs in a specified directory
+and the location can be changed from the configuration file. It is
+better to give a system-wide location for eggs directory. And this
+configuration can be added to your system-wide configuration file.
+The default configuration file for Buildout is
+`~/.buildout/default.cfg` . We are going to use `eggs` directory
+inside your home directory to keep all eggs, so first create those
+directories and global configuration file::
+
+ $ cd $HOME
+ $ mkdir .buildout
+ $ mkdir eggs
+ $ touch .buildout/default.cfg
+
+You can add the following to your global configuration file
+(`~/.buildout/default.cfg`)::
+
+ [buildout]
+ newest = false
+ eggs-directory = /home/guest/eggs
+ find-links = http://download.zope.org/ppix
+
+The `eggs-directory` is where Buildout stores the eggs that are
+downloaded. The last option, `find-links` points to a reliable
+mirror of the Python Package Index (PyPI). The default
+configurations given above will be available to all buildouts in your
+system.
+
+.. _egg: http://peak.telecommunity.com/DevCenter/PythonEggs
+
+
+Setting up development sandbox
+------------------------------
+
+To demonstrate the concepts, tools and techniques, we are going to
+develop a ticket collector application. To begin the work, first
+create a directory for the project. After creating the directory,
+create a configuration file, `buildout.cfg` as given below. To
+bootstrap this application checkout bootstrap.py and run it using a
+clean Python.
+
+::
+
+ $ mkdir ticketcollector
+ $ cd ticketcollector
+ $ echo "#Buildout configuration" > buildout.cfg
+ $ svn co svn://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap
+ $ ~/usr/bin/python2.4 bootstrap/bootstrap.py
+
+You can see a `buildout` script created inside `bin` directory. Now
+onwards, run this `buildout` script whenever you are changing
+Buildout configuration.
+
+.. note::
+
+ You can save `bootstrap.py` in a local repository. If you are
+ using svn for managing repository, create an `svn:external` to the
+ svn URL given above.
+
+Our application is basically a Python package. First, we will create
+an `src` directory to place our package. Inside the `src` directory,
+you can create `ticketcollector` Python package. You can create the
+`src` and the `ticketcollector` package like this::
+
+ $ mkdir src
+ $ mkdir src/ticketcollector
+ $ echo "#Python package" > src/ticketcollector/__init__.py
+
+To start building our package you have to create a `setup.py` file.
+The `setup.py` should have the minimum details as given below::
+
+ from setuptools import setup, find_packages
+
+ setup(
+ name='ticketcollector',
+ version='0.1',
+
+ packages=find_packages('src'),
+ package_dir={'': 'src'},
+
+ install_requires=['setuptools',
+ 'zope.app.zcmlfiles',
+ 'zope.app.twisted',
+ 'zope.app.securitypolicy',
+ ],
+ include_package_data=True,
+ zip_safe=False,
+ )
+
+We have included the bare minimum packages required for installation
+in `install_requires` argument: `zope.app.zcmlfiles`,
+`zope.app.twisted` , `zope.app.securitypolicy` and `setuptools`.
+
+To make this package buildout aware, we have to modify the
+`buildout.cfg` as given below::
+
+ [buildout]
+ develop = .
+ parts = py
+ extends = http://download.zope.org/zope3.4/3.4.0/versions.cfg
+ versions = versions
+
+ [py]
+ recipe = zc.recipe.egg
+ eggs = ticketcollector
+ interpreter = python
+
+Now run the `buildout` script inside `bin` directory. This will download
+all necessary eggs and install it.
+
+::
+
+ $ ./bin/buildout
+
+As you can see above, installing Zope is nothing but just setting up
+a buildout with `setup.py` with proper packages given as
+`install_requires` in it.
+
+.. note::
+
+ Unless you specify a parts section which use `ticketcollector` in some
+ way, Buildout will not download dependency packages. In the above
+ example, we created a `[py]` section with `zc.recipe.egg` recipe.
+
+
+A simple application
+--------------------
+
+
+Configuring application
+~~~~~~~~~~~~~~~~~~~~~~~
+
+We are going to continue the Ticket Collector application in this
+section. In the last section when you run `./bin/buildout` command
+all necessary Zope 3 packages required for running our application is
+downloaded inside `~/eggs` directory. Now to run the bare minimum
+Zope 3, we have to create Zope Configuration Markup Language (ZCML)
+file and extend the `buildout.cfg` with appropriate Buildout recipes.
+We are going to use `zc.zope3recipes:app`, `zc.zope3recipes:instance`
+and `zc.recipe.filestorage` recipes for setting up our application.
+Here is our modified buildout.cfg (inside the ticketcollector project
+directory)::
+
+ [buildout]
+ develop = .
+ parts = ticketcollectorapp instance
+
+ [zope3]
+ location =
+
+ [ticketcollectorapp]
+ recipe = zc.zope3recipes:app
+ site.zcml =
+ <include
+ package="ticketcollector"
+ file="application.zcml"
+ />
+ eggs = ticketcollector
+
+ [instance]
+ recipe = zc.zope3recipes:instance
+ application = ticketcollectorapp
+ zope.conf = ${database:zconfig}
+
+ [database]
+ recipe = zc.recipe.filestorage
+
+Then we will create `application.zcml` inside `src/ticketcollector`
+directory with the following text. Consider it as boiler plate code
+now, we will explain this in detail later::
+
+ <configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ >
+
+ <include package="zope.securitypolicy"
+ file="meta.zcml"
+ />
+
+ <include package="zope.app.zcmlfiles" />
+ <include package="zope.app.authentication" />
+ <include package="zope.app.securitypolicy" />
+ <include package="zope.app.twisted" />
+
+ <securityPolicy
+ component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy"
+ />
+
+ <role id="zope.Anonymous" title="Everybody"
+ description="All users have this role implicitly"
+ />
+
+ <role id="zope.Manager" title="Site Manager" />
+
+ <role id="zope.Member" title="Site Member" />
+
+ <grant permission="zope.View"
+ role="zope.Anonymous"
+ />
+
+ <grant permission="zope.app.dublincore.view"
+ role="zope.Anonymous"
+ />
+
+ <grantAll role="zope.Manager" />
+
+ <unauthenticatedPrincipal
+ id="zope.anybody"
+ title="Unauthenticated User"
+ />
+
+ <unauthenticatedGroup
+ id="zope.Anybody"
+ title="Unauthenticated Users"
+ />
+
+ <authenticatedGroup
+ id="zope.Authenticated"
+ title="Authenticated Users"
+ />
+
+ <everybodyGroup
+ id="zope.Everybody"
+ title="All Users"
+ />
+
+ <principal
+ id="zope.manager"
+ title="Manager"
+ login="admin"
+ password_manager="Plain Text"
+ password="admin"
+ />
+
+ <grant
+ role="zope.Manager"
+ principal="zope.manager"
+ />
+
+ </configure>
+
+
+Running application
+~~~~~~~~~~~~~~~~~~~
+
+Now you can run the application by executing `./bin/buildout` command
+followed by `./bin/instance` command.
+
+::
+
+ $ ./bin/buildout
+ $ ./bin/instance fg
+
+
+Using ZMI
+~~~~~~~~~
+
+After running your instance, If you open a web browser and go to
+`http://localhost:8080 <http://localhost:8080>`_ you'll see the ZMI
+(Zope Management Interface ).
+
+Go ahead and click the `Login` link at the upper right corner. Enter
+the user name and password as admin, which is given in
+`applications.zcml`. Now click on `[top]` under Navigation on the
+right. Play around with adding some content objects (the Zope 3 name
+for instances that are visible in the ZMI). Note how content objects
+can be arranged in a hierarchy by adding folders which are special
+content objects that can hold other content objects.
+
+There is nothing special about the ZMI, it is just the default skin
+for Zope 3. You can modify it to your liking, or replace it
+entirely.
+
+When you're done exploring with the ZMI, go back to the window where
+you typed `./bin/instance fg` and press Control-C to stop Zope 3.
+
+
+Hello world
+~~~~~~~~~~~
+
+Now you can begin your development inside `src/ticketcollector`
+directory. Create a `browser.py` with following content::
+
+ from zope.publisher.browser import BrowserView
+
+ class HelloView(BrowserView):
+
+ def __call__(self):
+ return """
+ <html>
+ <head>
+ <title>Hello World</title>
+ </head>
+ <body>
+ Hello World
+ </body>
+ </html>
+ """
+
+Now append the following text just above the last line of
+application.zcml::
+
+ <browser:page
+ for="*"
+ name="hello"
+ permission="zope.Public"
+ class="ticketcollector.browser.HelloView"
+ />
+
+After restarting Zope, open `http://localhost:8080/hello
+<http://localhost:8080/hello>`_, you can see that it displays `Hello
+World!`.
+
+
+Conclusion
+----------
+
+Setting up a Zope 3 project sandbox is nothing but creating a proper
+Buildout configuration.
Property changes on: zope3book/trunk/source/getting-started.rst
___________________________________________________________________
Added: svn:mergeinfo
+
Modified: zope3book/trunk/source/index.rst
===================================================================
--- zope3book/trunk/source/index.rst 2009-02-20 17:55:43 UTC (rev 96846)
+++ zope3book/trunk/source/index.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -1,16 +1,25 @@
-#######################
+.. _contents:
+
Zope 3 Developer's Book
-#######################
+=======================
.. toctree::
:maxdepth: 2
- Preface.rst
- InstallingZope3.rst
+ introduction
+ getting-started
+ development-tools
+ interfaces
+ component-architecture
+ testing
+ browser-resouces
+ browser-pages
+ content-components
+ skinning
-##################
+
Indices and tables
-##################
+==================
* :ref:`genindex`
* :ref:`modindex`
Added: zope3book/trunk/source/interfaces.rst
===================================================================
--- zope3book/trunk/source/interfaces.rst (rev 0)
+++ zope3book/trunk/source/interfaces.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,326 @@
+Interfaces
+==========
+
+
+Introduction
+------------
+
+Interfaces are objects that specify (document) the external behavior
+of objects that "provide" them. An interface specifies behavior
+through:
+
+* Informal documentation in a doc string
+
+* Attribute definitions
+
+* Invariants, which are conditions that must hold for objects that
+ provide the interface
+
+Some of the motivations for using interfaces are:
+
+* Avoid monolithic design by developing small, exchangeable pieces
+
+* Model external responsibility, functionality, and behavior
+
+* Establish contracts between pieces of functionality
+
+* Document the API
+
+The classic software engineering book `Design Patterns`_ by the Gang
+of Four recommends: "Program to an interface, not an implementation".
+Defining a formal interface is helpful in understanding a system.
+Moreover, interfaces bring you all the benefits of Zope Component
+Architecture which we are going to learn in next chapter.
+
+In some modern programming languages: Java, C#, VB.NET etc,
+interfaces are an explicit aspect of the language. Since Python
+lacks interfaces, Zope implements them as a meta-class to inherit
+from.
+
+.. _Design Patterns: http://en.wikipedia.org/wiki/Design_Patterns
+
+
+Types of contract
+-----------------
+
+:"I can do X": Describing the ability to do something is the classical
+ definition of an API. Those abilities are defined and implemented as
+ methods.
+
+
+:"I have X": This statement declares the availability of data, which
+ is classically associated with schemas. The data is stored in
+ attributes and properties.
+
+
+:"You can do X with me": Here we describe the behavior of an object.
+ Classically there is no analog. However, MIME-types are great example
+ of behavior declaration. This is implemented using empty "marker
+ interfaces" as they describe implicit behavior.
+
+
+The distinction between those three types of contracts was first
+pointed out in this form by Philipp von Weitershausen.
+
+Understanding those distinctions is very important, since other
+programming languages do not necessarily use all three of these
+notions. In fact, often only the first one is used.
+
+
+Defining interfaces
+-------------------
+
+* Python has no concept of interfaces
+
+* Not a problem
+
+* Interfaces are just objects
+
+* "Abuse" the class statement to create an interface
+
+* Syntax proposed in PEP 245
+
+Jim Fulton does not see this as a problem, since it makes interfaces
+first class citizens. In Java, for example, interfaces are special
+types of objects that can only serve as interfaces in their intended,
+limited scope.
+
+An interface from the zope.interface package, on the other hand,
+defines the interface by implementing a meta-class, a core concept of
+Python. Thus, interfaces are merely using an existing Python
+pattern.
+
+
+An example
+----------
+
+Here is a classic hello world style example::
+
+ >>> class Host(object):
+ ...
+ ... def goodmorning(self, name):
+ ... """Say good morning to guests"""
+ ...
+ ... return "Good morning, %s!" % name
+
+
+In the above class, you defined a goodmorning method. If you call
+the goodmorning method from an object created using this class, it
+will return Good morning, ...!
+
+::
+
+ >>> host = Host()
+ >>> host.goodmorning('Jack')
+ 'Good morning, Jack!'
+
+
+Here host is the actual object your code uses. If you want to
+examine implementation details you need to access the class Host,
+either via the source code or an API_ documentation tool.
+
+Now we will begin to use the Zope interfaces. For the class given
+above you can specify the interface like this::
+
+ >>> from zope.interface import Interface
+
+ >>> class IHost(Interface):
+ ...
+ ... def goodmorning(guest):
+ ... """Say good morning to guest"""
+
+
+As you can see, the interface inherits from zope.interface.Interface.
+This use (abuse?) of Python's class statement is how Zope defines an
+interface. The I prefix for the interface name is a useful
+convention.
+
+.. _API: http://en.wikipedia.org/wiki/Application_programming_interface
+
+
+Declaring interfaces
+--------------------
+
+You have already seen how to declare an interface using
+`zope.interface` in previous section. This section will explain the
+concepts in detail.
+
+Consider this example interface::
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface import Attribute
+
+ >>> class IHost(Interface):
+ ... """A host object"""
+ ...
+ ... name = Attribute("""Name of host""")
+ ...
+ ... def goodmorning(guest):
+ ... """Say good morning to guest"""
+
+
+The interface, `IHost` has two attributes, name and goodmorning.
+Recall that, at least in Python, methods are also attributes of
+classes. The name attribute is defined using
+zope.interface.Attribute class. When you add the attribute name to
+the IHost interface, you don't set an initial value. The purpose of
+defining the attribute name here is merely to indicate that any
+implementation of this interface will feature an attribute named
+name. In this case, you don't even say what type of attribute it has
+to be!. You can pass a documentation string as a first argument to
+Attribute.
+
+The other attribute, goodmorning is a method defined using a function
+definition. Note that self is not required in interfaces, because
+self is an implementation detail of class. For example, a module can
+implement this interface. If a module implement this interface,
+there will be a name attribute and goodmorning function defined. And
+the goodmorning function will accept one argument.
+
+Now you will see how to connect interface-class-object. So object is
+the real living thing, objects are instances of classes. And
+interface is the actual definition of the object, so classes are just
+the implementation details. This is why you should program to an
+interface and not to an implementation.
+
+Now you should familiarize two more terms to understand other
+concepts. First one is provide and the other one is implement.
+Object provides interfaces and classes implement interfaces. In
+other words, objects provide interfaces that their classes implement.
+In the above example host (object) provides IHost (interface) and
+Host (class) implement IHost (interface). One object can provide
+more than one interface also one class can implement more than one
+interface. Objects can also provide interfaces directly, in addition
+to what their classes implement.
+
+.. note::
+
+ Classes are the implementation details of objects. In Python,
+ classes are callable objects, so why other callable objects can't
+ implement an interface. Yes, it is possible. For any callable
+ object you can declare that it produces objects that provide some
+ interfaces by saying that the callable object implements the
+ interfaces. The callable objects are generally called as
+ factories. Since functions are callable objects, a function can be
+ an implementer of an interface.
+
+
+Implementing interfaces
+-----------------------
+
+To declare a class implements a particular interface, use the
+function `zope.interface.implements` in the class statement.
+
+Consider this example, here `Host` implements `IHost`::
+
+ >>> from zope.interface import implements
+
+ >>> class Host(object):
+ ...
+ ... implements(IHost)
+ ...
+ ... name = u''
+ ...
+ ... def goodmorning(self, guest):
+ ... """Say good morning to guest"""
+ ...
+ ... return "Good morning, %s!" % guest
+
+
+.. note::
+
+ If you wonder how implements function works, refer the blog post by
+ James Henstridge (`http://blogs.gnome.org/jamesh/2005/09/08
+ /python-class-advisors/ <http://blogs.gnome.org/jamesh/2005/09/08
+ /python-class-advisors/>`__) . In the adapter section, you will see
+ an adapts function, it is also working similarly.
+
+
+Since Host implements IHost, instances of Host provides IHost. There
+are some utility methods to introspect the declarations. The
+declaration can write outside the class also. If you don't write
+interface.implements(IHost) in the above example, then after defining
+the class statement, you can write like this::
+
+ >>> from zope.interface import classImplements
+ >>> classImplements(Host, IHost)
+
+
+Marker interfaces
+-----------------
+
+An interface can be used to declare that a particular object belongs
+to a special type. An interface without any attribute or method is
+called marker interface.
+
+Here is a marker interface::
+
+ >>> from zope.interface import Interface
+
+ >>> class ISpecialGuest(Interface):
+ ... """A special guest"""
+
+
+This interface can be used to declare an object is a special guest.
+
+
+Invariants
+----------
+
+Sometimes you will be required to use some rule for your component
+which involve one or more normal attributes. These kind of rule is
+called `invariants`. You can use `zope.interface.invariant` for
+setting `invariants` for your objects in their interface.
+
+Consider a simple example, there is a `person` object. A person
+object has `name`, `email` and `phone` attributes. How do you
+implement a validation rule that says either email or phone have to
+exist, but not necessarily both.
+
+First you have to make a callable object, either a simple function or
+callable instance of a class like this::
+
+ >>> def contacts_invariant(obj):
+ ...
+ ... if not (obj.email or obj.phone):
+ ... raise Exception(
+ ... "At least one contact info is required")
+
+Then define the `person` object's interface like this. Use the
+`zope.interface.invariant` function to set the invariant::
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface import Attribute
+ >>> from zope.interface import invariant
+
+ >>> class IPerson(Interface):
+ ...
+ ... name = Attribute("Name")
+ ... email = Attribute("Email Address")
+ ... phone = Attribute("Phone Number")
+ ...
+ ... invariant(contacts_invariant)
+
+Now use `validateInvariants` method of the interface to validate::
+
+ >>> from zope.interface import implements
+
+ >>> class Person(object):
+ ... implements(IPerson)
+ ...
+ ... name = None
+ ... email = None
+ ... phone = None
+
+ >>> jack = Person()
+ >>> jack.email = u"jack at some.address.com"
+ >>> IPerson.validateInvariants(jack)
+ >>> jill = Person()
+ >>> IPerson.validateInvariants(jill)
+ Traceback (most recent call last):
+ ...
+ Exception: At least one contact info is required
+
+As you can see `jack` object validated without raising any exception.
+But `jill` object didn't validated the invariant constraint, so it
+raised exception.
Added: zope3book/trunk/source/introduction.rst
===================================================================
--- zope3book/trunk/source/introduction.rst (rev 0)
+++ zope3book/trunk/source/introduction.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,178 @@
+Introduction
+============
+
+
+Overview
+--------
+
+This book is about `Zope 3`_, a Python_ framework for web application
+development. Zope 3 was developed by the Zope_ community with the
+leadership of Jim Fulton, the creator of original Zope. Zope 3
+consists of a number of small frameworks and libraries written in
+Python programming language and it is usable in pieces or in whole.
+These frameworks and libraries can be put together to build any kind
+of web application. Most of of the Zope 3 packages are built on top
+of a `component architecture`_ which helps to separate presentation
+code from the problem domain code and to create reusable components
+(zope.component).
+
+The goal for this book project is to create a complete, free,
+open-content, well-organized book for Zope 3. The target audience of
+this book are Python programmers looking for developing web
+applications. However, the book doesn't assume you are familiar with
+any other web framework. This book will require prior knowledge
+Python programming language and at least some exposure to the basics
+of HTML, CSS and JavaScript.
+
+Zope 3 has an object publisher (zope.publisher), web server
+(zope.server), transactional object database (ZODB), XML based
+configuration language for registering components
+(zope.configuration), flexible security architecture with pluggable
+security policies (zope.security), unit and functional testing
+frameworks (zope.testing , zope.testbrowser), XHTML-compliant
+templating language (zope.pagetemplate), schema engine and automatic
+form generation machinery (zope.schema , z3c.form) and many more core
+and third-party packages.
+
+Originally, the term ZOPE was used as an acronym for Z Object
+Publishing Environment (the Z doesn't really mean anything in
+particular). However, now-a-days ZOPE is simply written as Zope .
+
+Zope 3 is a ZPL (BSD like, GPL compatible license) licensed free/open
+source software. It was developed by the Zope community with the
+leadership of Jim Fulton. A brief history is given in the next
+section.
+
+.. _Zope 3: http://en.wikipedia.org/wiki/Zope_3
+.. _Python: http://en.wikipedia.org/wiki/Python_Programming
+.. _Zope: http://en.wikipedia.org/wiki/Zope
+.. _component architecture: http://wiki.zope.org/zope3/ComponentArchitecture
+.. _Buildout: http://pypi.python.org/pypi/zc.buildout
+
+
+Scope of the book
+-----------------
+
+The intension of this book is not to cover how to use Zope 3 packages
+independently or with other Python applications/frameworks. Rather,
+this book focus on developing web applications using Zope 3 packages.
+More specifically, this book is not going to cover using Zope 3
+technology in Zope 2, Plone, Grok or any other Python
+application/framework. WSGI is also not a current focus of this
+book. This book is not going to cover using `zopeproject` to
+bootstrap application (it's very easy, look at the PyPI page for
+zopeproject). This book use Buildout for setting up an isolated
+development environment for building applications. Setuptools and
+vitualenv are also covered.
+
+
+Audience
+--------
+
+The target audience of this book are Python programmers looking for
+developing web applications. However, the book doesn't assume you are
+familiar with any other web framework.
+
+
+Prerequisites
+-------------
+
+This book will require prior knowledge Python programming language and
+at least some exposure to the basics of HTML, CSS and JavaScript.
+
+
+Brief history
+-------------
+
+The beginning of Zope's story goes something like this, in 1996, Jim
+Fulton (CTO of Zope Corporation) was drafted to teach a class on
+common gateway interface (CGI) programming, despite not knowing very
+much about the subject. CGI programming is a commonly-used web
+development model that allows developers to construct dynamic
+websites. On his way to the class, Jim studied all the existing
+documentation on CGI. On the way back, Jim considered what he didn't
+like about traditional, CGI-based programming environments. From these
+initial musings, the core of Zope was written while flying back from
+the CGI class.
+
+Zope Corporation (then known as Digital Creations) went on to release
+three open-source software packages to support web publishing: Bobo,
+Document Template, and BoboPOS. These packages were written in a
+language called Python, and provided a web publishing facility, text
+templating, and an object database, respectively. Digital Creations
+developed a commercial application server based on their three
+opensource components. This product was called Principia. In November
+of 1998, investor Hadar Pedhazur convinced Digital Creations to open
+source Principia. These packages evolved into what are now the core
+components of Zope 2.
+
+In 2001, the Zope community began working on a component architecture
+for Zope, but after several years they ended up with something much
+more: Zope 3. While Zope 2 was powerful and popular, Zope 3 was
+designed to bring web application development to the next level. This
+book is about this Zope 3, which is not really a new version of Zope
+2.
+
+Most recently, in 2007 the Zope community created yet another
+framework based on Zope 3 called Grok. The original Zope which is now
+known as Zope 2 is also widely used.
+
+
+Organization of the book
+------------------------
+
+This book has divided into multiple chapters. Summary of each
+chapter is given below.
+
+
+Introduction
+~~~~~~~~~~~~
+
+This chapter introduce Zope 3 with an overview and scope of the book,
+then briefly go through the history of Zope 3. Later discuss
+organization of the book. And finish with a thanks section.
+
+
+Getting Started
+~~~~~~~~~~~~~~~
+
+This chapter begins with installation details of Python and Zope 3.
+Then introduce Buildout, the build system we use to setup an isolated
+Python working environment and its configurations. Later, it explore
+setting up development sandbox using Buildout. A simple application
+is developed further and it ends with a `hello world` page. During
+the application development we see how to use ZMI (Zope Management
+Interface) briefly. This chapter also provides a brief overview of
+important packages and installation of additional packages.
+
+
+Development Tools
+~~~~~~~~~~~~~~~~~
+
+This chapter is going to the details about how to develop a web
+application using Python and Zope components. You should familiarize
+some essential tools like Python eggs, setuptools and buildouts. If
+you are already familiar with these you may skip this chapter.
+
+
+Interfaces
+~~~~~~~~~~
+
+This chapter introduce the concept of interfaces. If you are already
+familiar with this you may skip this chapter.
+
+
+Component Architecture
+~~~~~~~~~~~~~~~~~~~~~~
+
+This chapter introduce Zope component architecture. If you are
+already familiar with this you may skip this chapter.
+
+
+Thanks
+------
+
+This book would not be possible if Zope 3 did not exist. For that,
+the I would like to thank all developers of Zope 3. I am grateful to
+Stephan Richter for allowing me to use his book and training material
+for this work.
Added: zope3book/trunk/source/skinning.rst
===================================================================
--- zope3book/trunk/source/skinning.rst (rev 0)
+++ zope3book/trunk/source/skinning.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,190 @@
+Skinnig
+=======
+
+Motivation
+
+* Need to build sites with equal/similar features, but different look
+ and feel
+
+* Variation of Look and Feel can be simple or complex
+
+ - Exchange a CSS file and some images
+
+ - Reconfigure the application to have different UI components, such
+ as widgets, tables, O-wrap, etc.
+
+* Often need to mix and match UI components from multiple packages
+
+The level of customization of Zope (2 and 3) has been a strong point
+for years. Initially the UI was customized relying on implicit
+acquisition, where it was simply a matter of adding an object higher
+in the object path to customize the UI. Since implicit acquisition is
+often hard to debug, the CMF introduced the concept of skins, where a
+skin describes the look and feel of a site. Skins could acquire from
+other skins explicitly.
+
+In Zope 3 the concept of skins was reconsidered and re-implemented to
+use the component architecture.
+
+Layers
+
+* Define the "feel" of a site
+
+* Contain presentation logic
+
+* Common artifacts: pages, content providers, viewlet managers, and
+ viewlets
+
+* Developed by Zope 3 Python developers
+
+Skins
+
+* Define the "look" of a site
+
+* Common artifacts: templates and resources (CSS, Javascript, etc.)
+
+* Use layers to retrieve the data for templates
+
+* Developed by HTML and Graphic Designer/Scripter
+
+Layers versus Skins
+
+* Both are implemented as interfaces
+
+* Zope 3 does not differentiate between the two
+
+* In fact, the distinction of layers defining the "feel" and skins
+ the "look" is a convention. You may not want to follow the
+ convention, if it is too abstract for you, but if you are
+ developing application with multiple look and feel, I strongly
+ suggest using this convention, since it cleanly separates concerns.
+
+
+* Both support inheritance/acquisition
+
+This is realized through a combination of interface inheritance and
+component lookup techniques. We will discuss this in more detail
+later.
+
+Skins are directly provided by a request
+
+Core Skins
+----------
+
+* Access skin using ++skin++Name after the server root
+
+* Core Skins that are part of the repository
+
+ - Rotterdam -- the default skin shown
+
+ - Boston -- a newer skin featuring viewlets
+
+ - Basic -- a skin with no layout styles
+
+ - Debug -- based on Rotterdam, shows debug information upon
+ failures
+
+* Try http://localhost:8080/++skin++Boston
+
+Unfortunately, it is hard to reuse the UI components developed for
+these skins, since they still rely on the not so flexible macro
+pattern. Thus, it is better if you start from scratch. This will also
+avoid a lot of the overhead that comes with the over-generalized core
+skins.
+
+A New Skin
+----------
+
+* Views registered for default layer by default
+ zope.publisher.interfaces.browser.IDefaultBrowserLayer
+
+* Default layer contains a lot of things we do not need (security
+ concerns)
+
+* Since pretty much everything in zope.app is registered into the
+ default layer, it has an uncontrollable amount of junk in it. It is
+ very hard to verify that all those registrations fulfill your
+ security needs. Another problem is that views might be available
+ that you do not want to be available.
+
+
+* Always want to develop skins from scratch
+
+* Some registrations in the default layer are very useful
+
+* Examples of those useful registrations include error views, traversal registrations, and widgets.
+
+* Useful set of registrations collected in the minimal layer z3c.layer.minimal
+
+* Add the z3c.layer.minimal package to your project dependencies
+
+
+Setting up a Layer
+------------------
+
+Write an interface for the layer that inherits the minimal layer::
+
+ from z3c.layer import minimal
+
+ class IHelloWorldLayer(minimal.IMinimalBrowserLayer):
+ """Hello World Application Layer"""
+
+
+Change all page, viewletmanager, and viewlet directives to specify
+this layer:
+
+ layer=".interfaces.IHelloWorldLayer"
+
+Once you changed those registrations, the helloworld.html page is not
+available anymore in the core skins. The templates by themselves do
+not matter.
+
+
+Setting up a Skin
+~~~~~~~~~~~~~~~~~
+
+Write an interface for each new skin that inherits the Hello World
+application layer::
+
+ class IBasicSkin(IHelloWorldLayer):
+ """Basic Skin for Hello World App."""
+
+Register the interface as a skin interface::
+
+ <zope:interface
+ interface=".interfaces.IBasicSkin"
+ type="zope.publisher.interfaces.browser.IBrowserSkinType"
+ name="HWBasic"
+ />
+
+Register all templates for this skin by adding the layer attribute:
+
+ layer=".interfaces.IBasicSkin"
+
+
+Using the Skin
+~~~~~~~~~~~~~~
+
+Access it via: http://localhost:8080/++skin++HWBasic
+
+Hide skin traversal step by using Apache's Virtual Hosting feature
+
+To change the default skin to something else use:
+
+ <browser:defaultSkin name="HWBasic" />
+
+Simply specifying the browser:defaultSkin directive in your
+configuration file will not work, since it has been specified in
+zope/app/zcmlfiles/browser.zcml already. You can either change the
+skin at this location or use the zope:includeOverrides directive,
+which will override the any included directives.
+
+Exercise
+--------
+
+* Develop the Hello World application layer.
+
+* Develop two skins based on this layer.
+
+* Write some tests that specifically test the difference between the
+ skins.
Added: zope3book/trunk/source/testing.rst
===================================================================
--- zope3book/trunk/source/testing.rst (rev 0)
+++ zope3book/trunk/source/testing.rst 2009-02-20 19:10:14 UTC (rev 96847)
@@ -0,0 +1,96 @@
+Testing
+=======
+
+
+Unit testing
+------------
+
+This chapter will discuss about unit testing and integration
+testing. Doctest-based testing is heavily used in Zope 3. And test
+driven development (TDD) is prefered in Zope 3. To explain the idea,
+consider a use case. A module is required with a function which
+returns "Good morning, name!". The name will be given as an
+argument. Before writing the real code write the unit test for
+this. In fact you will be writing the real code and it's test cases
+almost in parallel. So create a file named example1.py with the
+function definition::
+
+ def goodmorning(name):
+ "This returns a good morning message"
+
+See, you have not yet written the logic. But this is necessary to run
+tests successfully with failures!. Ok, now create a file named
+example1.txt with test cases, use reStructuredText format::
+
+ These are tests for example1 module.
+
+ First import the module:
+
+ >>> import example1
+
+Now call the function goodmorning without any arguments::
+
+ >>> example1.goodmorning()
+ Traceback (most recent call last):
+ ...
+ TypeError: goodmorning() takes exactly 1 argument (0 given)
+
+Now call the function goodmorning with one argument::
+
+ >>> example1.goodmorning('Jack')
+ 'Good morning, Jack!'
+
+See the examples are written like executed from prompt. You can use
+your python prompt and copy paste from there. Now create another file
+test_example1.py with this content::
+
+ import unittest
+ import doctest
+
+ def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('example1.txt'),
+ ))
+
+ if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
+This is just boilerplate code for running the test. Now run the test
+using python2.4 test_example1.py command. You will get output with
+following text::
+
+ File "example1.txt", line 16, in example1.txt
+ Failed example:
+ example1.goodmorning('Jack')
+ Expected:
+ 'Good morning, Jack!'
+ Got nothing
+
+
+Now one test failed, so implement the function now::
+
+ def goodmorning(name):
+ "This returns a good morning message"
+ return "Good morning, %s!" % name
+
+Now run the test again, it will run without failures.
+
+Now start thinking about other functionalities required for the
+module. Before start coding write about it in text file. Decide API,
+write test, write code, than continue this cycle until you finish
+your requirements.
+
+
+Running tests
+-------------
+
+By conventions your test modules are put in tests module under each
+package. But the doctest files can be placed in the package
+itself. For example if the package is ticketcollector. Then the main
+doctest file can be placed in ticketcollector/README.txt. And create
+a sub-package zopetic.tests, under this package create test modules
+like test_main.py, test_extra.py etc. To run the unit tests, change
+to instance home::
+
+ $ cd ticketcollector
+ $ ./bin/test
More information about the Checkins
mailing list