durusmail: quixote-users: Re: Quixote namespaces/callables in practice...
Quixote namespaces/callables in practice...
Re: Quixote namespaces/callables in practice...
2003-12-11
2003-12-11
2003-12-11
Re: Quixote namespaces/callables in practice...
Graham Fawcett
2003-12-11
Stuart Hungerford wrote:
> Hi all,
>
> More newbie questions.  I'm trying to get a feel for the idioms
> that people use in creating real-world Quixote applications,
> especially when dealing with the design choices involved in
> mapping URL's to callables or namespaces.
>
> Suppose I plan to support this URL schema at example.org:
>
>    http://example.org/
>    http://example.org/foo
>    http://example.org/bar/baz
>    http://example.org/bar/fiz
>
> Assuming that Apache re-writing is re-writing these URLs to
> the corresponding .../cgi-bin/ URLS for the local setup.
>
> Suppose the Quixote driver script loads the module "example.web".
> Then the _q_exports instance for "example.web" could contain
> simple callables (functions or templates) to implement the
> first and second URL's
>
>     _q_exports = ["_q_index", "foo"]
>
> For the third and fourth URL's however I could add a submodule
> "example.web.bar" with callables "baz" and "fiz", OR I could
> create a class with "baz", "fiz" member functions
> (or _q_lookup())?


Right. But you must be explicit in your exports: "bar" must also be
included; importing it isn't enough. The bar module doesn't have to live
in the example.web package, but of course it's a good organizational
practice.

_q_lookup() is the exception to the _q_exports rule. But it wouldn't
make sense to just look up a static module that you could simply import
(and then export).

>
> I *think* going the class route means you must use a _q_lookup()
> function within "example.web" module to catch the "bar" component
> of the URL and return a class instance that can then be traversed?

Only if it's turly a dynamic lookup. If 'baz' and 'fiz' refer to methods
rather than to named instances (lookups), then just define 'baz' and
'fiz' as methods in your class, then add the attribute _q_exports =
['baz', 'fiz'] to your class definition.

If they refer to instances, then _q_lookup is your friend. And yes, it's
a common practice to return a class instance that can be traversed. Note
that you don't *have* to do this; you could also return any other
traversable namespace.

Personally I like to use modules instead of classes for my user
interface code, so I often use a pattern like this in my lookups:


# ---------- widgets/web/main.ptl

import my_database
import widget_ui    # a module that knows how to render a Widget

def _q_lookup(req, name):
     w = my_database.get_widget(name)
     if w:
         req.widget = w      # add the widget to the *request* namespace
         return widget_ui    # return a static module that expects this.



# ---------- widgets/web/widget_ui.ptl

...
def _q_index [html] (req):
     ...
     "the widget you have asked for is "
     req.widget.get_description()


Your mileage may indeed vary!


> Which of these approaches (or other approaches) are more quixotic?
> Do Quixote developers end up in practice relying on _q_lookup()
> heavily for traversing deep URLs, or do they favour a more 1-1
> mapping to callables?



I think there should be a rough correspondence between the breadth/depth
of your data structure and the breadth/depth of your URL space. If your
database is very hierarchical, then you'll probably end up with a deep
nesting. No matter the shape of your data, a good correspondence here
will make your app more understandable (to yourself, your users and
future maintainers of your code).



-- Graham



reply