[Checkins] SVN: grok/trunk/doc/minitutorials/ Change txt extension into rst extension.

Jan-Wijbrand Kolman janwijbrand at gmail.com
Thu May 1 07:19:53 EDT 2008


Log message for revision 85984:
  Change txt extension into rst extension.

Changed:
  A   grok/trunk/doc/minitutorials/automatic_form_generation.rst
  D   grok/trunk/doc/minitutorials/automatic_form_generation.txt
  A   grok/trunk/doc/minitutorials/index.rst
  D   grok/trunk/doc/minitutorials/index.txt
  A   grok/trunk/doc/minitutorials/macros.rst
  D   grok/trunk/doc/minitutorials/macros.txt
  A   grok/trunk/doc/minitutorials/permissions.rst
  D   grok/trunk/doc/minitutorials/permissions.txt
  A   grok/trunk/doc/minitutorials/searching.rst
  D   grok/trunk/doc/minitutorials/searching.txt
  A   grok/trunk/doc/minitutorials/template-languages.rst
  D   grok/trunk/doc/minitutorials/template-languages.txt
  A   grok/trunk/doc/minitutorials/transient-objects.rst
  D   grok/trunk/doc/minitutorials/transient-objects.txt
  A   grok/trunk/doc/minitutorials/xmlrpc.rst
  D   grok/trunk/doc/minitutorials/xmlrpc.txt

-=-
Copied: grok/trunk/doc/minitutorials/automatic_form_generation.rst (from rev 85973, grok/trunk/doc/minitutorials/automatic_form_generation.txt)
===================================================================
--- grok/trunk/doc/minitutorials/automatic_form_generation.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/automatic_form_generation.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,309 @@
+=========================
+Automatic Form Generation
+=========================
+
+:Author: Dirceu Pereira Tiegs
+
+Introduction
+------------
+
+Grok supports automatic form generation by working with zope.interface, zope.schema and zope.formlib. This how-to will show you how to create an application that uses this feature and also how to use some more advanced widgets than the formlib defaults.
+
+Schema and Fields
+-----------------
+
+Fields are components that define a model's attributes, and schemas are collections of fields. For example:
+
++-------------------+
+| Person            |
++-------------------+
+| name: String      |
++-------------------+
+| birth: Date       |
++-------------------+
+| description: Text |
++-------------------+
+
+The model above can be translated into Grok code like this:
+
+.. code-block:: python
+
+    from zope import interface, schema
+    class IPerson(interface.Interface):
+        name = schema.TextLine(title="Name")
+        birth = schema.Date(title="Birth")
+        description = schema.Text(title="Description")
+
+Defining an interface with schema fields allows automatic form generation and validation. To do this, grok.AddForm, grok.EditForm and grok.DisplayForm are used. These components are called forms; forms are web components that use widgets to display and input data. Typically a template renders the widgets by calling attributes or methods of the displayed object.
+
+Widgets are components that display field values and, in the case of writable fields, allow the user to edit those values. Widgets:
+
+- Display current field values, either in a read-only format, or in a format that lets the user change 
+  the field value.
+
+- Update their corresponding field values based on values provided by users.
+
+- Manage the relationships between their representation of a field value and the object's field value.
+  For example, a widget responsible for editing a number will likely represent that number internally as
+  a string. For this reason, widgets must be able to convert between the two value formats. In the case
+  of the number-editing widget, string values typed by the user need to be converted to numbers such as
+  int or float.
+
+- Support the ability to assign a missing value to a field. For example, a widget may present a ``None`` 
+  option for selection that, when selected, indicates that the object should be updated with the field's 
+  ``missing`` value.
+
+
+The forms have default templates that are used if no other template is provided. 
+
+grok.AddForm and grok.EditForm use the default template [grok_egg]/templates/default_edit_form.pt. 
+
+grok.DisplayForm uses [grok_egg]/templates/default_display_form.pt.
+
+Input Validation - Constraints and Invariants
+---------------------------------------------
+
+A constraint is constraint (:-)) that is bound to a specific field:
+
+.. code-block:: python
+
+    import grok
+    from zope import interface, schema
+    import re
+
+    expr = re.compile(r"^(\w&.%#$&'\*+-/=?^_`{}|~]+!)*[\w&.%#$&'\*+-/=?^_`{}|~]+"
+                      r"@(([0-9a-z]([0-9a-z-]*[0-9a-z])?\.)+[a-z]{2,6}|([0-9]{1,3}"
+                      r"\.){3}[0-9]{1,3})$", re.IGNORECASE)
+    check_email = expr.match
+
+    class IMyUser(interface.Interface):
+        email = schema.TextLine(title="Email", constraint=check_email)
+
+    class MyUser(grok.Model)
+        interface.implements(IMyUser)
+
+        def __init__(self, email):
+            super(MyUser, self).__init__()
+            self.email = email
+
+An invariant is a constraint that involves more than one field:
+
+.. code-block:: python
+
+    import grok
+    from zope import interface, schema
+    from datetime import date
+
+    class IMyEvent(interface.Interface):
+        title = schema.TextLine(title="Title")
+        begin = schema.Date(title="Begin date")
+        end = schema.Date(title="End date")
+
+    class MyEvent(grok.Model)
+        interface.implements(IMyEvent)
+
+        def __init__(self, title, begin, end):
+            super(MyEvent, self).__init__()
+            self.title = title
+            self.begin = begin
+            self.end = end
+
+        @interface.invariant
+        def beginBeforeEnd(event):
+            if event.begin > event.end:
+                raise interface.Invalid("Begin date must be before end date")
+
+Example 1 - Birthday Reminder
+-----------------------------
+
+Grok want to remember his friends's birthday, so he created a simple application to do that.
+
+ME GROK SMASH CALENDAR!
+
+We want to use a custom widget to select dates, so you need to add 'z3c.widget' to setup.py of your package:
+
+.. code-block:: python
+
+    install_requires=['setuptools',
+                      'grok',
+                      'z3c.widget',
+                      # Add extra requirements here
+                      ],
+
+And run ./bin/buildout. This will install z3c.widget and make it available to your project.
+
+app.py is pretty simple:
+
+.. code-block:: python
+
+    import grok
+
+    class Friends(grok.Application, grok.Container):
+        pass
+
+    class Index(grok.View):
+        pass
+
+friend.py contains our content component and it's forms:
+
+.. code-block:: python
+
+    import grok
+    from zope import interface, schema
+    from app import Friends
+
+    from z3c.widget.dropdowndatewidget.widget import DropDownDateWidget
+
+    class IFriend(interface.Interface):
+        name = schema.TextLine(title=u"Name")
+        birth_date = schema.Date(title=u"Birth Date")
+        description = schema.Text(title=u"Description")
+
+    class Friend(grok.Model):
+        interface.implements(IFriend)
+    
+        def __init__(self, name, birth_date, description):
+            super(Friend, self).__init__()
+            self.name = name
+            self.birth_date = birth_date
+            self.description = description
+
+    class AddFriend(grok.AddForm):
+        grok.context(Friends)
+        form_fields = grok.AutoFields(Friend)
+
+        # Here is the trick. You set the 'custom_widget' attribute with the custom Widget's class
+        form_fields['birth_date'].custom_widget = DropDownDateWidget
+
+        @grok.action('Add event')
+        def add(self, **data):
+            obj = Friend(**data)
+            name = data['name'].lower().replace(' ', '_')
+            self.context[name] = obj
+
+    class Edit(grok.EditForm):
+        form_fields = grok.AutoFields(Friend)
+        form_fields['birth_date'].custom_widget = DropDownDateWidget
+
+    class Index(grok.DisplayForm):
+        pass
+
+
+Example 2 - Wiki
+----------------
+
+Grok wants to impress beautiful cavewomen with a cool Web 2.0 application, so he built a Wiki with a JavaScript enabled text editor. 
+
+ME GROK WANTS COLLABORATE AND RICH TEXT EDITOR!
+
+You need to add 'zc.resourcelibrary' and 'z3c.widget' to setup.py of your package and run ./bin/buildout to install the new components:
+
+setup.py
+
+.. code-block:: python
+
+    install_requires=['setuptools',
+                      'grok',
+                      'zc.resourcelibrary',
+                      'z3c.widget',
+                      # Add extra requirements here
+                      ],
+
+app.py won't contain any application logic, only the application and the default view called "index".
+
+.. code-block:: python
+
+    import grok
+
+    class Wiki(grok.Application, grok.Container):
+        pass
+
+    class Index(grok.View):
+        pass
+
+wikipage.py is almost identical to friend.py in our first example:
+
+.. code-block:: python
+
+    import grok
+    from zope import interface, schema
+    from app import Wiki
+
+    from z3c.widget.tiny.widget import TinyWidget
+
+    class IWikiPage(interface.Interface):
+        title = schema.TextLine(title=u"Title")
+        contents = schema.Text(title=u"Contents")
+
+    class WikiPage(grok.Model):
+        interface.implements(IWikiPage)
+    
+        def __init__(self, title, contents):
+            super(WikiPage, self).__init__()
+            self.title = title
+            self.contents = contents
+
+    class AddWikiPage(grok.AddForm):
+        grok.context(Wiki)
+        form_fields = grok.AutoFields(WikiPage)
+        form_fields['contents'].custom_widget = TinyWidget
+
+        @grok.action('Add event')
+        def add(self, **data):
+            obj = WikiPage(**data)
+            name = data['title'].lower().replace(' ', '_')
+            self.context[name] = obj
+
+    class Edit(grok.EditForm):
+        form_fields = grok.AutoFields(WikiPage)
+        form_fields['contents'].custom_widget = TinyWidget
+
+    class Index(grok.DisplayForm):
+        pass
+
+Here is the trick: to use TinyWidget you must load it's configuration. TinyWidget uses zc.resourcelibrary to load the JavaScript editor, and zc.resourcelibrary have some dependencies (on zope.app.component and zope.app.pagetemplate). Your package's configure.zcml must be like this:
+
+.. code-block:: html
+
+    <configure xmlns="http://namespaces.zope.org/zope"
+               xmlns:grok="http://namespaces.zope.org/grok">
+      <include package="zope.app.component" file="meta.zcml" />
+      <include package="zope.app.pagetemplate" file="meta.zcml" />
+      <include package="zc.resourcelibrary" file="meta.zcml" />
+      <include package="zc.resourcelibrary" />
+      <include package="z3c.widget.tiny" />
+      <include package="grok" />
+      <grok:grok package="." />
+    </configure>
+
+And we must add a directive to the AddForm template to load the TinyMCE editor. First, copy the default template:
+
+.. code-block:: sh
+
+    $ mkdir wikipage_templates 
+    $ cp [grok_egg]/grok/templates/default_edit_form.pt wikipage_templates/addwikipage.pt
+
+Then add this directive to the <head> tag of wikipage_templates/addwikipage.pt
+
+.. code-block:: html
+
+  <head>
+    <tal:block replace="resource_library:tiny_mce" />
+  </head>
+
+And that's it! Now AddWikiPage uses TinyMCE to edit the "contents" field.
+
+Learning More
+-------------
+
+Many topics not were covered here. You can learn more reading the source code of Zope 3 components such as zope.schema and zope.formlib. Zope is a great platform and have a pretty good automated testing culture, so you can evend read / run doctests like these:
+
+- http://svn.zope.org/zope.schema/trunk/src/zope/schema/README.txt?rev=80304&view=auto
+- http://svn.zope.org/zope.schema/trunk/src/zope/schema/fields.txt?rev=75170&view=auto
+- http://svn.zope.org/zope.schema/trunk/src/zope/schema/validation.txt?rev=79215&view=auto
+- http://svn.zope.org/zope.formlib/trunk/src/zope/formlib/form.txt?rev=81649&view=markup
+- http://svn.zope.org/zope.formlib/trunk/src/zope/formlib/errors.txt?rev=75131&view=markup
+
+Web Component Development with Zope 3 is a great book written by Philipp von Weitershausen (wich is a Grok core developer). While the book doesn't cover Grok directly, it covers all the underlying technology that Grok uses:
+
+- http://worldcookery.com/

Deleted: grok/trunk/doc/minitutorials/automatic_form_generation.txt
===================================================================
--- grok/trunk/doc/minitutorials/automatic_form_generation.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/automatic_form_generation.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,309 +0,0 @@
-=========================
-Automatic Form Generation
-=========================
-
-:Author: Dirceu Pereira Tiegs
-
-Introduction
-------------
-
-Grok supports automatic form generation by working with zope.interface, zope.schema and zope.formlib. This how-to will show you how to create an application that uses this feature and also how to use some more advanced widgets than the formlib defaults.
-
-Schema and Fields
------------------
-
-Fields are components that define a model's attributes, and schemas are collections of fields. For example:
-
-+-------------------+
-| Person            |
-+-------------------+
-| name: String      |
-+-------------------+
-| birth: Date       |
-+-------------------+
-| description: Text |
-+-------------------+
-
-The model above can be translated into Grok code like this:
-
-.. code-block:: python
-
-    from zope import interface, schema
-    class IPerson(interface.Interface):
-        name = schema.TextLine(title="Name")
-        birth = schema.Date(title="Birth")
-        description = schema.Text(title="Description")
-
-Defining an interface with schema fields allows automatic form generation and validation. To do this, grok.AddForm, grok.EditForm and grok.DisplayForm are used. These components are called forms; forms are web components that use widgets to display and input data. Typically a template renders the widgets by calling attributes or methods of the displayed object.
-
-Widgets are components that display field values and, in the case of writable fields, allow the user to edit those values. Widgets:
-
-- Display current field values, either in a read-only format, or in a format that lets the user change 
-  the field value.
-
-- Update their corresponding field values based on values provided by users.
-
-- Manage the relationships between their representation of a field value and the object's field value.
-  For example, a widget responsible for editing a number will likely represent that number internally as
-  a string. For this reason, widgets must be able to convert between the two value formats. In the case
-  of the number-editing widget, string values typed by the user need to be converted to numbers such as
-  int or float.
-
-- Support the ability to assign a missing value to a field. For example, a widget may present a ``None`` 
-  option for selection that, when selected, indicates that the object should be updated with the field's 
-  ``missing`` value.
-
-
-The forms have default templates that are used if no other template is provided. 
-
-grok.AddForm and grok.EditForm use the default template [grok_egg]/templates/default_edit_form.pt. 
-
-grok.DisplayForm uses [grok_egg]/templates/default_display_form.pt.
-
-Input Validation - Constraints and Invariants
----------------------------------------------
-
-A constraint is constraint (:-)) that is bound to a specific field:
-
-.. code-block:: python
-
-    import grok
-    from zope import interface, schema
-    import re
-
-    expr = re.compile(r"^(\w&.%#$&'\*+-/=?^_`{}|~]+!)*[\w&.%#$&'\*+-/=?^_`{}|~]+"
-                      r"@(([0-9a-z]([0-9a-z-]*[0-9a-z])?\.)+[a-z]{2,6}|([0-9]{1,3}"
-                      r"\.){3}[0-9]{1,3})$", re.IGNORECASE)
-    check_email = expr.match
-
-    class IMyUser(interface.Interface):
-        email = schema.TextLine(title="Email", constraint=check_email)
-
-    class MyUser(grok.Model)
-        interface.implements(IMyUser)
-
-        def __init__(self, email):
-            super(MyUser, self).__init__()
-            self.email = email
-
-An invariant is a constraint that involves more than one field:
-
-.. code-block:: python
-
-    import grok
-    from zope import interface, schema
-    from datetime import date
-
-    class IMyEvent(interface.Interface):
-        title = schema.TextLine(title="Title")
-        begin = schema.Date(title="Begin date")
-        end = schema.Date(title="End date")
-
-    class MyEvent(grok.Model)
-        interface.implements(IMyEvent)
-
-        def __init__(self, title, begin, end):
-            super(MyEvent, self).__init__()
-            self.title = title
-            self.begin = begin
-            self.end = end
-
-        @interface.invariant
-        def beginBeforeEnd(event):
-            if event.begin > event.end:
-                raise interface.Invalid("Begin date must be before end date")
-
-Example 1 - Birthday Reminder
------------------------------
-
-Grok want to remember his friends's birthday, so he created a simple application to do that.
-
-ME GROK SMASH CALENDAR!
-
-We want to use a custom widget to select dates, so you need to add 'z3c.widget' to setup.py of your package:
-
-.. code-block:: python
-
-    install_requires=['setuptools',
-                      'grok',
-                      'z3c.widget',
-                      # Add extra requirements here
-                      ],
-
-And run ./bin/buildout. This will install z3c.widget and make it available to your project.
-
-app.py is pretty simple:
-
-.. code-block:: python
-
-    import grok
-
-    class Friends(grok.Application, grok.Container):
-        pass
-
-    class Index(grok.View):
-        pass
-
-friend.py contains our content component and it's forms:
-
-.. code-block:: python
-
-    import grok
-    from zope import interface, schema
-    from app import Friends
-
-    from z3c.widget.dropdowndatewidget.widget import DropDownDateWidget
-
-    class IFriend(interface.Interface):
-        name = schema.TextLine(title=u"Name")
-        birth_date = schema.Date(title=u"Birth Date")
-        description = schema.Text(title=u"Description")
-
-    class Friend(grok.Model):
-        interface.implements(IFriend)
-    
-        def __init__(self, name, birth_date, description):
-            super(Friend, self).__init__()
-            self.name = name
-            self.birth_date = birth_date
-            self.description = description
-
-    class AddFriend(grok.AddForm):
-        grok.context(Friends)
-        form_fields = grok.AutoFields(Friend)
-
-        # Here is the trick. You set the 'custom_widget' attribute with the custom Widget's class
-        form_fields['birth_date'].custom_widget = DropDownDateWidget
-
-        @grok.action('Add event')
-        def add(self, **data):
-            obj = Friend(**data)
-            name = data['name'].lower().replace(' ', '_')
-            self.context[name] = obj
-
-    class Edit(grok.EditForm):
-        form_fields = grok.AutoFields(Friend)
-        form_fields['birth_date'].custom_widget = DropDownDateWidget
-
-    class Index(grok.DisplayForm):
-        pass
-
-
-Example 2 - Wiki
-----------------
-
-Grok wants to impress beautiful cavewomen with a cool Web 2.0 application, so he built a Wiki with a JavaScript enabled text editor. 
-
-ME GROK WANTS COLLABORATE AND RICH TEXT EDITOR!
-
-You need to add 'zc.resourcelibrary' and 'z3c.widget' to setup.py of your package and run ./bin/buildout to install the new components:
-
-setup.py
-
-.. code-block:: python
-
-    install_requires=['setuptools',
-                      'grok',
-                      'zc.resourcelibrary',
-                      'z3c.widget',
-                      # Add extra requirements here
-                      ],
-
-app.py won't contain any application logic, only the application and the default view called "index".
-
-.. code-block:: python
-
-    import grok
-
-    class Wiki(grok.Application, grok.Container):
-        pass
-
-    class Index(grok.View):
-        pass
-
-wikipage.py is almost identical to friend.py in our first example:
-
-.. code-block:: python
-
-    import grok
-    from zope import interface, schema
-    from app import Wiki
-
-    from z3c.widget.tiny.widget import TinyWidget
-
-    class IWikiPage(interface.Interface):
-        title = schema.TextLine(title=u"Title")
-        contents = schema.Text(title=u"Contents")
-
-    class WikiPage(grok.Model):
-        interface.implements(IWikiPage)
-    
-        def __init__(self, title, contents):
-            super(WikiPage, self).__init__()
-            self.title = title
-            self.contents = contents
-
-    class AddWikiPage(grok.AddForm):
-        grok.context(Wiki)
-        form_fields = grok.AutoFields(WikiPage)
-        form_fields['contents'].custom_widget = TinyWidget
-
-        @grok.action('Add event')
-        def add(self, **data):
-            obj = WikiPage(**data)
-            name = data['title'].lower().replace(' ', '_')
-            self.context[name] = obj
-
-    class Edit(grok.EditForm):
-        form_fields = grok.AutoFields(WikiPage)
-        form_fields['contents'].custom_widget = TinyWidget
-
-    class Index(grok.DisplayForm):
-        pass
-
-Here is the trick: to use TinyWidget you must load it's configuration. TinyWidget uses zc.resourcelibrary to load the JavaScript editor, and zc.resourcelibrary have some dependencies (on zope.app.component and zope.app.pagetemplate). Your package's configure.zcml must be like this:
-
-.. code-block:: html
-
-    <configure xmlns="http://namespaces.zope.org/zope"
-               xmlns:grok="http://namespaces.zope.org/grok">
-      <include package="zope.app.component" file="meta.zcml" />
-      <include package="zope.app.pagetemplate" file="meta.zcml" />
-      <include package="zc.resourcelibrary" file="meta.zcml" />
-      <include package="zc.resourcelibrary" />
-      <include package="z3c.widget.tiny" />
-      <include package="grok" />
-      <grok:grok package="." />
-    </configure>
-
-And we must add a directive to the AddForm template to load the TinyMCE editor. First, copy the default template:
-
-.. code-block:: sh
-
-    $ mkdir wikipage_templates 
-    $ cp [grok_egg]/grok/templates/default_edit_form.pt wikipage_templates/addwikipage.pt
-
-Then add this directive to the <head> tag of wikipage_templates/addwikipage.pt
-
-.. code-block:: html
-
-  <head>
-    <tal:block replace="resource_library:tiny_mce" />
-  </head>
-
-And that's it! Now AddWikiPage uses TinyMCE to edit the "contents" field.
-
-Learning More
--------------
-
-Many topics not were covered here. You can learn more reading the source code of Zope 3 components such as zope.schema and zope.formlib. Zope is a great platform and have a pretty good automated testing culture, so you can evend read / run doctests like these:
-
-- http://svn.zope.org/zope.schema/trunk/src/zope/schema/README.txt?rev=80304&view=auto
-- http://svn.zope.org/zope.schema/trunk/src/zope/schema/fields.txt?rev=75170&view=auto
-- http://svn.zope.org/zope.schema/trunk/src/zope/schema/validation.txt?rev=79215&view=auto
-- http://svn.zope.org/zope.formlib/trunk/src/zope/formlib/form.txt?rev=81649&view=markup
-- http://svn.zope.org/zope.formlib/trunk/src/zope/formlib/errors.txt?rev=75131&view=markup
-
-Web Component Development with Zope 3 is a great book written by Philipp von Weitershausen (wich is a Grok core developer). While the book doesn't cover Grok directly, it covers all the underlying technology that Grok uses:
-
-- http://worldcookery.com/

Copied: grok/trunk/doc/minitutorials/index.rst (from rev 85973, grok/trunk/doc/minitutorials/index.txt)
===================================================================
--- grok/trunk/doc/minitutorials/index.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/index.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,90 @@
+================
+Grok Mini-HowTos
+================
+
+.. image:: ../resources/evencaveman.jpg
+   :alt: Now even cavemen can use Zope3
+   :class: right
+
+.. toctree::
+   :maxdepth: 1
+
+   permissions.rst
+   searching.rst
+   macros.rst
+   xmlrpc.rst  
+   transient-objects.rst
+   rest.rst
+   template-languages.rst
+   automatic_form_generation.rst
+
+These mini-tutorials have been contributed by members of the Grok community.
+
+* `Permissions Tutorial <permissions.html>`_:
+
+  Zope3 and Grok come with authorization capabilities out of the box. While a
+  vanilla Zope3 application protects all content by default and performs
+  authorization checks on the content objects themselves, Grok allows access to
+  everything unless you explicitly restrict it. The authorization checks here are
+  done based on the Views used to access (display/manipulate) the content.
+
+  Authors: Luis De la Parra; Uli Fouquet; Jan-Wijbrand Kolman
+
+* `Search Tutorial <searching.html>`_:
+
+  Grok supports the vanilla indexing services available in Zope 3
+  straight out of the box. The catalog uses developer-defined indexes
+  for searching. In other words, you have to define the indexes you
+  want to use to search you objects before you perform the actual
+  search.
+
+  Author: Sebastian Ware
+
+* `Macros With Grok <macros.html>`_:
+
+  Macros are a way to define a chunk of presentation in one template,
+  and share it in others. Changes to the macro are immediately
+  reflected in all templates, that use it.
+
+  Author: Uli Fouquet
+
+* `XMLRPC With Grok <xmlrpc.html>`_:
+
+  XMLRPC (http://xmlrpc.com) is a spec and a set of implementations
+  that allow software running on disparate operating systems, running in
+  different environments to make procedure calls over the Internet.
+
+  Author: Kushal Das
+
+* `Navigating To Transient Objects Tutorial <transient-objects.html>`_:
+
+  Sometimes you need to create objects that do not persist in the ZODB.
+  For the purpose of this tutorial, we are going to call all such objects
+  transient objects. This highlights the fact that, from the point of view of
+  Grok, they are going to be instantiated on-the-fly as a user visits them.
+
+  Author: Brandon Craig Rhodes
+
+* `Pluggable template laguanges <template-languages.html>`_:
+
+  Grok, like the Zope 3 framework on which it is built, uses Zope Page
+  Templates as its default templating language. While you can, of course, use
+  whatever templating language you want in Grok by calling it manually, you can
+  also ?plug in? a template language such that both inline templates and
+  templates stored in files are automatically linked with your Views ? just
+  like inline ``grok.PageTemplates`` and files with the ``.pt`` extension are
+  by default.
+
+  Author: Lennart Regebro
+
+Buildout
+========
+
+Buildout is a python-based configuration-driven build tool for working with
+eggs.
+
+* `Buildout Tutorial </minitutorials/buildout.html>`_:
+
+  This is Jim Fulton's tutorial for using `buildout
+  <http://www.python.org/pypi/zc.buildout>`_ The original text document is
+  available at http://svn.zope.org/zc.buildout/trunk/doc/tutorial.txt.

Deleted: grok/trunk/doc/minitutorials/index.txt
===================================================================
--- grok/trunk/doc/minitutorials/index.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/index.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,87 +0,0 @@
-================
-Grok Mini-HowTos
-================
-
-.. image:: /resources/evencaveman.jpg
-   :alt: Now even cavemen can use Zope3
-   :class: right
-
-These mini-tutorials have been contributed by members of the Grok community.
-
-* `Permissions Tutorial </minitutorials/permissions.html>`_:
-
-  Zope3 and Grok come with authorization capabilities out of the box. While a
-  vanilla Zope3 application protects all content by default and performs
-  authorization checks on the content objects themselves, Grok allows access to
-  everything unless you explicitly restrict it. The authorization checks here are
-  done based on the Views used to access (display/manipulate) the content.
-
-  Author: Luis De la Parra; Uli Fouquet; Jan-Wijbrand Kolman
-
-* `Search Tutorial </minitutorials/searching.html>`_:
-
-  Grok supports the vanilla indexing services available in Zope 3
-  straight out of the box. The catalog uses developer-defined indexes
-  for searching. In other words, you have to define the indexes you
-  want to use to search you objects before you perform the actual
-  search.
-
-  Author: Sebastian Ware
-
-* `Macros With Grok </minitutorials/macros.html>`_:
-
-  Macros are a way to define a chunk of presentation in one template,
-  and share it in others. Changes to the macro are immediately
-  reflected in all templates, that use it.
-
-  Author: Uli Fouquet
-
-* `XMLRPC With Grok </minitutorials/xmlrpc.html>`_:
-
-  XMLRPC (http://xmlrpc.com) is a spec and a set of implementations
-  that allow software running on disparate operating systems, running in
-  different environments to make procedure calls over the Internet.
-
-  Author: Kushal Das
-
-* `Navigating To Transient Objects Tutorial </minitutorials/transient-objects.html>`_:
-
-  Sometimes you need to create objects that do not persist in the ZODB.
-  For the purpose of this tutorial, we are going to call all such objects
-  transient objects. This highlights the fact that, from the point of view of
-  Grok, they are going to be instantiated on-the-fly as a user visits them.
-
-  Author: Brandon Craig Rhodes
-
-* `REST With Grok </minitutorials/rest.html>`_:
-
-  REST is a way to build web services, i.e. a web application where the
-  user is another computer, not a human being. REST takes the approach
-  to make the web service look very similar to a normal web application,
-  using well-known semantics of HTTP.
-
-  Author: Martijn Faassen
-
-* `Pluggable template laguanges </minitutorials/template-languages.html>`_:
-
-  Grok, like the Zope 3 framework on which it is built, uses Zope Page
-  Templates as its default templating language. While you can, of course, use
-  whatever templating language you want in Grok by calling it manually, you can
-  also ?plug in? a template language such that both inline templates and
-  templates stored in files are automatically linked with your Views ? just
-  like inline ``grok.PageTemplates`` and files with the ``.pt`` extension are
-  by default.
-
-  Author: Lennart Regebro
-
-Buildout
-========
-
-Buildout is a python-based configuration-driven build tool for working with
-eggs.
-
-* `Buildout Tutorial </minitutorials/buildout.html>`_:
-
-  This is Jim Fulton's tutorial for using `buildout
-  <http://www.python.org/pypi/zc.buildout>`_ The original text document is
-  available at http://svn.zope.org/zc.buildout/trunk/doc/tutorial.txt.

Copied: grok/trunk/doc/minitutorials/macros.rst (from rev 85973, grok/trunk/doc/minitutorials/macros.txt)
===================================================================
--- grok/trunk/doc/minitutorials/macros.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/macros.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,275 @@
+============================
+Mini-Howto: Macros with Grok
+============================
+
+:Author: Uli Fouquet
+
+Intended Audience:
+
+  * Python Developers
+
+  * Zope 2 Developers
+
+  * Zope 3 Developers
+
+
+
+Introduction
+------------
+
+Macros are a way to define a chunk of presentation in one template,
+and share it in others. Changes to the macro are immediately reflected
+in all of the places, that share it.
+
+Such, a developer can easily write some sort of 'page-skeleton' (the
+macro), which can be reused in other pages to take care, for instance,
+for a certain and consistent look-and-feel of a whole site with less
+maintenance.
+
+Technically, macros are made available by ``METAL``, a Macro Expansion
+for TAL, which ships with nearly every Zope installation. They can be
+used in Zope Page Templates. See the `TAL`_ and `METAL`_ pages for
+details.
+
+.. _`TAL`: http://wiki.zope.org/ZPT/TAL
+
+.. _`METAL`: http://wiki.zope.org/ZPT/METAL
+
+
+
+Defining a simple macro
+-----------------------
+
+In Grok macros are defined in usual views, where the associated page
+templates contain `metal`-statements to define the desired
+macros. Macros generally are attributes of the page template wherein they
+are defined, but to get them rendered, we usually use views.
+
+We define a view ``MyMacros`` the usual way in ``app.py``:
+
+.. code-block:: python
+
+   import grok
+
+   class Sample(grok.Application, grok.Container):
+       pass
+
+   class Index(grok.View):
+       pass # see app_templates/index.pt
+
+   class MyMacros(grok.View):
+       """The macro holder"""
+       grok.context(Sample) # The default model this view is bound to.
+
+In the associated page template ``app_templates/mymacros.pt`` we
+define the macros we like to have available. You define macros with
+the ``METAL`` attribute::
+
+    metal:define-macro="<macro-name>"
+
+and the slots therein with::
+
+    metal:define-slot=<slot-name> 
+
+Let's define a very plain page macro in ``app_templates/mymacros.pt``:
+
+.. code-block:: html
+
+   <html metal:define-macro="mypage">
+     <head></head>
+     <body>
+       The content:
+       <div metal:define-slot="mycontent">
+         Put your content here...
+       </div>
+     </body>
+   </html>
+
+Here we defined a single macro ``mypage`` with only one slot
+``mycontent``. 
+
+If we restart our Zope instance (don't forget to put some ``index.pt``
+into ``app_templates/``) and have created our application as ``test``,
+we now can go to the following URL::
+
+    http://localhost:8080/test/mymacros
+
+and see the output::
+
+    The content:
+    Put your content here...
+
+Allright.
+
+
+Referencing a simple macro
+--------------------------
+
+In ``index.pt`` we now want to *use* the macro defined in
+``mymacros.pt``. Using a macro means to let it render a part of
+another page template, especially, filling the slots defined in
+``mymacros.pt`` with content defined in ``index.pt``. You call macros
+with the ``METAL`` attribute::
+
+     metal:use-macro="<macro-location>" 
+
+Our ``app_templates/index.pt`` can be that simple:
+
+.. code-block:: html
+
+    <html metal:use-macro="context/@@mymacros/macros/mypage">
+    </html>
+
+Watching::
+
+	http://localhost:8080/test/index
+
+should now give the same result as above, although we didn't call
+``mymacros`` in browser, but ``index``. That's what macros are made
+for.
+
+When we fill the slots, we get different content rendered within
+the same macro. You can fill slots using::
+
+    metal:fill-slot="<slot-name>"
+
+where the slot-name must be defined in the macro. Now, change
+``index.pt`` to:
+
+.. code-block:: html
+
+    <html metal:use-macro="context/@@mymacros/macros/mypage">
+      <body>
+        <!-- slot 'mycontent' was defined in the macro above -->
+        <div metal:fill-slot="mycontent">
+          My content from index.pt
+        </div>
+      </body>
+    </html>
+
+and you will get the output::
+
+    The content:
+    My content from index.pt
+
+The pattern of the macro reference (the <macro-location>) used here
+is::
+
+    context/<view-name>/macros/<macro-name>
+
+whereas ``context`` references the object being viewed, which in our
+case is the ``Sample`` application. In plain English we want Zope to
+look for a view for a ``Sample`` application object (``test``) which
+is called ``mymacros`` and contains a macro called ``mypage``.
+
+The logic behind this is, that views are always registered for certain
+object types. Registering a view with some kind of object (using
+``grok.context()`` for example), means, that we promise, that this
+view can render objects of that type. (It is up to you to make sure,
+that the view can handle rendering of that object type).
+
+It is not a bad idea to register views for interfaces (instead of
+implementing classes), because it means, that a view will remain
+usable, while an implementation of an interface can change. This is
+done in the section `Defining 'all-purpose' macros`_ below.
+
+
+Background: how ``grok.View`` and macros interact
+-------------------------------------------------
+
+In case of ``grok.View`` views are in fact ``BrowserPage`` objects
+with an attribute ``template``, which is the associated page
+template. The associated page template in turn has got an attribute
+``macros``, which is a dictionary containing all the macros defined in
+the page template with their names as keys (or ``None``). 
+
+This means, that you can also reference a macro of a ``grok.View``
+using::
+
+     context/<view-name>/template/macros/<macro-name>
+
+Grok shortens this path for you by mapping the ``macros`` dictionary
+keys to the associated ``grok.View``. If you define a macro
+``mymacro`` in a template associated with a ``grok.View`` called
+``myview``, this view will map ``mymacro`` as an own attribute, so
+that you can ask for the attribute ``mymacro`` of the *view*, wheras
+it is in fact an attribute of the associated template.
+
+Such, you can write in short for the above pattern::
+
+      context/<view-name>/macros/<macro-name>
+
+View names always start with the 'eyes' (``@@``) which is a shortcut
+for ``++view++<view-name>``.
+
+.. versionchanged:: 0.11
+
+  In older grok releases (before 0.11) even omitting the `macros` part
+  of a URI was possible. So you could write::
+
+    context/<view-name>/<macro-name>
+
+  instead of::
+
+    context/<view-name>/macros/<macro-name>
+
+  This is now deprecated. Use always `macros/` to indicate, that you
+  want to reference a macro of a view.
+
+
+Defining 'all-purpose' macros
+------------------------------
+
+To define an 'all-purpose' macro, i.e. a macro, that can render
+objects of (nearly) any type and thus be accessed from any
+other page template, just set a very general context for your macro
+view:
+
+.. code-block:: python
+
+    from zope.interface import Interface
+    import grok
+
+    class Master(grok.View):
+        grok.context(Interface)
+
+and reference the macros of the associated pagetemplate like this::
+
+    context/@@master/macros/<macro-name>
+
+Because the macros in ``Master`` now are 'bound' (in fact their view
+is bound) to ``Interface`` and every Grok application, model or
+container implements some interface, the ``Master`` macros will be
+accessible from nearly every other context. ``Master`` promises to be
+a view for every object, which implements ``Interface``.
+
+
+Accessing Zope3 standard macros
+-------------------------------
+
+The standard macros of Zope 3, which render also the default ZMI
+pages, are accessible under the view-name ``standard_macros`` and usually
+provide slots ``title``, ``headers`` and ``body``. It is
+good style to provide this slots with your homegrown views as well.
+
+To give your pages standard Zope3 look, you can do something like
+this in your page template:
+
+.. code-block:: html
+
+        <html metal:use-macro="context/@@standard_macros/macros/page">
+          <head>
+            <title metal:fill-slot="title">
+              Document Title
+            </title>
+            <metal:headers fill-slot="headers">
+              <!-- Additional headers here... -->
+            </metal:headers>
+          </head>
+          <body>
+            <div metal:fill-slot="body">
+              Your content here...
+            </div>
+          </body>
+        </html>
+

Deleted: grok/trunk/doc/minitutorials/macros.txt
===================================================================
--- grok/trunk/doc/minitutorials/macros.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/macros.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,275 +0,0 @@
-============================
-Mini-Howto: Macros with Grok
-============================
-
-:Author: Uli Fouquet
-
-Intended Audience:
-
-  * Python Developers
-
-  * Zope 2 Developers
-
-  * Zope 3 Developers
-
-
-
-Introduction
-------------
-
-Macros are a way to define a chunk of presentation in one template,
-and share it in others. Changes to the macro are immediately reflected
-in all of the places, that share it.
-
-Such, a developer can easily write some sort of 'page-skeleton' (the
-macro), which can be reused in other pages to take care, for instance,
-for a certain and consistent look-and-feel of a whole site with less
-maintenance.
-
-Technically, macros are made available by ``METAL``, a Macro Expansion
-for TAL, which ships with nearly every Zope installation. They can be
-used in Zope Page Templates. See the `TAL`_ and `METAL`_ pages for
-details.
-
-.. _`TAL`: http://wiki.zope.org/ZPT/TAL
-
-.. _`METAL`: http://wiki.zope.org/ZPT/METAL
-
-
-
-Defining a simple macro
------------------------
-
-In Grok macros are defined in usual views, where the associated page
-templates contain `metal`-statements to define the desired
-macros. Macros generally are attributes of the page template wherein they
-are defined, but to get them rendered, we usually use views.
-
-We define a view ``MyMacros`` the usual way in ``app.py``:
-
-.. code-block:: python
-
-   import grok
-
-   class Sample(grok.Application, grok.Container):
-       pass
-
-   class Index(grok.View):
-       pass # see app_templates/index.pt
-
-   class MyMacros(grok.View):
-       """The macro holder"""
-       grok.context(Sample) # The default model this view is bound to.
-
-In the associated page template ``app_templates/mymacros.pt`` we
-define the macros we like to have available. You define macros with
-the ``METAL`` attribute::
-
-    metal:define-macro="<macro-name>"
-
-and the slots therein with::
-
-    metal:define-slot=<slot-name> 
-
-Let's define a very plain page macro in ``app_templates/mymacros.pt``:
-
-.. code-block:: html
-
-   <html metal:define-macro="mypage">
-     <head></head>
-     <body>
-       The content:
-       <div metal:define-slot="mycontent">
-         Put your content here...
-       </div>
-     </body>
-   </html>
-
-Here we defined a single macro ``mypage`` with only one slot
-``mycontent``. 
-
-If we restart our Zope instance (don't forget to put some ``index.pt``
-into ``app_templates/``) and have created our application as ``test``,
-we now can go to the following URL::
-
-    http://localhost:8080/test/mymacros
-
-and see the output::
-
-    The content:
-    Put your content here...
-
-Allright.
-
-
-Referencing a simple macro
---------------------------
-
-In ``index.pt`` we now want to *use* the macro defined in
-``mymacros.pt``. Using a macro means to let it render a part of
-another page template, especially, filling the slots defined in
-``mymacros.pt`` with content defined in ``index.pt``. You call macros
-with the ``METAL`` attribute::
-
-     metal:use-macro="<macro-location>" 
-
-Our ``app_templates/index.pt`` can be that simple:
-
-.. code-block:: html
-
-    <html metal:use-macro="context/@@mymacros/macros/mypage">
-    </html>
-
-Watching::
-
-	http://localhost:8080/test/index
-
-should now give the same result as above, although we didn't call
-``mymacros`` in browser, but ``index``. That's what macros are made
-for.
-
-When we fill the slots, we get different content rendered within
-the same macro. You can fill slots using::
-
-    metal:fill-slot="<slot-name>"
-
-where the slot-name must be defined in the macro. Now, change
-``index.pt`` to:
-
-.. code-block:: html
-
-    <html metal:use-macro="context/@@mymacros/macros/mypage">
-      <body>
-        <!-- slot 'mycontent' was defined in the macro above -->
-        <div metal:fill-slot="mycontent">
-          My content from index.pt
-        </div>
-      </body>
-    </html>
-
-and you will get the output::
-
-    The content:
-    My content from index.pt
-
-The pattern of the macro reference (the <macro-location>) used here
-is::
-
-    context/<view-name>/macros/<macro-name>
-
-whereas ``context`` references the object being viewed, which in our
-case is the ``Sample`` application. In plain English we want Zope to
-look for a view for a ``Sample`` application object (``test``) which
-is called ``mymacros`` and contains a macro called ``mypage``.
-
-The logic behind this is, that views are always registered for certain
-object types. Registering a view with some kind of object (using
-``grok.context()`` for example), means, that we promise, that this
-view can render objects of that type. (It is up to you to make sure,
-that the view can handle rendering of that object type).
-
-It is not a bad idea to register views for interfaces (instead of
-implementing classes), because it means, that a view will remain
-usable, while an implementation of an interface can change. This is
-done in the section `Defining 'all-purpose' macros`_ below.
-
-
-Background: how ``grok.View`` and macros interact
--------------------------------------------------
-
-In case of ``grok.View`` views are in fact ``BrowserPage`` objects
-with an attribute ``template``, which is the associated page
-template. The associated page template in turn has got an attribute
-``macros``, which is a dictionary containing all the macros defined in
-the page template with their names as keys (or ``None``). 
-
-This means, that you can also reference a macro of a ``grok.View``
-using::
-
-     context/<view-name>/template/macros/<macro-name>
-
-Grok shortens this path for you by mapping the ``macros`` dictionary
-keys to the associated ``grok.View``. If you define a macro
-``mymacro`` in a template associated with a ``grok.View`` called
-``myview``, this view will map ``mymacro`` as an own attribute, so
-that you can ask for the attribute ``mymacro`` of the *view*, wheras
-it is in fact an attribute of the associated template.
-
-Such, you can write in short for the above pattern::
-
-      context/<view-name>/macros/<macro-name>
-
-View names always start with the 'eyes' (``@@``) which is a shortcut
-for ``++view++<view-name>``.
-
-.. versionchanged:: 0.11
-
-  In older grok releases (before 0.11) even omitting the `macros` part
-  of a URI was possible. So you could write::
-
-    context/<view-name>/<macro-name>
-
-  instead of::
-
-    context/<view-name>/macros/<macro-name>
-
-  This is now deprecated. Use always `macros/` to indicate, that you
-  want to reference a macro of a view.
-
-
-Defining 'all-purpose' macros
-------------------------------
-
-To define an 'all-purpose' macro, i.e. a macro, that can render
-objects of (nearly) any type and thus be accessed from any
-other page template, just set a very general context for your macro
-view:
-
-.. code-block:: python
-
-    from zope.interface import Interface
-    import grok
-
-    class Master(grok.View):
-        grok.context(Interface)
-
-and reference the macros of the associated pagetemplate like this::
-
-    context/@@master/macros/<macro-name>
-
-Because the macros in ``Master`` now are 'bound' (in fact their view
-is bound) to ``Interface`` and every Grok application, model or
-container implements some interface, the ``Master`` macros will be
-accessible from nearly every other context. ``Master`` promises to be
-a view for every object, which implements ``Interface``.
-
-
-Accessing Zope3 standard macros
--------------------------------
-
-The standard macros of Zope 3, which render also the default ZMI
-pages, are accessible under the view-name ``standard_macros`` and usually
-provide slots ``title``, ``headers`` and ``body``. It is
-good style to provide this slots with your homegrown views as well.
-
-To give your pages standard Zope3 look, you can do something like
-this in your page template:
-
-.. code-block:: html
-
-        <html metal:use-macro="context/@@standard_macros/macros/page">
-          <head>
-            <title metal:fill-slot="title">
-              Document Title
-            </title>
-            <metal:headers fill-slot="headers">
-              <!-- Additional headers here... -->
-            </metal:headers>
-          </head>
-          <body>
-            <div metal:fill-slot="body">
-              Your content here...
-            </div>
-          </body>
-        </html>
-

Copied: grok/trunk/doc/minitutorials/permissions.rst (from rev 85973, grok/trunk/doc/minitutorials/permissions.txt)
===================================================================
--- grok/trunk/doc/minitutorials/permissions.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/permissions.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,245 @@
+====================
+Permissions Tutorial
+====================
+
+:Author: Luis De la Parra; Uli Fouquet; Jan-Wijbrand Kolman
+
+Intended Audience:
+
+  * Python Developers
+
+  * Zope 2 Developers
+
+  * Zope 3 Developers
+
+Introduction
+-------------
+
+Zope3 and Grok come with authorization capabilities out of the box.  While a
+vanilla Zope3 application protects all content by default and performs
+authorization checks on the content objects themselves, Grok allows access to
+everything unless you explicitly restrict it. The authorization checks here
+are done based on the ``Views`` used to access (display/manipulate) the
+content.
+
+Setup
+-----
+
+.. code-block:: python
+
+     #contact.py
+     from zope import component, interface, schema
+     import grok
+
+     class IContactInfo(interface.Interface):
+         """ Interface/Schema for Contact Information """
+         first_name = schema.Text(title=u'First Name')
+         last_name  = schema.Text(title=u'Last Name')
+         email      = schema.Text(title=u'E-mail')
+
+
+     class ContactInfo(grok.Model):
+         interface.implements(IContactInfo)
+
+         first_name = ''
+         last_name  = ''
+         email = ''
+
+     class ViewContact(grok.View)
+         """Display Contact Info, without e-mail.
+
+         Anyone can use this view, even unauthenticated users
+         over the internet
+         """
+         def render(self):
+             contact = self.context
+             return 'Contact: ' + contact.first_name + contact.last_name
+
+Defining Permissions and restricting access
+-------------------------------------------
+
+As all Views in Grok default to public access, anyone can use the
+``ViewContact``-view defined above. If you want to restrict access to a view,
+you have to explicitly protect it with a permission:
+
+.. code-block:: python
+
+     # Define Permissions. The grok.name can be any string, but it is strongly
+     # recommended to make them unique by prefixing them with the application
+     # name.
+     class ViewContacts(grok.Permission):
+         grok.name('mysite.ViewContacts')
+         grok.title('View Contacts') # optional
+
+     class AddContacts(grok.Permission):
+         grok.name('mysite.AddContacts')
+
+     class EditContacts(grok.Permission):
+         grok.name('mysite.EditContacts')
+
+     class ViewContactComplete(grok.View)
+         """Display Contact Info, including email.
+
+         Only users which have the permission 'mysite.ViewContacts'
+         can use this view.
+         """"
+         grok.require('mysite.ViewContacts')  #this is the security declaration
+
+         def render(self):
+             contact = self.context
+             return 'Contact: %s%s%s' % (contact.first_name,
+                                         contact.last_name,
+                                         contact.email)
+
+*Note* The ``grok.Permission`` component base class was introduced *after* the
+release 0.10. In earlier versions of Grok a permission was defined using a
+module level directive, like so:
+
+.. code-block:: python
+
+     grok.define_permission('mysite.ViewContacts')
+
+If you are using ``grokproject`` this change currently does not affect your
+installation. In this case use ``grok.define_permission`` as described above.
+
+Granting Permissions
+--------------------
+
+You can grant permissions to principals with a ``PermissionManager``. For
+example, if all registered users should have permission to view contact
+details and to create new contacts, you could grant them the permissions when
+the user account is created:
+
+.. code-block:: python
+
+     from zope.app.security.interfaces import IAuthentication
+     from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager
+
+     def addUser(username, password, realname):
+         """Create a new user.
+
+         create a new user and give it the authorizations,
+         ``ViewContacts`` and ``EditContacts``. This example assumes
+         you are using a Pluggable Authentication Utility (PAU) /
+         PrincipalFolder, which you have to create and register when
+         creating your Application.
+         """
+
+         pau = component.getUtility(IAuthentication)
+         principals = pau['principals']
+         principals[username] = InternalPrincipal(username, password, realname)
+
+         # grant the user permission to view and create contacts
+         # everywhere in the site
+         permission_man = IPrincipalPermissionManager(grok.getSite())
+
+         # NOTE that you need a principal ID. If you are
+         # authenticating users with a PAU this is normally the user
+         # name prepended with the principals-folder prefix (and the
+         # PAU-prefix as well, if set)
+         permission_man.grantPermissionToPrincipal (
+            'mysite.ViewContacts',
+            principals.prefix + username)
+         permission_man.grantPermissionToPrincipal(
+            'mysite.AddContacts',
+            principals.prefix + username)
+
+Permissions are granted for the context for which the PermissionManager is
+created, and -- if not explicitly overridden -- all its children. The above
+example grants ``View`` and ``Add`` permissions for the complete site, unless
+a folder down in the hierarchy revokes the permission.
+
+If you want users to be able to edit only their own ``ContactInfos``, you have
+to give them the ``Edit`` permission only within the context of the
+``ContactInfo``-object itself
+
+.. code-block:: python
+
+     class AddContact(grok.AddForm):
+         """Add a contact.
+         """
+
+         # Only users with permission 'mysite.AddContacts' can use
+         # this.
+         #
+         # NOTE that if you don't protect this Form, anyone -- even
+         # anonymous/unauthenticated users -- could add ``Contacts``
+         # to the site.
+         grok.require('mysite.AddContacts')
+
+         #automagically generate form fields
+         form_fields = grok.AutoFields(IContactInfo)
+
+         @grok.action('Create')
+         def create(self, **kw):
+             # Create and add the ``ContactInfo`` to our context
+             # (normally a folder/container)
+             contact = ContactInfo()
+             self.applyData(contact, **kw)
+             self.context[contact.first_name] = contact
+
+             # Grant the current user the Edit permission, but only in
+	     # the context of the newly created object.
+             permission_man = IPrincipalPermissionManager(contact)
+             permission_man.grantPermissionToPrincipal(
+                 'mysite.EditContacts',
+                 self.request.principal.id)
+             self.redirect(self.url(contact))
+
+     class EditContact(grok.EditForm):
+         """Edit a contact.
+         """
+
+         #only users with permission 'mysite.EditContacts' can use this
+         grok.require('mysite.EditContacts')
+
+         form_fields = grok.AutoFields(IContactInfo)
+
+         @grok.action('Save Changes')
+         def edit(self, **data):
+             self.applyData(self.context, **data)
+             self.redirect(self.url(self.context))
+
+Checking Permissions
+--------------------
+
+[FIXME How to check permissions in a page template and from python
+code?  User Interfaces should not contain any links/actions which
+users cannot access / for which users don't have authorizations]
+
+Defining Roles
+--------------
+
+Permissions can be grouped together in ``Roles``, which makes granting all the
+permissions for a particular type of user much easier. Defining roles is
+similar to defining permissions.
+
+As an example, let's group all permissions in two roles: one for normal site
+members, and one for administrators:
+
+.. code-block:: python
+
+     class MemberRole(grok.Role):
+         grok.name('mysite.Member')
+         grok.title('Contacts Member') # optional
+         grok.permissions(
+             'mysite.ViewContacts',
+             'mysite.AddContacts')
+
+     class AdministratorRole(grok.Role):
+         grok.name('mysite.Editor')
+         grok.title('Contacts Administrator') # optional
+         grok.permissions(
+             'mysite.ViewContacts',
+             'mysite.AddContacts',
+             'mysite.EditContacts')
+
+Now, if the context here is the site/application, users with the administrator
+role can edit all ContactInfos, regardless of who the creator is.
+
+.. code-block:: python
+
+     from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
+
+     role_man = IPrincipalRoleManager(context)
+     role_man.assignRoleToPrincipal('mysite.Administrator', principalID)

Deleted: grok/trunk/doc/minitutorials/permissions.txt
===================================================================
--- grok/trunk/doc/minitutorials/permissions.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/permissions.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,245 +0,0 @@
-====================
-Permissions Tutorial
-====================
-
-:Author: Luis De la Parra; Uli Fouquet; Jan-Wijbrand Kolman
-
-Intended Audience:
-
-  * Python Developers
-
-  * Zope 2 Developers
-
-  * Zope 3 Developers
-
-Introduction
--------------
-
-Zope3 and Grok come with authorization capabilities out of the box.  While a
-vanilla Zope3 application protects all content by default and performs
-authorization checks on the content objects themselves, Grok allows access to
-everything unless you explicitly restrict it. The authorization checks here
-are done based on the ``Views`` used to access (display/manipulate) the
-content.
-
-Setup
------
-
-.. code-block:: python
-
-     #contact.py
-     from zope import component, interface, schema
-     import grok
-
-     class IContactInfo(interface.Interface):
-         """ Interface/Schema for Contact Information """
-         first_name = schema.Text(title=u'First Name')
-         last_name  = schema.Text(title=u'Last Name')
-         email      = schema.Text(title=u'E-mail')
-
-
-     class ContactInfo(grok.Model):
-         interface.implements(IContactInfo)
-
-         first_name = ''
-         last_name  = ''
-         email = ''
-
-     class ViewContact(grok.View)
-         """Display Contact Info, without e-mail.
-
-         Anyone can use this view, even unauthenticated users
-         over the internet
-         """
-         def render(self):
-             contact = self.context
-             return 'Contact: ' + contact.first_name + contact.last_name
-
-Defining Permissions and restricting access
--------------------------------------------
-
-As all Views in Grok default to public access, anyone can use the
-``ViewContact``-view defined above. If you want to restrict access to a view,
-you have to explicitly protect it with a permission:
-
-.. code-block:: python
-
-     # Define Permissions. The grok.name can be any string, but it is strongly
-     # recommended to make them unique by prefixing them with the application
-     # name.
-     class ViewContacts(grok.Permission):
-         grok.name('mysite.ViewContacts')
-         grok.title('View Contacts') # optional
-
-     class AddContacts(grok.Permission):
-         grok.name('mysite.AddContacts')
-
-     class EditContacts(grok.Permission):
-         grok.name('mysite.EditContacts')
-
-     class ViewContactComplete(grok.View)
-         """Display Contact Info, including email.
-
-         Only users which have the permission 'mysite.ViewContacts'
-         can use this view.
-         """"
-         grok.require('mysite.ViewContacts')  #this is the security declaration
-
-         def render(self):
-             contact = self.context
-             return 'Contact: %s%s%s' % (contact.first_name,
-                                         contact.last_name,
-                                         contact.email)
-
-*Note* The ``grok.Permission`` component base class was introduced *after* the
-release 0.10. In earlier versions of Grok a permission was defined using a
-module level directive, like so:
-
-.. code-block:: python
-
-     grok.define_permission('mysite.ViewContacts')
-
-If you are using ``grokproject`` this change currently does not affect your
-installation. In this case use ``grok.define_permission`` as described above.
-
-Granting Permissions
---------------------
-
-You can grant permissions to principals with a ``PermissionManager``. For
-example, if all registered users should have permission to view contact
-details and to create new contacts, you could grant them the permissions when
-the user account is created:
-
-.. code-block:: python
-
-     from zope.app.security.interfaces import IAuthentication
-     from zope.app.securitypolicy.interfaces import IPrincipalPermissionManager
-
-     def addUser(username, password, realname):
-         """Create a new user.
-
-         create a new user and give it the authorizations,
-         ``ViewContacts`` and ``EditContacts``. This example assumes
-         you are using a Pluggable Authentication Utility (PAU) /
-         PrincipalFolder, which you have to create and register when
-         creating your Application.
-         """
-
-         pau = component.getUtility(IAuthentication)
-         principals = pau['principals']
-         principals[username] = InternalPrincipal(username, password, realname)
-
-         # grant the user permission to view and create contacts
-         # everywhere in the site
-         permission_man = IPrincipalPermissionManager(grok.getSite())
-
-         # NOTE that you need a principal ID. If you are
-         # authenticating users with a PAU this is normally the user
-         # name prepended with the principals-folder prefix (and the
-         # PAU-prefix as well, if set)
-         permission_man.grantPermissionToPrincipal (
-            'mysite.ViewContacts',
-            principals.prefix + username)
-         permission_man.grantPermissionToPrincipal(
-            'mysite.AddContacts',
-            principals.prefix + username)
-
-Permissions are granted for the context for which the PermissionManager is
-created, and -- if not explicitly overridden -- all its children. The above
-example grants ``View`` and ``Add`` permissions for the complete site, unless
-a folder down in the hierarchy revokes the permission.
-
-If you want users to be able to edit only their own ``ContactInfos``, you have
-to give them the ``Edit`` permission only within the context of the
-``ContactInfo``-object itself
-
-.. code-block:: python
-
-     class AddContact(grok.AddForm):
-         """Add a contact.
-         """
-
-         # Only users with permission 'mysite.AddContacts' can use
-         # this.
-         #
-         # NOTE that if you don't protect this Form, anyone -- even
-         # anonymous/unauthenticated users -- could add ``Contacts``
-         # to the site.
-         grok.require('mysite.AddContacts')
-
-         #automagically generate form fields
-         form_fields = grok.AutoFields(IContactInfo)
-
-         @grok.action('Create')
-         def create(self, **kw):
-             # Create and add the ``ContactInfo`` to our context
-             # (normally a folder/container)
-             contact = ContactInfo()
-             self.applyData(contact, **kw)
-             self.context[contact.first_name] = contact
-
-             # Grant the current user the Edit permission, but only in
-	     # the context of the newly created object.
-             permission_man = IPrincipalPermissionManager(contact)
-             permission_man.grantPermissionToPrincipal(
-                 'mysite.EditContacts',
-                 self.request.principal.id)
-             self.redirect(self.url(contact))
-
-     class EditContact(grok.EditForm):
-         """Edit a contact.
-         """
-
-         #only users with permission 'mysite.EditContacts' can use this
-         grok.require('mysite.EditContacts')
-
-         form_fields = grok.AutoFields(IContactInfo)
-
-         @grok.action('Save Changes')
-         def edit(self, **data):
-             self.applyData(self.context, **data)
-             self.redirect(self.url(self.context))
-
-Checking Permissions
---------------------
-
-[FIXME How to check permissions in a page template and from python
-code?  User Interfaces should not contain any links/actions which
-users cannot access / for which users don't have authorizations]
-
-Defining Roles
---------------
-
-Permissions can be grouped together in ``Roles``, which makes granting all the
-permissions for a particular type of user much easier. Defining roles is
-similar to defining permissions.
-
-As an example, let's group all permissions in two roles: one for normal site
-members, and one for administrators:
-
-.. code-block:: python
-
-     class MemberRole(grok.Role):
-         grok.name('mysite.Member')
-         grok.title('Contacts Member') # optional
-         grok.permissions(
-             'mysite.ViewContacts',
-             'mysite.AddContacts')
-
-     class AdministratorRole(grok.Role):
-         grok.name('mysite.Editor')
-         grok.title('Contacts Administrator') # optional
-         grok.permissions(
-             'mysite.ViewContacts',
-             'mysite.AddContacts',
-             'mysite.EditContacts')
-
-Now, if the context here is the site/application, users with the administrator
-role can edit all ContactInfos, regardless of who the creator is.
-
-.. code-block:: python
-
-     from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
-
-     role_man = IPrincipalRoleManager(context)
-     role_man.assignRoleToPrincipal('mysite.Administrator', principalID)

Copied: grok/trunk/doc/minitutorials/searching.rst (from rev 85973, grok/trunk/doc/minitutorials/searching.txt)
===================================================================
--- grok/trunk/doc/minitutorials/searching.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/searching.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,133 @@
+===============
+Search Tutorial
+===============
+
+:Author: Sebastian Ware
+
+Introduction
+------------
+Grok supports the vanilla indexing services available in Zope 3 straight out of
+the box. Catalog uses developer defined indexes for searching. In other words,
+you have to define the indexes you want to use to search you objects before you
+perform the actual search.
+
+* FieldIndex: search matching an entire field
+* SetIndex: search for keywords in a field
+* TextIndex: full-text searching
+* ValueSearch: search for values using ranges
+
+The time for Zope to generate a new index is proportional to the amount of
+objects that need to be analysed.
+
+Setup
+-----
+The egg (package) containing the search functionality is called
+[zc.catalog-x.x.x-py2.x.egg] and is installed when "buildout.cfg" contains
+"zope.app.catalog" in the list of the directive "zcml=". This is the default
+configuration.
+
+Some applications might require specific versions of catalog. This is specified
+in the "setup.py" script. The following directive indicates that zc.catalog
+version 1.1.1 is required.
+
+.. code-block:: python
+
+    install_requires=['setuptools',
+                  'grok',
+                  'zc.catalog==1.1.1',
+                  'hurry.query',
+                  'hurry.workflow',
+                  ],
+
+The "hurry.query" package gives you some simple tools to perform advanced
+searching. (add "hurry.query" to "zcml=" in "buildout.cfg")
+
+Example
+-------
+
+.. code-block:: python
+
+    # interfaces.py
+    class IProtonObject(Interface):
+        """
+        This is an interface to the class who's objects I want to index.
+        """
+        body = schema.Text(title=u'Body', required=False)
+
+.. code-block:: python
+
+    # protonobject.py
+    class ProtonObject(grok.Model):
+        """
+        This is the actual class.
+        """
+        interface.implements(interfaces.IProtonObject)
+
+        def __init__(self, body):
+            self.body = body
+
+.. code-block:: python
+
+    # app.py
+    from hurry.query.query import Query, Text
+    # hurry.query is a simplified search query language that
+    # allows you to create ANDs and ORs.
+
+    class ContentIndexes(grok.Indexes):
+        """
+        This is where I setup my indexes. I have two indexes;
+        one full-text index called "text_body",
+        one field index called "body".
+        """
+        grok.site(ProtonCMS)
+
+        grok.context(interfaces.IProtonObject)
+        # grok.context() tells Grok that objects implementing
+        # the interface IProtonObject should be indexed.
+
+        grok.name('proton_catalog')
+        # grok.name() tells Grok what to call the catalog.
+        # if you have named the catalog anything but "catalog"
+        # you need to specify the name of the catalog in your
+        # queries.
+
+        text_body = index.Text(attribute='body')
+        body = index.Field(attribute='body')
+        # The attribute='body' parameter is actually unnecessary if the attribute to
+        # be indexed has the same name as the index.
+
+    class Index(grok.View):
+        grok.context(ProtonCMS)
+
+        def search_content(self, search_query):
+                # The following query does a search on the field index "body".
+                # It will return a list of object where the entire content of the body attribute
+                # matches the search term exactly. I.e. search_query == body
+                result_a = Query().searchResults(
+                                   query.Eq(('proton_catalog', 'body'), search_query)
+                                   )
+
+                # The following query does a search on the full-text index "text_body".
+                # It will return objects that match the search_query. You can use wildcards and
+                # boolean operators.
+                #
+                # Examples:
+                # "grok AND zope" returns objects where "body" contains the words "grok" and "zope"
+                # "grok or dev*" returns objects where "body" contains the word "grok" or any word
+                # beginning with "dev"
+                result_b = Query().searchResults(
+                                   Text( ('proton_catalog', 'text_body'), search_query)
+                                   )
+
+                return result_a, result_b
+
+Note
+----
+In the above example, the indexes are only added when a new application is
+installed. You will have to manually create new indexes if you wish to add them
+to an existing application.
+
+Learning More
+-------------
+The "hurry.query" package contains the DocTest "query.txt" that shows how to
+perform more complex search queries.

Deleted: grok/trunk/doc/minitutorials/searching.txt
===================================================================
--- grok/trunk/doc/minitutorials/searching.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/searching.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,133 +0,0 @@
-===============
-Search Tutorial
-===============
-
-:Author: Sebastian Ware
-
-Introduction
-------------
-Grok supports the vanilla indexing services available in Zope 3 straight out of
-the box. Catalog uses developer defined indexes for searching. In other words,
-you have to define the indexes you want to use to search you objects before you
-perform the actual search.
-
-* FieldIndex: search matching an entire field
-* SetIndex: search for keywords in a field
-* TextIndex: full-text searching
-* ValueSearch: search for values using ranges
-
-The time for Zope to generate a new index is proportional to the amount of
-objects that need to be analysed.
-
-Setup
------
-The egg (package) containing the search functionality is called
-[zc.catalog-x.x.x-py2.x.egg] and is installed when "buildout.cfg" contains
-"zope.app.catalog" in the list of the directive "zcml=". This is the default
-configuration.
-
-Some applications might require specific versions of catalog. This is specified
-in the "setup.py" script. The following directive indicates that zc.catalog
-version 1.1.1 is required.
-
-.. code-block:: python
-
-    install_requires=['setuptools',
-                  'grok',
-                  'zc.catalog==1.1.1',
-                  'hurry.query',
-                  'hurry.workflow',
-                  ],
-
-The "hurry.query" package gives you some simple tools to perform advanced
-searching. (add "hurry.query" to "zcml=" in "buildout.cfg")
-
-Example
--------
-
-.. code-block:: python
-
-    # interfaces.py
-    class IProtonObject(Interface):
-        """
-        This is an interface to the class who's objects I want to index.
-        """
-        body = schema.Text(title=u'Body', required=False)
-
-.. code-block:: python
-
-    # protonobject.py
-    class ProtonObject(grok.Model):
-        """
-        This is the actual class.
-        """
-        interface.implements(interfaces.IProtonObject)
-
-        def __init__(self, body):
-            self.body = body
-
-.. code-block:: python
-
-    # app.py
-    from hurry.query.query import Query, Text
-    # hurry.query is a simplified search query language that
-    # allows you to create ANDs and ORs.
-
-    class ContentIndexes(grok.Indexes):
-        """
-        This is where I setup my indexes. I have two indexes;
-        one full-text index called "text_body",
-        one field index called "body".
-        """
-        grok.site(ProtonCMS)
-
-        grok.context(interfaces.IProtonObject)
-        # grok.context() tells Grok that objects implementing
-        # the interface IProtonObject should be indexed.
-
-        grok.name('proton_catalog')
-        # grok.name() tells Grok what to call the catalog.
-        # if you have named the catalog anything but "catalog"
-        # you need to specify the name of the catalog in your
-        # queries.
-
-        text_body = index.Text(attribute='body')
-        body = index.Field(attribute='body')
-        # The attribute='body' parameter is actually unnecessary if the attribute to
-        # be indexed has the same name as the index.
-
-    class Index(grok.View):
-        grok.context(ProtonCMS)
-
-        def search_content(self, search_query):
-                # The following query does a search on the field index "body".
-                # It will return a list of object where the entire content of the body attribute
-                # matches the search term exactly. I.e. search_query == body
-                result_a = Query().searchResults(
-                                   query.Eq(('proton_catalog', 'body'), search_query)
-                                   )
-
-                # The following query does a search on the full-text index "text_body".
-                # It will return objects that match the search_query. You can use wildcards and
-                # boolean operators.
-                #
-                # Examples:
-                # "grok AND zope" returns objects where "body" contains the words "grok" and "zope"
-                # "grok or dev*" returns objects where "body" contains the word "grok" or any word
-                # beginning with "dev"
-                result_b = Query().searchResults(
-                                   Text( ('proton_catalog', 'text_body'), search_query)
-                                   )
-
-                return result_a, result_b
-
-Note
-----
-In the above example, the indexes are only added when a new application is
-installed. You will have to manually create new indexes if you wish to add them
-to an existing application.
-
-Learning More
--------------
-The "hurry.query" package contains the DocTest "query.txt" that shows how to
-perform more complex search queries.

Copied: grok/trunk/doc/minitutorials/template-languages.rst (from rev 85973, grok/trunk/doc/minitutorials/template-languages.txt)
===================================================================
--- grok/trunk/doc/minitutorials/template-languages.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/template-languages.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,97 @@
+==================================
+Plugging in new template languages
+==================================
+
+:Author: Lennart Regebro
+
+Introduction
+------------
+
+Grok, like the Zope 3 framework on which it is built, uses Zope Page
+Templates as its default templating language.  While you can, of
+course, use whatever templating language you want in Grok by calling
+it manually, you can also “plug in” a template language such that both
+inline templates and templates stored in files are automatically
+linked with your Views — just like inline ``grok.PageTemplates`` and
+files with the ``.pt`` extension are by default.
+
+
+Inline templates
+----------------
+
+“Inline” templates are templates that you create right in your Python
+code — for example, by instantiating the default ``grok.PageTemplate``
+class with a literal string value as its argument.  Such templates are
+automatically associated with nearby ``View`` classes: if you create a
+View named ``Mammoth`` and next to it instantiate a template named
+``mammoth``, then Grok will use them together.
+
+To enable such automatic association for a new templating language, you need
+to write a subclass of ``grok.components.GrokTemplate``. You will need to
+override three methods. The ``setFromFilename`` and ``setFromString`` methods
+should each load the template from disk or a given string, depending on
+method. Your ``render`` method should run the template with the dictionary of
+values returned by ``self.getNamespace()`` and return the resulting string.
+
+Here is an example of a minimal page template integration:
+
+.. code-block:: python
+
+class MyPageTemplate(grok.components.GrokTemplate):
+
+    def setFromString(self, string):
+        self._template = MyTemplate(string)
+
+    def setFromFilename(self, filename, _prefix=None):
+        file = open(os.path.join(_prefix, filename))
+        self._template = MyTemplate(file.read())
+
+    def render(self, view):
+        return self._template.render(\**self.getNamespace(view))
+
+With this class finished you can create an inline template, like this:
+
+.. code-block:: python
+
+    class AView(grok.View):
+        pass
+
+    aview = MyPageTemplate('<html><body>Some text</body></html>')
+
+And also you can create a filebase template, inline:
+
+.. code-block:: python
+
+    class AView(grok.View):
+        pass
+
+    aview = MyTemplateFile('lasceuax.html')
+
+
+Templates in the _templates directory
+-------------------------------------
+
+The most common use case, however, is to place templates for a file
+``foo.py`` in the corresponding ``foo_templates`` directory.  Grok, of
+course, already recognizes that files with a ``.pt`` extension each
+contain a Zope Page Template.  To tell Grok about a new file
+extension, simply register a global utility that generates a
+``MyPageTemplate`` when passed a filename.  That utility needs to
+implement the ``ITemplateFileFactory`` interface.
+
+.. code-block:: python
+
+class MyPageTemplateFactory(grok.GlobalUtility):
+
+    grok.implements(grok.interfaces.ITemplateFileFactory)
+    grok.name('mtl')
+
+    def __call__(self, filename, _prefix=None):
+        return MyPageTemplate(filename=filename, _prefix=_prefix)
+
+When your module gets grokked, Grok will discover the
+``MyPageTemplateFactory`` class, register it as a global utility for
+templates with the ``.mtl`` extension, and you can start creating
+``.mtl`` files in the template directory for your class.
+
+That's all you need!  Have fun!

Deleted: grok/trunk/doc/minitutorials/template-languages.txt
===================================================================
--- grok/trunk/doc/minitutorials/template-languages.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/template-languages.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,97 +0,0 @@
-==================================
-Plugging in new template languages
-==================================
-
-:Author: Lennart Regebro
-
-Introduction
-------------
-
-Grok, like the Zope 3 framework on which it is built, uses Zope Page
-Templates as its default templating language.  While you can, of
-course, use whatever templating language you want in Grok by calling
-it manually, you can also “plug in” a template language such that both
-inline templates and templates stored in files are automatically
-linked with your Views — just like inline ``grok.PageTemplates`` and
-files with the ``.pt`` extension are by default.
-
-
-Inline templates
-----------------
-
-“Inline” templates are templates that you create right in your Python
-code — for example, by instantiating the default ``grok.PageTemplate``
-class with a literal string value as its argument.  Such templates are
-automatically associated with nearby ``View`` classes: if you create a
-View named ``Mammoth`` and next to it instantiate a template named
-``mammoth``, then Grok will use them together.
-
-To enable such automatic association for a new templating language, you need
-to write a subclass of ``grok.components.GrokTemplate``. You will need to
-override three methods. The ``setFromFilename`` and ``setFromString`` methods
-should each load the template from disk or a given string, depending on
-method. Your ``render`` method should run the template with the dictionary of
-values returned by ``self.getNamespace()`` and return the resulting string.
-
-Here is an example of a minimal page template integration:
-
-.. code-block:: python
-
-class MyPageTemplate(grok.components.GrokTemplate):
-
-    def setFromString(self, string):
-        self._template = MyTemplate(string)
-
-    def setFromFilename(self, filename, _prefix=None):
-        file = open(os.path.join(_prefix, filename))
-        self._template = MyTemplate(file.read())
-
-    def render(self, view):
-        return self._template.render(\**self.getNamespace(view))
-
-With this class finished you can create an inline template, like this:
-
-.. code-block:: python
-
-    class AView(grok.View):
-        pass
-
-    aview = MyPageTemplate('<html><body>Some text</body></html>')
-
-And also you can create a filebase template, inline:
-
-.. code-block:: python
-
-    class AView(grok.View):
-        pass
-
-    aview = MyTemplateFile('lasceuax.html')
-
-
-Templates in the _templates directory
--------------------------------------
-
-The most common use case, however, is to place templates for a file
-``foo.py`` in the corresponding ``foo_templates`` directory.  Grok, of
-course, already recognizes that files with a ``.pt`` extension each
-contain a Zope Page Template.  To tell Grok about a new file
-extension, simply register a global utility that generates a
-``MyPageTemplate`` when passed a filename.  That utility needs to
-implement the ``ITemplateFileFactory`` interface.
-
-.. code-block:: python
-
-class MyPageTemplateFactory(grok.GlobalUtility):
-
-    grok.implements(grok.interfaces.ITemplateFileFactory)
-    grok.name('mtl')
-
-    def __call__(self, filename, _prefix=None):
-        return MyPageTemplate(filename=filename, _prefix=_prefix)
-
-When your module gets grokked, Grok will discover the
-``MyPageTemplateFactory`` class, register it as a global utility for
-templates with the ``.mtl`` extension, and you can start creating
-``.mtl`` files in the template directory for your class.
-
-That's all you need!  Have fun!

Copied: grok/trunk/doc/minitutorials/transient-objects.rst (from rev 85973, grok/trunk/doc/minitutorials/transient-objects.txt)
===================================================================
--- grok/trunk/doc/minitutorials/transient-objects.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/transient-objects.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,914 @@
+========================================
+Navigating To Transient Objects Tutorial
+========================================
+
+:Author: Brandon Craig Rhodes
+
+Introduction
+------------
+
+If you have already read the Grok tutorial,
+you are familiar with the fact that behind Grok
+lives a wonderful object database called the *Zope Object Database*,
+or the *ZODB* for short.
+Thanks to the magic of this database,
+your web apps can create Python objects
+that are automatically saved to disk
+and are available every time your application runs.
+In particular,
+every ``grok.Model`` and ``grok.Container`` object you generate
+can be written safely to your application's ``Data.fs`` file.
+
+But sometimes you need to create objects
+that do not persist in the ZODB,
+wonderful though it is.
+Sometimes these will be objects you design yourself
+but have no need to save once you are done displaying them,
+like summary statistics or search results.
+On other occasions,
+you will find yourself using libraries or packages written by other people
+and will need to present the objects they return in your Grok app —
+whether those objects are LDAP entries,
+file system directory listings,
+or rows from a relational database.
+
+For the purpose of this tutorial,
+we are going to call all such objects *transient* objects.
+This highlights the fact that,
+from the point of view of Grok,
+they are going to be instantiated on-the-fly as a user visits them.
+Of course,
+they might (or might not) persist in some other application,
+like a file system or LDAP server or relational database!
+But as far as Grok can tell,
+they are being created the moment before they are used
+and then, very often, pass right back out of existence —
+and out of your application's memory —
+once Grok is finished composing the response.
+
+To try out the examples in this tutorial,
+start a Grok project named ``TransientApp``
+and edit the ``app.py`` and other files
+that you are instructed to create or edit.
+
+Choosing a method
+-----------------
+
+In this tutorial,
+we introduce four methods for creating an object
+which you need to present on the web:
+
+* Creating it in your View's ``update()``, using no external data.
+* Creating it in your View's ``update()``, using URL or form data.
+* Creating it in a ``Traverser`` that gets called for certain URLs.
+* Creating it in a ``Container`` that gets called for certain URLs.
+
+To choose among these methods,
+the big question you need to ask yourself
+is whether the object you are planning to display
+is one that will live at its own particular URL or not.
+There are three basic relationships we can imagine
+between an object on a web page and the URL of the page itself.
+
+The simplest case,
+which is supported by the *first* method listed above,
+is when you need to create an object
+during the rendering of a page that already exists in your application.
+An example would be decorating the bottom of your front page
+with a random quotation
+selected by instantiating a ``RandomQuotation`` class you have written,
+so that each time a user reloads the page they see a different quote.
+None of the quotations would thereby have URLs of their own;
+there would, in fact, be no way for the user
+to demand that a particular quotation be displayed;
+and the user could not force the site to display again
+a quote from Bertrand Russell
+that they remember enjoying yesterday but have forgotten.
+Such objects can simply be instantiated
+in the ``update()`` method of your View,
+and this technique will be our first example below.
+
+The situation is only slightly more complex
+when you need to use form parameters the user has submitted
+to tailor the object you are creating.
+This is very common when supporting searching of a database:
+the user enters some search terms,
+and the application needs to instantiate an object —
+maybe a ``SearchResult`` or a ``DatabaseQuery`` —
+using those user-provided search terms,
+so that the page template can loop across and display the results.
+The *second* method listed above is best for this;
+since the form parameters are available in the ``update()`` method,
+you are free to use them when creating the result object.
+This will be the technique illustrated in our second example below.
+
+Finally,
+the really interesting case is when an object actually gets its own URL.
+You are probably already familiar with several kinds of object
+which have their own URLs on the Web —
+such as books on Amazon.com, photographs on Flickr, and people on Facebook,
+all of which live at their own URL.
+Each web site has a particular scheme
+which associates a URL with the object it names or identifies.
+You can probably guess, for example, just by looking at them,
+which object is named by each of the following three Amazon URLs::
+
+ http://www.amazon.com/Web-Component-Development-Zope-3/dp/3540223592
+ http://www.amazon.com/Harry-Potter-Deathly-Hallows-Book/dp/0545010225
+ http://www.amazon.com/J-R-R-Tolkien-Boxed-Hobbit-Rings/dp/0345340426
+
+The Grok framework, of course,
+already supports URL traversal for persistent objects in the ZODB;
+if you create a ``Container`` named ``polygons``
+that contains two objects named ``triangle`` and ``square``,
+then your Grok site will already support URLs like::
+
+ http://yoursite.com/app/polygons/triangle
+ http://yoursite.com/app/polygons/square
+
+But the point of this tutorial, of course,
+is how you can support URL traversal
+for objects which are *not* persistent,
+which you will create on-the-fly once someone looks up their URL.
+And the answer is that, to support such objects,
+you will choose between the last two methods listed above:
+you will either create a custom ``Traverser``,
+or actually define your own kind of ``Container``,
+that knows how to find and instantiate the object the URL is naming.
+These two techniques are described last in this tutorial,
+because they involve the most code.
+
+But before starting our first example,
+we need to define an object that we want to display.
+We want to avoid choosing an obvious example,
+like an object whose data is loaded from a database,
+because then this tutorial would have to teach database programming too!
+Plus, you would have to set up a database just to try the examples.
+Instead,
+we need an object
+rich enough to support interesting attributes and navigation,
+but simple enough
+that we will not have to reach outside of Python to instantiate it.
+
+Our Topic: The Natural Numbers
+------------------------------
+
+To make this tutorial simple,
+we will build a small web site
+that lets the user visit what some people call the *natural numbers*:
+the integers beginning with *1*
+and continuing with *2*, *3*, *4*, and so forth.
+We will define a ``Natural`` class
+which knows a few simple things about each number —
+like which number comes before it, which comes after it,
+and what its prime factors are.
+
+We should start by writing a test suite for our ``Natural`` class.
+Not only is writing tests before code an excellent programming practice
+that forces you to think through how your new class should behave,
+but it will make this tutorial easier to understand.
+When you are further down in the tutorial,
+and want to remember something about the ``Natural`` class,
+you may find yourself re-reading the tests instead of the code
+as the fastest way to remember how the class behaves!
+
+The reason this test will be so informative
+is that it is a Python “doctest”,
+which intersperses normal text with the example Python code.
+Create a file in your Grok instance named ``src/transient/natural.txt``
+and give it the following contents::
+
+ 
+               A Simple Implementation of Natural Numbers
+ 
+ The "natural" module of this application provides a simple class for
+ representing any postive integer, named "Natural".
+ 
+     >>> from transient.natural import Natural
+ 
+ To instantiate it, provide a Python integer to its constructor:
+ 
+     >>> three = Natural(3)
+     >>> print 'This object is known to Python as a "%r".' % three
+     This object is known to Python as a "Natural(3)".
+     >>> print 'The number of the counting shall be %s.' % three
+     The number of the counting shall be 3.
+ 
+ You will find that there are very many natural numbers available; to
+ help you navigate among them all, each of them offers a "previous" and
+ "next" attribute to help you find the ones adjacent to it.
+ 
+     >>> print 'Previous: %r  Next: %r' % (three.previous, three.next)
+     Previous: Natural(2)  Next: Natural(4)
+ 
+ Since we define the set of "natural numbers" as beginning with 1, you
+ will find that the number 1 lacks a "previous" attribute:
+ 
+     >>> hasattr(three, 'previous')
+     True
+     >>> one = Natural(1)
+     >>> hasattr(one, 'previous')
+     False
+     >>> one.previous
+     Traceback (most recent call last):
+      ...
+     AttributeError: There is no natural number less than 1.
+ 
+ You can also ask a number to tell you which prime factors must be
+ multiplied together to produce it.  The number 1 will return no
+ factors:
+ 
+     >>> one.factors
+     []
+ 
+ Prime numbers will return only themselves as factors:
+ 
+     >>> print Natural(2).factors, Natural(11).factors, Natural(251).factors
+     [Natural(2)] [Natural(11)] [Natural(251)]
+ 
+ Compound numbers return several factors, sorted in increasing order,
+ and each appearing the correct number of times:
+ 
+     >>> print Natural(4).factors
+     [Natural(2), Natural(2)]
+     >>> print Natural(12).factors
+     [Natural(2), Natural(2), Natural(3)]
+     >>> print Natural(2310).factors
+     [Natural(2), Natural(3), Natural(5), Natural(7), Natural(11)]
+ 
+ Each natural number can also simply return a boolean value indicating
+ whether it is prime, and whether it is composite.
+
+     >>> print Natural(6).is_prime, Natural(6).is_composite
+     False True
+     >>> print Natural(7).is_prime, Natural(7).is_composite
+     True False
+
+
+Next,
+we need to tell Grok about this doctest.
+Create a file in your instance named ``src/transient/tests.py``
+that looks like:
+
+.. code-block:: python
+
+ import unittest
+ from doctest import DocFileSuite
+
+ def test_suite():
+     return unittest.TestSuite([ DocFileSuite('natural.txt') ])
+
+
+You should now find that running ``./bin/test`` inside of your instance
+now results in a whole series of test failures.
+This is wonderful and means that everything is working!
+At this point Grok is able to find your doctest,
+successfully execute it,
+and correctly report (if you examine the first error message)
+that you have not yet provided a ``Natural`` class
+that could make the doctest able to succeed.
+
+The Class Itself
+----------------
+
+Now we merely have to provide an implementation for our ``Natural`` class.
+Create a file ``src/transient/natural.py`` under your Grok instance
+and give it the contents:
+
+.. code-block:: python
+
+ class Natural(object):
+     """A natural number, here defined as an integer greater than zero."""
+ 
+     def __init__(self, n):
+         self.n = abs(int(n)) or 1
+ 
+     def __str__(self):
+         return '%d' % self.n
+ 
+     def __repr__(self):
+         return 'Natural(%d)' % self.n
+ 
+     @property
+     def previous(self):
+         if self.n < 2:
+             raise AttributeError('There is no natural number less than 1.')
+         return Natural(self.n - 1)
+ 
+     @property
+     def next(self):
+         return Natural(self.n + 1)
+
+     @property
+     def factors(self):
+         if not hasattr(self, '_factors'):  # compute factors only once!
+             n, i = self.n, 2
+             self._factors = []
+             while i <= n:
+                 while n % i == 0:          # while n is divisible by i
+                     self._factors.append(Natural(i))
+                     n /= i
+                 i += 1
+         return self._factors
+
+     @property
+     def is_prime(self):
+         return len(self.factors) < 2
+
+     @property
+     def is_composite(self):
+	 return len(self.factors) > 1
+
+If you try running ``./bin/test`` again after creating this file,
+you should find that the entire ``natural.txt`` docfile
+now runs correctly!
+
+I hope that if you are new to Python,
+you are not too confused by the code above,
+which uses ``@property``
+which may not have been covered in the Python tutorial.
+But I prefer to show you “real Python” like this,
+that reflects how people actually use the language,
+rather than artifically simple code
+that hides from you the best ways to use Python.
+Note that it is *not* necessary to understand ``natural.py``
+to enjoy the rest of this tutorial!
+Everything we do from this point on
+will involve building a framework to use this object on the web;
+we will be doing no further development on the class itself.
+So all you actually need to understand is how a ``Natural`` behaves,
+which was entirely explained in the doctest.
+
+Note that the ``Natural`` class knows nothing about Grok!
+This is an important feature of the whole Zope 3 framework,
+that bears frequent repeating:
+objects are supposed to be simple,
+and not have to know that they are being presented on the web.
+You should be able to grab objects created anywhere,
+from any old library of useful functions you happen to download,
+and suit them up to be displayed and manipulated with a browser.
+And the ``Natural`` class is exactly like that:
+it has no idea that we are about to build a framework around it
+that will soon be publishing it on the web.
+
+Having Your View Directly Instantiate An Object
+-----------------------------------------------
+
+We now reach the first of our four techniques!
+
+The simplest way to create a transient object for display on the web
+involves a technique you may remember from the main Grok tutorial:
+providing an ``update()`` method on your View
+that creates the object you need
+and saves it as an attribute of the View.
+As a simple example,
+create an ``app.py`` file with these contents:
+
+.. code-block:: python
+
+ import grok
+ from transient.natural import Natural
+
+ class TransientApp(grok.Application, grok.Container):
+     pass
+
+ class Index(grok.View):
+     def update(self):
+         self.num = Natural(126)
+
+Do you see what will happen?
+Right before Grok renders your View to answer a web request,
+Grok will call its ``update()`` method,
+and your View will gain an attribute named ``num``
+whose value is a new instance of the ``Natural`` class.
+This attribute can then be referenced from the page template
+corresponding to your view!
+Let use write a small page template that accesses the new object.
+Try creating an ``/app_templates/index.pt`` file that looks like:
+
+.. code-block:: html
+
+ <html><body>
+  <p>
+   Behold the number <b tal:content="view/num">x</b>!
+   <span tal:condition="view/num/is_prime">It is prime.</span>
+   <span tal:condition="view/num/is_composite">Its prime factors are:</span>
+  </p>
+  <ul tal:condition="view/num/factors">
+   <li tal:repeat="factor view/num/factors">
+    <b tal:content="factor">f</b>
+   </li>
+  </ul>
+ </body></html>
+
+If you now run your instance
+and view the main page of your application,
+your browser should show you something like::
+
+ Behold the number 126!  It has several prime factors:
+
+    * 2
+    * 3
+    * 3
+    * 7
+
+
+You should remember,
+when creating an object through an ``update()`` method,
+that a new object gets created every time your page is viewed!
+This is hard to see with the above example,
+of course,
+because no matter how many times you hit “reload” on your web browser
+you will still see the same number.
+So adjust your ``app.py`` file so that it now looks like this:
+
+.. code-block:: python
+
+ import grok, random
+ from transient.natural import Natural
+ 
+ class TransientApp(grok.Application, grok.Container):
+     pass
+ 
+ class Index(grok.View):
+     def update(self):
+         self.num = Natural(random.randint(1,1000))
+
+Re-run your application and hit “reload” several times;
+each time you should see a different number.
+
+The most important thing to realize when using this method
+is that this ``Natural`` object is *not* the object
+that Grok is wrapping with the View for display!
+The object actually selected by the URL in this example
+is your ``TransientApp`` application object itself;
+it is this application object which is the ``context`` of the View.
+The ``Natural`` object we are creating is nothing more
+than an incidental attribute of the View;
+it neither has its own URL, nor a View of its own to display it.
+
+
+Creating Objects Based on Form Input
+------------------------------------
+
+What if we wanted the user
+to be able to designate which ``Natural`` object was instantiated
+for display on this web page?
+This is a very common need
+when implementing things like a database search form,
+where the user's search terms need to be provided as inputs
+to the object that will return the search results.
+
+The answer is given in the main Grok tutorial:
+if you can write your ``update()`` method
+so that it takes keyword parameters,
+they will be filled in with any form parameters the user provides.
+Rewrite your ``app.py`` to look like:
+
+.. code-block:: python
+
+ import grok, random
+ from transient.natural import Natural
+ 
+ class TransientApp(grok.Application, grok.Container):
+     pass
+ 
+ class Index(grok.View):
+     def update(self, n=None):
+         self.badnum = self.num = None
+         if n:
+             try:
+                 self.num = Natural(int(n))
+             except:
+                 self.badnum = n
+
+And make your ``app_templates/index.pt`` look like:
+
+.. code-block:: html
+
+ <html><body>
+  <p tal:condition="view/badnum">This does not look like a natural number:
+   &ldquo;<b tal:content="view/badnum">string</b>&rdquo;
+  </p>
+  <p tal:condition="view/num">
+   You asked about the number <b tal:content="view/num">x</b>!<br/>
+   <span tal:condition="view/num/is_prime">It is prime.</span>
+   <span tal:condition="view/num/is_composite">Its prime factors are:
+    <span tal:repeat="factor view/num/factors">
+     <b tal:content="factor">f</b
+     ><span tal:condition="not:repeat/factor/end">,</span>
+    </span>
+   </span>
+  </p>
+  <form tal:attributes="action python:view.url()" method="GET">
+   Choose a number: <input type="text" name="n" value="" />
+   <input type="submit" value="Go" />
+  </form>
+ </body></html>
+
+This time, when you restart your Grok instance
+and look at your application front page,
+you will see a form asking for a number::
+
+ Choose a number: __________  [Go]
+
+Enter a positive integer and submit the form
+(try to choose something with less than seven digits
+to keep the search for prime factors short),
+and you will see something like::
+
+ You asked about the number 48382!
+ Its prime factors are: 2, 17, 1423
+ Choose a number: __________  [Go]
+
+And if you examine the URL to which the form has delivered you,
+you will see that the number you have selected
+is part of the URL's query section:
+
+   http://localhost:8080/app/index?n=48382
+
+So none of these numbers get their own URL;
+they all live on the page ``/app/index``
+and have to be selected by submitting a query to that one page.
+
+
+Custom Traversers
+-----------------
+
+But what about situations
+where you want each of your transient objects
+to have its own URL on your site?
+The answer is that you can create ``grok.Traverser`` objects that,
+when the user enters a URL
+and Grok tries to find the object which the URL names,
+intercept those requests
+and return objects of your own design instead.
+
+For our example application ``app``,
+let's make each ``Natural`` object live at a URL like::
+
+   http://localhost:8080/app/natural/496
+
+There is nothing magic about the fact that this URL has three parts,
+by the way —
+the three parts being the application name ``"app"``,
+the word ``"natural"``,
+and finally the name of the integer ``"496"``.
+You should easily be able to figure out
+how to adapt the example application below
+either to the situation
+where you want all the objects to live at your application root
+(which would make the URLs look like ``/app/496``),
+or where you want URLs to go several levels deeper
+(like if you wanted ``/app/numbers/naturals/496``).
+
+The basic rule is that for each slash-separated URL component
+(like ``"natural"`` or ``"496"``)
+that does not actually name an object in the ZODB,
+you have to provide a ``grok.Traverser``.
+Make the ``grok.context`` of the Traverser
+the object that lives at the previous URL component,
+and give your Traverser a ``traverse()`` method
+that takes as its argument the next name in the URL
+and returns the object itself.
+If the name submitted to your traverser
+does not name an object,
+simply return ``None``;
+this is very easy to do,
+since ``None`` is the default return value
+of a Python function that ends without a ``return`` statement.
+
+So place the following inside your ``app.py`` file:
+
+.. code-block:: python
+
+ import grok
+ from transient.natural import Natural
+
+ class TransientApp(grok.Application, grok.Container):
+     pass
+
+ class BaseTraverser(grok.Traverser):
+     grok.context(TransientApp)
+     def traverse(self, name):
+         if name == 'natural':
+             return NaturalDir()
+
+ class NaturalDir(object):
+     pass
+
+ class NaturalTraverser(grok.Traverser):
+     grok.context(NaturalDir)
+     def traverse(self, name):
+         if name.isdigit() and int(name) > 0:
+             return Natural(int(name))
+
+ class NaturalIndex(grok.View):
+     grok.context(Natural)
+     grok.name('index.html')
+
+
+And you will only need one template to go with this file,
+which you should place in ``app_templates/naturalindex.pt``:
+
+.. code-block:: html
+
+ <html><body>
+  This is the number <b tal:content="context">x</b>!<br/>
+   <span tal:condition="context/is_prime">It is prime.</span>
+   <span tal:condition="context/is_composite">Its prime factors are:
+    <span tal:repeat="factor context/factors">
+     <b tal:content="factor">f</b
+     ><span tal:condition="not:repeat/factor/end">,</span>
+    </span>
+   </span><br>
+ </body></html>
+
+Now, if you view the URL ``/app/natural/496`` on your test server,
+you should see::
+
+ This is the number 496!
+ Its prime factors are: 2, 2, 2, 2, 31
+
+Note that there is no view name after the URL.
+That's because we chose to name our View ``index.html``,
+which is the default view name in Zope 3.
+(With ``grok.Model`` and ``grok.Container`` objects,
+by contrast,
+the default view selected if none is named is simply ``index``
+without the ``.html`` at the end.)
+You can always name the view explicitly, though,
+so you will find that you can also view the number 496 at::
+
+ http://kenaniah.ten22:8080/app/natural/496/index.html
+
+It's important to realize this because,
+if you need to add more views to a transient object,
+you of course will have to add them with other names —
+and to see the information in those other views,
+users (or the links they use) will have to name the views explicitly.
+
+Two final notes:
+
+* In order to make this example brief,
+  the application above does not support
+  either the user navigating simply to ``/app``,
+  nor will it allow them to view ``/app/natural``,
+  because we have provided neither our ``TransientApp`` application object
+  nor the ``NaturalDir`` stepping-stone with ``grok.View`` objects
+  that could let them be displayed.
+  You will almost always,
+  of course,
+  want to provide a welcoming page
+  for the top level of your application;
+  but it's up to you whether you think it makes sense
+  for users to be able to visit the intermediate ``/app/natural``
+  URL or not.
+  If not,
+  then follow the example above
+  and simply do not provide a view,
+  and everything else will work just fine.
+
+* In order to provide symmetry in the example above,
+  neither the ``TransientApp`` object nor the ``NaturalDir`` object
+  knows how to send users to the next objects below them.
+  Instead, they are both provided with Traversers.
+  It turns out,
+  I finally admin here at the bottom of the example,
+  that this was not necessary!
+  Grok objects like a ``grok.Container`` or a ``grok.Model``
+  already have enough magic built-in
+  that you can put a ``traverse()`` method
+  right on the object
+  and Grok will find it when trying to resolve a URL.
+  This would not have helped our ``NaturalDir`` object,
+  of course,
+  because it's not a Grok anything;
+  but it means that we can technically delete the first Traverser
+  and simply declare the first class as:
+
+  .. code-block:: python
+
+   class TransientApp(grok.Application, grok.Container):
+       def traverse(self, name):
+           if name == 'natural':
+               return NaturalDir()
+
+  The reason I did not do this in the actual example above
+  is that showing two different ways to traverse in the same example
+  seemed a bit excessive!
+  I preferred instead to use a single method, twice,
+  that is universal and works everywhere,
+  rather than by starting off with a technique
+  that does not work for most kinds of Python object.
+
+
+Providing Links To Other Objects
+--------------------------------
+
+What if the object you are wrapping
+can return other objects to which the user might want to navigate?
+Imagine the possibilities:
+a filesystem object you are presenting on the web
+might be able to return the files inside of it;
+a genealogical application might have person objects
+that can return their spouse, children, or grandparents.
+In the example we are working on here,
+a ``Natural`` object can return
+both the previous and the next number;
+wouldn't it be nice to give the users links to them?
+
+If in a page template
+you naively ask your Grok view
+for the URL of a transient object,
+you will be disappointed.
+Grok *does* know the URL of the object
+to which the user has just navigated,
+because, well, it's just navigated there,
+so adding this near the bottom of your ``naturalindex.pt``
+should work just fine::
+
+  This page lives at: <b tal:content="python: view.url(context)">url</b><br>
+
+But if you rewrite your template
+so that it tries asking for the URL of any other object,
+the result will be a minor explosion.
+Try adding this to your ``naturalindex.pt`` file::
+
+  Next number: <b tal:content="python: view.url(context.next)">url</b><br>
+
+and try reloading the page.
+On the command line,
+your application will return the exception::
+
+ TypeError: There isn't enough context to get URL information.
+ This is probably due to a bug in setting up location information.
+
+Do you see the problem?
+Because this new ``Natural`` object does not live inside of the ZopeDB,
+Grok cannot guess the URL at which you intend it to live.
+In order to provide this information,
+it is best to call a Zope function called ``locate()``
+that marks as object as belonging inside of a particular container.
+To get the chance to do this magic,
+you'll have to avoid calling ``Natural.previous`` and ``Natural.next``
+directly from your page template.
+Instead,
+provide your view with two new properties
+that will grab the ``previous`` and ``next`` attributes
+off of the ``Natural`` object which is your current context,
+and then perform the required modification before returning them:
+
+.. code-block:: python
+
+ class NaturalIndex(grok.View):
+
+     ...
+
+     @property
+     def previous(self):
+         if getattr(self.context, 'previous', None):
+             n = self.context.previous
+             traverser = BaseTraverser(grok.getSite(), None)
+             parent = traverser.publishTraverse(None, 'natural')
+             return zope.location.location.located(n, parent, str(n))
+ 
+     @property
+     def next(self):
+         n = self.context.next
+         traverser = BaseTraverser(grok.getSite(), None)
+         parent = traverser.publishTraverse(None, 'natural')
+         return zope.location.location.located(n, parent, str(n))
+
+
+This forces upon your objects
+enough information that Zope can determine their URL —
+it will believe that they live inside of the object
+named by the URL ``/app/natural``
+(or whatever other name you use in the ``PublishTraverse`` call).
+With the above in place,
+you can add these links to the bottom of your ``naturalindex.pt``
+and they should work just fine:
+
+.. code-block:: html
+
+  <tal:if tal:condition="view/previous">
+   Previous number: <a tal:attributes="href python: view.url(view.previous)"
+    tal:content="view/previous">123</a><br>
+  </tal:if>
+  Next number: <a tal:attributes="href python: view.url(view.next)"
+   tal:content="view/next">123</a><br>
+
+This should get easier in a future version of Grok and Zope!
+
+
+Writing Your Own Container
+--------------------------
+
+The above approach, using Traversers, gives Grok
+just enough information
+to let users visit your objects,
+and for you to assign URLs to them.
+But there are several features of a normal ``grok.Container``
+that are missing —
+there is no way for Grok to list or iterate over the objects,
+for example,
+nor can it ask whether a particular object lives in the container or not.
+
+While taking full advantage of containers
+is beyond the scope of this tutorial,
+I ought to show you how the above would be accomplished:
+
+.. code-block:: python
+
+ import grok
+ from transient.natural import Natural
+ from zope.app.container.interfaces import IItemContainer
+ from zope.app.container.contained import Contained
+ import zope.location.location
+ 
+ class TransientApp(grok.Application, grok.Container):
+     pass
+ 
+ class BaseTraverser(grok.Traverser):
+     grok.context(TransientApp)
+     def traverse(self, name):
+         if name == 'natural':
+             return NaturalBox()
+ 
+ class NaturalBox(Contained):
+     grok.implements(IItemContainer)
+     def __getitem__(self, key):
+         if key.isdigit() and int(key) > 0:
+             n = Natural(int(key))
+             return zope.location.location.located(n, self, key)
+         else:
+             raise KeyError
+ 
+ class NaturalIndex(grok.View):
+     grok.context(Natural)
+     grok.name('index.html')
+ 
+     @property
+     def previous(self):
+         if getattr(self.context, 'previous'):
+             n = self.context.previous
+             parent = self.context.__parent__
+             return zope.location.location.located(n, parent, str(n))
+ 
+     @property
+     def next(self):
+         n = self.context.next
+         parent = self.context.__parent__
+         return zope.location.location.located(n, parent, str(n))
+
+
+Note, first, that this is almost identical to the application
+we built in the last section;
+the ``grok.Application``,
+its ``Traverser``,
+and the ``NaturalIndex`` are all the same —
+and you can leave alone the ``naturalindex.pt`` you wrote as well.
+
+But instead of placing a ``Traverser`` between our ``Application``
+and the actual objects we are delivering,
+we have created an actual “container”
+that follows a more fundamental protocol.
+There are a few differences
+in even this simple example.
+
+* A container is supposed to act like a Python dictionary,
+  so we have overriden the Python operation ``__getitem__``
+  instead of providing a ``traverse()`` method.
+  This means that other code using the container
+  can find objects inside of it using the ``container[key]``
+  Python dictionary syntax.
+
+* A Python ``__getitem__`` method
+  is required to raise the ``KeyError`` exception
+  when someone tries to look up a key
+  that does not exist in the container.
+  It is *not* sufficient to merely return ``None``,
+  like it was in our ``Traverser`` above,
+  because, without the exception,
+  Python will assume that the key lookup was successful
+  and that ``None`` is the value that was found!
+
+* Finally,
+  before returning an object from your container,
+  you need to call the Zope ``located()`` function
+  to make sure the object gets marked up
+  with information about where it lives on your site.
+  A Grok ``Traverser`` does this for you.
+
+Again,
+in most circumstances I can imagine,
+you will be happier just using a Traverser
+like the third example shows,
+and not incurring the slight bit of extra work
+necessary to offer a full-fledged container.
+But,
+in case you ever find yourself
+wanting to use a widget or utility
+that needs an actual container to process,
+I wanted you to have this example available.

Deleted: grok/trunk/doc/minitutorials/transient-objects.txt
===================================================================
--- grok/trunk/doc/minitutorials/transient-objects.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/transient-objects.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,914 +0,0 @@
-========================================
-Navigating To Transient Objects Tutorial
-========================================
-
-:Author: Brandon Craig Rhodes
-
-Introduction
-------------
-
-If you have already read the Grok tutorial,
-you are familiar with the fact that behind Grok
-lives a wonderful object database called the *Zope Object Database*,
-or the *ZODB* for short.
-Thanks to the magic of this database,
-your web apps can create Python objects
-that are automatically saved to disk
-and are available every time your application runs.
-In particular,
-every ``grok.Model`` and ``grok.Container`` object you generate
-can be written safely to your application's ``Data.fs`` file.
-
-But sometimes you need to create objects
-that do not persist in the ZODB,
-wonderful though it is.
-Sometimes these will be objects you design yourself
-but have no need to save once you are done displaying them,
-like summary statistics or search results.
-On other occasions,
-you will find yourself using libraries or packages written by other people
-and will need to present the objects they return in your Grok app —
-whether those objects are LDAP entries,
-file system directory listings,
-or rows from a relational database.
-
-For the purpose of this tutorial,
-we are going to call all such objects *transient* objects.
-This highlights the fact that,
-from the point of view of Grok,
-they are going to be instantiated on-the-fly as a user visits them.
-Of course,
-they might (or might not) persist in some other application,
-like a file system or LDAP server or relational database!
-But as far as Grok can tell,
-they are being created the moment before they are used
-and then, very often, pass right back out of existence —
-and out of your application's memory —
-once Grok is finished composing the response.
-
-To try out the examples in this tutorial,
-start a Grok project named ``TransientApp``
-and edit the ``app.py`` and other files
-that you are instructed to create or edit.
-
-Choosing a method
------------------
-
-In this tutorial,
-we introduce four methods for creating an object
-which you need to present on the web:
-
-* Creating it in your View's ``update()``, using no external data.
-* Creating it in your View's ``update()``, using URL or form data.
-* Creating it in a ``Traverser`` that gets called for certain URLs.
-* Creating it in a ``Container`` that gets called for certain URLs.
-
-To choose among these methods,
-the big question you need to ask yourself
-is whether the object you are planning to display
-is one that will live at its own particular URL or not.
-There are three basic relationships we can imagine
-between an object on a web page and the URL of the page itself.
-
-The simplest case,
-which is supported by the *first* method listed above,
-is when you need to create an object
-during the rendering of a page that already exists in your application.
-An example would be decorating the bottom of your front page
-with a random quotation
-selected by instantiating a ``RandomQuotation`` class you have written,
-so that each time a user reloads the page they see a different quote.
-None of the quotations would thereby have URLs of their own;
-there would, in fact, be no way for the user
-to demand that a particular quotation be displayed;
-and the user could not force the site to display again
-a quote from Bertrand Russell
-that they remember enjoying yesterday but have forgotten.
-Such objects can simply be instantiated
-in the ``update()`` method of your View,
-and this technique will be our first example below.
-
-The situation is only slightly more complex
-when you need to use form parameters the user has submitted
-to tailor the object you are creating.
-This is very common when supporting searching of a database:
-the user enters some search terms,
-and the application needs to instantiate an object —
-maybe a ``SearchResult`` or a ``DatabaseQuery`` —
-using those user-provided search terms,
-so that the page template can loop across and display the results.
-The *second* method listed above is best for this;
-since the form parameters are available in the ``update()`` method,
-you are free to use them when creating the result object.
-This will be the technique illustrated in our second example below.
-
-Finally,
-the really interesting case is when an object actually gets its own URL.
-You are probably already familiar with several kinds of object
-which have their own URLs on the Web —
-such as books on Amazon.com, photographs on Flickr, and people on Facebook,
-all of which live at their own URL.
-Each web site has a particular scheme
-which associates a URL with the object it names or identifies.
-You can probably guess, for example, just by looking at them,
-which object is named by each of the following three Amazon URLs::
-
- http://www.amazon.com/Web-Component-Development-Zope-3/dp/3540223592
- http://www.amazon.com/Harry-Potter-Deathly-Hallows-Book/dp/0545010225
- http://www.amazon.com/J-R-R-Tolkien-Boxed-Hobbit-Rings/dp/0345340426
-
-The Grok framework, of course,
-already supports URL traversal for persistent objects in the ZODB;
-if you create a ``Container`` named ``polygons``
-that contains two objects named ``triangle`` and ``square``,
-then your Grok site will already support URLs like::
-
- http://yoursite.com/app/polygons/triangle
- http://yoursite.com/app/polygons/square
-
-But the point of this tutorial, of course,
-is how you can support URL traversal
-for objects which are *not* persistent,
-which you will create on-the-fly once someone looks up their URL.
-And the answer is that, to support such objects,
-you will choose between the last two methods listed above:
-you will either create a custom ``Traverser``,
-or actually define your own kind of ``Container``,
-that knows how to find and instantiate the object the URL is naming.
-These two techniques are described last in this tutorial,
-because they involve the most code.
-
-But before starting our first example,
-we need to define an object that we want to display.
-We want to avoid choosing an obvious example,
-like an object whose data is loaded from a database,
-because then this tutorial would have to teach database programming too!
-Plus, you would have to set up a database just to try the examples.
-Instead,
-we need an object
-rich enough to support interesting attributes and navigation,
-but simple enough
-that we will not have to reach outside of Python to instantiate it.
-
-Our Topic: The Natural Numbers
-------------------------------
-
-To make this tutorial simple,
-we will build a small web site
-that lets the user visit what some people call the *natural numbers*:
-the integers beginning with *1*
-and continuing with *2*, *3*, *4*, and so forth.
-We will define a ``Natural`` class
-which knows a few simple things about each number —
-like which number comes before it, which comes after it,
-and what its prime factors are.
-
-We should start by writing a test suite for our ``Natural`` class.
-Not only is writing tests before code an excellent programming practice
-that forces you to think through how your new class should behave,
-but it will make this tutorial easier to understand.
-When you are further down in the tutorial,
-and want to remember something about the ``Natural`` class,
-you may find yourself re-reading the tests instead of the code
-as the fastest way to remember how the class behaves!
-
-The reason this test will be so informative
-is that it is a Python “doctest”,
-which intersperses normal text with the example Python code.
-Create a file in your Grok instance named ``src/transient/natural.txt``
-and give it the following contents::
-
- 
-               A Simple Implementation of Natural Numbers
- 
- The "natural" module of this application provides a simple class for
- representing any postive integer, named "Natural".
- 
-     >>> from transient.natural import Natural
- 
- To instantiate it, provide a Python integer to its constructor:
- 
-     >>> three = Natural(3)
-     >>> print 'This object is known to Python as a "%r".' % three
-     This object is known to Python as a "Natural(3)".
-     >>> print 'The number of the counting shall be %s.' % three
-     The number of the counting shall be 3.
- 
- You will find that there are very many natural numbers available; to
- help you navigate among them all, each of them offers a "previous" and
- "next" attribute to help you find the ones adjacent to it.
- 
-     >>> print 'Previous: %r  Next: %r' % (three.previous, three.next)
-     Previous: Natural(2)  Next: Natural(4)
- 
- Since we define the set of "natural numbers" as beginning with 1, you
- will find that the number 1 lacks a "previous" attribute:
- 
-     >>> hasattr(three, 'previous')
-     True
-     >>> one = Natural(1)
-     >>> hasattr(one, 'previous')
-     False
-     >>> one.previous
-     Traceback (most recent call last):
-      ...
-     AttributeError: There is no natural number less than 1.
- 
- You can also ask a number to tell you which prime factors must be
- multiplied together to produce it.  The number 1 will return no
- factors:
- 
-     >>> one.factors
-     []
- 
- Prime numbers will return only themselves as factors:
- 
-     >>> print Natural(2).factors, Natural(11).factors, Natural(251).factors
-     [Natural(2)] [Natural(11)] [Natural(251)]
- 
- Compound numbers return several factors, sorted in increasing order,
- and each appearing the correct number of times:
- 
-     >>> print Natural(4).factors
-     [Natural(2), Natural(2)]
-     >>> print Natural(12).factors
-     [Natural(2), Natural(2), Natural(3)]
-     >>> print Natural(2310).factors
-     [Natural(2), Natural(3), Natural(5), Natural(7), Natural(11)]
- 
- Each natural number can also simply return a boolean value indicating
- whether it is prime, and whether it is composite.
-
-     >>> print Natural(6).is_prime, Natural(6).is_composite
-     False True
-     >>> print Natural(7).is_prime, Natural(7).is_composite
-     True False
-
-
-Next,
-we need to tell Grok about this doctest.
-Create a file in your instance named ``src/transient/tests.py``
-that looks like:
-
-.. code-block:: python
-
- import unittest
- from doctest import DocFileSuite
-
- def test_suite():
-     return unittest.TestSuite([ DocFileSuite('natural.txt') ])
-
-
-You should now find that running ``./bin/test`` inside of your instance
-now results in a whole series of test failures.
-This is wonderful and means that everything is working!
-At this point Grok is able to find your doctest,
-successfully execute it,
-and correctly report (if you examine the first error message)
-that you have not yet provided a ``Natural`` class
-that could make the doctest able to succeed.
-
-The Class Itself
-----------------
-
-Now we merely have to provide an implementation for our ``Natural`` class.
-Create a file ``src/transient/natural.py`` under your Grok instance
-and give it the contents:
-
-.. code-block:: python
-
- class Natural(object):
-     """A natural number, here defined as an integer greater than zero."""
- 
-     def __init__(self, n):
-         self.n = abs(int(n)) or 1
- 
-     def __str__(self):
-         return '%d' % self.n
- 
-     def __repr__(self):
-         return 'Natural(%d)' % self.n
- 
-     @property
-     def previous(self):
-         if self.n < 2:
-             raise AttributeError('There is no natural number less than 1.')
-         return Natural(self.n - 1)
- 
-     @property
-     def next(self):
-         return Natural(self.n + 1)
-
-     @property
-     def factors(self):
-         if not hasattr(self, '_factors'):  # compute factors only once!
-             n, i = self.n, 2
-             self._factors = []
-             while i <= n:
-                 while n % i == 0:          # while n is divisible by i
-                     self._factors.append(Natural(i))
-                     n /= i
-                 i += 1
-         return self._factors
-
-     @property
-     def is_prime(self):
-         return len(self.factors) < 2
-
-     @property
-     def is_composite(self):
-	 return len(self.factors) > 1
-
-If you try running ``./bin/test`` again after creating this file,
-you should find that the entire ``natural.txt`` docfile
-now runs correctly!
-
-I hope that if you are new to Python,
-you are not too confused by the code above,
-which uses ``@property``
-which may not have been covered in the Python tutorial.
-But I prefer to show you “real Python” like this,
-that reflects how people actually use the language,
-rather than artifically simple code
-that hides from you the best ways to use Python.
-Note that it is *not* necessary to understand ``natural.py``
-to enjoy the rest of this tutorial!
-Everything we do from this point on
-will involve building a framework to use this object on the web;
-we will be doing no further development on the class itself.
-So all you actually need to understand is how a ``Natural`` behaves,
-which was entirely explained in the doctest.
-
-Note that the ``Natural`` class knows nothing about Grok!
-This is an important feature of the whole Zope 3 framework,
-that bears frequent repeating:
-objects are supposed to be simple,
-and not have to know that they are being presented on the web.
-You should be able to grab objects created anywhere,
-from any old library of useful functions you happen to download,
-and suit them up to be displayed and manipulated with a browser.
-And the ``Natural`` class is exactly like that:
-it has no idea that we are about to build a framework around it
-that will soon be publishing it on the web.
-
-Having Your View Directly Instantiate An Object
------------------------------------------------
-
-We now reach the first of our four techniques!
-
-The simplest way to create a transient object for display on the web
-involves a technique you may remember from the main Grok tutorial:
-providing an ``update()`` method on your View
-that creates the object you need
-and saves it as an attribute of the View.
-As a simple example,
-create an ``app.py`` file with these contents:
-
-.. code-block:: python
-
- import grok
- from transient.natural import Natural
-
- class TransientApp(grok.Application, grok.Container):
-     pass
-
- class Index(grok.View):
-     def update(self):
-         self.num = Natural(126)
-
-Do you see what will happen?
-Right before Grok renders your View to answer a web request,
-Grok will call its ``update()`` method,
-and your View will gain an attribute named ``num``
-whose value is a new instance of the ``Natural`` class.
-This attribute can then be referenced from the page template
-corresponding to your view!
-Let use write a small page template that accesses the new object.
-Try creating an ``/app_templates/index.pt`` file that looks like:
-
-.. code-block:: html
-
- <html><body>
-  <p>
-   Behold the number <b tal:content="view/num">x</b>!
-   <span tal:condition="view/num/is_prime">It is prime.</span>
-   <span tal:condition="view/num/is_composite">Its prime factors are:</span>
-  </p>
-  <ul tal:condition="view/num/factors">
-   <li tal:repeat="factor view/num/factors">
-    <b tal:content="factor">f</b>
-   </li>
-  </ul>
- </body></html>
-
-If you now run your instance
-and view the main page of your application,
-your browser should show you something like::
-
- Behold the number 126!  It has several prime factors:
-
-    * 2
-    * 3
-    * 3
-    * 7
-
-
-You should remember,
-when creating an object through an ``update()`` method,
-that a new object gets created every time your page is viewed!
-This is hard to see with the above example,
-of course,
-because no matter how many times you hit “reload” on your web browser
-you will still see the same number.
-So adjust your ``app.py`` file so that it now looks like this:
-
-.. code-block:: python
-
- import grok, random
- from transient.natural import Natural
- 
- class TransientApp(grok.Application, grok.Container):
-     pass
- 
- class Index(grok.View):
-     def update(self):
-         self.num = Natural(random.randint(1,1000))
-
-Re-run your application and hit “reload” several times;
-each time you should see a different number.
-
-The most important thing to realize when using this method
-is that this ``Natural`` object is *not* the object
-that Grok is wrapping with the View for display!
-The object actually selected by the URL in this example
-is your ``TransientApp`` application object itself;
-it is this application object which is the ``context`` of the View.
-The ``Natural`` object we are creating is nothing more
-than an incidental attribute of the View;
-it neither has its own URL, nor a View of its own to display it.
-
-
-Creating Objects Based on Form Input
-------------------------------------
-
-What if we wanted the user
-to be able to designate which ``Natural`` object was instantiated
-for display on this web page?
-This is a very common need
-when implementing things like a database search form,
-where the user's search terms need to be provided as inputs
-to the object that will return the search results.
-
-The answer is given in the main Grok tutorial:
-if you can write your ``update()`` method
-so that it takes keyword parameters,
-they will be filled in with any form parameters the user provides.
-Rewrite your ``app.py`` to look like:
-
-.. code-block:: python
-
- import grok, random
- from transient.natural import Natural
- 
- class TransientApp(grok.Application, grok.Container):
-     pass
- 
- class Index(grok.View):
-     def update(self, n=None):
-         self.badnum = self.num = None
-         if n:
-             try:
-                 self.num = Natural(int(n))
-             except:
-                 self.badnum = n
-
-And make your ``app_templates/index.pt`` look like:
-
-.. code-block:: html
-
- <html><body>
-  <p tal:condition="view/badnum">This does not look like a natural number:
-   &ldquo;<b tal:content="view/badnum">string</b>&rdquo;
-  </p>
-  <p tal:condition="view/num">
-   You asked about the number <b tal:content="view/num">x</b>!<br/>
-   <span tal:condition="view/num/is_prime">It is prime.</span>
-   <span tal:condition="view/num/is_composite">Its prime factors are:
-    <span tal:repeat="factor view/num/factors">
-     <b tal:content="factor">f</b
-     ><span tal:condition="not:repeat/factor/end">,</span>
-    </span>
-   </span>
-  </p>
-  <form tal:attributes="action python:view.url()" method="GET">
-   Choose a number: <input type="text" name="n" value="" />
-   <input type="submit" value="Go" />
-  </form>
- </body></html>
-
-This time, when you restart your Grok instance
-and look at your application front page,
-you will see a form asking for a number::
-
- Choose a number: __________  [Go]
-
-Enter a positive integer and submit the form
-(try to choose something with less than seven digits
-to keep the search for prime factors short),
-and you will see something like::
-
- You asked about the number 48382!
- Its prime factors are: 2, 17, 1423
- Choose a number: __________  [Go]
-
-And if you examine the URL to which the form has delivered you,
-you will see that the number you have selected
-is part of the URL's query section:
-
-   http://localhost:8080/app/index?n=48382
-
-So none of these numbers get their own URL;
-they all live on the page ``/app/index``
-and have to be selected by submitting a query to that one page.
-
-
-Custom Traversers
------------------
-
-But what about situations
-where you want each of your transient objects
-to have its own URL on your site?
-The answer is that you can create ``grok.Traverser`` objects that,
-when the user enters a URL
-and Grok tries to find the object which the URL names,
-intercept those requests
-and return objects of your own design instead.
-
-For our example application ``app``,
-let's make each ``Natural`` object live at a URL like::
-
-   http://localhost:8080/app/natural/496
-
-There is nothing magic about the fact that this URL has three parts,
-by the way —
-the three parts being the application name ``"app"``,
-the word ``"natural"``,
-and finally the name of the integer ``"496"``.
-You should easily be able to figure out
-how to adapt the example application below
-either to the situation
-where you want all the objects to live at your application root
-(which would make the URLs look like ``/app/496``),
-or where you want URLs to go several levels deeper
-(like if you wanted ``/app/numbers/naturals/496``).
-
-The basic rule is that for each slash-separated URL component
-(like ``"natural"`` or ``"496"``)
-that does not actually name an object in the ZODB,
-you have to provide a ``grok.Traverser``.
-Make the ``grok.context`` of the Traverser
-the object that lives at the previous URL component,
-and give your Traverser a ``traverse()`` method
-that takes as its argument the next name in the URL
-and returns the object itself.
-If the name submitted to your traverser
-does not name an object,
-simply return ``None``;
-this is very easy to do,
-since ``None`` is the default return value
-of a Python function that ends without a ``return`` statement.
-
-So place the following inside your ``app.py`` file:
-
-.. code-block:: python
-
- import grok
- from transient.natural import Natural
-
- class TransientApp(grok.Application, grok.Container):
-     pass
-
- class BaseTraverser(grok.Traverser):
-     grok.context(TransientApp)
-     def traverse(self, name):
-         if name == 'natural':
-             return NaturalDir()
-
- class NaturalDir(object):
-     pass
-
- class NaturalTraverser(grok.Traverser):
-     grok.context(NaturalDir)
-     def traverse(self, name):
-         if name.isdigit() and int(name) > 0:
-             return Natural(int(name))
-
- class NaturalIndex(grok.View):
-     grok.context(Natural)
-     grok.name('index.html')
-
-
-And you will only need one template to go with this file,
-which you should place in ``app_templates/naturalindex.pt``:
-
-.. code-block:: html
-
- <html><body>
-  This is the number <b tal:content="context">x</b>!<br/>
-   <span tal:condition="context/is_prime">It is prime.</span>
-   <span tal:condition="context/is_composite">Its prime factors are:
-    <span tal:repeat="factor context/factors">
-     <b tal:content="factor">f</b
-     ><span tal:condition="not:repeat/factor/end">,</span>
-    </span>
-   </span><br>
- </body></html>
-
-Now, if you view the URL ``/app/natural/496`` on your test server,
-you should see::
-
- This is the number 496!
- Its prime factors are: 2, 2, 2, 2, 31
-
-Note that there is no view name after the URL.
-That's because we chose to name our View ``index.html``,
-which is the default view name in Zope 3.
-(With ``grok.Model`` and ``grok.Container`` objects,
-by contrast,
-the default view selected if none is named is simply ``index``
-without the ``.html`` at the end.)
-You can always name the view explicitly, though,
-so you will find that you can also view the number 496 at::
-
- http://kenaniah.ten22:8080/app/natural/496/index.html
-
-It's important to realize this because,
-if you need to add more views to a transient object,
-you of course will have to add them with other names —
-and to see the information in those other views,
-users (or the links they use) will have to name the views explicitly.
-
-Two final notes:
-
-* In order to make this example brief,
-  the application above does not support
-  either the user navigating simply to ``/app``,
-  nor will it allow them to view ``/app/natural``,
-  because we have provided neither our ``TransientApp`` application object
-  nor the ``NaturalDir`` stepping-stone with ``grok.View`` objects
-  that could let them be displayed.
-  You will almost always,
-  of course,
-  want to provide a welcoming page
-  for the top level of your application;
-  but it's up to you whether you think it makes sense
-  for users to be able to visit the intermediate ``/app/natural``
-  URL or not.
-  If not,
-  then follow the example above
-  and simply do not provide a view,
-  and everything else will work just fine.
-
-* In order to provide symmetry in the example above,
-  neither the ``TransientApp`` object nor the ``NaturalDir`` object
-  knows how to send users to the next objects below them.
-  Instead, they are both provided with Traversers.
-  It turns out,
-  I finally admin here at the bottom of the example,
-  that this was not necessary!
-  Grok objects like a ``grok.Container`` or a ``grok.Model``
-  already have enough magic built-in
-  that you can put a ``traverse()`` method
-  right on the object
-  and Grok will find it when trying to resolve a URL.
-  This would not have helped our ``NaturalDir`` object,
-  of course,
-  because it's not a Grok anything;
-  but it means that we can technically delete the first Traverser
-  and simply declare the first class as:
-
-  .. code-block:: python
-
-   class TransientApp(grok.Application, grok.Container):
-       def traverse(self, name):
-           if name == 'natural':
-               return NaturalDir()
-
-  The reason I did not do this in the actual example above
-  is that showing two different ways to traverse in the same example
-  seemed a bit excessive!
-  I preferred instead to use a single method, twice,
-  that is universal and works everywhere,
-  rather than by starting off with a technique
-  that does not work for most kinds of Python object.
-
-
-Providing Links To Other Objects
---------------------------------
-
-What if the object you are wrapping
-can return other objects to which the user might want to navigate?
-Imagine the possibilities:
-a filesystem object you are presenting on the web
-might be able to return the files inside of it;
-a genealogical application might have person objects
-that can return their spouse, children, or grandparents.
-In the example we are working on here,
-a ``Natural`` object can return
-both the previous and the next number;
-wouldn't it be nice to give the users links to them?
-
-If in a page template
-you naively ask your Grok view
-for the URL of a transient object,
-you will be disappointed.
-Grok *does* know the URL of the object
-to which the user has just navigated,
-because, well, it's just navigated there,
-so adding this near the bottom of your ``naturalindex.pt``
-should work just fine::
-
-  This page lives at: <b tal:content="python: view.url(context)">url</b><br>
-
-But if you rewrite your template
-so that it tries asking for the URL of any other object,
-the result will be a minor explosion.
-Try adding this to your ``naturalindex.pt`` file::
-
-  Next number: <b tal:content="python: view.url(context.next)">url</b><br>
-
-and try reloading the page.
-On the command line,
-your application will return the exception::
-
- TypeError: There isn't enough context to get URL information.
- This is probably due to a bug in setting up location information.
-
-Do you see the problem?
-Because this new ``Natural`` object does not live inside of the ZopeDB,
-Grok cannot guess the URL at which you intend it to live.
-In order to provide this information,
-it is best to call a Zope function called ``locate()``
-that marks as object as belonging inside of a particular container.
-To get the chance to do this magic,
-you'll have to avoid calling ``Natural.previous`` and ``Natural.next``
-directly from your page template.
-Instead,
-provide your view with two new properties
-that will grab the ``previous`` and ``next`` attributes
-off of the ``Natural`` object which is your current context,
-and then perform the required modification before returning them:
-
-.. code-block:: python
-
- class NaturalIndex(grok.View):
-
-     ...
-
-     @property
-     def previous(self):
-         if getattr(self.context, 'previous', None):
-             n = self.context.previous
-             traverser = BaseTraverser(grok.getSite(), None)
-             parent = traverser.publishTraverse(None, 'natural')
-             return zope.location.location.located(n, parent, str(n))
- 
-     @property
-     def next(self):
-         n = self.context.next
-         traverser = BaseTraverser(grok.getSite(), None)
-         parent = traverser.publishTraverse(None, 'natural')
-         return zope.location.location.located(n, parent, str(n))
-
-
-This forces upon your objects
-enough information that Zope can determine their URL —
-it will believe that they live inside of the object
-named by the URL ``/app/natural``
-(or whatever other name you use in the ``PublishTraverse`` call).
-With the above in place,
-you can add these links to the bottom of your ``naturalindex.pt``
-and they should work just fine:
-
-.. code-block:: html
-
-  <tal:if tal:condition="view/previous">
-   Previous number: <a tal:attributes="href python: view.url(view.previous)"
-    tal:content="view/previous">123</a><br>
-  </tal:if>
-  Next number: <a tal:attributes="href python: view.url(view.next)"
-   tal:content="view/next">123</a><br>
-
-This should get easier in a future version of Grok and Zope!
-
-
-Writing Your Own Container
---------------------------
-
-The above approach, using Traversers, gives Grok
-just enough information
-to let users visit your objects,
-and for you to assign URLs to them.
-But there are several features of a normal ``grok.Container``
-that are missing —
-there is no way for Grok to list or iterate over the objects,
-for example,
-nor can it ask whether a particular object lives in the container or not.
-
-While taking full advantage of containers
-is beyond the scope of this tutorial,
-I ought to show you how the above would be accomplished:
-
-.. code-block:: python
-
- import grok
- from transient.natural import Natural
- from zope.app.container.interfaces import IItemContainer
- from zope.app.container.contained import Contained
- import zope.location.location
- 
- class TransientApp(grok.Application, grok.Container):
-     pass
- 
- class BaseTraverser(grok.Traverser):
-     grok.context(TransientApp)
-     def traverse(self, name):
-         if name == 'natural':
-             return NaturalBox()
- 
- class NaturalBox(Contained):
-     grok.implements(IItemContainer)
-     def __getitem__(self, key):
-         if key.isdigit() and int(key) > 0:
-             n = Natural(int(key))
-             return zope.location.location.located(n, self, key)
-         else:
-             raise KeyError
- 
- class NaturalIndex(grok.View):
-     grok.context(Natural)
-     grok.name('index.html')
- 
-     @property
-     def previous(self):
-         if getattr(self.context, 'previous'):
-             n = self.context.previous
-             parent = self.context.__parent__
-             return zope.location.location.located(n, parent, str(n))
- 
-     @property
-     def next(self):
-         n = self.context.next
-         parent = self.context.__parent__
-         return zope.location.location.located(n, parent, str(n))
-
-
-Note, first, that this is almost identical to the application
-we built in the last section;
-the ``grok.Application``,
-its ``Traverser``,
-and the ``NaturalIndex`` are all the same —
-and you can leave alone the ``naturalindex.pt`` you wrote as well.
-
-But instead of placing a ``Traverser`` between our ``Application``
-and the actual objects we are delivering,
-we have created an actual “container”
-that follows a more fundamental protocol.
-There are a few differences
-in even this simple example.
-
-* A container is supposed to act like a Python dictionary,
-  so we have overriden the Python operation ``__getitem__``
-  instead of providing a ``traverse()`` method.
-  This means that other code using the container
-  can find objects inside of it using the ``container[key]``
-  Python dictionary syntax.
-
-* A Python ``__getitem__`` method
-  is required to raise the ``KeyError`` exception
-  when someone tries to look up a key
-  that does not exist in the container.
-  It is *not* sufficient to merely return ``None``,
-  like it was in our ``Traverser`` above,
-  because, without the exception,
-  Python will assume that the key lookup was successful
-  and that ``None`` is the value that was found!
-
-* Finally,
-  before returning an object from your container,
-  you need to call the Zope ``located()`` function
-  to make sure the object gets marked up
-  with information about where it lives on your site.
-  A Grok ``Traverser`` does this for you.
-
-Again,
-in most circumstances I can imagine,
-you will be happier just using a Traverser
-like the third example shows,
-and not incurring the slight bit of extra work
-necessary to offer a full-fledged container.
-But,
-in case you ever find yourself
-wanting to use a widget or utility
-that needs an actual container to process,
-I wanted you to have this example available.

Copied: grok/trunk/doc/minitutorials/xmlrpc.rst (from rev 85973, grok/trunk/doc/minitutorials/xmlrpc.txt)
===================================================================
--- grok/trunk/doc/minitutorials/xmlrpc.rst	                        (rev 0)
+++ grok/trunk/doc/minitutorials/xmlrpc.rst	2008-05-01 11:19:53 UTC (rev 85984)
@@ -0,0 +1,149 @@
+====================
+XML-RPC using Grok
+====================
+
+:Author: Kushal Das
+
+What is XML-RPC ?
+------------------
+
+From the site (http://xmlrpc.com): it's a spec and a set of implementations
+that allow software running on disparate operating systems, running in
+different environments to make procedure calls over the Internet.
+
+So, What is Grok?
+------------------
+
+From the site: Grok is a web application framework for Python developers. It
+is aimed at both beginners and very experienced web developers. Grok has an
+emphasis on agile development. Grok is easy and powerful.
+
+Grok accomplishes this by being based on Zope 3, an advanced object-oriented
+web framework. While Grok is based on Zope 3, and benefits a lot from it, you
+do not need to know Zope at all in order to get productive with Grok. 
+
+So, it is cool, isn't it? :)
+
+Installation
+--------------
+
+To install the latest grok, give the following command::
+
+    $ sudo easy_install grokproject
+
+This will download and install grok for you. After this we are ready to rock...
+
+Creating our first project
+-----------------------------
+
+Let's create the project named "Foo". For that give the command::
+
+    $ grokproject Foo
+
+This will create a subdirectory in the current directory named "Foo", then it
+will download Zope3 and install Grok with that which you can start working
+with. It will ask you a few questions like::
+
+    Enter module (Name of a demo Python module placed into the package) ['app.py']:
+
+Press Enter for the default value. Then::
+
+    Enter user (Name of an initial administrator user): grok
+    Enter passwd (Password for the initial administrator user): grok
+
+We typed "grok" for both the user and password.
+
+Starting up Zope
+--------------------
+
+Switch to the Foo directory, and give the command::
+
+    $ bin/zopectl fg
+
+This will startup Zope for you, you can access it through a web browser 
+pointing to http://localhost:8080/ . Then add an application named *foo*.
+
+You can access it by http://localhost:8080/foo, it will show::
+
+    Congratulations!
+
+    Your Grok application is up and running. Edit foo/app_templates/index.pt to
+    change this page.
+
+Now we are going to write our xmlrpc stuffs inside it.
+
+XML-RPC class
+-----------------
+
+Now you can open the file src/foo/app.py in a text editor. The default is
+shown below::
+
+    import grok
+
+    class Foo(grok.Application, grok.Container):
+        pass
+    
+    class Index(grok.View):
+        pass # see app_templates/index.pt
+
+We will another class which will be available through this application class,
+the new class should inherit ``grok.XMLRPC for this``, and we will write a 
+``say()`` method. It will return "Hello World!". So, the changed file::
+
+    import grok
+
+    class Foo(grok.Application, grok.Container):
+        pass
+
+    class Index(grok.View):
+        pass # see app_templates/index.pt
+
+    class FooXMLRPC(grok.XMLRPC):
+        """The methods in this class will be available as XMLRPC methods
+           on 'Foo' applications."""
+
+        def say(self):
+            return 'Hello world!'
+
+The name of the class doesn't matter, so you can give it any name.
+Restart the Zope in the console, and you can connect to it through any xmlrpc
+client. Below is an example (fooclient.py)::
+
+    #!/usr/bin/env python
+    import xmlrpclib
+    
+    s = xmlrpclib.Server('http://localhost:8080/foo')
+    print s.say()
+
+Run this and see !!
+
+Class in a different file
+---------------------------
+
+What if you want to write the class in a different file in the src/foo
+directory and still want to have the methods to be available under Foo
+application. For that you need to tell grok explicitly that the new class to
+associate it to the Foo model by using the grok.context class annotation.
+
+What is a class annotation?
+-----------------------------
+
+A class annotation is a declarative way to tell grok something about a Python
+class. Let's see the example, we write a Boom.py with a Boom class::
+
+    import grok
+    from app import Foo
+
+    class Boom(grok.XMLRPC):
+        grok.context(Foo)
+
+        def dance(self):
+            return "Boom is dancing!!"
+
+Look at the line where it says ``grok.context(Foo)`` this is doing all the
+magic. In the fooclient.py you just need to call ``s.dance()`` instead of 
+``s.say()``.
+
+So, now write your dream system...
+
+

Deleted: grok/trunk/doc/minitutorials/xmlrpc.txt
===================================================================
--- grok/trunk/doc/minitutorials/xmlrpc.txt	2008-05-01 11:19:15 UTC (rev 85983)
+++ grok/trunk/doc/minitutorials/xmlrpc.txt	2008-05-01 11:19:53 UTC (rev 85984)
@@ -1,149 +0,0 @@
-====================
-XML-RPC using Grok
-====================
-
-:Author: Kushal Das
-
-What is XML-RPC ?
-------------------
-
-From the site (http://xmlrpc.com): it's a spec and a set of implementations
-that allow software running on disparate operating systems, running in
-different environments to make procedure calls over the Internet.
-
-So, What is Grok?
-------------------
-
-From the site: Grok is a web application framework for Python developers. It
-is aimed at both beginners and very experienced web developers. Grok has an
-emphasis on agile development. Grok is easy and powerful.
-
-Grok accomplishes this by being based on Zope 3, an advanced object-oriented
-web framework. While Grok is based on Zope 3, and benefits a lot from it, you
-do not need to know Zope at all in order to get productive with Grok. 
-
-So, it is cool, isn't it? :)
-
-Installation
---------------
-
-To install the latest grok, give the following command::
-
-    $ sudo easy_install grokproject
-
-This will download and install grok for you. After this we are ready to rock...
-
-Creating our first project
------------------------------
-
-Let's create the project named "Foo". For that give the command::
-
-    $ grokproject Foo
-
-This will create a subdirectory in the current directory named "Foo", then it
-will download Zope3 and install Grok with that which you can start working
-with. It will ask you a few questions like::
-
-    Enter module (Name of a demo Python module placed into the package) ['app.py']:
-
-Press Enter for the default value. Then::
-
-    Enter user (Name of an initial administrator user): grok
-    Enter passwd (Password for the initial administrator user): grok
-
-We typed "grok" for both the user and password.
-
-Starting up Zope
---------------------
-
-Switch to the Foo directory, and give the command::
-
-    $ bin/zopectl fg
-
-This will startup Zope for you, you can access it through a web browser 
-pointing to http://localhost:8080/ . Then add an application named *foo*.
-
-You can access it by http://localhost:8080/foo, it will show::
-
-    Congratulations!
-
-    Your Grok application is up and running. Edit foo/app_templates/index.pt to
-    change this page.
-
-Now we are going to write our xmlrpc stuffs inside it.
-
-XML-RPC class
------------------
-
-Now you can open the file src/foo/app.py in a text editor. The default is
-shown below::
-
-    import grok
-
-    class Foo(grok.Application, grok.Container):
-        pass
-    
-    class Index(grok.View):
-        pass # see app_templates/index.pt
-
-We will another class which will be available through this application class,
-the new class should inherit ``grok.XMLRPC for this``, and we will write a 
-``say()`` method. It will return "Hello World!". So, the changed file::
-
-    import grok
-
-    class Foo(grok.Application, grok.Container):
-        pass
-
-    class Index(grok.View):
-        pass # see app_templates/index.pt
-
-    class FooXMLRPC(grok.XMLRPC):
-        """The methods in this class will be available as XMLRPC methods
-           on 'Foo' applications."""
-
-        def say(self):
-            return 'Hello world!'
-
-The name of the class doesn't matter, so you can give it any name.
-Restart the Zope in the console, and you can connect to it through any xmlrpc
-client. Below is an example (fooclient.py)::
-
-    #!/usr/bin/env python
-    import xmlrpclib
-    
-    s = xmlrpclib.Server('http://localhost:8080/foo')
-    print s.say()
-
-Run this and see !!
-
-Class in a different file
----------------------------
-
-What if you want to write the class in a different file in the src/foo
-directory and still want to have the methods to be available under Foo
-application. For that you need to tell grok explicitly that the new class to
-associate it to the Foo model by using the grok.context class annotation.
-
-What is a class annotation?
------------------------------
-
-A class annotation is a declarative way to tell grok something about a Python
-class. Let's see the example, we write a Boom.py with a Boom class::
-
-    import grok
-    from app import Foo
-
-    class Boom(grok.XMLRPC):
-        grok.context(Foo)
-
-        def dance(self):
-            return "Boom is dancing!!"
-
-Look at the line where it says ``grok.context(Foo)`` this is doing all the
-magic. In the fooclient.py you just need to call ``s.dance()`` instead of 
-``s.say()``.
-
-So, now write your dream system...
-
-



More information about the Checkins mailing list