Skip to content
This repository
tree: a4c04a43cc
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 110 lines (96 sloc) 3.287 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/object/blank'
require 'set'

module ActionController
  # See <tt>Renderers.add</tt>
  def self.add_renderer(key, &block)
    Renderers.add(key, &block)
  end

  module Renderers
    extend ActiveSupport::Concern

    included do
      class_attribute :_renderers
      self._renderers = Set.new.freeze
    end

    module ClassMethods
      def use_renderers(*args)
        renderers = _renderers + args
        self._renderers = renderers.freeze
      end
      alias use_renderer use_renderers
    end

    def render_to_body(options)
      _handle_render_options(options) || super
    end

    def _handle_render_options(options)
      _renderers.each do |name|
        if options.key?(name)
          _process_options(options)
          return send("_render_option_#{name}", options.delete(name), options)
        end
      end
      nil
    end

    # Hash of available renderers, mapping a renderer name to its proc.
    # Default keys are :json, :js, :xml.
    RENDERERS = Set.new

    # Adds a new renderer to call within controller actions.
    # A renderer is invoked by passing its name as an option to
    # <tt>AbstractController::Rendering#render</tt>. To create a renderer
    # pass it a name and a block. The block takes two arguments, the first
    # is the value paired with its key and the second is the remaining
    # hash of options passed to +render+.
    #
    # === Example
    # Create a csv renderer:
    #
    # ActionController::Renderers.add :csv do |obj, options|
    # filename = options[:filename] || 'data'
    # str = obj.respond_to?(:to_csv) ? obj.to_csv : obj.to_s
    # send_data str, :type => Mime::CSV,
    # :disposition => "attachment; filename=#{filename}.csv"
    # end
    #
    # Note that we used Mime::CSV for the csv mime type as it comes with Rails.
    # For a custom renderer, you'll need to register a mime type with
    # <tt>Mime::Type.register</tt>.
    #
    # To use the csv renderer in a controller action:
    #
    # def show
    # @csvable = Csvable.find(params[:id])
    # respond_to do |format|
    # format.html
    # format.csv { render :csv => @csvable, :filename => @csvable.name }
    # }
    # end
    # To use renderers and their mime types in more concise ways, see
    # <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt> and
    # <tt>ActionController::MimeResponds#respond_with</tt>
    def self.add(key, &block)
      define_method("_render_option_#{key}", &block)
      RENDERERS << key.to_sym
    end

    module All
      extend ActiveSupport::Concern
      include Renderers

      included do
        self._renderers = RENDERERS
      end
    end

    add :json do |json, options|
      json = json.to_json(options) unless json.kind_of?(String)
      json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
      self.content_type ||= Mime::JSON
      json
    end

    add :js do |js, options|
      self.content_type ||= Mime::JS
      js.respond_to?(:to_js) ? js.to_js(options) : js
    end

    add :xml do |xml, options|
      self.content_type ||= Mime::XML
      xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
    end
  end
end
Something went wrong with that request. Please try again.