Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/branches/1-2-stable/actionpack/lib/action_controller/mime_type.rb

Revision 5699, 5.5 kB (checked in by bitsweat, 2 years ago)

Merge [5694]-[5698] from trunk: respond_to json and render :json => ...

Line 
1 module Mime
2   # Encapsulates the notion of a mime type. Can be used at render time, for example, with:
3   #
4   #   class PostsController < ActionController::Base
5   #     def show
6   #       @post = Post.find(params[:id])
7   #
8   #       respond_to do |format|
9   #         format.html
10   #         format.ics { render :text => post.to_ics, :mime_type => Mime::Type["text/calendar"]  }
11   #         format.xml { render :xml => @people.to_xml }
12   #       end
13   #     end
14   #   end
15   class Type
16     # A simple helper class used in parsing the accept header
17     class AcceptItem #:nodoc:
18       attr_accessor :order, :name, :q
19
20       def initialize(order, name, q=nil)
21         @order = order
22         @name = name.strip
23         q ||= 0.0 if @name == "*/*" # default "*/*" to end of list
24         @q = ((q || 1.0).to_f * 100).to_i
25       end
26
27       def to_s
28         @name
29       end
30
31       def <=>(item)
32         result = item.q <=> q
33         result = order <=> item.order if result == 0
34         result
35       end
36
37       def ==(item)
38         name == (item.respond_to?(:name) ? item.name : item)
39       end
40     end
41
42     class << self
43       def lookup(string)
44         LOOKUP[string]
45       end
46
47       def register(string, symbol, synonyms = [])
48         Mime.send :const_set, symbol.to_s.upcase, Type.new(string, symbol, synonyms)
49         SET << Mime.send(:const_get, symbol.to_s.upcase)
50         LOOKUP[string] = EXTENSION_LOOKUP[symbol.to_s] = SET.last       
51       end
52
53       def parse(accept_header)
54         # keep track of creation order to keep the subsequent sort stable
55         index = 0
56         list = accept_header.split(/,/).map! do |i|
57           AcceptItem.new(index += 1, *i.split(/;\s*q=/))
58         end.sort!
59
60         # Take care of the broken text/xml entry by renaming or deleting it
61         text_xml = list.index("text/xml")
62         app_xml = list.index("application/xml")
63
64         if text_xml && app_xml
65           # set the q value to the max of the two
66           list[app_xml].q = [list[text_xml].q, list[app_xml].q].max
67
68           # make sure app_xml is ahead of text_xml in the list
69           if app_xml > text_xml
70             list[app_xml], list[text_xml] = list[text_xml], list[app_xml]
71             app_xml, text_xml = text_xml, app_xml
72           end
73
74           # delete text_xml from the list
75           list.delete_at(text_xml)
76  
77         elsif text_xml
78           list[text_xml].name = "application/xml"
79         end
80
81         # Look for more specific xml-based types and sort them ahead of app/xml
82
83         if app_xml
84           idx = app_xml
85           app_xml_type = list[app_xml]
86
87           while(idx < list.length)
88             type = list[idx]
89             break if type.q < app_xml_type.q
90             if type.name =~ /\+xml$/
91               list[app_xml], list[idx] = list[idx], list[app_xml]
92               app_xml = idx
93             end
94             idx += 1
95           end
96         end
97
98         list.map! { |i| Mime::Type.lookup(i.name) }.uniq!
99         list
100       end
101     end
102    
103     def initialize(string, symbol = nil, synonyms = [])
104       @symbol, @synonyms = symbol, synonyms
105       @string = string
106     end
107    
108     def to_s
109       @string
110     end
111    
112     def to_str
113       to_s
114     end
115    
116     def to_sym
117       @symbol || @string.to_sym
118     end
119
120     def ===(list)
121       if list.is_a?(Array)
122         (@synonyms + [ self ]).any? { |synonym| list.include?(synonym) }
123       else
124         super
125       end
126     end
127    
128     def ==(mime_type)
129       (@synonyms + [ self ]).any? { |synonym| synonym.to_s == mime_type.to_s } if mime_type
130     end
131   end
132
133   ALL   = Type.new "*/*", :all
134   TEXT  = Type.new "text/plain", :text
135   HTML  = Type.new "text/html", :html, %w( application/xhtml+xml )
136   JS    = Type.new "text/javascript", :js, %w( application/javascript application/x-javascript )
137   ICS   = Type.new "text/calendar", :ics
138   CSV   = Type.new "text/csv", :csv
139   XML   = Type.new "application/xml", :xml, %w( text/xml application/x-xml )
140   RSS   = Type.new "application/rss+xml", :rss
141   ATOM  = Type.new "application/atom+xml", :atom
142   YAML  = Type.new "application/x-yaml", :yaml, %w( text/yaml )
143   JSON  = Type.new "application/json", :json, %w( text/x-json )
144
145   SET   = [ ALL, TEXT, HTML, JS, ICS, XML, RSS, ATOM, YAML, JSON ]
146
147   LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k == "" }
148
149   LOOKUP["*/*"]                      = ALL
150
151   LOOKUP["text/plain"]               = TEXT
152
153   LOOKUP["text/html"]                = HTML
154   LOOKUP["application/xhtml+xml"]    = HTML
155
156   LOOKUP["text/javascript"]          = JS
157   LOOKUP["application/javascript"]   = JS
158   LOOKUP["application/x-javascript"] = JS
159
160   LOOKUP["text/calendar"]            = ICS
161
162   LOOKUP["text/csv"]                 = CSV
163
164   LOOKUP["application/xml"]          = XML
165   LOOKUP["text/xml"]                 = XML
166   LOOKUP["application/x-xml"]        = XML
167
168   LOOKUP["text/yaml"]                = YAML
169   LOOKUP["application/x-yaml"]       = YAML
170
171   LOOKUP["application/rss+xml"]      = RSS
172   LOOKUP["application/atom+xml"]     = ATOM
173
174   LOOKUP["application/json"]         = JSON
175   LOOKUP["text/x-json"]              = JSON
176
177
178   EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k == "" }
179
180   EXTENSION_LOOKUP["html"]  = HTML
181   EXTENSION_LOOKUP["xhtml"] = HTML
182
183   EXTENSION_LOOKUP["txt"]   = TEXT
184
185   EXTENSION_LOOKUP["xml"]   = XML
186
187   EXTENSION_LOOKUP["js"]    = JS
188
189   EXTENSION_LOOKUP["ics"]   = ICS
190
191   EXTENSION_LOOKUP["csv"]   = CSV
192
193   EXTENSION_LOOKUP["yml"]   = YAML
194   EXTENSION_LOOKUP["yaml"]  = YAML
195
196   EXTENSION_LOOKUP["rss"]   = RSS
197   EXTENSION_LOOKUP["atom"]  = ATOM
198
199   EXTENSION_LOOKUP["json"]  = JSON
200 end
Note: See TracBrowser for help on using the browser.