| « Psst...CrackAJAX is in SVN. | Getting ready for Subway 0.2 » |
Subway's new Ajax framework
As many of the #cherrypy regulars know, I've been developing a top-secret Ajax framework code-named CrackAJAX, which will soon be integrated into Subway. Though it's not quite ready for a release, I will show you a quick teaser of its current functionality, and some of the motivation behind developing it.
I hate Ajax. It's a silly name, and it's bad technology. JavaScript is a horrid language to develop in, and the destandardized DOM that exists in the current browser market makes maintenance a nightmare. HTTP wasn't designed to support this sort of thing, and Ajax breaks URLs and the back button.
But it's a cool idea, and the functionality is great.
Well, there wasn't much I could do to fix the latter problems, but I figured, what if I could write an Ajax application in Python? I set out to work, and came up with CrackAJAX, which uses the jsolait JavaScript library.
CrackAJAX is based around the concept of an AjaxPage, an HTML page that is "ajaxified." In its current incarnation, you can write the HTML code right in the docstring, or pass it a callable template rendering method. You extend the AjaxPage class, add your markup, and then add special methods. These special methods are decorated as either @clientside or @serverside, depending on where you want them to be run. @clientside methods translate the Python source code of the method to client-side JavaScript, and @serverside methods automatically generate an XML-RPC call to the server. You can call these seamlessly from your DHTML handlers, just like regular JavaScript.
It's quite a joy to develop with, actually. I built an Ajax application that emulates iTunes' search functionality. Granted, the JavaScript loops are a bit dicey, but look how slick this is:
import crackajax
import cherrypy
import ituneslib
class iTunesAjaxPage(crackajax.AjaxPage):
"""
<html>
<head>
$crackajax
<title>CrackAJAX iTunes Example</title>
</head>
<body onload="load_list()">
Welcome to the CrackAJAX iTunes example. This search system is similar to
the iTunes search mechanism; just start typing characters to limit your search.
This application is pulling data directly from a "Library.xml" file located
in the current working directory.
<form>
<b>Search:</b> <input type="text" id="searchbox" onkeyup="do_search()" />
</form>
<ul id="songlist">
</ul>
</body>
</html>
"""
def __init__(self, lib, *args, **kwargs):
crackajax.AjaxPage.__init__(self, *args, **kwargs)
self.SONGS = []
lib.load()
try:
while True:
track_info = lib.getTrack()
if track_info:
self.SONGS.append(track_info.get("Artist", "(no artist)") + " - " + track_info.get("Name", "(no name)"))
except EOFError:
pass
@crackajax.clientside
def load_list():
update_list(get_all_songs())
@crackajax.clientside
def update_list(songs):
the_song_list = document.getElementById("songlist")
while true:
if the_song_list.childNodes.length == 0:
break
the_song_list.removeChild(the_song_list.childNodes[0])
c = songs.length
if c > 0:
i = 0
while true:
song = songs[i]
newitem = document.createElement("li")
newitem.appendChild(document.createTextNode(song))
the_song_list.appendChild(newitem)
i = i + 1
if i >= c:
break
@crackajax.clientside
def do_search():
update_list(search_songs(document.getElementById("searchbox").value))
@crackajax.serverside
def get_all_songs(self):
return [self.SONGS]
@crackajax.serverside
def search_songs(self, query):
query = query.lower()
return [filter(lambda s: self.does_song_match(query, s), self.SONGS)]
def does_song_match(self, query, song):
song = song.lower()
words = query.split(" ")
for word in words:
if word not in song:
return False
return True
crackajax.init("jsolait")
cherrypy.root = iTunesAjaxPage(ituneslib.Library("Library.xml"), "")
cherrypy.server.start()
14 comments
a) This seems cool
b) So, when you say that you 'translate' the @clientside methods into JavaScript, what, exactly, do you mean? I'm guessing that you don't mean that you parse them and then generate equivalent JS (because, well, my god). From the code example, it looks more like you're writing something which works in python and can be trivially translated to JS (by, e.g. adding semi-colons or some such). Otherwise, you would presumably be writing:
for song in songs:
....
instead of mucking about with c and i and all that.
Yeah, what Dan said. How does this get converted into JavaScript?
It uses inspect.getsource(), mucks with the indentation a bit to make it parsable, and then parses it into ASTs. Then I plugged it into a modified version of a Python-to-JScript.NET compiler I wrote to do the translation. This has the unfortunate side effects of requiring the replication of a couple of important Python builtins, and that the for...in JavaScript loop is a lot different than Python's (hence the c and i).
I am going to fix the loops in the next revision. They suck right now.
ohh my this is good stuff,besides of the syntax i am imaging a complete map of python basic types to javascript, str, list, dict, date , datetime, bool and on top of that maybe later a translation of a usable, portable python html-dom interface to the crap w3 html-dom one.
so basically we dont ever have to write crapy javascript. The api mappings shouldnt be hard to do, but a bit tedious, and if a python function doesnt exists in javascript, its easy to create it.
Update: the for loop now works "python-style," that is, I have now done away with all of those disgusting while loops.
Sounds like a nightmare to debug....
I honestly don't get what is supposed to be so bad about javascript.
That leaves the question, where can one download crackajax?
Andreas
Um. Does this mean that the stuff in @crackajax.clientside functions isn't "real" Python? As in, it doesn't support full Python syntax, etc? If that's the case, then yuk.
Andreas, to download, see www.aminus.org/blogs/index.php/phunt/2005/10/09/psst_crackajax_is_in_svn
dude, just because Python has a nicer syntax than Javascript doesn't that it's the syntax that makes Javascript suck. Python syntax won't fix a language that's dirty in other respects.. but I'm sure you had fun coding this up! ;-)
I would agree with Peter's negative comments about AJAX, however I think that this issue revolves around people looking at AJAX methodologies supplanting traditional web pages ( in the case of CGI I would eagerly agree to this supplating ). I tend to look to AJAX related pages as great replacements for RADs. I think AJAX pages would make a great replacement for things along the lines of 4D, Filemaker, Access etc. As Google has shown, AJAX apps are a breeze to distribute and update. This alone makes me a big fan. I personally see the se two things ( the traditional web-page, and AJAX apps ) living side-by-side, perhaps literally in the case of tabbed browsing. I think CrackAJAX is certainly going in the right direction, a library,framework , etc should make your life easier by giving you LESS to learn not more in the form of Javascript, DHTML,HTML,XML,DOM etc. I really look forward to trying it out on some sample projects of my own. The itunes.py sample in SVN worked swimmingly hot off the download.
Thanks very much
Where can I find the CrackAjax library?
Thanks on forward
Nice website
This post has 2 feedbacks awaiting moderation...