From 3f445b316d34a49a8b6f27bde72979828baefaa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 28 Jul 2009 15:49:59 +0200 Subject: Refactor Responder to only calculate available mime types. Those are sent to the controller that knows what to do with it (render a block or call default render). Signed-off-by: Yehuda Katz --- .../lib/action_controller/base/mime_responds.rb | 129 ++++++++++++--------- actionpack/test/controller/mime_responds_test.rb | 6 +- 2 files changed, 74 insertions(+), 61 deletions(-) diff --git a/actionpack/lib/action_controller/base/mime_responds.rb b/actionpack/lib/action_controller/base/mime_responds.rb index ed0d58dba1..7320b0f858 100644 --- a/actionpack/lib/action_controller/base/mime_responds.rb +++ b/actionpack/lib/action_controller/base/mime_responds.rb @@ -1,5 +1,6 @@ module ActionController #:nodoc: module MimeResponds #:nodoc: + # Without web-service support, an action which collects the data for displaying a list of people # might look something like this: # @@ -92,40 +93,39 @@ module ActionController #:nodoc: # environment.rb as follows. # # Mime::Type.register "image/jpg", :jpg - def respond_to(*types, &block) - raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block - block ||= lambda { |responder| types.each { |type| responder.send(type) } } - responder = Responder.new(self) - block.call(responder) - responder.respond - end - - class Responder #:nodoc: - - def initialize(controller) - @controller = controller - @request = controller.request - @response = controller.response + def respond_to(*mimes, &block) + raise ArgumentError, "respond_to takes either types or a block, never both" unless mimes.any? ^ block - @mime_type_priority = @request.formats + responder = Responder.new(request.formats) - @order = [] - @responses = {} + if block_given? + block.call(responder) + else + mimes.each { |mime| responder.send(mime) } 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 + mime = responder.respond - @responses[mime_type] ||= Proc.new do - # TODO: Remove this when new base is merged in - @controller.formats = [mime_type.to_sym] - @controller.content_type = mime_type - @controller.template.formats = [mime_type.to_sym] + if mime + self.formats = [mime.to_sym] + self.content_type = mime + self.template.formats = [mime.to_sym] - block_given? ? block.call : @controller.send(:render, :action => @controller.action_name) + if response = responder.response_for(mime) + response.call + else + default_render end + else + head :not_acceptable + end + end + + class Responder #:nodoc: + + def initialize(priorities) + @mime_type_priority = priorities + @order, @responses = [], {} end def any(*args, &block) @@ -135,51 +135,64 @@ module ActionController #:nodoc: custom(@mime_type_priority.first, &block) end end - - def self.generate_method_for_mime(mime) - sym = mime.is_a?(Symbol) ? mime : mime.to_sym - const = sym.to_s.upcase - class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{sym}(&block) # def html(&block) - custom(Mime::#{const}, &block) # custom(Mime::HTML, &block) - end # end - RUBY + + 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 + @responses[mime_type] ||= block end - Mime::SET.each do |mime| - generate_method_for_mime(mime) + def respond + available_mimes.first end + def response_for(mime) + @responses[mime] + end + + # Compares mimes sent by the client (@mime_type_priorities) with the ones + # that the user configured in the controller respond_to. Returns them + # all in an array. + # + def available_mimes + mimes = [] + + @mime_type_priority.each do |priority| + if priority == Mime::ALL + mimes << @order.first unless mimes.include?(@order.first) + elsif @order.include?(priority) + mimes << priority + end + end + + mimes << Mime::ALL if @order.include?(Mime::ALL) + mimes + end + + protected + def method_missing(symbol, &block) mime_constant = Mime.const_get(symbol.to_s.upcase) - + if Mime::SET.include?(mime_constant) - self.class.generate_method_for_mime(mime_constant) + generate_method_for_mime(mime_constant) send(symbol, &block) else super end end - def respond - for priority in @mime_type_priority - if priority == Mime::ALL - @responses[@order.first].call - return - else - if @responses[priority] - @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 - @controller.send :head, :not_acceptable - end + def generate_method_for_mime(mime) + sym = mime.is_a?(Symbol) ? mime : mime.to_sym + const = sym.to_s.upcase + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{sym}(&block) # def html(&block) + custom(Mime::#{const}, &block) # custom(Mime::HTML, &block) + end # end + RUBY end + end end end diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 93ca34c41c..bee327998b 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -436,9 +436,9 @@ class MimeControllerTest < ActionController::TestCase def test_render_action_for_html @controller.instance_eval do def render(*args) - unless args.empty? - @action = args.first[:action] || action_name - end + @action = args.first[:action] unless args.empty? + @action ||= action_name + response.body = "#{@action} - #{@template.formats}" end end -- cgit v1.2.3