You Win, Ruby
After the last three months, I've come to the conclusion: Ruby is a wonderful language, and I don't want to write code in Perl any more. I like Perl: it's fast, powerful, and has a terrific community around it. If you wanted to run your television through a LEGO USB IR transceiver, yeah, there's probably something in CPAN for that. However, I'm finding that the rocky syntax of Perl gets in the way of my thinking. I don't want to use $hash_of_hashes->{'key'}->{'key2'}
to get at at what should be a simple data structure. Using five special characters on a variable makes my code hard to understand, and makes it easier to cause bugs. It's a good language, but Perl has its limits. After spending months writing clean, joyful code, I think that the Ruby language maps more closely to the domains of the problems I'm trying to solve.
There are a lot of things I like very much about Ragnar: it's quite fast, extensively configurable, and compliant with web standards by design. XSLT transforms keep logic and presentation well separated, and the powerful query engine makes node-level logic simple. I plan to preserve the best aspects of this design, but refactor the code into a Ruby platform, separate node data taipus into a more traditional database schema for efficiency, and define a plugin architecture with callbacks for node lifecycle handling. For now, at least, I'll avoid the temptation to use Rails for this project: I prefer XSLT, and working this way is more fun for me. :-)
New Ragnar Functions
Work on Ragnar continues, but mostly behind the scenes. I've written a simple node management tool to edit their properties, a friendly interface for deleting nodes, and a node addition page generated from the defined data taipus. Doing this entailed a redesign of the CGI parser, so things feel a bit cleaner now. Finally, an XML export mode is the result of a more flexible output function--this makes designing templates much easier, and lets other programs access Ragnar data without scraping.
Adding text content is now much easier. The filter understands both plain text conventions and html formatting, but strips disallowed tags and attributes through HTML::Scrubber. This behavior is fully configurable, and works well for small comments and large bodies of text alike.