Sporkmonger

purveyor of fabulously ambiguous eating utensils

Chameleon Classes

Posted by sporkmonger
Written December 7th, 2005

One of the big advantages that Mark Pilgrim’s UFP has over FeedTools is in its *_detail methods. The UFP basically gives you a bunch more information without having to dive into XPath or some such. In a couple of obvious places, like the author field, FeedTools also does this, but it used to do it with an interesting trick.

I really didn’t like the idea of having two different methods to retrieve what was essentially the same piece of information. But I also didn’t like forcing people who were used to element names from RSS being stuck using a more unfamiliar Atom-like class structure.

So awhile back, I made it so that there were these special funky classes, like the FeedTools::Author class, that were basically a structure containing the author’s name, email, url, and the raw data in the case of an RSS feed. So you could write:

1
2
3
4
5
6
7
8
9

feed = FeedTools::Feed.open(
  'http://sporkmonger.com/xml/atom10/feed.xml')
feed.author.name
=> 'Bob Aman'
feed.author.email
=> 'bob@sporkmonger.com'
feed.author.url
=> 'http://sporkmonger.com/'

But… you could also write:

1
2
3
4
5

feed = FeedTools::Feed.open(
  'http://sporkmonger.com/xml/atom10/feed.xml')
feed.author
=> 'Bob Aman'

Because I had used method_missing to relay any missing methods on the class to the name object, and overwritten the inspect method and a few others to do the same.

I eventually removed it because the code was quite repetitive (though I know how to fix that at this point), but also because I was worried that someone might actually need one of those overwritten methods for some reason, and also because I thought ‘chameleon classes’ might be surprising to some people. Actually, quite possibly very surprising. And you know, we supposedly want ‘least surprise.’

Now, the reason I’m bringing this up is because I wanted to get more information attached to the content element. I could change the API and have the content method return a class instead of a string, I could leave it the way it is and go with the Mark Pilgrim method, or I could return to the ‘chameleon classes’ only better written the second time round.

My personal preference is actually the shape changing niftiness, despite my reservations. Aesthetically, I think it’s the nicest looking solution, because it keeps the API much, much closer to the names of the elements in the respective syndication formats. Remember, our fearless leaders are of the opinion that beauty and productivity go hand in hand. But I worry, so I’m just going to ask you guys, what do you prefer, and why?

Oh yeah, and I’m strongly considering following Mark’s example and using ‘href’ everywhere for consistency.

  1. Ross Karchner Ross Karchner :
    Written December 8th, 2005 at 10:07 AM

    So far, the “Chameleon” effect hasn’t gotten in my way, but I’ve been mostly interested in the string representations anyway.

  2. Hal Fulton Hal Fulton :
    Written December 8th, 2005 at 02:27 PM

    I think the shape-changing niftiness is cool, but I’m uncertain how you implemented it (then or now).

    One possibility might be to return a string object with actual singleton methods on it (name, email, etc.).

    A lesser possibility might be to define a to_str for the Author class. Then any core method that used it would be able to silently convert it to a string. The downside is that a simple assignment wouldn’t do the conversion for you.

    How does your method_missing trick work?

    Hal

  3. Hal Fulton Hal Fulton :
    Written December 8th, 2005 at 02:45 PM

    Oh, actually I think I see. You’re just delegating to the author object, right? Didn’t you mean to say “author” there instead of “name”?

    Hal

  4. Written December 8th, 2005 at 03:44 PM

    No, I said it correctly. Could’ve been clearer though.

    Ok, more implementation details are in order I guess.

    The Author class has a method_missing function. This relays any missing methods that are called on it to the name object within the Author class. This effectively causes the Author class to function exactly like a string, except with the four additional methods.

    This is superior to the singleton technique, because, as you pointed out, assignment would break with singletons. It doesn’t break with this.

    But again, this is not obvious, and requires a certain amount of explaining, so I’m not sure it’s the best way of doing things.

  5. Hal Fulton Hal Fulton :
    Written December 8th, 2005 at 05:05 PM

    OK, I see now.

    But we are talking about different things when we talk about assignment. I meant that if we used to_str, there would be no way to have it invoked automatically when assigning that value to a variable:

    x = feed.author   # need a .to_str

    But I’m thinking over all this stuff again now. Forget the to_str and let’s look at the singletons.

    Are you concerned about breaking assignment of attributes or what? If so, I don’t think you need be worried about it.

    For example:

    feed.author = some_string
    feed.author = some_author_object

    If we don’t use a “naive” accessor, but write our own author= method, we can do whatever conversion or magic we want on assignment, and both of the above could “work” (depending on your definition of work).

    Am I offbase here?

    Hal

  6. Written December 9th, 2005 at 12:15 PM

    Alright. Now how are you going to reuse the code? There’s a ton of fields this would have to be done on.

  7. Hal Fulton Hal Fulton :
    Written December 9th, 2005 at 12:31 PM

    I’d have to think about that. I think it’s worth discussing if you do.

    Continue here or take it to email?

    By the way, when I said “we” above, it’s strictly a figure of speech. :) I’d be willing to help with this project if you wanted, but I assume my opinion carries little or no weight.

  8. Written December 9th, 2005 at 12:58 PM

    Opinion carries a lot less weight than code. But that’s normal.

    Having thought about it for awhile, I think you may be right about singletons, because there’s definately going to be issues if someone decides not to use duck-typing with my technique. Singletons will definately be more of a hassle, but I can probably work it out. I’ll have to play around a bit and figure out what I can come up with.

    Of course, this is exactly why I asked for comments. :-)

  9. Hal Fulton Hal Fulton :
    Written December 9th, 2005 at 05:08 PM

    OK, then, I’m sending you some code in email…

    It’s a little sketchy, but let me know what you think.

Leave a Response

NOTE: I'm afraid Javascript needs to be on in order to comment.

Comments should be formatted using Textile.

Ruby code should be enclosed within a <macro:code lang="ruby"> element. Other languages are supported. For output you can simply omit the lang attribute.