[Repoze-checkins] r1379 - in repoze.lxmlgraph/trunk/docs: . step00 step01 step01/myapp

Paul Everitt paul at agendaless.com
Fri Jul 18 15:58:30 EDT 2008


Author: Paul Everitt <paul at agendaless.com>
Date: Fri Jul 18 15:58:30 2008
New Revision: 1379

Log:
Document in excruciating depth the smallest non-XML repoze.bfg application possible.

Added:
   repoze.lxmlgraph/trunk/docs/step00/
   repoze.lxmlgraph/trunk/docs/step00/simplemodel.xml
   repoze.lxmlgraph/trunk/docs/step01/
   repoze.lxmlgraph/trunk/docs/step01/myapp/
   repoze.lxmlgraph/trunk/docs/step01/myapp/__init__.py
   repoze.lxmlgraph/trunk/docs/step01/myapp/configure.zcml
   repoze.lxmlgraph/trunk/docs/step01/myapp/models.py
   repoze.lxmlgraph/trunk/docs/step01/myapp/views.py
   repoze.lxmlgraph/trunk/docs/step01/run.py
Modified:
   repoze.lxmlgraph/trunk/docs/background.rst
   repoze.lxmlgraph/trunk/docs/step01.rst

Modified: repoze.lxmlgraph/trunk/docs/background.rst
==============================================================================
--- repoze.lxmlgraph/trunk/docs/background.rst	(original)
+++ repoze.lxmlgraph/trunk/docs/background.rst	Fri Jul 18 15:58:30 2008
@@ -80,6 +80,11 @@
 And finally, I could pass in just a single node and render it, or pass
 in the entire tree with a parameter identifying the context node.
 
+In the course of this writeup, we'll build ``repoze.lxmlgraph``
+step-by-step, starting with no XML.  Each of those decisions will be
+analyzed an implemented.  At the end, you'll see both the resulting
+demo application, plus the thought process that went along with it.
+
 What It Might Do
 --------------------
 

Added: repoze.lxmlgraph/trunk/docs/step00/simplemodel.xml
==============================================================================
--- (empty file)
+++ repoze.lxmlgraph/trunk/docs/step00/simplemodel.xml	Fri Jul 18 15:58:30 2008
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<root>
+    <site>
+        <title>My XMLGRAPH Website</title>
+    </site>
+    <folder xml:id="n1" id="folder1">
+        <document xml:id="n11" id="doc1">
+            <title>doc1 in folder1</title>
+            <body>
+                <div xmlns="http://www.w3.org/1999/xhtml">
+                    <p>Welcome to the site.  We have lots to say.</p>
+                    <p>Or, <em>maybe</em> not.</p>
+                </div>
+            </body>
+        </document>
+        <document xml:id="n12" id="doc2">
+            <title>doc2 in folder1</title>
+        </document>
+    </folder>
+    <folder xml:id="n2" id="folder2">
+        <document xml:id="n21" id="doc1">
+            <title>doc1 in folder2</title>
+        </document>
+        <document xml:id="n22" id="doc2">
+            <title>doc2 in folder2</title>
+        </document>
+    </folder>
+</root>

Modified: repoze.lxmlgraph/trunk/docs/step01.rst
==============================================================================
--- repoze.lxmlgraph/trunk/docs/step01.rst	(original)
+++ repoze.lxmlgraph/trunk/docs/step01.rst	Fri Jul 18 15:58:30 2008
@@ -0,0 +1,188 @@
+================================================
+Step 01: Non-XML Hello World for ``repoze.bfg``
+================================================
+
+Before we work on implementing an XML graph, we need a simple starting
+point for a basic ``repoze.bfg`` application.  In this step we'll do
+the least amount possible to run a ``repoze.bfg`` sample application.
+
+.. note::
+
+  All steps in this writeup presume that you have a virtualenv setup
+  as shown in the Installation step.  More specifically: *make sure
+  you are using that virtualenv's Python* !!
+
+Directory Layout
+====================
+
+Each step in this writeup has a subdirectory for the working
+application described in that step.  Thus, starting at this docs
+directory, we have::
+
+  docs/
+    step01/
+      myapp/
+        __init__.py
+      	configure.zcml
+      	models.py
+      	views.py
+      run.py
+    step02/
+    step03/
+
+Below we discuss each file in the ``step01``, then show how to run and
+use the demo application.
+
+
+Directory ``myapp``
+---------------------
+
+This directory contains the *package* to be published.  That's right,
+I said *package*.  ``repoze.bfg``, as we will see in a moment, uses
+Python packages as the unit of publishing.
+
+
+Module ``myapp/__init__.py``
+------------------------------
+
+This is (usually-empty) file that makes a directory into a Python
+"package."  For ``repoze.bfg`` this is particularly important
+
+
+Module ``myapp/configure.zcml``
+--------------------------------
+
+Unlike other frameworks, ``repoze.bfg`` doesn't try to hide
+configuration.  Instead, configuration using ZCML is the central
+wiring point.  At the same time, ZCML is used in a very basic way, to
+avoid confusion it can cause.
+
+.. literalinclude:: step01/myapp/configure.zcml
+   :linenos:
+   :language: xml
+
+1) Lines 1-3 provide the root element and namespaces for the
+configuration language.  ``bfg`` is the namespace for
+``repoze.bfg``-specific configuration directives.
+
+2) Line 5 initializes those ``repoze.bfg``-specific configuration
+directives.
+
+3) Lines 8-11 register a single view for model objects that support
+the IMyModel interface.  In this case we made a default view, which
+means going to ``/a`` triggers the default view of instance ``a``.
+Finally, the ``factory`` attribute points at a Python function that
+does all the work for this view.
+
+
+Module ``myapp/models.py``
+-----------------------------
+
+In our sample app, the ``models.py`` module provides the model data.
+We create an interface ``IMyModel`` that gives us the "type system"
+for our data.  We then write a class ``MyModel`` that provides the
+behavior for instances of the ``IMyModel`` type.
+
+.. literalinclude:: step01/myapp/models.py
+   :linenos:
+
+1) Lines 5-6 define the interface.
+
+2) Lines 8-11 provide a class for that interface.
+
+3) Lines 13-15 make a small tree of sample data (``/a`` and ``/b`` for
+URLs.)
+
+4) Line 17 is a function that will be grabbed by the server when it
+wants to find the top of the model.
+
+
+Module ``myapp/views.py``
+---------------------------
+
+Much of the heavy liftin in a ``repoze.bfg`` application comes in the
+views.  These are the bridge between the content in the model, and the
+HTML given back to the browser.  Since ``repoze.bfg`` is very
+type-centric, URLs grab information of a certain type.  Once we have
+the information and its type, we can grab a view that is registered
+for that type.
+
+.. note::
+
+  This "Step 01" doesn't use a template.  The "view" we define is done
+  in Python, which generates the HTML.  Most applications will use
+  templates to generate markup.
+
+.. literalinclude:: step01/myapp/models.py
+   :linenos:
+
+1) Lines 3 provide the ``my_hello_view`` that was registered as the
+view.  ``configure.zcml``, on Line 10, said that the default URL for
+IMyModel content should run this ``my_hello_view`` function.
+
+The function is handed two pieces of information: the ``context`` and
+the ``request``.  The ``context`` is the data at the current hop in
+the URL.  (That data comes from the model.)  The request is an
+instance of a WebOb request.
+
+2) Lines 4-7 generate a WebOb Response object and return it.
+
+
+Module ``run.py``
+---------------------
+
+We need a small Python module that sets everything, fires up a web
+server, and handles incoming requests.  Later we'll see how to use a
+Paste configuration file to do this work for us.
+
+.. literalinclude:: step01/run.py
+   :linenos:
+
+1) Line 1 uses the web server from the Paste project.
+
+2) Line 3 imports the big gun from ``repoze.bfg``.
+
+3) Line 4 grabs the function that hands back the top of the
+application's model data.
+
+4) Line 5 imports the package that we want to "publish".
+
+5) Line 7 loads the big gun with the data and the package.
+
+6) And finally, line 8 starts the web server on port 5432.
+
+
+Running and Browsing the Application
+---------------------------------------
+
+We have our minimal application now in place.  We can run the
+application as follows::
+
+  cd docs/step01
+  python run.py
+
+.. note::
+
+  Just to say it AGAIN: make sure the Python you are using is the
+  Python from your virtual environment.  One way to ensure you always
+  get the right scripts is to do ``source bin/activate`` from the top
+  of your virtualenv.  This will modify your PATH to look first in the
+  virtual env.
+
+You should then see::
+
+  $ python ./run.py 
+  serving on 0.0.0.0:5432 view at http://127.0.0.1:5432
+
+If you connect in a web browser to ``http://localhost:5432/a`` you
+will see::
+
+  Hello from a @ /a
+
+This also works for ``http://localhost:5432/b``.  However, if you
+connect to ``http://localhost:5432/c`` you will get::
+
+  404 Not Found
+  The resource could not be found.
+
+  http://localhost:5432/c
\ No newline at end of file

Added: repoze.lxmlgraph/trunk/docs/step01/myapp/__init__.py
==============================================================================
--- (empty file)
+++ repoze.lxmlgraph/trunk/docs/step01/myapp/__init__.py	Fri Jul 18 15:58:30 2008
@@ -0,0 +1 @@
+#

Added: repoze.lxmlgraph/trunk/docs/step01/myapp/configure.zcml
==============================================================================
--- (empty file)
+++ repoze.lxmlgraph/trunk/docs/step01/myapp/configure.zcml	Fri Jul 18 15:58:30 2008
@@ -0,0 +1,13 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+	   xmlns:bfg="http://namespaces.repoze.org/bfg">
+
+  <!-- this must be included for the view declarations to work -->
+  <include package="repoze.bfg" />
+
+  <!-- the default view for a MyModel -->
+  <bfg:view
+     for=".models.IMyModel"
+     factory=".views.my_hello_view"
+     />
+
+</configure>

Added: repoze.lxmlgraph/trunk/docs/step01/myapp/models.py
==============================================================================
--- (empty file)
+++ repoze.lxmlgraph/trunk/docs/step01/myapp/models.py	Fri Jul 18 15:58:30 2008
@@ -0,0 +1,18 @@
+from zope.interface import implements
+from zope.interface import Attribute
+from zope.interface import Interface
+
+class IMyModel(Interface):
+    __name__ = Attribute('Name of the model instance')
+
+class MyModel(dict):
+    implements(IMyModel)
+    def __init__(self, name):
+        self.__name__ = name
+
+root = MyModel('root')
+root['a'] = MyModel('a')
+root['b'] = MyModel('b')
+
+def get_root(environ):
+    return root

Added: repoze.lxmlgraph/trunk/docs/step01/myapp/views.py
==============================================================================
--- (empty file)
+++ repoze.lxmlgraph/trunk/docs/step01/myapp/views.py	Fri Jul 18 15:58:30 2008
@@ -0,0 +1,7 @@
+from webob import Response
+
+def my_hello_view(context, request):
+    response = Response('Hello from %s @ %s' % (
+            context.__name__, 
+            request.environ['PATH_INFO']))
+    return response

Added: repoze.lxmlgraph/trunk/docs/step01/run.py
==============================================================================
--- (empty file)
+++ repoze.lxmlgraph/trunk/docs/step01/run.py	Fri Jul 18 15:58:30 2008
@@ -0,0 +1,8 @@
+from paste import httpserver
+
+from repoze.bfg import make_app
+from myapp.models import get_root
+import myapp
+
+app = make_app(get_root, myapp)
+httpserver.serve(app, host='0.0.0.0', port='5432')


More information about the Repoze-checkins mailing list