[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