Class: Rack::Acceptable::Provides

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/acceptable/middleware/provides.rb

Overview

Inspired (partially) by the Rack::AcceptFormat.

  • Fishes out the best one of available MIME-Types.

  • Adds an associated format (extension) to the path_info (optional).

  • Stops processing and responds with 406 ‘Not Acceptable’, when there’s nothing to provide.

  • Memoizes results, since the full negotiation is not the ‘week’ (but quick!) lookup.

Example

use Rack::Acceptable::Provides w(text/x-json application/json text/plain),
  :force_format   => true,
  :default_format => '.txt'

Constant Summary collapse

CANDIDATE =
'rack-acceptable.provides.candidate'
CANDIDATE_INFO =
'rack-acceptable.provides.candidate_info'

Instance Method Summary collapse

Constructor Details

#initialize(app, provides, options = {}) ⇒ Provides

Parameters

app<#call>

Rack application.

provides<Array>

List of available MIME-Types.

options<Hash>

Additional options, like negotiate_by. See also the Rack::Acceptable::MIMETypes#detect_best_mime_type method.



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/rack/acceptable/middleware/provides.rb', line 33

def initialize(app, provides, options = {})
  raise "You should provide the list of available MIME-Types." if provides.empty?
  @app = app
  @provides = provides.map { |type| MIMETypes.parse_media_range(type) << type }
  @provides << (options[:negotiate_by] == :qvalue_only ? true : false)
  @lookup = {}
  @force_format = !!options[:force_format]
  if @force_format && options.key?(:default_format)
    ext = options[:default_format].to_s.strip
    @_extension = ext[0] == ?. ? ext : ".#{ext}" unless ext.empty?
  end
end

Instance Method Details

#call(env) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rack/acceptable/middleware/provides.rb', line 46

def call(env)
  request = Rack::Acceptable::Request.new(env)
  return Const::NOT_ACCEPTABLE_RESPONSE unless preferred = _negotiate(request)

  simple = preferred.last
  request.env[CANDIDATE] = simple
  request.env[CANDIDATE_INFO] = preferred[0..2]

  if @force_format &&
    (path = request.path_info) != Const::SLASH &&
    ext = _extension_for(simple)
    request.path_info = path.sub(/\/*$/, ext)
  end

  status, headers, body = @app.call(env)
  unless Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i)
    headers = Rack::Utils::HeaderHash.new(headers)
    headers[Const::CONTENT_TYPE] ||= simple
  end
  [status, headers.to_hash, body]
end