Confused Development

I develop software and I often get confused in the process. I usually find the answers after a while, but a month later I can't remember them. So from now on, I will write them down here.

Thursday, July 27, 2006

Cocoa XML-RPC Client

A nice way to test all the various blogging API methods listed in the previous post is Todd Ditchendorf's Cocoa XML-RPC client. E.g., to test the metaweblog.getRecentPosts, you can just type the following into this nice little app, hit execute and get a response! Not earth-shaking, but useful.

Cocoa XML-RPC Client

Wednesday, July 26, 2006

Blogging APIs ("get me those posts!")

I know less about all these blogging APIs than I thought I did, and than I should: today I just set out to begin work on an import function for semiBlog, allowing it to import a complete blog from e.g. WordPress. The idea is that you could say "Here is the URL of my blog, now go and get all the posts, so that I can work on them in semiBlog." Without thinking, I assumed that any self-respecting blogging API would allow one to say something like "Give me all posts" or at least "Give me the postIDs of all posts". However, after looking around for a while, it seems that this functionality does not exist. So maybe I should take a step back and have a closer look at all the various APIs. I'll collect all the relevant information here in this post.

Blogger API

I started my quest for knowledge with the Blogger API (which is actually deprecated by Blogger itself, in favour of the Atom API). The spec lists the following API calls:

  • blogger.newPost
    Makes a new post to a designated blog. Optionally, will publish the blog after making the post.
  • blogger.editPost
    Edits a given post. Optionally, will publish the blog after making the edit.
  • blogger.getUsersBlogs
    Returns information on all the blogs a given user is a member of.
  • blogger.getUserInfo
    Authenticates a user and returns basic user info (name, email, userid, etc).
  • blogger.getTemplate
    Returns the main or archive index template of a given blog.
  • blogger.setTemplate
    Edits the main or archive index template of a given blog.

None of these strike me as particularly helpful in my task of getting all posts for a given blog.

MetaWeblogAPI

The MetaWeblogAPI is "designed to enhance the Blogger API", as its specification states. That document lists the following API calls:

Ah, I seem to be getting closer: getPost and getRecentPosts seem to help somewhat. getPost will of course only give me one post, specified by its postID. The documentation for getRecentPost says: If numberOfPosts is 1, you get the most recent post. If it's 2 you also get the second most recent post, as the second array element. If numberOfPosts is greater than the number of posts in the weblog you get all the posts in the weblog. That last bit is interesting - however, I still have to know how many post there are. Alternatively, I could just pass a ridiculously high number, and hope that it will be higher than the total number of posts. Hm...

Out of curiosity I tried passing 0 as the numberOfPosts parameter. This is not documented in the spec, but with my WordPress 2.0.2 test blog it consistently gives me all posts back - just what I wanted! :-) After stumbling upon this, I tried to figure out if this was documented anywhere. All I found was the statement "using blogger.getRecentPosts with the number 'zero' returns all posts in the blog". Apart from the fact that it seems slightly wrong (it should read metaWeblog.getRecentPosts), I couldn't find its original source. The statement appears in various places on the web, which all apparently copy from each other (and now it also appears here). Also, I'm afraid I can't expect this to work with all systems supporting MetaWeblog API - or can I?

Monday, July 24, 2006

Cocoa Bindings to "virtual" data

Uh, this took me a while to figure out, even though it's fairly obvious now. I have the following situation:

  • I have an application which loads a bunch of plugins.
  • Each plugin has a UI, defined as a NIB file I created in Interface Builder.
  • The UI elements are bound to what I think could be called "virtual" attributes of an object (an instance of the plugin class). What do I mean by virtual attributes? The object doesn't actually have these attributes (e.g. "blogURL", "userName", ...) as data. Instead, it has one big data object ("publisherDetails"), and when it receives a message such as valueForKey: @"blogURL", the return value gets computed from the publisherDetails object.
  • Now, in IB I have e.g. bound an NSTextField to someObject.blogURL.
  • However, the publisherDetails only get set _after_ these bindings where established. As a result, the TextField shows a NULL value. No KVC (Key-Value Coding) method like setBlogURL: or setValue: bla forKey: @"blogURL" ever gets called.

Sort of complicated, but I don't have the patience to explain it any better now. Anyway, what has to happen is that the UI elements have to be notified that the virtual data they are bound to has changed. That data changes every time the big publisherDetails object is changed, so that's where we have to add some code. What we have to do is call the KVO (Key-Value Observing) methods willChangeValueForKey: and didChangeValueForKey: for each of the virtual attributes. Here is what my setPublisherDetails: method looks like:

- (void)setPublisherDetails: (NSManagedObject *)object
{
  [object retain];
  [publisherDetails release];
  publisherDetails = object;
  
  // when the publisher details are changed, I want observers watching
  // the individual detail settings to be informed that these
  // details changed as well.
  // detailKeys is an array with the names of all the "virtual" attributes
  NSEnumerator *detailKeyEnum = [[self detailKeys] objectEnumerator];
  NSString *key;
  while (key = [detailKeyEnum nextObject]) {
    [self willChangeValueForKey: key];
    [self didChangeValueForKey: key];
  }
}

Now each time the big publisherDetails data gets set, the UI elements get notified that the "virtual" attributes which they are bound to also changed. Thus they will update themselves neatly!

Wednesday, July 19, 2006

WordPress locally on MacOS X

Uuuuhhh, i'm a lazy blogger. The last post is over a months old.

Anyhow, I had trouble installing a local WordPress on my Mac. It should be very easy, but there were always some annoying problems arising from PhP not being able to talk to MySQL. Once I figured out how to do it, and then the next time I had forgotten how. However, there is a really easy way to do it, using the brilliant MAMP installation ("Macintosh, Apache, MySQL and PHP"). This post from Michael Doig's blog explains exactly how to do it. Hooray!