module Sinatra::RespondTo

Constants

Version

Public Class Methods

registered(app) click to toggle source
# File lib/sinatra/respond_to.rb, line 10
    def self.registered(app)
      app.helpers RespondTo::Helpers

      app.set :default_content, :html
      app.set :assume_xhr_is_js, true

      # We remove the trailing extension so routes
      # don't have to be of the style
      #
      #   get '/resouce.:format'
      #
      # They can instead be of the style
      #
      #   get '/resource'
      #
      # and the format will automatically be available in <tt>format</tt>
      app.before do
        # Let through sinatra image urls in development
        next if self.class.development? && request.path_info =~ %r{/__sinatra__/.*?.png}

        unless settings.static? && settings.public_folder? && (request.get? || request.head?) && static_file?(request.path_info)
          if request.params.has_key? 'format'
            format params['format']

            # Rewrite the accept header with the determined format to allow
            # downstream middleware to make use the the mime type
            env['HTTP_ACCEPT'] = ::Sinatra::Base.mime_type(format)
            request.accept.replace [env['HTTP_ACCEPT']]
          else
            # Consider first Accept type as default, otherwise
            # fall back to settings.default_content
            default_content = Rack::Mime::MIME_TYPES.invert[request.accept.first]
            default_content = default_content ? default_content[1..-1] : settings.default_content
            
            # Special case, as the specified default_content may use a different symbol than that
            # found through lookup based on Content-Type
            default_content = settings.default_content if
              default_content != settings.default_content &&
              ::Sinatra::Base.mime_type(default_content) == ::Sinatra::Base.mime_type(settings.default_content)

            ext = $1 if request.path_info.match(%r{\.([^\./]+)$})
            if ext
              # Sinatra relies on a side-effect from path_info= to determine
              # its routes. A direct string change (e.g., sub!) would bypass
              # that and fail to have the effect we're looking for.
              request.path_info = request.path_info[0..-(ext.length+2)]

              format ext

              # Rewrite the accept header with the determined format to allow
              # downstream middleware to make use the the mime type
              env['HTTP_ACCEPT'] = ::Sinatra::Base.mime_type(format)
              request.accept.replace [env['HTTP_ACCEPT']]
            else
              format(request.xhr? && settings.assume_xhr_is_js? ? :js : default_content)
            end
          end
        end
      end

      app.configure :development do |dev|
        dev.error UnhandledFormat do
          content_type :html, :charset => 'utf-8'

          ("          <!DOCTYPE html>
          <html>
          <head>
            <style type="text/css">
            body { text-align:center;font-family:helvetica,arial;font-size:22px;
              color:#888;margin:20px}
            #c {margin:0 auto;width:500px;text-align:left}
            </style>
          </head>
          <body>
            <h2>Sinatra doesn't know this ditty.</h2>
            <img src='/__sinatra__/404.png'>
            <div id="c">
              Try this:
              <pre>#{request.request_method.downcase} '#{request.path_info}' do\n  respond_to do |wants|\n    wants.#{format} { "Hello World" }\n  end\nend</pre>
            </div>
          </body>
          </html>
").gsub(/^ {10}/, '')
        end

        dev.error MissingTemplate do
          content_type :html, :charset => 'utf-8'
          response.status = 500

          engine = request.env['sinatra.error'].message.split('.').last
          engine = 'haml' unless ['haml', 'builder', 'erb'].include? engine

          path = File.basename(request.path_info)
          path = "root" if path.nil? || path.empty?

          format = engine == 'builder' ? 'xml' : 'html'

          layout = case engine
                   when 'haml' then "!!!\n%html\n  %body= yield"
                   when 'erb' then "<html>\n  <body>\n    <%= yield %>\n  </body>\n</html>"
                   when 'builder' then "xml << yield"
                   end

          layout = "<small>app.#{format}.#{engine}</small>\n<pre>#{escape_html(layout)}</pre>"

          ("          <!DOCTYPE html>
          <html>
          <head>
            <style type="text/css">
            body { text-align:center;font-family:helvetica,arial;font-size:22px;
              color:#888;margin:20px}
            #c {margin:0 auto;width:500px;text-align:left;}
            small {float:right;clear:both;}
            pre {clear:both;}
            </style>
          </head>
          <body>
            <h2>Sinatra can't find #{request.env['sinatra.error'].message}</h2>
            <img src='/__sinatra__/500.png'>
            <div id="c">
              Try this:<br />
              #{layout}
              <small>#{path}.#{format}.#{engine}</small>
              <pre>Hello World!</pre>
              <small>application.rb</small>
              <pre>#{request.request_method.downcase} '#{request.path_info}' do\n  respond_to do |wants|\n    wants.#{engine == 'builder' ? 'xml' : 'html'} { #{engine} :#{path}#{",\n#{' '*32}layout => :app" if layout} }\n  end\nend</pre>
            </div>
          </body>
          </html>
").gsub(/^ {10}/, '')
        end
      end
    end