module ActionController #:nodoc: module MimeResponds #:nodoc: def self.included(base) base.send(:include, ActionController::MimeResponds::InstanceMethods) end module InstanceMethods def respond_to(*types, &block) raise ArgumentError, "respond_to takes either types or a block, never bot" unless types.any? ^ block block ||= lambda { |responder| types.each { |type| responder.send(type) } } responder = Responder.new(block.binding) block.call(responder) responder.respond end end class Responder #:nodoc: DEFAULT_BLOCKS = { :html => 'Proc.new { render }', :js => 'Proc.new { render :action => "#{action_name}.rjs" }', :xml => 'Proc.new { render :action => "#{action_name}.rxml" }' } def initialize(block_binding) @block_binding = block_binding @mime_type_priority = eval("request.accepts", block_binding) @order = [] @responses = {} end def custom(mime_type, &block) mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s) @order << mime_type if block_given? @responses[mime_type] = block else @responses[mime_type] = eval(DEFAULT_BLOCKS[mime_type.to_sym], @block_binding) end end for mime_type in %w( all html js xml rss atom yaml ) eval <<-EOT def #{mime_type}(&block) custom(Mime::#{mime_type.upcase}, &block) end EOT end def any(*args, &block) args.each { |type| send(type, &block) } end def respond for priority in @mime_type_priority if priority == Mime::ALL @responses[@order.first].call return else if priority === @order @responses[priority].call return # mime type match found, be happy and return end end end if @order.include?(Mime::ALL) @responses[Mime::ALL].call else eval 'render(:nothing => true, :status => "406 Not Acceptable")', @block_binding end end end end end