From: Rick DeNatale Date: 2007-03-16T05:28:20+09:00 Subject: Re: Anyone playing with higher order messaging in ruby? On 3/14/07, Benjohn Barnes wrote: > > On 14 Mar 2007, at 19:57, Jason Roelofs wrote: > > > I haven't personally messed with this kind of stuff but code like > > this just > > makes me love Ruby even more. These types of, well DSL is really > > the best > > way to describe it, in such little code, makes Ruby such a blast to > > program > > in, and it's readable too! > > I think I must be getting too old, or I'm being a spring time Scrouge... > > While it's neat, and it's cool Ruby can do that stuff, I've got to > ask "Why?". > > I've come across this used in DSLs, but I generally think, "I'm sure > you're going to get in to trouble down the line. Why don't you just > use the regular syntax?" Yes it's powerful, and it's useful, but it needs to be done with thought and care. We used to call similar things like this in Smalltalk "stupid Smalltalk tricks." It's like any other tool, it can be used for good or evil, it's the workman who determines this. I just blogged about some of the ramifications of this this morning. (see my signature for the URL of my blog). Rails makes use of this and similar techniques a lot. Two examples, which I've recently encountered reading the rails code: 1) Named routes. Normally you set up routes which represent mappings between urls and actions and their parameters with the connect method of an internal class called ActionController::Routing::RouteSet in code like this, in your config/routs.rb file: ActionController::Routing::Routes.draw do | map | map.connect ':controller/xyz/:arg1/:arg2' end Routes are used both to map an incoming url to an controller, action and parameters, and also to map the other way to generate a url. Routes defined above are anonymous, when asked to generate a url it picks which route to use itself. But you can also name routes so that you can explicitly give a particular route to use when generating a url. Let's say you want to name that route above xyz. To do this you use the method xyz instead of connect: map.xyz 'controller/xyz/:arg1/:arg1' which does the same thing as above but also defines a helper method called xyz_url. Of course the mechanism used to do this is to catch :xyz with method_missing and turn it into a call to named_route passing the name (:xyz) and any other parameters, which in turn invokes connect and then creates the helper. 2) mime content negotiation An action might be able to respond to a request with more than one mime-type. An HTTP request can give a prioritized lists of mime-types which the client will accept. The way to handle this negotiation in an action is to use the respond_to method you might have code in an action like: respond_to do |wants| wants.html { redirect_to(person_list_url) } wants.js wants.xml { render :xml => @person.to_xml(:include => @company) } end What this code says is something like: if the requester wants html redirect to the person_list_url if the requester wants java script perform the normal rendering for javascript (such as look for an rjs template with the right name and render that) etc. It's kind of like a case statement, except what really happens also depends on which of those alternatives came first in the requests list of acceptable types. Now what happens under the covers is that the respond_to method creates an ActionController::MimeResponds::Responder object which becomes map in the code above. Then it yields to the block. The html method adds html to the list of available mime types, along with the block, or as in the case of the invocation of the js method where no block is given, a default block. Then once the block given to respond_to returns, the Responder is asked to respond by executing the first block found using the list of requested mime-types. In Rails 1.2, ActionController::MimeResponds:Responder uses method__missing to support new mime types not 'baked in' to Rails. These are just two examples from Rails, there are many more. It's good to read such carefully crafted code and understand the techniques and the possibilities, but I'd caution about getting too carried away with such things before you are ready, and most folks thing they are ready before they really are. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/