From e6855bbd24a006e729bacc343660e3001cae3919 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 2 Jul 2009 10:06:34 +0000 Subject: - Added an "Extending" chapter to the narrative documentation which explains how to extend or modify an existing BFG application using another Python package and ZCML. --- docs/index.rst | 3 +- docs/narr/extending.rst | 112 +++++++++++++++++++++++++++++++++++++++++++++ docs/narr/introduction.rst | 12 ++++- docs/narr/resources.rst | 7 +++ docs/narr/views.rst | 4 +- 5 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 docs/narr/extending.rst (limited to 'docs') diff --git a/docs/index.rst b/docs/index.rst index 928ded272..b3b053c6b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -35,13 +35,14 @@ Narrative documentation in chapter form explaining how to use narr/templates narr/models narr/security - narr/resources narr/hybrid narr/vhosting narr/events narr/environment narr/unittesting narr/hooks + narr/extending + narr/resources narr/router glossary diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst new file mode 100644 index 000000000..06883031b --- /dev/null +++ b/docs/narr/extending.rst @@ -0,0 +1,112 @@ +.. _extending_chapter: + +Extending An Existing :mod:`repoze.bfg` Application +=================================================== + +If the developer of a :mod:`repoze.bfg` has obeyed certain constraints +while building the application, a third party should be able to change +the behavior of that application without touching the actual source +code that makes up the application. The behavior of a +:mod:`repoze.bfg` application that obeys these constraints can be +*extended* or *changed* without modification. + +Rules for Building An Extensible Application +-------------------------------------------- + +There's only one rule you need to obey if you want to build an +application that is extensible using :mod:`repoze.bfg`: you must not +use the ``@bfg_view`` decorator (or any other decorator meant to be +detected via the ZCML ```` directive) to associate a view with a +context. Instead, you must use :term:`ZCML` for this +purpose. :term:`ZCML` statements that belong to an application can be +"overridden" by integrators as necessary, but decorators cannot. + +If you've inherited a :mod:`repoze.bfg` application that you'd like to +extend, but which *does* use ``@bfg_view`` decorators, you'll (at +least) need to change the source code of the original application, +moving the view declarations out of the decorators and into +:term:`ZCML`. Once this is done, you should be able to extend or +modify the application like any other. + +It's also often helpful for third party application "extenders" (aka +"integrators") if you break your ZCML into separate files which do +very specific things, and include them in the application's main +``configure.zcml`` via ```` +statements. This way, an integrator can avoid including any ZCML he +does not want by including only the ZCML files which contain the +registrations he needs. + +Extending an Existing Application +--------------------------------- + +To extend or change the behavior of an existing application, the only +hard-and-fast rule is that you need to write some :term:`ZCML`, and +perhaps some implementations of the types of things you'd like to +override (such as views), which is referred to within that ZCML. + +The general pattern for extending an application looks something like this: + +- Create a new Python package. The easiest way to do this is to + create a new :mod:`repoze.bfg` application using the "paster" + template mechanism. See :ref:`creating_a_project` for more + information. + +- Install the new package into the same Python environment as the + original application (e.g. ``python setup.py develop`` or ``python + setup.py install``). + +- Change the ``configure.zcml`` in the new package to the original + :mod:`repoze.bfg` application's ``configure.zcml`` via an include + statement, e.g. ````. + +- On a line in the new package's ``configure.zcml`` file that falls + after (XML-ordering-wise) the ``include`` of the original package, + put an ``includeOverride`` statement that includes another ZCML file + within the new package (for example ````. + +- Create an ``overrides.zcml`` file within the new package. The + statements in the ``overrides.zcml`` file will override any ZCML + statements made within the original application (such as views). + +- Create Python files containing views (and other overridden elements, + such as templates) as necessary, and wire these up, either extending + or overriding the original view registrations from the base + application within the ``overrides.zcml`` file. The ZCML ```` + statements you make which *modify* behavior will usually have the + same ``for`` and ``name`` (and ``request_type`` if used) as the + original, and will be in a form like:: + + + + Views which modify the behavior of an application will usually be + cutnpaste jobs from the original application with slight tweaks. + + A similar pattern can be used to extend the application. Just + register a new view against some existing model type. + +- Change the Paste ``.ini`` file that starts up the original + application. Add a ``configure_zcml`` statement within the + application's section in the file which points at your *new* + package's ``configure.zcml`` file. See :ref:`environment_chapter` + for more information about this setting. + +Dealing With ZCML Inclusions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes it's possible to include only certain ZCML files from an +application that contain only the registrations you really need, +omitting others. But sometimes it's not. For brute force purposes, +when you're getting ``view`` or ``route`` registrations that you don't +actually want in your overridden application, it's always appropriate +to just *not include* any ZCML file from the overridden application. +Instead, just cut and paste the entire contents of the +``configure.zcml`` (and any ZCML file included by the overridden +application's ``configure.zcml``) into your own package and omit the +```` ZCML statement in the overriding package's +``configure.zcml``. + + diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index f8d066d06..53f3763a2 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -18,7 +18,9 @@ Architecture ("CA") internally, as do Zope 2, Zope 3, and :term:`Grok`. Application :mod:`repoze.bfg` developers use either :term:`ZCML` (an XML dialect, used in Zope) or decorators to perform various configuration tasks. The decorator support is provided by the -:term:`Grok` project. +:term:`Grok` project. Like Zope, :mod:`repoze.bfg` allows you to +create applications which do not need to be forked to be extended by a +third party developer. Like :term:`Pylons`, :mod:`repoze.bfg` is mostly policy-free. It makes no assertions about which database you should use, and its @@ -89,6 +91,14 @@ framework itself rather than by user code. Such a task would typically be performed by user-space decorators in other Python web frameworks. +Like Zope, but unlike :term:`Pylons` or :term:`Django`, when you build +a :mod:`repoze.bfg` application, if you obey certain constraints, the +application you produce can be reused, modified, re-integrated, or +extended by third-party developers without modification to the +original application itself. See :ref:`extending_chapter` for more +information about extending or modifying an existing :mod:`repoze.bfg` +application. + Unlike application development using Zope, application developers don't interact with the Zope Component Architecture ("CA") very much during :mod:`repoze.bfg` application development. Instead, the diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst index fb6e82de0..4a042f140 100644 --- a/docs/narr/resources.rst +++ b/docs/narr/resources.rst @@ -132,6 +132,13 @@ performing the following steps: package's ``configure.zcml`` file. See :ref:`environment_chapter` for more information about this setting. +Note that overriding resources is not the only way to extend or modify +the behavior of an existing :mod:`repoze.bfg` application. A "heavier +hammer" way to do the same thing is explained in +:ref:`extending_chapter`. The heavier hammer way allows you to +replace a :term:`view` wholesale rather than resources that might be +used by a view. + .. _resource_directive: The ``resource`` ZCML Directive diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 2b465b1d1..d68f5cd3d 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -298,7 +298,9 @@ decorator to do this work. to scan for view declarations. Also, if you use decorators, it means that other people will not be able to override your view declarations externally using ZCML: this is a common requirement if - you're developing an exensible application (e.g. a framework). + you're developing an exensible application (e.g. a framework). See + :ref:`extending_chapter` for more information about building + extensible applications. The ``bfg_view`` Decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3