Class: Rack::Conneg
- Inherits:
-
Object
- Object
- Rack::Conneg
- Defined in:
- lib/rack/conneg.rb
Constant Summary collapse
- VERSION =
'0.1.4'
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?
95 96 97 |
# File 'lib/rack/conneg.rb', line 95 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 |
# 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 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 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.
101 102 103 |
# File 'lib/rack/conneg.rb', line 101 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.
107 108 109 110 |
# File 'lib/rack/conneg.rb', line 107 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().
118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/rack/conneg.rb', line 118 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.
89 90 91 |
# File 'lib/rack/conneg.rb', line 89 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).
134 135 136 137 138 139 |
# File 'lib/rack/conneg.rb', line 134 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
146 147 148 149 150 151 152 |
# File 'lib/rack/conneg.rb', line 146 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 |