Last week’s filter project is now a standard part of Typo, so I’ve been spending time on a new Typo project: unified RSS feeds. Typo has had support for RSS 2.0 and Atom 0.3 for months, as well as RSS feeds for site-wide comments, site-wide trackbacks, and per-article comments. Each feed was generated by its own distinct view code. This wasn’t scaling very well–every time we add a new feed type (like per-category or per-tag feeds), we have to write a bunch of new code and copy existing templates, and replicate that work once for each feed format that we want to support. That’s why most of the feed types were only available in RSS–creating Atom feeds for them was too much work and too error-prone.

So I decided to rip all of the feed code out and replace it with a new system. Instead of having one template per feed type, I have one master template per feed format (RSS 2.0, Atom 0.3, and now Atom 1.0), plus a per-item template for articles, comments, and trackbacks in each format. That’s a total of 12 templates for 3 different formats. My controller then generates a list of items based on some set of queries and then asks the view to assemble itself based on the type of items that it finds in @items. So the recent articles RSS feed produces a list of the 15 most recent articles, shoves that into @items, and asks the view to take care of it. The trackbacks Atom feed works the same way–@items gets a list of the 15 most recent trackbacks and the same basic view logic does the work. Mixed-type feeds like the article+comments feed work too. This will make adding new feed types mostly trivial.

While I was at it, I added Atom 1.0 support. NetNewsWire 2.0.1 has Atom 1.0 support, so it’s time for us to add it too. Because of our nice new template infrastructure, every feed type that was available in RSS before is now available in Atom 1.0 as well. I also added per-category and per-tag feeds, although they aren’t linked in anywhere yet, so users have to type in the feed URL by hand in order to use them.

The big problem with having so many different feed types (6 types times 3 different formats) is keeping them all standards-compliant. Ruby doesn’t have a feed validator class yet, so I decided to cheat. The Python code from feedvalidator.com is available from SourceForge, so I grabbed it and installed it locally. Then I took their demo wrapper, copied it into /usr/local/bin/feedvalidator, and told Typo’s feed tests to test each feed type using the Python validator code. This helped immensely, and I was able to get all three feed formats back into compliance in no time at all. Frankly, this was the coolest application of unit testing that I’ve ever done, and it was massively and immediately useful. I’ve been trying to get into unit tests for a long time, and this is the first time that I feel like I’m really getting things right.

Hopefully I’ll be able to commit this to the Typo trunk later tonight, and then I can move on to my next little Typo project. I’m not really sure which one to pick up next–either podcasts, context-sensitive sidebars, action caching, statistics, or schema generation from migrations. So many choices.