Chris McDonough wrote:
...
>> On the other hand, I do understand some motivation for this for 
>> creating eclectic URL layouts.  But I wonder if there's a better way?  
>> In particular, make sure that writing routing code isn't hard, so that 
>> custom code for different site layouts is easy.  There are at least 
>> two modest methods in WebOb for this -- req.path_info_peek() and 
>> req.path_info_pop(), which both get the next segment of the URL.  
>> Along with req.urlvars (and req.urlargs) there's a way to save the 
>> captured data without having to instantly inspect the model (unless 
>> you want to inspect the model).  And domain names can be just as valid 
>> a thing to parse, and don't really fit any traversal pattern.
> 
> That blew my stack, sorry.

Well, maybe an example where graph traversal seems easier is something 
like a filesystem (or ZODB filesystemish system) with verbs at the end. 
  E.g., /path/to/file.txt/view, /path/to/file.txt/edit, etc.  You could 
do something like:

def route_fs(req):
     path, verb = req.path_info.rsplit('/', 1)[-1]
     if not verb:
         verb = 'index'
     obj = File(path)
     return getattr(obj, verb)(req)

Though I think even better would be something like:

def route_fs(req):
     fs = Filesystem()
     while 1:
         segment = req.path_info_peek()
         if segment is None:
             return fs.view()
         elif segment == '': # trailing /
             return fs.index()
         else:
             try:
                 fs = fs[segment]
             except KeyError:
                 return fs(req)
             else:
                 req.path_info_pop()

And maybe that's more complicated than simple traversal, I don't know. 
One thing I was thinking about as a general idea was to look for 
.wsgi_application on objects, and use that.  Then traversable objects 
might look like:

class Filesystem(object):
     def __init__(self, path):
         self.path = path
     wsgi_application = TraverseGetitem('index')
     @wsgiapp
     def index(req):
         ...
         return resp
     def __getitem__(self, segment):
         return self.__class__(os.path.join(self.path, segment))

class TraverseGetitem(object):
     def __init__(self, index_meth=None):
         self.index_meth = index_meth
     def __get__(self, obj, type=None):
         if obj is None:
             return self
         def app(environ, start_response):
             req = Request(environ)
             next = req.path_info_peek()
             if next:
                 try:
                     next = obj[next]
                 except KeyError:
                     next = None
                 else:
                     req.path_info_pop()
             else:
                 next = None
             if next is None:
                 next = self.index_meth
                 if isinstance(next, basestring):
                     next = getattr(obj, next)
                 if hasattr(next, '__get__'):
                     next = next.__get__(obj)
             if hasattr(next, 'wsgi_application'):
                 next = next.wsgi_application
             return next(environ, start_response)
          return app


>> So I'd be interested in use cases people have where Routes alone isn't 
>> enough.  I'm sure these exist (I could come up with a few), but I'm 
>> also pretty sure there's other solutions than object publishing.
>>
>>>   - Its equivalent of the publisher doesn't attempt to traverse into
>>>     *code* stored in the object graph.  All code is on the filesystem.
>>>     The only thing in the object graph is "model" data.
>>
>> How do you deal with distinguishing between model instantiation data, 
>> and traversal of the models themselves?  E.g., /archive/2008/06/ -- 
>> /archive probably points to an Archive class or an instance 
>> (singleton?) of ArchiveManager or something.  /2008 and /06 probably 
>> translate to datetime(2008, 6) or something along those lines, which 
>> provide the arguments to instantiate an Archive object, and then you 
>> call some default method like index or __call__. 
> 
> It's simpler than that.  We are always traversing model instances.  We 
> just call __geitem__ the whole way through the model graph until we 
> either exhaust the path or find an item that doesnt have a __getitem__ 
> or whose __getitem__ raises a KeyError.  The "next" name becomes the 
> view name.  Any leftover path elements become a "subpath".  It really is 
> just block and tackle graph traversal of data, there's nothing tricky 
> going on.

The views are code, yes?  How are view names mapped to code?  Presumably 
you can have a URL ".../view" where the actual function called depends 
on the type of object you traversed to.  The examples don't make this clear.


-- 
Ian Bicking : [EMAIL PROTECTED] : http://blog.ianbicking.org
_______________________________________________
Repoze-dev mailing list
Repoze-dev@lists.repoze.org
http://lists.repoze.org/listinfo/repoze-dev

Reply via email to