Friday, December 29, 2006

Smalltalk Cleverness Translated Into Ruby

So a couple days ago I discovered something in Seaside which I thought was the coolest thing ever, and I went into Gmail to post to the Ruby-Talk mailing list to see if it was possible in Ruby as well. But midway through, I thought, wait, this would make a great Ruby Quiz, so I sent it to James Gray (he of Ruby Quiz fame) as a submission. And the challenge was, do this in Ruby.

Unfortunately James was forced to crush my ego with his overwhelmingly superior Ruby-fu, but I imagine he has to do this all the time. He answered the challenge himself and proved it was easy:

classes = Hash.new
ObjectSpace.each_object { |obj| classes[obj] = true if obj.is_a? Class }
p classes.keys


This will return a list of all classes active in Ruby -- core language, gems you've loaded, models or controllers or what have you built in Rails, anything which is now part of the object space. Hence the name, ObjectSpace.

Now, obviously, this is way too easy to be a Ruby Quiz. All it tests is your knowledge of the existence of ObjectSpace. However, just for the fun of it, the Seaside component I was originally so ga-ga about, it didn't just do that. In Smalltalk, that's two words: Smalltalk allClasses. (Of course in English it's four words, but whatever.) What had me so stoked about the Seaside version was that it puts this facility in a text field linked to a Scriptaculous Ajax.Autocompleter, so you can easily get access to your Smalltalk (and Seaside, etc.) classes just by typing their names, or the closest approximations you happen to remember at any particular moment.

So, how much extra work would it take to supply this kind of functionality in Rails?

Just to contextualize, Seaside is actually an acronym -- something like "Smalltalk Enterprise Application Server Integrated Development Environment." I don't think that's 100% accurate, in fact I think it's way off, but I am pretty sure I got the last three letters right. Developing in Seaside is pretty weird for me, because I'm a vi guy at heart, and Seaside actually turns your web application into an IDE for itself, which takes some getting used to. And this of course is why it has a nifty autocompleter for reflection like that. Because it gives you a context where you'd actually need one.

To supply all this extra functionality in Rails -- to turn Rails into an IDE for itself -- well, I imagine that would take tons of work. It'd certainly take a serious chunk out of my quality time. But this particular slice of functionality? Easy.

First you limp to the side like your legs was broken
Shaking and twitching kinda like you've been smoking
Crazy wack funky
People say, "You look like MC Hammer on crack, Humpty!"

Whoops.

That was the set of instructions for another task.

Mmmmmmmm caffeine. Maybe I'll write a tutorial for that task one day, but in the meantime, let's get back to the point.

First you set up a Rails app. Just for fun, use the Rails 1.2 release candidate.

The controller code is easy. Unfortunately, due to some problem within Blogger, and my own laziness in upgrading, posting code samples inline is essentially impossible (except maybe with iframes). I sure hope Blogger is reading this, I was really happy til I tried to paste the code in. I just edited out some seriously irate abuse againt Blogger. I am other than a passionate user at this particular moment.

Anyway, the incredibly easy controller code is behind this link.

It's just James' code, plus something in the controller to filter (case-insensitive) according to whatever the user's search parameter was.

Unfortunately, though, the dynamic dropdown is a little more work. You have to do it by hand. If you've worked on this kind of thing before, or if you've read Chad Fowler's book Rails Recipes, you know that Rails has a one-line solution for this sort of thing -- and that the standard Rails one-line solution only works if you're making a dropdown which corresponds to some attribute of every instance of some Rails model. Now we could do it that way, but only if we salted every class name in the database, which would be pretty ridiculous, and also cost us the dynamicity which is the whole point of the exercise.

So we have to resort to a slightly more involved implementation, with (*shudder*) hand-written JavaScript! (Gasp!)

So you make a view called index.rhtml. (Linky linky.)

(And yes, if we're resorting to handwritten JavaScript, we might as well use handwritten HTML too.)

"But what about that partial?" you say.

We do indeed need code for the partial, but since it's just rendering the list returned for the dropdown, it's pretty basic.

And there you have it. That's the whole thing. Of course using "klass" rather than "class" is pretty vital, otherwise you're using the built-in Ruby method class and you get all kinds of weird errors. Other than that, though, pretty straight forward.

At this point, all you need to do is fire up Mongrel and view it in a browser. By the way, if you followed my advice and used the Rails 1.2 release candidate, you now have an automated way to familiarize yourself with the new classes in that code base. Pretty cool, right? Fun toy. Are you wondering where in that code base the new ActiveResource stuff lives? Just type in "resource" and see what comes back. Wanna see what's new in ActiveSupport? Pretty easy to do.

So, although this isn't the vitally useful technology in Rails that it is in Seaside, it's still a very fun little widget.

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hey Giles, I sent you an email with a quick solution that lets you use auto_complete_for.

    ReplyDelete
  3. Pat, the solution's awesome, I have a thing on my whiteboard that says "Pat Maddox Solution." Hoping to blog it tomorrow.

    ReplyDelete

Note: Only a member of this blog may post a comment.