[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