IMified: on the vanguard of human-computer interaction!

A colleague sent me a message titled “IM as the new command line”. It was a link to IMified, an single instant-messaging gateway to things like to-dos, reminders, stock quotes and, through an API for creating other gateways, numerous third-party sites like Google Calendar, Basecamp, Twitter and stuff.

The UI has some web aspects, as for the directory of available widgets, creation of custom shortcuts and so on. But the main interface, the one in IM?

Numbered menus.

With “B” to go “back” to the previous menu and “M” to go back to the main menu.

That’s right:

1981 all overĀ again.

It’s Compuserve, circa 1981, down to typing “M” to go to the main menu!

No Sam Goody online store offering vinyl and cassettes yet, and they do have lowercase support, which is very fancy.

I do think it’s a coincidence, though. If they really were ripping off Compuserve, each service would have a predefined keyword you could use to access it directly, like “GO REMINDERS” to jump straight to the reminder service, “GO QUOTES” to get stock quotes, etc. No such staggering feats of productivity-enhancement here yet. Give them time, though. They’ll stumble on the idea sooner or later.

Published in: on June 9, 2007 at 1:52 pm Comments (1)

Apache on Vista

No doubt this will get fixed in the next few months. Probably. But at the time of this writing in early June of ‘07, the official Apache 2.2 installer fails to install the Apache service and the Apache Monitor applet won’t run at all. But you can get it to work if you do the following (h/t some person on some forum I found via Google):

  1. Disable User Access Control, the Vista feature that protects you from malware by dimming the display and asking you if you’re SURE you want to do anything to your system, every five minutes or so. You can do this vai a link in the Users and Groups control panel.
  2. Reboot so the above takes effect.
  3. Install Apache
  4. Re-enable UAC if you want. Reboot.
  5. Use Apache.
Published in: on June 1, 2007 at 12:33 pm Comments (0)

Pitfalls of Parsing

I was pretty pleased with myself a few days ago. I was staring down some badly-formed HTML pages containing real estate listings that I needed to scrape in order to include direct links to a few properties at koppelmanteam.com. Using a tidy, standards-compliant XML parser was out of the question. When I tried to load a page into one, I got an eyeful of error messages starting with the abesnce of an XML DTD declaration. Tags didn’t close properly. Barely anything had a Class or ID, and the few that did didn’t have the attribute values quoted properly. This was no good.

RubyfulSoup was just what the doctor ordered. Within a half-hour of tinkering and making the best of so-so documentation, I was pulling out prices, MLS numbers, image URLs and all that other good stuff via syntax something like

doc.html.find_all('table')[4].each do |tr|
  listing['price'] = tr.find_all(’td’)[3].string
end

Not too shabby.

Like a good lad, I put the data on each property in a data structure. First I used Structs, then I tried a simple custom class, then I arrived on keeping it simple with a hash. Then I bundled the hashes of a whole set of properties into an outer hash. Armed with my hash of hashes, the next step was to store them.

Since I’m not building an MLS search engine and simply wanted to be able to display these lists of properties as-is, there was no need to create ActiveRecord objects to store the individual properties’ information. All I needed was a way to store and retrieve the entire hash.

Enter ActiveRecord’s serialize declaration, which would automagically serialize my hash into a text column in the database. I’m using the acts_as_commentable plugin to store these search objects, so I had to put the declaration elsewhere, but for a normal AR model, it’s as simple as something like:

class Feed > ActiveRecord::Base
  belongs_to :community
  serialize :search_results
end

Easy as pie! Except it didn’t work.

Debugging and hair-pulling ensued. I tried serializing other things to the field, which worked perfectly fine. I tried serializing data structures that resembled my real one: hashes of strings, hashes of hashes, all fine. Eventually, after clearing away a few other bugs, it was still complaining that I was trying to serialize a Proc, which is a no-no. What? It was a hash of hashes of strings, right? I wasn’t creating anything with a custom constructor. What gave?

When I constructed a hash of hashes seemingly just like the ones I was generating and that serialized, it finally dawned on me: RubyfulSoup was the culprit.

I went into the Rails console, generated one of the real hashes of hashes that was failing, and started examining the members of the inner hashes with Object#class. And there it was. The RubyfulSoup #string method wasn’t returning Strings. It was returning instances of its own custom class, a NavigableString. Which made sense, of course. How else would one of the <TR> elements magically respond to a #find_all method to pull the <TD> tags inside it?

Duh.

So tr.find_all('td')[3].string became tr.find_all('td')[3].string.to_s and all was well in the world.

If you ain’t returning a String, don’t call the method #string, I say.

Published in: on December 11, 2006 at 12:08 pm Comments (0)

Converting a Struct’s key-value pairs into a Hash

There’s some pre-alpha software I’ve been messing with. The company has its own proprietary object store that works more or less like an extended XML store, with XQuery as the basis for the main query language. They’ve put together the beginnings of an ActiveRecord-like data access layer that allows things like:

g = Gorilla.find(:first, :conditions => 'name ftcontains "Magilla"')

So far so good. But

g.attributes

returns an error, so it’s not quite an AR-alike. The data that comes back gets returned in a much more complex object with all sorts of pointers and metadata on each top-level element. For the sake of sanity, the subset of name-value pairs most developers will be interested in, analagous to AR attributes, are accessible as an array returned by g.keys and g.values, or as pairs returned by g.each. In other words, it currently behaves more or less like a Struct — except that while g.height will return a value, it also doesn’t respond to things like g[:height], so right now it’s kinda-sorta like a half-implemented Struct, but being half-implemented maybe there’s a chance to make it act more AR-like.

One key part of AR is its elegant handling of relations. In this spirit, I set out on some initial exploration into what it would take to access a monkey’s or gorilla’s uncles via g.uncles (which right now would just return a pointer to another of these Struct-like representations of XML). I first wanted to begin getting those name-value pairs into a concise AR-like hash of their own. After some trial and error and a look through the pickaxe book, I arrived at this:

h = {}
g.each {|a,b| h.merge!({a,b}) }

and now, glory be, after this, h contains a hash of name-value pairs of the attributes. Traversing the pointers to referenced external objects to get nested hashes of Uncle-attributes inside g.uncles will be another story entirely, to say nothing of getting these things to act more like AR objects, mind you…

Published in: on November 27, 2006 at 11:45 pm Comments (0)

Consumer Guide to Rails Plugins, Part I

acts_as_commentable: It’s easy to add to an existing application. It works as advertised: any object can have comments associated with it. It’s super-useful. If you’re developing anything that involves comments, like a commerce site with reviews, a CRM tool, a collaboration site or any number of other things, it’s pretty swell. It’s also very lightly documented, and since it’s a plugin, it’s a bit constrained in how one can go about extending it beyond simply adding more fields, short of modifying the plugin. I’m using it to hold comments and system-generated log entries (like status changes) for the same objects, and I’d love to be able to use single-table inheritance to segregate the custom finders and different validations required by each one, instead of cluttering application.rb or an external library with clunky helper methods. Then again, maybe I just haven’t tried hard enough. Either way, it’s pretty swell. GRADE: A MINUS
login_engine/user_engine (from rails-engines.org): They’re fussy. The underlying Engines plugin that they run on top of breaks with every significant new update to Rails. Once it’s up and going, the Engines approach is nifty: extending the engines is as simple as overriding or adding methods to models and controllers you create in your own application, all without having to mess with the plugins themselves. Does it work? Yep. LoginEngine does rudimentary account management, lost-password recovery and basic access control at the application, controller or method level, and UserEngine adds simple role-based authentication. Am I using it in production? Yep. Well, LoginEngine, anyway. After a while, it became clear that the UserEngine approach to RBAC didn’t really fit where FLHomeprices was going, so while I haven’t actually removed it from the app yet, I’m doing my administrative access control with my own methods. Frankly, the whole clever-hack aspect of Engines is a turnoff. Unless it becomes part of the Rails core, it’s vulnerable to being abandoned sometime down the road and may cause problems for applications that depend on it. For my next project, I’m probably going to write my own athentication and authorization framework so I’m not as dependent on someone else’s fragile code. That said, LoginEngine is the most polished drop-in authentication module I’ve tried, and if time is of the essence, it’s not bad. GRADE: B PLUS

Published in: on October 12, 2006 at 10:28 pm Comments (0)