On Jun 13, 2011, at 6:30 PM, Laurens Van Houtven wrote:

> On Mon, Jun 13, 2011 at 3:38 PM, <exar...@twistedmatrix.com> wrote:
> Another thing we want is something closer to locateChild as Nevow and
> web2 had.  The key feature is being able to consume multiple path
> segments (or none at all) at a time if desired.
> 
> Jean-Paul
> 
> I added it to the ticket.
> 
> Someone on IRC mentioned that locateChild isn't exactly perfect either -- how 
> does it differ from the idealized API? 
> 
> For the people who hadn't seen locateChild before (much like myself) -- the 
> main difference is that instead of just taking the *next* segment, it takes 
> all of the remaining ones, and instead of returning a single child, it 
> returns a child and the remaining segments. A possible problem with this is 
> that people might get the impression they should mess with the segments... 
> Comments welcome.

Yeah, messing with segments is an issue.  There's a thing that some Nevow 
applications would do which, while I'm not entirely sure it was a terrible 
idea, definitely exposed a weakness in this model.  We called it an "internal 
redirect".  The basic idea is that your resource gets called with "request, [a, 
b, c]" and you return "resource, [d, e, f]".  The problem with allowing this is 
that it decouples the resource from any sane way to identify its URL based on 
the request.  It's handy to have something like the 'prepath' attribute to 
assist in generating absolute URIs that can be passed to external systems, but 
you can't make that consistent in the face of code that arbitrarily manipulates 
the segments list.

Also, you can internally redirect this way based on path-based dispatch but you 
can't redirect based on hostname or other features of the request without 
mutating it.  So it seemed like a lopsided half-feature.

One off-the-cuff idea to address this would be to have a 'path' object with an 
API of its own; something like this:

def locateDescendant(self, request, path):
    year, month, day = path.consume(3)
    rsrc = self.resourceFromDate(year, month, day)
    return rsrc

.consume(integer) is something of a strawman here; you'd probably need a way to 
say stuff like "consume all of the path segments" or "consume everything up to 
a segment with the value 'x'", so that we didn't lose the (legitimate) 
flexibility of having a list.  We could of course just pass in a mutable list 
and not return it, but that provides a little more flexibility than I'd like, 
because it would allow you to do all the same stuff as returning your own 
arbitrary sequence.

Really this 'path' is actually cursor over the URI inside the request.  It 
would be nice if the state associated with traversal were encapsulated entirely 
in that object, so that the request itself didn't get mutated as it traveled 
down the path.

> I'm also not sure if it should be allowed to return an IResource (and 
> basically use the IResource getChild behavior whenever you see an 
> IResource...) or if it should only return the new things.

One return-type signature is a good idea.  Convenience APIs are better.  That 
said, if we do go with 2-tuple as the return type, good error reporting is 
crucial; it's very easy to accidentally return a resource.

> Perhaps there could be an adapter: if entity.locateChild([a, b, c]) returns a 
> (resource, [b, c]), the resource is adapted to IEntity (working title for 
> I2NewResource2), and the adapter's .locateChild([b, c]) call gets translated 
> into self.wrappedResource.getChild(b).getChild(c), or something.

That seems sensible.


_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to