Selectively handle undefined methods in Ruby
xml.channel {
xml.title Option[:blogname]
xml.link Option[:siteurl]
xml.description Option[:blogdescription]
xml.pubDate @posts.first.post_date_gmt
xml.generator $GOSLING_URL
xml.language Option[:rss_language]
xml.<< render(
:partial => "item", :collection => @posts)
}
This is the code that actually generates the RSS feed for this blog.
Note that calling xml.channel encapsulates everything in its curly braces with the tag <channel>. xml.title Option[:blogname] asks the ActiveRecord model Option for a record from the database, so it executes the SQL find this (along with the other Option[] calls in this script) and wraps what’s returned with the XML element <title>.
These methods of the xml object weren’t prefined anywhere. The line xml.morrisseyquote "For the Good Life is out there somewhere, so stay on my arm, you little charmer" would generate the XML <morrisseyquote>For the Good Life is out there somewhere, so stay on my arm, you little charmer</morrisseyquote>
Ruby allows this dynamism through its clever handling of its namespace. When the Ruby interpreter encounters a token not in the namespace, it invokes a method—namely Kernel#method_missing. By default Kernel#method_missing simply raises a NameError politely notifying you of your typo.
But the XmlMarkup class actually overrides this method with the signature XmlMarkup#method_missing(sym, *args, &block). When constructing XML in this way, you’re calling methods that don’t exist, which are caught, parsed, and recompiled as XML.
Astute readers may be calling foul here. One may say, “sure, it works for Builder, but what if only certain methods should be overridden?” Because of Ruby’s clever inheriting here, the super keyword can be used to invoke Kernel#method_missing as normal if the given method doesn’t match a set of conditions. For example:def method_missing(name, *args)
super unless name.to_s =~ /^w+_ismyname$/
puts "Why, hello #{name}!"
end
This allows virtually any combination of letters and numbers to be given as a method, as long as they’re succeeded by “_ismyname”. If this is declared in an Object instance called greeter, this can be invoked with greeter.Jay_ismyname, which evokes the output “Why, hello Jay!”
Now that you’re all excited, go fall in love.
Trackbacks
Use the following link to trackback from your own site:
http://jicksta.com/articles/trackback/12
-
I found your site on technorati and read a few of your other posts. Keep up the good work. I just added your RSS feed to my Google News Reader. Looking forward to reading more from you.