Archive for February, 2010|Monthly archive page
I’ll try to summarize what I’ve learned over the last week or so. What I was looking for was a simple way to get into this stuff, and as I discovered it’s not so simple, for a hobbyist like myself, once you combine two or three frameworks in a project. Maybe this post will help someone else in the same situation.
Python already was the choice for the server-side script. What I then needed was a way for the browser to communicate with the script. There are literally dozens of ways to do this, and the Python wiki has a good page on web programming. I also found this conversation springing from a post by the BDFL at Artima a good read, though it’s a few years old now.
I decided to keep it simple (though I still want to learn frameworks like Django, TurboGears, etcetera at some point in the future). I considered looking into using CGI with Python, but then I found web.py, a lightweight web framework, and liked it immediately.
The web.py framework can run its own basic web server or interface with others such as Apache or lighttpd. It includes a simple HTML template language that basically is just HTML + Python. It works with databases or not. In short it has all you need to get things running quickly.
OK, first let’s look at the basic project structure. Note that I’m using web.py’s templates, though this isn’t required:
Our app.py is the web.py script that controls our app. It looks like this:
import web def make_text(string): return string urls = ('/', 'tutorial') render = web.template.render('templates/') app = web.application(urls, globals()) my_form = web.form.Form( web.form.Textbox('', class_='textfield', id='textfield'), ) class tutorial: def GET(self): form = my_form() return render.tutorial(form, "Your text goes here.") def POST(self): form = my_form() form.validates() s = form.value['textfield'] return make_text(s) if __name__ == '__main__': app.run()
Other than the simple echo function defined for this tutorial, there are some critical parts to the code above, so let’s look at it more closely.
First of all web.py will map the URL to classes in the script. That’s why we have urls = (‘/’, ‘tutorial’), which says map the root URL address to what happens in the tutorial class defined later.
Second, if we’re using templates we tell web.py where to find our HTML templates with render = web.template.render(‘templates/’). The my_form creates an HTML text entry box that we’ll render later. We give it an empty string for a name simply for aesthetic reasons (otherwise you’ll see it on the HTML page).
Finally we define the tutorial class. We create the GET and POST methods ( web.py intentionally requires this)to define the behaviour of our web.py app in response to browser client requests. Looking at GET:
def GET(self): form = my_form() return render.tutorial(form, "Your text goes here.")
Defining form = my_form() gives us a copy of the form instance we created earlier. The method render.tutorial() returns a rendering of the tutorial HTML template (using the same name tutorial here in the class definition, the call, and eventually the HTML template are important here!), passing the arguments form and the text string to the template at the same time.
Now for POST:
def POST(self): form = my_form() form.validates() s = form.value['textfield'] return make_text(s)
Again using a copy of the form instance, we automatically validate it (simply because I haven’t learned how to validate forms yet!). We can then access the value of our textfield box with form.value['textfield'], and send it to our echo function defined earlier.
That’s all you need in the app.py, now to look at the HTML template (located in the templates directory):
(we’ll see how WP handles the syntax styling with that…)
There’s a little more going on here so let’s take it one step at a time.
In a web.py template the first line of the file defines what data is passed to the template by web.py. So here we have $def with (form, text), which as you’ll recall parallels the call we made in the GET method above. So when a client requests this page, those arguments are passed along.
It’s actually pretty simple. All this does is send what’s in the textfield box to the server when the button is clicked. If the action is successful (i.e. the server accepts the input data and returns it OK), jQuery replaces what’s in the foo element with the data returned. This uses the ajax() function — so the page doesn’t reload (it’s not really AJAX as you may realize, since there’s no XML exchanged — that’s OK, I don’t like XML anyway! )
I’ll point out some conventions that a beginner should know. Saying “.button” just refers to the element with the button class (defined in our app.py script, look above). Saying “input#textfield” refers to the input element with the CSS id of textfield (also defined in app.py).
The success function passed through ajax() is called if the action is successful; the part with hide() and then fadeIn() is just a prettier way of displaying the new text on the HTML page (otherwise, it just replaces it with no transition effect).
Lastly, returning false prevents the page from reloading.
Moving on to the body of the HTML page:
<body> <br> <form class="form" method="post"> $:form.render() <input class="button" type="submit" value="send"/> </form> <br><br> <span id="foo">$text</span> </body>
All we do here is enclose a rendering of the textfield and button in form tags. This isn’t totally necessary, but as I discovered, without the form tags pressing return in the textfield box doesn’t activate the button (i.e. you have to click on the button). Apparently you can process keyboard events with jQuery but this seemed simpler.
An additional note about $ is that you need to use $: if the expression will contain some HTML that you don’t want escaped, as we do with $:form.render.
The foo span element is just a basic container that the jQuery function can replace with the new text.
There are some obvious improvements to be made here. First of all there’s nothing stopping the user from clicking the button multiple times and sending multiple POST requests (probably not a desirable situation). There also isn’t any user session setup or form validation. In any case these things are next in my list to learn, but my experience with web.py and jQuery has been great so far. I’m looking forward to more!
Also, the documentation for web.py and jQuery are good, so check those out for more information on their APIs.
I’d like to thank the members of the web.py mailing list, particularly Branko Vukelić, for their feedback on an earlier draft of this post. Naturally all errors are (most definitely) my own.
If you’d like a zipped copy of the files in this tutorial, you can get it here. Run app.py and then point your browser to http://localhost:8080 (on Windows; use the appropriate address for your setup).
maybe this is too dumb? Oh well.
egrep ‘ing.$’ sonnets.txt
O! how thy worth with manners may I sing,
What can mine own praise to mine own self bring?
Farewell! thou art too dear for my possessing,
The charter of thy worth gives thee releasing;
For how do I hold thee but by thy granting?
And for that riches where is my deserving?
The cause of this fair gift in me is wanting,
And so my patent back again is swerving.
Thy self thou gav’st, thy own worth then not knowing,
Or me to whom thou gav’st it, else mistaking;
So thy great gift, upon misprision growing,
Comes home again, on better judgement making.
From you have I been absent in the spring,
Hath put a spirit of youth in every thing,
My love is strengthen’d, though more weak in seeming;
That love is merchandiz’d, whose rich esteeming,
Our love was new, and then but in the spring,
As Philomel in summer’s front doth sing,
Of this our time, all you prefiguring;
They had not skill enough your worth to sing:
O! ’tis the first, ’tis flattery in my seeing,
To bitter sauces did I frame my feeding;
To be diseas’d, ere that there was true needing.
The Spring class started recently. Though I make it a habit to browse the UW and Hugo House class schedules for any similar kind of course (on the craft and practice of elit), I’ve never found one, so though I’m a little behind I’ve decided to follow along with this one as best I can. There’s some great material in the syllabus and the class notes. From the first class:
This is just to grep. Use a combination of the UNIX commands discussed in class (along with any other commands that you discover) to compose a text. Your “source code” for this exercise will simply consist of what you executed on the command line. Indicate what kind of source text the “program” expects, and give an example of what text it generates. Use man to discover command line options that you might not have known about (grep -i is a good one).
[matingball ~/rwet]$ grep you | tr . \\n | sort This is just to grep. Use a combination of the UNIX commands discussed in class (along with any other commands that you discover) to compose a text. Your “source code” for this exercise will simply consist of what you executed on the command line. Indicate what kind of source text the “program” expects, and give an example of what text it generates. Use man to discover command line options that you might not have known about (grep -i is a good one). ^D Indicate what kind of source text the “program” expects, and give an example of what text it generates Use a combination of the UNIX commands discussed in class (along with any other commands that you discover) to compose a text Use man to discover command line options that you might not have known about (grep -i is a good one) Your “source code” for this exercise will simply consist of what you executed on the command line This is just to grep [matingball ~/rwet]$
Physical therapy. Take a text on paper–a newspaper, a restaurant menu, a book, whatever–and perform a transformation on it equivalent to the way one of the UNIX text commands we discussed transforms digital text. For example, to grep a book, you might highlight or cut out all of the lines in the book that match a particular string.
Of course purists will say, ‘playing text games in the web browser’. Only in the last year or two have web clients for muds and interactive fiction really started to gain momentum. As far as I can tell there hasn’t been a single source that attempts to note them all in one place, so that’s what I’ll try to do here. I’ll treat IF and muds separately (though in many ways the use case isn’t that different).
Traditionally IF in the browser used java applets or java web start. Zplet and Zag are java interpreters for the z-machine and glulx, respectively, the former using applets and the latter web start. ZMPP is in this category as well.
While web start launches a new window, applets typically run within the browser window. For example, Jetty, a TADS 2 applet, looks like this:
But you also can style applets how you like within the page; for example, contrast the above with this game:
Of special note is that the IFDB offers plugins so that it’ll start a game automatically (using an interpreter on your local computer). In essence this is like using Java web start, but with a much greater variety of game formats available.
The IFDB is not only the IF site where you can play games; the IFwiki has a good list of sites with various web-based interpreters.
A lesser known z-machine/glulx interpreter is iffy. It’s a CGI application, so it needs a web host to run from (rather than running completely on the player’s computer).
To be honest, though, all of this is a lead up for the new generation of IF interpreters, the standard bearer of which is the z-machine’s Parchment.
The Parchment development site links to instructions on how an author can get their game running. Because Parchment uses the Google app engine, all the author needs to do is put their game file on a publically accessible computer somewhere. Of course, an author can download the Parchment package to their own host as well.
Parchment isn’t the only representative of this new breed of interpreters. Quixe is a work in progress to emulate Parchment for glulx games (not yet released). Leaflet was developed by Jay Is Games for playing IF at their site. Another Flash z-code interpreter is Flaxo.
Other interpreters in this class include ifrotz, written in Ruby and C:
As well as SilverGlulxe, a glulx interpreter in Silverlight:
Of special note here is Guncho, essentially a mud server written with Inform 7. As a mud server, you can connect to it with mud clients. Guncho hosts a java client on its homepage, and these work a lot like the applet and web start interpreters shown above.
Well, since I’m talking about mud servers, that’s our bridge to jump over to…
Web clients for muds got their start with the java applets and java web start clients just mentioned. Since many of these were made for specific games, and were an attempt in some way to compete with native clients (such as mushclient, Zmud, and so on), they often look a little fancier than comparable IF interpreters.
Also due to the server-based nature of muds, they more often have employed socket-based Flash clients for players;
That’s a souped up example of Fmud, available for free (but not open source) from the developer. Fmud is not the only Flash mud client out there, but it’s simply harder to track down these clients (compared to IF clients), and Fmud is probably the most feature complete and polished one you’ll find. Of note is Soiled, a haXe client (which compiles to Flash).
There are also generic telnet clients such as anyterm that use AJAX. I even found a Firefox plugin to do a similar thing (though I couldn’t get that to work for muds very well — I think it was designed for BBSes).
The PHuDBase client is a very new php-based platform (which currently requires Google Chrome to try out).
This represents my current knowledge of what’s available; with a little more digging I know I can find more clients particular to specific muds, but I don’t think they progress beyond the examples shown here. Any other references are of course very welcome.
One topic I haven’t touched here is hypertext, web-based gamebooks and CYOA, boutique systems such as Twine and Twee, or the range of digital poetry and literature ‘playable’ in the browser. There obviously is a lot more to talk about when talking about ‘playing text games on the web’, and something I’d like to get to in future posts. I feel that all of these genres could learn something from the technology that each presents itself with.
I found a neat little site for game development in Python, PyedPyers. Apparently it’s been around for more than a year (and this is the first time I’ve heard of it). The neat thing about it is it has some additional resources besides just a forum, such as a spot to host projects. It’s rather small at the moment and very quiet, but perhaps with a core group of some active people there some interesting stuff could happen. Check it out!