Ruby has certainly won me over as far as command-line scripting is concerned, but I want to do more than that. Apart from wanting to write web apps with it (which I’ll probably discuss in a later post), I also want to use Ruby to write small, cross-platform GUI applications. So I spent a good deal of my free time last week doing just that, and found it to be at times rewarding and at times incredibly frustrating.
There’s a huge selection of GUI bindings for Ruby, allowing you to work with a wide variety of GUI toolkits. Unfortunately, most of these toolkits were intended to be used by C or C++ developers. As a result their APIs tend to be stodgy and, well, C-like, rather than Ruby-like, which is annoying since it can effectively suck the joy out of using Ruby.
That said, they’re not all bad; but none of them is all good either. Here’s a brief collection of thoughts on each of the toolkits I investigated.
The crotchety old man of cross-platform GUI toolkits. Took one look and ran away screaming. The API is a badly-documented mess, the widgets are non-native and ugly, and everyone who’s used it seems to hate it. Screw that.
I want to like FOX. Its Ruby API, provided by FXRuby, is good and well-documented, but FOX itself is a young project, and it shows. It seems to be developed primarily by one person, which is okay except that this person doesn’t have access to a Mac OS X system and thus can’t provide an OS X port. For me, this is a killer: Windows and OS X are my primary targets, followed by FreeBSD and Linux.
A very stable, very mature toolkit with a good selection of widgets. Its most appealing feature is the fact that it uses native widgets whenever possible, thus ensuring a consistent look and feel with other applications on each platform. Furthermore, wxWidgets has excellent support for all the platforms I care about.
Unfortunately, the API is very C++-oriented, and the bindings provided by wxRuby do almost nothing to make it more Rubyish. What’s more, WxRuby has no documentation aside from a virtually useless auto-generated class and function list. They seem to expect developers to use the wxWidget API reference, which is, admittedly, well-written and very complete. However, WxRuby inexplicably leaves out a surprising number of API functions and, even more inexplicably, sometimes uses function signatures and constant names that differ from those of wxWidgets, occasionally even going so far as to change the actual purpose of a function. The result is a muddled mess, even though everything seems to work well if you actually take the time to cross-reference the wxWidgets API documentation with the WxRuby source code to figure out what you should be doing.
By far the easiest to use of all the toolkits I looked at, which is due in no small part to Glade, a free UI designer that makes it a piece of pie to throw together a GTK+ GUI quickly with very little effort. The API bindings provided by Ruby-GNOME2 are excellent as well, and mostly do things in the Ruby Way™. The Ruby-GNOME2 project also provides excellent documentation and tutorials.
Unfortunately, GTK+ has its drawbacks. Windows support isn’t bad, and even uses native widgets in many places under Windows XP, but it requires a hefty set of runtime libraries. Unix support is excellent, of course, with the sad exception of—you guessed it —Mac OS X. It’s possible to run GTK+ apps in OS X using the X Windowing System, but this means your app looks inconsistent and ugly compared to the rest of the OS X interface.
To sum up, I’m frustrated. I want to like FOX, but it’s useless to me without OS X support. I think wxWidgets is superior to the others in almost every respect, except that it’s also useless to me because wxRuby is crap. And GTK+, while easy and painless and an absolute joy to use, has crappy OS X support and requires annoying runtimes on Windows.
Nevertheless, I think I’ve pretty much decided to use GTK+ for now. I’ve already developed one complete application with it (which I’ll release shortly), and I didn’t find it at all painful, especially compared to wxWidgets, which, thanks to WxRuby, makes me want to kill things.