Class: Rack::Conneg
- Inherits:
-
Object
- Object
- Rack::Conneg
- Defined in:
- lib/rack/conneg.rb
Constant Summary collapse
- VERSION =
'0.1.6'
Instance Attribute Summary collapse
-
#ignores ⇒ Object
readonly
Returns the value of attribute ignores.
Instance Method Summary collapse
-
#accept_all_extensions? ⇒ Boolean
Should content negotiation accept any file extention passed as part of the URI path, even if it’s not one of the registered provided types?.
- #call(env) ⇒ Object
-
#fallback ⇒ Object
What MIME type should be used as a fallback if negotiation fails? Defaults to ‘text/html’ since that’s what’s used to deliver most error message content.
-
#ignore(route) ⇒ Object
Specifies a route prefix or Regexp that should be ignored by the content negotiator.
-
#ignore_contents_of(path, prefix = '') ⇒ Object
Specifies a directory whose contents should be considered static and therefore ignored.
-
#ignored?(path_info) ⇒ Boolean
Determine if the given path matches any items in the ignore list.
-
#initialize(app) ⇒ Conneg
constructor
A new instance of Conneg.
-
#provide(*args) ⇒ Object
Register one or more content types that the application offers.
-
#set(key, value) ⇒ Object
Set a content negotiation option.
Constructor Details
#initialize(app) ⇒ Conneg
Returns a new instance of Conneg.
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 |
# File 'lib/rack/conneg.rb', line 12 def initialize(app) @app = app @ignores = [] @opts = { :accept_all_extensions => false, :fallback => 'text/html' } @types = [] @app.class.module_eval { def negotiated_ext ; @rack_conneg_ext ; end #:nodoc:# def negotiated_type ; @rack_conneg_type ; end #:nodoc:# def negotiated? ; not @rack_conneg_type.nil? ; end #:nodoc:# def respond_to wants = { '*/*' => Proc.new { raise TypeError, "No handler for #{@rack_conneg_type}" } } def wants.method_missing(ext, *args, &handler) type = ext == :other ? '*/*' : Rack::Mime::MIME_TYPES[".#{ext.to_s}"] self[type] = handler end yield wants (wants[@rack_conneg_type] || wants['*/*']).call end } if block_given? yield self end end |
Instance Attribute Details
#ignores ⇒ Object (readonly)
Returns the value of attribute ignores.
10 11 12 |
# File 'lib/rack/conneg.rb', line 10 def ignores @ignores end |
Instance Method Details
#accept_all_extensions? ⇒ Boolean
Should content negotiation accept any file extention passed as part of the URI path, even if it’s not one of the registered provided types?
97 98 99 |
# File 'lib/rack/conneg.rb', line 97 def accept_all_extensions? @opts[:accept_all_extensions] ? true : false end |
#call(env) ⇒ Object
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 |
# File 'lib/rack/conneg.rb', line 43 def call(env) extension = nil path_info = env['PATH_INFO'] unless ignored?(path_info) # First, check to see if there's an explicit type requested # via the file extension mime_type = Rack::Mime.mime_type(::File.extname(path_info),nil) if mime_type env['PATH_INFO'] = path_info.sub!(/(\..+?)$/,'') extension = $1 if !(accept_all_extensions? || @types.include?(mime_type)) mime_type = nil end else # Create an array of types out of the HTTP_ACCEPT header, sorted # by q value and original order if env['HTTP_ACCEPT'] accept_types = env['HTTP_ACCEPT'].split(/,/) accept_types.each_with_index { |t,i| (accept_type,weight) = t.split(/;/) weight = weight.nil? ? 1.0 : weight.split(/\=/).last.to_f accept_types[i] = { :type => accept_type, :weight => weight, :order => i } } accept_types.sort! { |a,b| ord = b[:weight] <=> a[:weight] if ord == 0 ord = a[:order] <=> b[:order] end ord } # Find the first item in accept_types that matches a registered # content type accept_types.find { |t| re = %r{^#{Regexp.escape(t[:type].gsub(/\*/,'.+'))}$} @types.find { |type| re.match(type) ? mime_type = type : nil } } end end mime_type ||= fallback @app.instance_variable_set('@rack_conneg_ext',env['rack.conneg.ext'] = extension) @app.instance_variable_set('@rack_conneg_type',env['rack.conneg.type'] = mime_type) end @app.call(env) unless @app.nil? end |
#fallback ⇒ Object
What MIME type should be used as a fallback if negotiation fails? Defaults to ‘text/html’ since that’s what’s used to deliver most error message content.
103 104 105 |
# File 'lib/rack/conneg.rb', line 103 def fallback find_mime_type(@opts[:fallback]) end |
#ignore(route) ⇒ Object
Specifies a route prefix or Regexp that should be ignored by the content negotiator. Use for static files or any other route that should be passed through unaltered.
109 110 111 112 |
# File 'lib/rack/conneg.rb', line 109 def ignore(route) route_re = route.kind_of?(Regexp) ? route : %r{^#{Regexp.escape(route)}} @ignores << route_re end |
#ignore_contents_of(path, prefix = '') ⇒ Object
Specifies a directory whose contents should be considered static and therefore ignored. Use with caution, since it acts recursively and can therefore build a pretty big ignore list, slowing down each request. It’s smart enough not to add anything that’s already been ignored, so if you ignore(‘/javascripts/’) before you ignore_contents_of(‘public’), public/javascripts/* won’t be added. In short, do all of your general ignore()ing before you ignore_contents_of().
120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/rack/conneg.rb', line 120 def ignore_contents_of(path, prefix = '') dir = Dir.open(path) dir.select { |f| f !~ /^\.\.?$/ }.each { |entry| entry_path = "#{prefix}/#{entry}" unless ignored?(entry_path) if ::File.directory?(::File.join(dir.path,entry)) ignore_contents_of(::File.join(dir.path,entry),entry_path) else ignore(%r{^#{Regexp.escape(entry_path)}$}) end end } end |
#ignored?(path_info) ⇒ Boolean
Determine if the given path matches any items in the ignore list.
91 92 93 |
# File 'lib/rack/conneg.rb', line 91 def ignored?(path_info) @ignores.find { |ignore| ignore.match(path_info) } ? true : false end |
#provide(*args) ⇒ Object
Register one or more content types that the application offers. Can be a content type string, a file extension, or a symbol (e.g., ‘application/xml’, ‘.xml’, and :xml are all equivalent).
136 137 138 139 140 141 |
# File 'lib/rack/conneg.rb', line 136 def provide(*args) args.flatten.each { |type| mime_type = find_mime_type(type) @types << mime_type } end |
#set(key, value) ⇒ Object
Set a content negotiation option. Valid options are:
-
:accept_all_extensions - true if all file extensions should be mapped to MIME types whether or not their associated types are specifically provided
-
:fallback - a content type string, file extention, or symbol representing the MIME type to fall back on if negotiation fails
148 149 150 151 152 153 154 |
# File 'lib/rack/conneg.rb', line 148 def set(key, value) opt_key = key.to_sym if !@opts.include?(opt_key) raise IndexError, "Unknown option: #{key.to_s}" end @opts[opt_key] = value end |