[Checkins] SVN: megrok.traject/trunk/ Support traject.Model, a more compact way to define trajects if the
Martijn Faassen
faassen at startifact.com
Mon Nov 30 08:16:43 EST 2009
Log message for revision 106115:
Support traject.Model, a more compact way to define trajects if the
developer controls the model definition.
Changed:
U megrok.traject/trunk/CHANGES.txt
U megrok.traject/trunk/README.txt
A megrok.traject/trunk/TODO.txt
U megrok.traject/trunk/src/megrok/traject/__init__.py
U megrok.traject/trunk/src/megrok/traject/components.py
A megrok.traject/trunk/src/megrok/traject/directive.py
A megrok.traject/trunk/src/megrok/traject/ftests/traject/model.py
U megrok.traject/trunk/src/megrok/traject/meta.py
-=-
Modified: megrok.traject/trunk/CHANGES.txt
===================================================================
--- megrok.traject/trunk/CHANGES.txt 2009-11-30 12:28:25 UTC (rev 106114)
+++ megrok.traject/trunk/CHANGES.txt 2009-11-30 13:16:41 UTC (rev 106115)
@@ -4,12 +4,12 @@
0.10 (unreleased)
=================
-- Nothing changed yet.
+- Support ``traject.Model``, a more compact way to define trajects if
+ the model is under the control of the developer.
-
0.9 (2009-11-16)
================
-* Initial public release.
+- Initial public release.
Modified: megrok.traject/trunk/README.txt
===================================================================
--- megrok.traject/trunk/README.txt 2009-11-30 12:28:25 UTC (rev 106114)
+++ megrok.traject/trunk/README.txt 2009-11-30 13:16:41 UTC (rev 106115)
@@ -9,23 +9,30 @@
.. _grok: http://grok.zope.org
Include ``megrok.traject`` by adding it in your Grok project's
-``setup.py`` (in ``install_requires``) and re-running buildout.
+``setup.py`` (in ``install_requires``) and re-run buildout.
+External trajects
+-----------------
+
+External trajects are most useful if you do not directly control the
+models. This may for instance be the case if the models are defined in
+an external package.
+
With ``megrok.traject`` you can declare trajects in Grok like this::
from megrok import traject
class SomeTraject(traject.Traject):
- grok.context(App)
+ grok.context(App)
- pattern = 'departments/:department_id'
- model = Department
+ pattern = 'departments/:department_id'
+ model = Department
- def factory(department_id):
- return get_department(department_id)
+ def factory(department_id):
+ return get_department(department_id)
- def arguments(department):
- return dict(department_id=department.id)
+ def arguments(department):
+ return dict(department_id=department.id)
This registers ``factory`` and the inverse ``arguments`` functions for
the pattern ``departments/:department_id``, the root ``App`` and the
@@ -38,8 +45,32 @@
You can register grok views for ``Department`` as usual.
-Tips:
+Traject models
+--------------
+If you have control over the model definitions yourself, traject
+allows a more compact notation that lets you define traject-based
+models directly::
+
+ import traject
+
+ class Department(traject.Model):
+ traject.context(App)
+ traject.pattern('departments/:department_id')
+
+ def factory(department_id):
+ return get_department(department_id)
+
+ def arguments(self):
+ return dict(department_id=self.id)
+
+Note that Traject models are not persistent in the ZODB sense. If you
+need a persistent Traject models you can mix in ``grok.Model`` or
+``persistent.Persistent``.
+
+Tips
+----
+
* return ``None`` in factory if the model cannot be found. The system
then falls back to normal traversal to look up the view. Being too
aggressive in consuming any arguments will break view traversal.
Added: megrok.traject/trunk/TODO.txt
===================================================================
--- megrok.traject/trunk/TODO.txt (rev 0)
+++ megrok.traject/trunk/TODO.txt 2009-11-30 13:16:41 UTC (rev 106115)
@@ -0,0 +1,7 @@
+TODO
+====
+
+* decorators traject.factory and traject.arguments don't do anything
+ right now. Should we support them at all?
+
+* the traject.pattern decorator doesn't work on explicit trajects.
Modified: megrok.traject/trunk/src/megrok/traject/__init__.py
===================================================================
--- megrok.traject/trunk/src/megrok/traject/__init__.py 2009-11-30 12:28:25 UTC (rev 106114)
+++ megrok.traject/trunk/src/megrok/traject/__init__.py 2009-11-30 13:16:41 UTC (rev 106115)
@@ -14,6 +14,8 @@
"""megrok.traject - URL routing for Grok
"""
-from megrok.traject.components import Traject
+from megrok.traject.components import Traject, Model
from traject import locate
+from megrok.traject.directive import pattern, factory, arguments
+from grokcore.component import context
Modified: megrok.traject/trunk/src/megrok/traject/components.py
===================================================================
--- megrok.traject/trunk/src/megrok/traject/components.py 2009-11-30 12:28:25 UTC (rev 106114)
+++ megrok.traject/trunk/src/megrok/traject/components.py 2009-11-30 13:16:41 UTC (rev 106115)
@@ -16,6 +16,7 @@
import grok
import traject
+from grokcore.component import Context
class Traject(object):
grok.baseclass()
@@ -53,3 +54,6 @@
class DefaultModel(grok.Model):
def __init__(self, **kw):
self.kw = kw
+
+class Model(Context):
+ pass
Added: megrok.traject/trunk/src/megrok/traject/directive.py
===================================================================
--- megrok.traject/trunk/src/megrok/traject/directive.py (rev 0)
+++ megrok.traject/trunk/src/megrok/traject/directive.py 2009-11-30 13:16:41 UTC (rev 106115)
@@ -0,0 +1,14 @@
+import martian
+
+class pattern(martian.Directive):
+ scope = martian.CLASS
+ store = martian.ONCE
+ validate = martian.validateText
+
+# these are dummy decorators for now
+def factory(object):
+ return object
+
+def arguments(object):
+ return object
+
Added: megrok.traject/trunk/src/megrok/traject/ftests/traject/model.py
===================================================================
--- megrok.traject/trunk/src/megrok/traject/ftests/traject/model.py (rev 0)
+++ megrok.traject/trunk/src/megrok/traject/ftests/traject/model.py 2009-11-30 13:16:41 UTC (rev 106115)
@@ -0,0 +1,83 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+We create an app:
+
+ >>> getRootFolder()["app"] = app = App()
+
+We set up a test browser:
+
+ >>> from zope.testbrowser.testing import Browser
+ >>> browser = Browser()
+ >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+ >>> browser.handleErrors = False
+
+We we traverse from the app URL, we expect things to happen::
+
+ >>> browser.open("http://localhost/app/mammoths/Knuth")
+ >>> print browser.contents
+ The name of this mammoth is Knuth.
+
+We can also go to another view::
+
+ >>> browser.open("http://localhost/app/mammoths/Knuth/other")
+ >>> print browser.contents
+ This is indeed Knuth
+
+We can also locate a mammoth::
+
+ >>> mammoth = Mammoth('Dijkstra')
+ >>> class Default(object):
+ ... def __init__(self, *args, **kw):
+ ... pass
+ >>> traject.locate(app, mammoth, Default)
+ >>> mammoth.__name__
+ u'Dijkstra'
+ >>> mammoth.__parent__
+ <megrok.traject.ftests.traject.model.Default object at ...>
+
+"""
+
+import grok
+
+from megrok import traject
+
+class App(grok.Application, grok.Model):
+ pass
+
+class Mammoth(traject.Model):
+ traject.context(App)
+ traject.pattern('mammoths/:name')
+
+ def __init__(self, name):
+ self.name = name
+
+ def factory(name):
+ return Mammoth(name)
+
+ def arguments(self):
+ return dict(name=self.name)
+
+class MammothIndex(grok.View):
+ grok.context(Mammoth)
+ grok.name('index')
+ def render(self):
+ return 'The name of this mammoth is %s.' % self.context.name
+
+class MammothOther(grok.View):
+ grok.context(Mammoth)
+ grok.name('other')
+ def render(self):
+ return "This is indeed %s" % self.context.name
Modified: megrok.traject/trunk/src/megrok/traject/meta.py
===================================================================
--- megrok.traject/trunk/src/megrok/traject/meta.py 2009-11-30 12:28:25 UTC (rev 106114)
+++ megrok.traject/trunk/src/megrok/traject/meta.py 2009-11-30 13:16:41 UTC (rev 106115)
@@ -1,6 +1,6 @@
import traject
import martian
-from megrok.traject import components
+from megrok.traject import components, directive
import grokcore.component
from zope import component
from zope.publisher.interfaces.browser import (IBrowserPublisher)
@@ -17,26 +17,47 @@
factory_func = factory.factory.im_func
arguments_func = factory.arguments.im_func
- # register
- config.action(
- discriminator=('traject.register', context, pattern_str),
- callable=traject.register,
- args=(context, pattern_str, factory_func),
- )
+ _register_traject(config, context, pattern_str, model,
+ factory_func, arguments_func)
+ return True
+
+class ModelGrokker(martian.ClassGrokker):
+ martian.component(components.Model)
- # register_inverse
- config.action(
- discriminator=('traject.register_inverse', context, model,
- pattern_str),
- callable=traject.register_inverse,
- args=(context, model, pattern_str, arguments_func))
+ martian.directive(grokcore.component.context)
+ martian.directive(directive.pattern)
+
+ def execute(self, factory, config, context, pattern, **kw):
+ pattern_str = pattern
+ model = factory
+ factory_func = factory.factory.im_func
+ arguments_func = factory.arguments.im_func
- # register traverser on context; overwrite previous as they're
- # all the same
- config.action(
- discriminator=object(), # we always want a different discriminator
- callable=component.provideAdapter,
- args=(components.TrajectTraverser, (context, IHTTPRequest),
- IBrowserPublisher),
- )
+ _register_traject(config, context, pattern_str, model,
+ factory_func, arguments_func)
return True
+
+def _register_traject(config, context,
+ pattern_str, model, factory_func, arguments_func):
+ # register
+ config.action(
+ discriminator=('traject.register', context, pattern_str),
+ callable=traject.register,
+ args=(context, pattern_str, factory_func),
+ )
+
+ # register_inverse
+ config.action(
+ discriminator=('traject.register_inverse', context, model,
+ pattern_str),
+ callable=traject.register_inverse,
+ args=(context, model, pattern_str, arguments_func))
+
+ # register traverser on context; overwrite previous as they're
+ # all the same
+ config.action(
+ discriminator=object(), # we always want a different discriminator
+ callable=component.provideAdapter,
+ args=(components.TrajectTraverser, (context, IHTTPRequest),
+ IBrowserPublisher),
+ )
More information about the checkins
mailing list