danmarvelous | web journeyman

stepping through some Ruby code

Posted on Wednesday, March 07, 2007

Ryan had nice snippet to render printable pages in Rails. the code in the controller uses the responds_to method:


respond_to do |format|
  format.html
  format.print { render :layout => "print" }
end

I have used the repond_to method a bit, and I know what is happening above. as I looked at the code, I realized that I didn’t understand at all what is actually doing.

it looks like a switch statement. if format is html, do this, if format is print, do that. I don’t know if it’s intentional or not, but I believe that would be called syntactic sugar, because it’s not a switch statement, and I wanted to look at the responds_to method in more detail to figure out what is going on.

mostly for a personal exercise, because I can see that th is rambling doesn’t really establish me as an expert of anything.


def respond_to(*types, &block)
  raise ArgumentError, "respond_to takes either types or a block, never both" 
  unless types.any? ^ block

seeing the arguments to the method indicates that code calling the respond_to method in Ryan’s snippet is passing a code block (the portion from the do to the end).

the first line raises an error if both of the possible arguments to the method are passed. the ^ operator / method is called an Exclusive Or.


  block ||= lambda { |responder| types.each { |type| responder.send(type) } }

the lambda method creates a new proc, or “something that can be run” according to my tight definitions. the ||= method there is assigning the proc created by the lambda call to the block variable, if the block variable has not been set.

in the case of the snippet above, the block variable is set with the arguments, so this line will not be executed.


  responder = Responder.new(block.binding)

the Responder class is also defined in the mime_responds.rb file along with the responds_to method. I could do more research on the binding property on the block, but it has to do with sending the environment of the block to the new object.


  block.call(responder)

and this is where the block sent to the respond_to method is executed, passing the new responder object.

in the snippet, the responder object becomes format, or whatever variables is inside the pipes.

within that context, I’d say the code in the block (like format.print { render :layout => "print" }) is defining methods on the responder object for each mime type that the Controller should respond to. after doing some debugging, I see that print and html are also proc’s.


  responder.respond
end

once the actions are set for the available types, the respond method uses one of those actions (or procs) based on the actual mime type detected in the request.

the mime type detected seems to be set on the responder object in the initialize method on line 117 of mime_response.rb.

Etc.

danmarvelo.us animated by SimpleLog, hosted gently by TextDrive.