I've spent most of today hacking python. The target has been to exploit the
possiblity of REST in a non-web programming envioronment. I chose to target
a
glade
replacement built from REST principles.
Glade is a useful bare bones tool for constructing widget trees that can
be embedded into software as generated source code or read on the fly by
libglade. Python interfaces are available for libglade and gtk, but there are
a few things I wanted to resolve and improve.
- The event handling model, and
- The XML schema
The XML schema is bleugh. Awfully verbose and not much use. It is full of
elements like "widget" and "child" and "parameter" that don't mean anything,
leaving the real semantic stuff as magic constant values in various attribute
fields. In my prototype I've collapsed each parameter into an attribute of its
parent, and made all elements either widgets or event handling objects.
The real focus of my attention, though, was the event handling. Currently
gtk widgets can emit certain notifications, and it is possible to register with
the objects to have your own functions called when the associated event goes
off. Because a function call is the only way to interact with these signals,
you immediately have to start writing code for potentially trivial
applications. I wanted to reduce the complexity of this first line of event
handling so much that it could be included into the glade file instead. I
wanted to reduce the complexity to a set of GET, and PUT operations.
I've defined my only event handler for the prototype application with
four fields:
- The name of the event to use as a trigger (I use the position of the Event
element to determine which object to associate the event with)
- The method to use, typically PUT
- The url to send the PUT to
- The url to get data from as content to the PUT
To make this URL-heavy approach to interface design useful, I put in place
a few schemes for internal use in the application. The "literal:" scheme just
returns the percent-decoded data of its path component. It can't be PUT to.
The "object:" scheme is handled by a resolver that allows objects to register
with it by name. Once a parent has been identified, attributes of the parent
can be burrowed into by adding path segments.
The prototype example was a simple one. I create a gtk window with a label
in it. The label initially reads "Hello, world". On a mouse click, it becomes
"Goodbye, world". It's not going to win any awards for oringinality, but it
demonstrates a program that can be entirely defined in terms of generic
URI-handling and XML loading code and an XML file that contains the program
data. An abbreviated version of the XML file I used looks like this:
<gtk.Window id="window1">
<gtk.Label id="label1" label="literal:Hello,%20world">
<Event
name="button_press_event"
url="object:/label1/label"
verb="PUT"
data="literal:Goodbye,%20world"
/>
</gtk.Label>
</gtk.Window>
You can see that the literal URI schem handling is a little clunky, and
needs to have some unicode issues thought out. The Event node is triggered
by a button_press_event on label1, and sends the literal "Goodbye, world"
to lable1's own "label" attribute. You can see some of the potential power
emerging already, though. If you changed either the initial label url to
data extracte from a database or from http we have immediately developed
not a static snapshot in this file but a dynamic beast. The data in our
event handler could refer to an object or XML file that had been built up
XForms-style via other event interactions. It is possible that even quite
sophisticated applications could be written in this way as combinations of
queries and updates to a generic store. Only geniunely complicated interactions
would need to be modelled in code, and that code would not be clouded by
the needless complexity of widget event handling.
It is my theory that if REST works at all, it will work in this kind of
programming environment as well as it could on the web. I'm not trying to
preclude the use of other languages or methods for controlling the logic
of a single window's behaviour, but I am hoping to clearly define the level
of complexity you can apply through a glade-like editor. I think it needs to
be higher than it is presently to be really productive, but I don't think
it should become a software IDE in itself.
All in all my prototype came to 251 lines of python, including whitespace
and very minimal comments. That includes code for the event handler (12 lines),
a gtk object loader (54 lines, and generic python object actually), and URI
resolution classes including http support through urllib2. The object resolver
is the largest file, weighing in at 109 lines. It is made slightly more complex
by having to deal with pygtk's use of setters and getters as well as the more
generic python approaches to attribute assignment.
My example was trivial, but I do think that this kind of approach could
be considerably more powerful than that of existing glade. The real test
(either of the method or of gtk's design) will probably come in list and
tree handling code. This will be especially true where column data comes
from a dynamic source such as an sqlite database. I do anticpate some tree
problems, where current even handlers often need to pass strange contexts
around in order to correctly place popup windows. It may come together, though.
Benajamin