mime-types 1.25.1 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.autotest +5 -0
- data/.minitest.rb +2 -0
- data/.travis.yml +0 -4
- data/Contributing.rdoc +13 -14
- data/Gemfile +1 -0
- data/History.rdoc +100 -7
- data/Licence.rdoc +1 -1
- data/Manifest.txt +17 -24
- data/README.rdoc +26 -47
- data/Rakefile +42 -185
- data/data/mime-types.json +1 -0
- data/docs/COPYING.txt +339 -339
- data/docs/artistic.txt +127 -127
- data/lib/mime.rb +50 -0
- data/lib/mime/type.rb +634 -0
- data/lib/mime/types.rb +254 -912
- data/lib/mime/types/cache.rb +73 -0
- data/lib/mime/types/loader.rb +248 -0
- data/lib/mime/types/loader_path.rb +16 -0
- data/support/benchmarker.rb +55 -0
- data/support/convert.rb +130 -0
- data/support/iana_downloader.rb +201 -0
- data/test/fixture/json.json +1 -0
- data/test/fixture/old-data +9 -0
- data/test/fixture/yaml.yaml +75 -0
- data/test/minitest_helper.rb +22 -0
- data/test/test_mime_type.rb +337 -143
- data/test/test_mime_types.rb +75 -84
- data/test/test_mime_types_cache.rb +30 -29
- data/test/test_mime_types_class.rb +135 -0
- data/test/test_mime_types_lazy.rb +3 -2
- data/test/test_mime_types_loader.rb +42 -0
- metadata +61 -90
- metadata.gz.sig +0 -0
- data/lib/mime/types/application +0 -1010
- data/lib/mime/types/application.mac +0 -3
- data/lib/mime/types/application.nonstandard +0 -132
- data/lib/mime/types/application.obsolete +0 -41
- data/lib/mime/types/audio +0 -138
- data/lib/mime/types/audio.nonstandard +0 -11
- data/lib/mime/types/audio.obsolete +0 -1
- data/lib/mime/types/image +0 -46
- data/lib/mime/types/image.nonstandard +0 -20
- data/lib/mime/types/image.obsolete +0 -5
- data/lib/mime/types/message +0 -18
- data/lib/mime/types/message.obsolete +0 -2
- data/lib/mime/types/model +0 -15
- data/lib/mime/types/multipart +0 -14
- data/lib/mime/types/multipart.nonstandard +0 -1
- data/lib/mime/types/multipart.obsolete +0 -7
- data/lib/mime/types/other.nonstandard +0 -8
- data/lib/mime/types/text +0 -61
- data/lib/mime/types/text.nonstandard +0 -7
- data/lib/mime/types/text.obsolete +0 -8
- data/lib/mime/types/text.vms +0 -1
- data/lib/mime/types/video +0 -75
- data/lib/mime/types/video.nonstandard +0 -16
- data/lib/mime/types/video.obsolete +0 -3
data/lib/mime/types.rb
CHANGED
@@ -1,968 +1,310 @@
|
|
1
1
|
# -*- ruby encoding: utf-8 -*-
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
42
|
-
|
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
|
-
end
|
78
|
-
|
79
|
-
# Compares the MIME::Type based on how reliable it is before doing a
|
80
|
-
# normal <=> comparison. Used by MIME::Types#[] to sort types. The
|
81
|
-
# comparisons involved are:
|
82
|
-
#
|
83
|
-
# 1. self.simplified <=> other.simplified (ensures that we
|
84
|
-
# don't try to compare different types)
|
85
|
-
# 2. IANA-registered definitions < other definitions.
|
86
|
-
# 3. Generic definitions < platform definitions.
|
87
|
-
# 3. Complete definitions < incomplete definitions.
|
88
|
-
# 4. Current definitions < obsolete definitions.
|
89
|
-
# 5. Obselete with use-instead references < obsolete without.
|
90
|
-
# 6. Obsolete use-instead definitions are compared.
|
91
|
-
def priority_compare(other)
|
92
|
-
pc = simplified <=> other.simplified
|
93
|
-
|
94
|
-
if pc.zero?
|
95
|
-
pc = if registered? != other.registered?
|
96
|
-
registered? ? -1 : 1 # registered < unregistered
|
97
|
-
elsif platform? != other.platform?
|
98
|
-
platform? ? 1 : -1 # generic < platform
|
99
|
-
elsif complete? != other.complete?
|
100
|
-
complete? ? -1 : 1 # complete < incomplete
|
101
|
-
elsif obsolete? != other.obsolete?
|
102
|
-
obsolete? ? 1 : -1 # current < obsolete
|
103
|
-
else
|
104
|
-
0
|
105
|
-
end
|
106
|
-
|
107
|
-
if pc.zero? and obsolete? and (use_instead != other.use_instead)
|
108
|
-
pc = if use_instead.nil?
|
109
|
-
-1
|
110
|
-
elsif other.use_instead.nil?
|
111
|
-
1
|
112
|
-
else
|
113
|
-
use_instead <=> other.use_instead
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
pc
|
119
|
-
end
|
120
|
-
|
121
|
-
# Returns +true+ if the other object is a MIME::Type and the content
|
122
|
-
# types match.
|
123
|
-
def eql?(other)
|
124
|
-
other.kind_of?(MIME::Type) and self == other
|
125
|
-
end
|
126
|
-
|
127
|
-
# Returns the whole MIME content-type string.
|
128
|
-
#
|
129
|
-
# text/plain => text/plain
|
130
|
-
# x-chemical/x-pdb => x-chemical/x-pdb
|
131
|
-
attr_reader :content_type
|
132
|
-
# Returns the media type of the simplified MIME type.
|
133
|
-
#
|
134
|
-
# text/plain => text
|
135
|
-
# x-chemical/x-pdb => chemical
|
136
|
-
attr_reader :media_type
|
137
|
-
# Returns the media type of the unmodified MIME type.
|
138
|
-
#
|
139
|
-
# text/plain => text
|
140
|
-
# x-chemical/x-pdb => x-chemical
|
141
|
-
attr_reader :raw_media_type
|
142
|
-
# Returns the sub-type of the simplified MIME type.
|
143
|
-
#
|
144
|
-
# text/plain => plain
|
145
|
-
# x-chemical/x-pdb => pdb
|
146
|
-
attr_reader :sub_type
|
147
|
-
# Returns the media type of the unmodified MIME type.
|
148
|
-
#
|
149
|
-
# text/plain => plain
|
150
|
-
# x-chemical/x-pdb => x-pdb
|
151
|
-
attr_reader :raw_sub_type
|
152
|
-
# The MIME types main- and sub-label can both start with <tt>x-</tt>,
|
153
|
-
# which indicates that it is a non-registered name. Of course, after
|
154
|
-
# registration this flag can disappear, adds to the confusing
|
155
|
-
# proliferation of MIME types. The simplified string has the <tt>x-</tt>
|
156
|
-
# removed and are translated to lowercase.
|
157
|
-
#
|
158
|
-
# text/plain => text/plain
|
159
|
-
# x-chemical/x-pdb => chemical/pdb
|
160
|
-
attr_reader :simplified
|
161
|
-
# The list of extensions which are known to be used for this MIME::Type.
|
162
|
-
# Non-array values will be coerced into an array with #to_a. Array
|
163
|
-
# values will be flattened and +nil+ values removed.
|
164
|
-
attr_accessor :extensions
|
165
|
-
remove_method :extensions= ;
|
166
|
-
def extensions=(ext) #:nodoc:
|
167
|
-
@extensions = [ext].flatten.compact
|
168
|
-
end
|
169
|
-
|
170
|
-
# The encoding (7bit, 8bit, quoted-printable, or base64) required to
|
171
|
-
# transport the data of this content type safely across a network, which
|
172
|
-
# roughly corresponds to Content-Transfer-Encoding. A value of +nil+ or
|
173
|
-
# <tt>:default</tt> will reset the #encoding to the #default_encoding
|
174
|
-
# for the MIME::Type. Raises ArgumentError if the encoding provided is
|
175
|
-
# invalid.
|
176
|
-
#
|
177
|
-
# If the encoding is not provided on construction, this will be either
|
178
|
-
# 'quoted-printable' (for text/* media types) and 'base64' for eveything
|
179
|
-
# else.
|
180
|
-
attr_accessor :encoding
|
181
|
-
remove_method :encoding= ;
|
182
|
-
def encoding=(enc) #:nodoc:
|
183
|
-
if enc.nil? or enc == :default
|
184
|
-
@encoding = self.default_encoding
|
185
|
-
elsif enc =~ ENCODING_RE
|
186
|
-
@encoding = enc
|
187
|
-
else
|
188
|
-
raise ArgumentError, "The encoding must be nil, :default, base64, 7bit, 8bit, or quoted-printable."
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
# The regexp for the operating system that this MIME::Type is specific
|
193
|
-
# to.
|
194
|
-
attr_accessor :system
|
195
|
-
remove_method :system= ;
|
196
|
-
def system=(os) #:nodoc:
|
197
|
-
if os.nil? or os.kind_of?(Regexp)
|
198
|
-
@system = os
|
199
|
-
else
|
200
|
-
@system = %r|#{os}|
|
201
|
-
end
|
202
|
-
end
|
203
|
-
# Returns the default encoding for the MIME::Type based on the media
|
204
|
-
# type.
|
205
|
-
attr_reader :default_encoding
|
206
|
-
remove_method :default_encoding
|
207
|
-
def default_encoding
|
208
|
-
(@media_type == 'text') ? 'quoted-printable' : 'base64'
|
209
|
-
end
|
210
|
-
|
211
|
-
# Returns the media type or types that should be used instead of this
|
212
|
-
# media type, if it is obsolete. If there is no replacement media type,
|
213
|
-
# or it is not obsolete, +nil+ will be returned.
|
214
|
-
attr_reader :use_instead
|
215
|
-
remove_method :use_instead
|
216
|
-
def use_instead
|
217
|
-
return nil unless @obsolete
|
218
|
-
@use_instead
|
219
|
-
end
|
220
|
-
|
221
|
-
# Returns +true+ if the media type is obsolete.
|
222
|
-
def obsolete?
|
223
|
-
@obsolete ? true : false
|
224
|
-
end
|
225
|
-
# Sets the obsolescence indicator for this media type.
|
226
|
-
attr_writer :obsolete
|
227
|
-
|
228
|
-
# The documentation for this MIME::Type. Documentation about media
|
229
|
-
# types will be found on a media type definition as a comment.
|
230
|
-
# Documentation will be found through #docs.
|
231
|
-
attr_accessor :docs
|
232
|
-
remove_method :docs= ;
|
233
|
-
def docs=(d)
|
234
|
-
if d
|
235
|
-
a = d.scan(%r{use-instead:#{MEDIA_TYPE_RE}})
|
236
|
-
|
237
|
-
if a.empty?
|
238
|
-
@use_instead = nil
|
239
|
-
else
|
240
|
-
@use_instead = a.map { |el| "#{el[0]}/#{el[1]}" }
|
241
|
-
end
|
242
|
-
end
|
243
|
-
@docs = d
|
244
|
-
end
|
245
|
-
|
246
|
-
# The encoded URL list for this MIME::Type. See #urls for more
|
247
|
-
# information.
|
248
|
-
attr_accessor :url
|
249
|
-
# The decoded URL list for this MIME::Type.
|
250
|
-
# The special URL value IANA will be translated into:
|
251
|
-
# http://www.iana.org/assignments/media-types/<mediatype>/<subtype>
|
252
|
-
#
|
253
|
-
# The special URL value RFC### will be translated into:
|
254
|
-
# http://www.rfc-editor.org/rfc/rfc###.txt
|
255
|
-
#
|
256
|
-
# The special URL value DRAFT:name will be translated into:
|
257
|
-
# https://datatracker.ietf.org/public/idindex.cgi?
|
258
|
-
# command=id_detail&filename=<name>
|
259
|
-
#
|
260
|
-
# The special URL value LTSW will be translated into:
|
261
|
-
# http://www.ltsw.se/knbase/internet/<mediatype>.htp
|
262
|
-
#
|
263
|
-
# The special URL value [token] will be translated into:
|
264
|
-
# http://www.iana.org/assignments/contact-people.htm#<token>
|
265
|
-
#
|
266
|
-
# These values will be accessible through #urls, which always returns an
|
267
|
-
# array.
|
268
|
-
def urls
|
269
|
-
@url.map do |el|
|
270
|
-
case el
|
271
|
-
when %r{^IANA$}
|
272
|
-
IANA_URL % [ @media_type, @sub_type ]
|
273
|
-
when %r{^RFC(\d+)$}
|
274
|
-
RFC_URL % $1
|
275
|
-
when %r{^DRAFT:(.+)$}
|
276
|
-
DRAFT_URL % $1
|
277
|
-
when %r{^LTSW$}
|
278
|
-
LTSW_URL % @media_type
|
279
|
-
when %r{^\{([^=]+)=([^\}]+)\}}
|
280
|
-
[$1, $2]
|
281
|
-
when %r{^\[([^=]+)=([^\]]+)\]}
|
282
|
-
[$1, CONTACT_URL % $2]
|
283
|
-
when %r{^\[([^\]]+)\]}
|
284
|
-
CONTACT_URL % $1
|
285
|
-
else
|
286
|
-
el
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
class << self
|
292
|
-
# The MIME types main- and sub-label can both start with <tt>x-</tt>,
|
293
|
-
# which indicates that it is a non-registered name. Of course, after
|
294
|
-
# registration this flag can disappear, adds to the confusing
|
295
|
-
# proliferation of MIME types. The simplified string has the
|
296
|
-
# <tt>x-</tt> removed and are translated to lowercase.
|
297
|
-
def simplified(content_type)
|
298
|
-
matchdata = MEDIA_TYPE_RE.match(content_type)
|
299
|
-
|
300
|
-
if matchdata.nil?
|
301
|
-
simplified = nil
|
302
|
-
else
|
303
|
-
media_type = matchdata.captures[0].downcase.gsub(UNREG_RE, '')
|
304
|
-
subtype = matchdata.captures[1].downcase.gsub(UNREG_RE, '')
|
305
|
-
simplified = "#{media_type}/#{subtype}"
|
306
|
-
end
|
307
|
-
simplified
|
308
|
-
end
|
309
|
-
|
310
|
-
# Creates a MIME::Type from an array in the form of:
|
311
|
-
# [type-name, [extensions], encoding, system]
|
312
|
-
#
|
313
|
-
# +extensions+, +encoding+, and +system+ are optional.
|
314
|
-
#
|
315
|
-
# MIME::Type.from_array("application/x-ruby", ['rb'], '8bit')
|
316
|
-
# MIME::Type.from_array(["application/x-ruby", ['rb'], '8bit'])
|
317
|
-
#
|
318
|
-
# These are equivalent to:
|
319
|
-
#
|
320
|
-
# MIME::Type.new('application/x-ruby') do |t|
|
321
|
-
# t.extensions = %w(rb)
|
322
|
-
# t.encoding = '8bit'
|
323
|
-
# end
|
324
|
-
def from_array(*args) #:yields MIME::Type.new:
|
325
|
-
# Dereferences the array one level, if necessary.
|
326
|
-
args = args.first if args.first.kind_of? Array
|
327
|
-
|
328
|
-
unless args.size.between?(1, 8)
|
329
|
-
raise ArgumentError, "Array provided must contain between one and eight elements."
|
330
|
-
end
|
331
|
-
|
332
|
-
MIME::Type.new(args.shift) do |t|
|
333
|
-
t.extensions, t.encoding, t.system, t.obsolete, t.docs, t.url,
|
334
|
-
t.registered = *args
|
335
|
-
yield t if block_given?
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
# Creates a MIME::Type from a hash. Keys are case-insensitive,
|
340
|
-
# dashes may be replaced with underscores, and the internal Symbol
|
341
|
-
# of the lowercase-underscore version can be used as well. That is,
|
342
|
-
# Content-Type can be provided as content-type, Content_Type,
|
343
|
-
# content_type, or :content_type.
|
344
|
-
#
|
345
|
-
# Known keys are <tt>Content-Type</tt>,
|
346
|
-
# <tt>Content-Transfer-Encoding</tt>, <tt>Extensions</tt>, and
|
347
|
-
# <tt>System</tt>.
|
348
|
-
#
|
349
|
-
# MIME::Type.from_hash('Content-Type' => 'text/x-yaml',
|
350
|
-
# 'Content-Transfer-Encoding' => '8bit',
|
351
|
-
# 'System' => 'linux',
|
352
|
-
# 'Extensions' => ['yaml', 'yml'])
|
353
|
-
#
|
354
|
-
# This is equivalent to:
|
355
|
-
#
|
356
|
-
# MIME::Type.new('text/x-yaml') do |t|
|
357
|
-
# t.encoding = '8bit'
|
358
|
-
# t.system = 'linux'
|
359
|
-
# t.extensions = ['yaml', 'yml']
|
360
|
-
# end
|
361
|
-
def from_hash(hash) #:yields MIME::Type.new:
|
362
|
-
type = {}
|
363
|
-
hash.each_pair do |k, v|
|
364
|
-
type[k.to_s.tr('A-Z', 'a-z').gsub(/-/, '_').to_sym] = v
|
365
|
-
end
|
366
|
-
|
367
|
-
MIME::Type.new(type[:content_type]) do |t|
|
368
|
-
t.extensions = type[:extensions]
|
369
|
-
t.encoding = type[:content_transfer_encoding]
|
370
|
-
t.system = type[:system]
|
371
|
-
t.obsolete = type[:obsolete]
|
372
|
-
t.docs = type[:docs]
|
373
|
-
t.url = type[:url]
|
374
|
-
t.registered = type[:registered]
|
375
|
-
|
376
|
-
yield t if block_given?
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
# Essentially a copy constructor.
|
381
|
-
#
|
382
|
-
# MIME::Type.from_mime_type(plaintext)
|
383
|
-
#
|
384
|
-
# is equivalent to:
|
385
|
-
#
|
386
|
-
# MIME::Type.new(plaintext.content_type.dup) do |t|
|
387
|
-
# t.extensions = plaintext.extensions.dup
|
388
|
-
# t.system = plaintext.system.dup
|
389
|
-
# t.encoding = plaintext.encoding.dup
|
390
|
-
# end
|
391
|
-
def from_mime_type(mime_type) #:yields the new MIME::Type:
|
392
|
-
MIME::Type.new(mime_type.content_type.dup) do |t|
|
393
|
-
t.extensions = mime_type.extensions.map { |e| e.dup }
|
394
|
-
t.url = mime_type.url && mime_type.url.map { |e| e.dup }
|
395
|
-
|
396
|
-
mime_type.system && t.system = mime_type.system.dup
|
397
|
-
mime_type.encoding && t.encoding = mime_type.encoding.dup
|
398
|
-
|
399
|
-
t.obsolete = mime_type.obsolete?
|
400
|
-
t.registered = mime_type.registered?
|
401
|
-
|
402
|
-
mime_type.docs && t.docs = mime_type.docs.dup
|
403
|
-
|
404
|
-
yield t if block_given?
|
405
|
-
end
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
# Builds a MIME::Type object from the provided MIME Content Type value
|
410
|
-
# (e.g., 'text/plain' or 'applicaton/x-eruby'). The constructed object
|
411
|
-
# is yielded to an optional block for additional configuration, such as
|
412
|
-
# associating extensions and encoding information.
|
413
|
-
def initialize(content_type) #:yields self:
|
414
|
-
matchdata = MEDIA_TYPE_RE.match(content_type)
|
415
|
-
|
416
|
-
if matchdata.nil?
|
417
|
-
raise InvalidContentType, "Invalid Content-Type provided ('#{content_type}')"
|
418
|
-
end
|
419
|
-
|
420
|
-
@content_type = content_type
|
421
|
-
@raw_media_type = matchdata.captures[0]
|
422
|
-
@raw_sub_type = matchdata.captures[1]
|
423
|
-
|
424
|
-
@simplified = MIME::Type.simplified(@content_type)
|
425
|
-
matchdata = MEDIA_TYPE_RE.match(@simplified)
|
426
|
-
@media_type = matchdata.captures[0]
|
427
|
-
@sub_type = matchdata.captures[1]
|
428
|
-
|
429
|
-
self.extensions = nil
|
430
|
-
self.encoding = :default
|
431
|
-
self.system = nil
|
432
|
-
self.registered = true
|
433
|
-
self.url = nil
|
434
|
-
self.obsolete = nil
|
435
|
-
self.docs = nil
|
436
|
-
|
437
|
-
yield self if block_given?
|
438
|
-
end
|
439
|
-
|
440
|
-
# MIME content-types which are not regestered by IANA nor defined in
|
441
|
-
# RFCs are required to start with <tt>x-</tt>. This counts as well for
|
442
|
-
# a new media type as well as a new sub-type of an existing media
|
443
|
-
# type. If either the media-type or the content-type begins with
|
444
|
-
# <tt>x-</tt>, this method will return +false+.
|
445
|
-
def registered?
|
446
|
-
if (@raw_media_type =~ UNREG_RE) || (@raw_sub_type =~ UNREG_RE)
|
447
|
-
false
|
448
|
-
else
|
449
|
-
@registered
|
450
|
-
end
|
451
|
-
end
|
452
|
-
attr_writer :registered #:nodoc:
|
453
|
-
|
454
|
-
# MIME types can be specified to be sent across a network in particular
|
455
|
-
# formats. This method returns +true+ when the MIME type encoding is set
|
456
|
-
# to <tt>base64</tt>.
|
457
|
-
def binary?
|
458
|
-
@encoding == 'base64'
|
459
|
-
end
|
460
|
-
|
461
|
-
# MIME types can be specified to be sent across a network in particular
|
462
|
-
# formats. This method returns +false+ when the MIME type encoding is
|
463
|
-
# set to <tt>base64</tt>.
|
464
|
-
def ascii?
|
465
|
-
not binary?
|
466
|
-
end
|
467
|
-
|
468
|
-
# Returns +true+ when the simplified MIME type is in the list of known
|
469
|
-
# digital signatures.
|
470
|
-
def signature?
|
471
|
-
SIGNATURES.include?(@simplified.downcase)
|
472
|
-
end
|
473
|
-
|
474
|
-
# Returns +true+ if the MIME::Type is specific to an operating system.
|
475
|
-
def system?
|
476
|
-
not @system.nil?
|
477
|
-
end
|
478
|
-
|
479
|
-
# Returns +true+ if the MIME::Type is specific to the current operating
|
480
|
-
# system as represented by RUBY_PLATFORM.
|
481
|
-
def platform?
|
482
|
-
system? and (RUBY_PLATFORM =~ @system)
|
483
|
-
end
|
3
|
+
require 'mime/type'
|
4
|
+
require 'mime/types/cache'
|
5
|
+
require 'mime/types/loader'
|
6
|
+
|
7
|
+
# MIME::Types is a registry of MIME types. It is both a class (created with
|
8
|
+
# MIME::Types.new) and a default registry (loaded automatically or through
|
9
|
+
# interactions with MIME::Types.[] and MIME::Types.type_for).
|
10
|
+
#
|
11
|
+
# == The Default mime-types Registry
|
12
|
+
#
|
13
|
+
# The default mime-types registry is loaded automatically when the library
|
14
|
+
# is required (<tt>require 'mime/types'</tt>), but it may be lazily loaded
|
15
|
+
# (loaded on first use) with the use of the environment variable
|
16
|
+
# +RUBY_MIME_TYPES_LAZY_LOAD+ having any value other than +false+. The
|
17
|
+
# initial startup is about 14× faster (~10 ms vs ~140 ms), but the
|
18
|
+
# registry will be loaded at some point in the future.
|
19
|
+
#
|
20
|
+
# The default mime-types registry can also be loaded from a Marshal cache
|
21
|
+
# file specific to the version of MIME::Types being loaded. This will be
|
22
|
+
# handled automatically with the use of a file referred to in the
|
23
|
+
# environment variable +RUBY_MIME_TYPES_CACHE+. MIME::Types will attempt to
|
24
|
+
# load the registry from this cache file (MIME::Type::Cache.load); if it
|
25
|
+
# cannot be loaded (because the file does not exist, there is an error, or
|
26
|
+
# the data is for a different version of mime-types), the default registry
|
27
|
+
# will be loaded from the normal JSON version and then the cache file will
|
28
|
+
# be *written* to the location indicated by +RUBY_MIME_TYPES_CACHE+. Cache
|
29
|
+
# file loads just over 4½× faster (~30 ms vs ~140 ms).
|
30
|
+
# loads.
|
31
|
+
#
|
32
|
+
# Notes:
|
33
|
+
# * The loading of the default registry is *not* atomic; when using a
|
34
|
+
# multi-threaded environment, it is recommended that lazy loading is not
|
35
|
+
# used and mime-types is loaded as early as possible.
|
36
|
+
# * Cache files should be specified per application in a multiprocess
|
37
|
+
# environment and should be initialized during deployment or before
|
38
|
+
# forking to minimize the chance that the multiple processes will be
|
39
|
+
# trying to write to the same cache file at the same time, or that two
|
40
|
+
# applications that are on different versions of mime-types would be
|
41
|
+
# thrashing the cache.
|
42
|
+
# * Unless cache files are preinitialized, the application using the
|
43
|
+
# mime-types cache file must have read/write permission to the cache file.
|
44
|
+
#
|
45
|
+
# == Usage
|
46
|
+
# require 'mime/types'
|
47
|
+
#
|
48
|
+
# plaintext = MIME::Types['text/plain']
|
49
|
+
# print plaintext.media_type # => 'text'
|
50
|
+
# print plaintext.sub_type # => 'plain'
|
51
|
+
#
|
52
|
+
# puts plaintext.extensions.join(" ") # => 'asc txt c cc h hh cpp'
|
53
|
+
#
|
54
|
+
# puts plaintext.encoding # => 8bit
|
55
|
+
# puts plaintext.binary? # => false
|
56
|
+
# puts plaintext.ascii? # => true
|
57
|
+
# puts plaintext.obsolete? # => false
|
58
|
+
# puts plaintext.registered? # => true
|
59
|
+
# puts plaintext == 'text/plain' # => true
|
60
|
+
# puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
|
61
|
+
#
|
62
|
+
class MIME::Types
|
63
|
+
# The release version of Ruby MIME::Types
|
64
|
+
VERSION = MIME::Type::VERSION
|
65
|
+
|
66
|
+
include Enumerable
|
67
|
+
|
68
|
+
# The data version.
|
69
|
+
attr_reader :data_version
|
70
|
+
|
71
|
+
# Creates a new MIME::Types registry.
|
72
|
+
def initialize
|
73
|
+
@type_variants = Container.new
|
74
|
+
@extension_index = Container.new
|
75
|
+
@data_version = VERSION.dup.freeze
|
76
|
+
end
|
484
77
|
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
end
|
78
|
+
def add_type_variant(mime_type) # :nodoc:
|
79
|
+
MIME.deprecated(self, __method__, :private)
|
80
|
+
add_type_variant!(mime_type)
|
81
|
+
end
|
490
82
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
83
|
+
def index_extensions(mime_type) # :nodoc:
|
84
|
+
MIME.deprecated(self, __method__, :private)
|
85
|
+
index_extensions!(mime_type)
|
86
|
+
end
|
495
87
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
88
|
+
def defined_types # :nodoc:
|
89
|
+
MIME.deprecated(self, __method__)
|
90
|
+
@type_variants.values.flatten
|
91
|
+
end
|
500
92
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
@url, registered? ]
|
506
|
-
end
|
93
|
+
# Returns the number of known type variants.
|
94
|
+
def count
|
95
|
+
@type_variants.values.reduce(0) { |m, o| m + o.size }
|
96
|
+
end
|
507
97
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
{ 'Content-Type' => @content_type,
|
512
|
-
'Content-Transfer-Encoding' => @encoding,
|
513
|
-
'Extensions' => @extensions,
|
514
|
-
'System' => @system,
|
515
|
-
'Obsolete' => @obsolete,
|
516
|
-
'Docs' => @docs,
|
517
|
-
'URL' => @url,
|
518
|
-
'Registered' => registered?,
|
519
|
-
}
|
520
|
-
end
|
98
|
+
# Iterates through the type variants.
|
99
|
+
def each
|
100
|
+
@type_variants.values.each { |tv| tv.each { |t| yield t } }
|
521
101
|
end
|
522
102
|
|
523
|
-
|
524
|
-
|
525
|
-
#
|
526
|
-
#
|
527
|
-
#
|
528
|
-
#
|
529
|
-
#
|
530
|
-
#
|
531
|
-
# types (see below for reference).
|
103
|
+
@__types__ = nil
|
104
|
+
|
105
|
+
# Returns a list of MIME::Type objects, which may be empty. The optional
|
106
|
+
# flag parameters are <tt>:complete</tt> (finds only complete MIME::Type
|
107
|
+
# objects) and <tt>:registered</tt> (finds only MIME::Types that are
|
108
|
+
# registered). It is possible for multiple matches to be returned for
|
109
|
+
# either type (in the example below, 'text/plain' returns two values --
|
110
|
+
# one for the general case, and one for VMS systems).
|
532
111
|
#
|
533
|
-
#
|
534
|
-
#
|
535
|
-
# useful at times to have information available about MIME types (or,
|
536
|
-
# inversely, about files). A MIME::Type stores the known information about
|
537
|
-
# one MIME type.
|
112
|
+
# puts "\nMIME::Types['text/plain']"
|
113
|
+
# MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
|
538
114
|
#
|
539
|
-
#
|
540
|
-
#
|
115
|
+
# puts "\nMIME::Types[/^image/, complete: true]"
|
116
|
+
# MIME::Types[/^image/, :complete => true].each do |t|
|
117
|
+
# puts t.to_a.join(", ")
|
118
|
+
# end
|
541
119
|
#
|
542
|
-
#
|
543
|
-
#
|
544
|
-
#
|
120
|
+
# If multiple type definitions are returned, returns them sorted as
|
121
|
+
# follows:
|
122
|
+
# 1. Complete definitions sort before incomplete ones;
|
123
|
+
# 2. IANA-registered definitions sort before LTSW-recorded
|
124
|
+
# definitions.
|
125
|
+
# 3. Generic definitions sort before platform-specific ones;
|
126
|
+
# 4. Current definitions sort before obsolete ones;
|
127
|
+
# 5. Obsolete definitions with use-instead clauses sort before those
|
128
|
+
# without;
|
129
|
+
# 6. Obsolete definitions use-instead clauses are compared.
|
130
|
+
# 7. Sort on name.
|
545
131
|
#
|
546
|
-
#
|
132
|
+
# An additional flag of :platform (finds only MIME::Types for the current
|
133
|
+
# platform) is currently supported but deprecated.
|
134
|
+
def [](type_id, flags = {})
|
135
|
+
if flags[:platform]
|
136
|
+
MIME.deprecated(self, __method__, "using the :platform flag")
|
137
|
+
end
|
138
|
+
|
139
|
+
matches = case type_id
|
140
|
+
when MIME::Type
|
141
|
+
@type_variants[type_id.simplified]
|
142
|
+
when Regexp
|
143
|
+
match(type_id)
|
144
|
+
else
|
145
|
+
@type_variants[MIME::Type.simplified(type_id)]
|
146
|
+
end
|
147
|
+
|
148
|
+
prune_matches(matches, flags).sort { |a, b| a.priority_compare(b) }
|
149
|
+
end
|
150
|
+
|
151
|
+
# Return the list of MIME::Types which belongs to the file based on its
|
152
|
+
# filename extension. If there is no extension, the filename will be used
|
153
|
+
# as the matching criteria on its own.
|
547
154
|
#
|
548
|
-
#
|
549
|
-
# puts plaintext.binary? # => false
|
550
|
-
# puts plaintext.ascii? # => true
|
551
|
-
# puts plaintext.obsolete? # => false
|
552
|
-
# puts plaintext.registered? # => true
|
553
|
-
# puts plaintext == 'text/plain' # => true
|
554
|
-
# puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
|
155
|
+
# This will always return a merged, flatten, priority sorted, unique array.
|
555
156
|
#
|
556
|
-
#
|
557
|
-
#
|
558
|
-
#
|
559
|
-
#
|
560
|
-
#
|
561
|
-
#
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
{}.merge(self)
|
577
|
-
end
|
578
|
-
|
579
|
-
def marshal_load(hash)
|
580
|
-
self.merge!(hash)
|
581
|
-
end
|
157
|
+
# puts MIME::Types.type_for('citydesk.xml')
|
158
|
+
# => [application/xml, text/xml]
|
159
|
+
# puts MIME::Types.type_for('citydesk.gif')
|
160
|
+
# => [image/gif]
|
161
|
+
# puts MIME::Types.type_for(%w(citydesk.xml citydesk.gif))
|
162
|
+
# => [application/xml, image/gif, text/xml]
|
163
|
+
#
|
164
|
+
# If +platform+ is +true+, then only file types that are specific to the
|
165
|
+
# current platform will be returned. This parameter has been deprecated.
|
166
|
+
def type_for(filename, platform = false)
|
167
|
+
types = [ filename ].flatten.map { |fn|
|
168
|
+
@extension_index[File.basename(fn.chomp.downcase).gsub(/.*\./o, '')]
|
169
|
+
}.flatten.sort { |a, b| a.priority_compare(b) }.uniq
|
170
|
+
|
171
|
+
if platform
|
172
|
+
MIME.deprecated(self, __method__,
|
173
|
+
"using the platform parameter")
|
174
|
+
types.select(&:platform?)
|
175
|
+
else
|
176
|
+
types
|
582
177
|
end
|
178
|
+
end
|
179
|
+
alias_method :of, :type_for
|
583
180
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
181
|
+
# Add one or more MIME::Type objects to the set of known types. If the
|
182
|
+
# type is already known, a warning will be displayed.
|
183
|
+
#
|
184
|
+
# The last parameter may be the value <tt>:silent</tt> or +true+ which
|
185
|
+
# will suppress duplicate MIME type warnings.
|
186
|
+
def add(*types)
|
187
|
+
quiet = ((types.last == :silent) or (types.last == true))
|
188
|
+
|
189
|
+
types.each do |mime_type|
|
190
|
+
case mime_type
|
191
|
+
when true, false, nil, Symbol
|
192
|
+
nil
|
193
|
+
when MIME::Types
|
194
|
+
variants = mime_type.instance_variable_get(:@type_variants)
|
195
|
+
add(*variants.values.flatten, quiet)
|
196
|
+
when Array
|
197
|
+
add(*mime_type, quiet)
|
198
|
+
else
|
199
|
+
add_type(mime_type, quiet)
|
588
200
|
end
|
589
201
|
end
|
202
|
+
end
|
590
203
|
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
204
|
+
# Add a single MIME::Type object to the set of known types. If the type is
|
205
|
+
# already known, a warning will be displayed. The +quiet+ parameter may be
|
206
|
+
# a truthy value to suppress that warning.
|
207
|
+
def add_type(mime_type, quiet = false)
|
208
|
+
if !quiet and @type_variants[mime_type.simplified].include?(mime_type)
|
209
|
+
warn("Type %s is already registered as a variant of %s." % [
|
210
|
+
mime_type, mime_type.simplified ])
|
595
211
|
end
|
596
212
|
|
597
|
-
|
598
|
-
|
599
|
-
|
213
|
+
add_type_variant!(mime_type)
|
214
|
+
index_extensions!(mime_type)
|
215
|
+
end
|
216
|
+
|
217
|
+
class << self
|
218
|
+
include Enumerable
|
600
219
|
|
601
|
-
|
602
|
-
|
220
|
+
# Load MIME::Types from a v1 file registry.
|
221
|
+
#
|
222
|
+
# This method has been deprecated.
|
223
|
+
def load_from_file(filename)
|
224
|
+
MIME.deprecated(self, __method__)
|
225
|
+
MIME::Types::Loader.load_from_v1(filename)
|
603
226
|
end
|
604
227
|
|
605
|
-
|
606
|
-
|
228
|
+
# MIME::Types#[] against the default MIME::Types registry.
|
229
|
+
def [](type_id, flags = {})
|
230
|
+
__types__[type_id, flags]
|
607
231
|
end
|
608
232
|
|
609
|
-
#
|
610
|
-
# (Keep in mind that this is memory intensive, cache the result to spare
|
611
|
-
# resources)
|
233
|
+
# MIME::Types#count against the default MIME::Types registry.
|
612
234
|
def count
|
613
|
-
|
235
|
+
__types__.count
|
614
236
|
end
|
615
237
|
|
238
|
+
# MIME::Types#each against the default MIME::Types registry.
|
616
239
|
def each
|
617
|
-
|
240
|
+
__types__.each {|t| yield t }
|
618
241
|
end
|
619
242
|
|
620
|
-
|
243
|
+
# MIME::Types#type_for against the default MIME::Types registry.
|
244
|
+
def type_for(filename, platform = false)
|
245
|
+
__types__.type_for(filename, platform)
|
246
|
+
end
|
247
|
+
alias_method :of, :type_for
|
621
248
|
|
622
|
-
#
|
623
|
-
|
624
|
-
|
625
|
-
# possible for multiple matches to be returned for either type (in the
|
626
|
-
# example below, 'text/plain' returns two values -- one for the general
|
627
|
-
# case, and one for VMS systems.
|
628
|
-
#
|
629
|
-
# puts "\nMIME::Types['text/plain']"
|
630
|
-
# MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
|
631
|
-
#
|
632
|
-
# puts "\nMIME::Types[/^image/, :complete => true]"
|
633
|
-
# MIME::Types[/^image/, :complete => true].each do |t|
|
634
|
-
# puts t.to_a.join(", ")
|
635
|
-
# end
|
636
|
-
#
|
637
|
-
# If multiple type definitions are returned, returns them sorted as
|
638
|
-
# follows:
|
639
|
-
# 1. Complete definitions sort before incomplete ones;
|
640
|
-
# 2. IANA-registered definitions sort before LTSW-recorded
|
641
|
-
# definitions.
|
642
|
-
# 3. Generic definitions sort before platform-specific ones;
|
643
|
-
# 4. Current definitions sort before obsolete ones;
|
644
|
-
# 5. Obsolete definitions with use-instead clauses sort before those
|
645
|
-
# without;
|
646
|
-
# 6. Obsolete definitions use-instead clauses are compared.
|
647
|
-
# 7. Sort on name.
|
648
|
-
def [](type_id, flags = {})
|
649
|
-
matches = case type_id
|
650
|
-
when MIME::Type
|
651
|
-
@type_variants[type_id.simplified]
|
652
|
-
when Regexp
|
653
|
-
match(type_id)
|
654
|
-
else
|
655
|
-
@type_variants[MIME::Type.simplified(type_id)]
|
656
|
-
end
|
657
|
-
|
658
|
-
prune_matches(matches, flags).sort { |a, b| a.priority_compare(b) }
|
249
|
+
# MIME::Types#add against the default MIME::Types registry.
|
250
|
+
def add(*types)
|
251
|
+
__types__.add(*types)
|
659
252
|
end
|
660
253
|
|
661
|
-
#
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
# This will always return an array.
|
666
|
-
#
|
667
|
-
# puts "MIME::Types.type_for('citydesk.xml')
|
668
|
-
# => [application/xml, text/xml]
|
669
|
-
# puts "MIME::Types.type_for('citydesk.gif')
|
670
|
-
# => [image/gif]
|
671
|
-
def type_for(filename, platform = false)
|
672
|
-
ext = filename.chomp.downcase.gsub(/.*\./o, '')
|
673
|
-
list = @extension_index[ext]
|
674
|
-
list.delete_if { |e| not e.platform? } if platform
|
675
|
-
list
|
254
|
+
# Returns the currently defined cache file, if any.
|
255
|
+
def cache_file
|
256
|
+
MIME.deprecated(self, __method__)
|
257
|
+
ENV['RUBY_MIME_TYPES_CACHE']
|
676
258
|
end
|
677
259
|
|
678
|
-
|
679
|
-
|
680
|
-
type_for(filename, platform)
|
260
|
+
def add_type_variant(mime_type) # :nodoc:
|
261
|
+
__types__.add_type_variant(mime_type)
|
681
262
|
end
|
682
263
|
|
683
|
-
|
684
|
-
|
685
|
-
# is already known, a warning will be displayed.
|
686
|
-
#
|
687
|
-
# <strong>Please inform the maintainer of this module when registered
|
688
|
-
# types are missing.</strong>
|
689
|
-
def add(*types)
|
690
|
-
types.each do |mime_type|
|
691
|
-
if mime_type.kind_of? MIME::Types
|
692
|
-
add(*mime_type.defined_types)
|
693
|
-
else
|
694
|
-
if @type_variants.include?(mime_type.simplified)
|
695
|
-
if @type_variants[mime_type.simplified].include?(mime_type)
|
696
|
-
warn "Type #{mime_type} already registered as a variant of #{mime_type.simplified}." unless defined? MIME::Types::LOAD
|
697
|
-
end
|
698
|
-
end
|
699
|
-
add_type_variant(mime_type)
|
700
|
-
index_extensions(mime_type)
|
701
|
-
end
|
702
|
-
end
|
264
|
+
def index_extensions(mime_type) # :nodoc:
|
265
|
+
__types__.index_extensions(mime_type)
|
703
266
|
end
|
704
267
|
|
705
268
|
private
|
706
|
-
def
|
707
|
-
|
708
|
-
matches.delete_if { |e| not e.platform? } if flags[:platform]
|
709
|
-
matches
|
269
|
+
def lazy_load?
|
270
|
+
(lazy = ENV['RUBY_MIME_TYPES_LAZY_LOAD']) && (lazy != 'false')
|
710
271
|
end
|
711
272
|
|
712
|
-
def
|
713
|
-
|
714
|
-
if matches.respond_to? :values
|
715
|
-
matches.values.flatten
|
716
|
-
else
|
717
|
-
matches.map { |m| m.last }.flatten
|
718
|
-
end
|
273
|
+
def __types__
|
274
|
+
(defined?(@__types__) and @__types__) or load_default_mime_types
|
719
275
|
end
|
720
276
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
def index_extensions(mime_type) #:nodoc:
|
727
|
-
__types__.index_extensions(mime_type)
|
728
|
-
end
|
729
|
-
|
730
|
-
# The regular expression used to match a file-based MIME type
|
731
|
-
# definition.
|
732
|
-
TEXT_FORMAT_RE = %r{
|
733
|
-
\A
|
734
|
-
\s*
|
735
|
-
([*])? # 0: Unregistered?
|
736
|
-
(!)? # 1: Obsolete?
|
737
|
-
(?:(\w+):)? # 2: Platform marker
|
738
|
-
#{MIME::Type::MEDIA_TYPE_RE}? # 3,4: Media type
|
739
|
-
(?:\s+@([^\s]+))? # 5: Extensions
|
740
|
-
(?:\s+:(#{MIME::Type::ENCODING_RE}))? # 6: Encoding
|
741
|
-
(?:\s+'(.+))? # 7: URL list
|
742
|
-
(?:\s+=(.+))? # 8: Documentation
|
743
|
-
(?:\s*([#].*)?)?
|
744
|
-
\s*
|
745
|
-
\z
|
746
|
-
}x
|
747
|
-
|
748
|
-
# Build the type list from a file in the format:
|
749
|
-
#
|
750
|
-
# [*][!][os:]mt/st[<ws>@ext][<ws>:enc][<ws>'url-list][<ws>=docs]
|
751
|
-
#
|
752
|
-
# == *
|
753
|
-
# An unofficial MIME type. This should be used if and only if the MIME type
|
754
|
-
# is not properly specified (that is, not under either x-type or
|
755
|
-
# vnd.name.type).
|
756
|
-
#
|
757
|
-
# == !
|
758
|
-
# An obsolete MIME type. May be used with an unofficial MIME type.
|
759
|
-
#
|
760
|
-
# == os:
|
761
|
-
# Platform-specific MIME type definition.
|
762
|
-
#
|
763
|
-
# == mt
|
764
|
-
# The media type.
|
765
|
-
#
|
766
|
-
# == st
|
767
|
-
# The media subtype.
|
768
|
-
#
|
769
|
-
# == <ws>@ext
|
770
|
-
# The list of comma-separated extensions.
|
771
|
-
#
|
772
|
-
# == <ws>:enc
|
773
|
-
# The encoding.
|
774
|
-
#
|
775
|
-
# == <ws>'url-list
|
776
|
-
# The list of comma-separated URLs.
|
777
|
-
#
|
778
|
-
# == <ws>=docs
|
779
|
-
# The documentation string.
|
780
|
-
#
|
781
|
-
# That is, everything except the media type and the subtype is optional. The
|
782
|
-
# more information that's available, though, the richer the values that can
|
783
|
-
# be provided.
|
784
|
-
def load_from_file(filename) #:nodoc:
|
785
|
-
if defined? ::Encoding
|
786
|
-
data = File.open(filename, 'r:UTF-8:-') { |f| f.read }
|
787
|
-
else
|
788
|
-
data = File.open(filename) { |f| f.read }
|
789
|
-
end
|
790
|
-
data = data.split($/)
|
791
|
-
mime = MIME::Types.new
|
792
|
-
data.each_with_index { |line, index|
|
793
|
-
item = line.chomp.strip
|
794
|
-
next if item.empty?
|
795
|
-
|
796
|
-
begin
|
797
|
-
m = TEXT_FORMAT_RE.match(item).captures
|
798
|
-
rescue Exception
|
799
|
-
puts "#{filename}:#{index}: Parsing error in MIME type definitions."
|
800
|
-
puts "=> #{line}"
|
801
|
-
raise
|
802
|
-
end
|
803
|
-
|
804
|
-
unregistered, obsolete, platform, mediatype, subtype, extensions,
|
805
|
-
encoding, urls, docs, comment = *m
|
806
|
-
|
807
|
-
if mediatype.nil?
|
808
|
-
if comment.nil?
|
809
|
-
puts "#{filename}:#{index}: Parsing error in MIME type definitions."
|
810
|
-
puts "=> #{line}"
|
811
|
-
raise RuntimeError
|
812
|
-
end
|
813
|
-
|
814
|
-
next
|
815
|
-
end
|
816
|
-
|
817
|
-
extensions &&= extensions.split(/,/)
|
818
|
-
urls &&= urls.split(/,/)
|
819
|
-
|
820
|
-
mime_type = MIME::Type.new("#{mediatype}/#{subtype}") do |t|
|
821
|
-
t.extensions = extensions
|
822
|
-
t.encoding = encoding
|
823
|
-
t.system = platform
|
824
|
-
t.obsolete = obsolete
|
825
|
-
t.registered = false if unregistered
|
826
|
-
t.docs = docs
|
827
|
-
t.url = urls
|
828
|
-
end
|
829
|
-
|
830
|
-
mime.add(mime_type)
|
831
|
-
}
|
832
|
-
mime
|
833
|
-
end
|
834
|
-
|
835
|
-
# Returns a list of MIME::Type objects, which may be empty. The
|
836
|
-
# optional flag parameters are :complete (finds only complete
|
837
|
-
# MIME::Type objects) and :platform (finds only MIME::Types for the
|
838
|
-
# current platform). It is possible for multiple matches to be
|
839
|
-
# returned for either type (in the example below, 'text/plain' returns
|
840
|
-
# two values -- one for the general case, and one for VMS systems.
|
841
|
-
#
|
842
|
-
# puts "\nMIME::Types['text/plain']"
|
843
|
-
# MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
|
844
|
-
#
|
845
|
-
# puts "\nMIME::Types[/^image/, :complete => true]"
|
846
|
-
# MIME::Types[/^image/, :complete => true].each do |t|
|
847
|
-
# puts t.to_a.join(", ")
|
848
|
-
# end
|
849
|
-
def [](type_id, flags = {})
|
850
|
-
__types__[type_id, flags]
|
851
|
-
end
|
852
|
-
|
853
|
-
include Enumerable
|
854
|
-
|
855
|
-
def count
|
856
|
-
__types__.count
|
857
|
-
end
|
858
|
-
|
859
|
-
def each
|
860
|
-
__types__.each {|t| yield t }
|
861
|
-
end
|
862
|
-
|
863
|
-
# Return the list of MIME::Types which belongs to the file based on
|
864
|
-
# its filename extension. If +platform+ is +true+, then only file
|
865
|
-
# types that are specific to the current platform will be returned.
|
866
|
-
#
|
867
|
-
# This will always return an array.
|
868
|
-
#
|
869
|
-
# puts "MIME::Types.type_for('citydesk.xml')
|
870
|
-
# => [application/xml, text/xml]
|
871
|
-
# puts "MIME::Types.type_for('citydesk.gif')
|
872
|
-
# => [image/gif]
|
873
|
-
def type_for(filename, platform = false)
|
874
|
-
__types__.type_for(filename, platform)
|
875
|
-
end
|
876
|
-
|
877
|
-
# A synonym for MIME::Types.type_for
|
878
|
-
def of(filename, platform = false)
|
879
|
-
__types__.type_for(filename, platform)
|
880
|
-
end
|
881
|
-
|
882
|
-
# Add one or more MIME::Type objects to the set of known types. Each
|
883
|
-
# type should be experimental (e.g., 'application/x-ruby'). If the
|
884
|
-
# type is already known, a warning will be displayed.
|
885
|
-
#
|
886
|
-
# <strong>Please inform the maintainer of this module when registered
|
887
|
-
# types are missing.</strong>
|
888
|
-
def add(*types)
|
889
|
-
__types__.add(*types)
|
890
|
-
end
|
891
|
-
|
892
|
-
# Returns the currently defined cache file, if any.
|
893
|
-
def cache_file
|
894
|
-
ENV['RUBY_MIME_TYPES_CACHE']
|
895
|
-
end
|
896
|
-
|
897
|
-
private
|
898
|
-
def load_mime_types_from_cache
|
899
|
-
load_mime_types_from_cache! if cache_file
|
900
|
-
end
|
901
|
-
|
902
|
-
def load_mime_types_from_cache!
|
903
|
-
raise ArgumentError, "No RUBY_MIME_TYPES_CACHE set." unless cache_file
|
904
|
-
return false unless File.exists? cache_file
|
905
|
-
|
906
|
-
begin
|
907
|
-
data = File.read(cache_file)
|
908
|
-
container = Marshal.load(data)
|
909
|
-
|
910
|
-
if container.version == VERSION
|
911
|
-
@__types__ = Marshal.load(container.data)
|
912
|
-
true
|
913
|
-
else
|
914
|
-
false
|
915
|
-
end
|
916
|
-
rescue => e
|
917
|
-
warn "Could not load MIME::Types cache: #{e}"
|
918
|
-
false
|
919
|
-
end
|
920
|
-
end
|
921
|
-
|
922
|
-
def write_mime_types_to_cache
|
923
|
-
write_mime_types_to_cache! if cache_file
|
924
|
-
end
|
925
|
-
|
926
|
-
def write_mime_types_to_cache!
|
927
|
-
raise ArgumentError, "No RUBY_MIME_TYPES_CACHE set." unless cache_file
|
928
|
-
|
929
|
-
File.open(cache_file, 'w') do |f|
|
930
|
-
cache = MIME::Types::CacheContainer.new(VERSION,
|
931
|
-
Marshal.dump(__types__))
|
932
|
-
f.write Marshal.dump(cache)
|
933
|
-
end
|
934
|
-
|
935
|
-
true
|
936
|
-
end
|
937
|
-
|
938
|
-
def load_and_parse_mime_types
|
939
|
-
const_set(:LOAD, true) unless $DEBUG
|
940
|
-
Dir[File.join(File.dirname(__FILE__), 'types', '*')].sort.each { |f|
|
941
|
-
add(load_from_file(f))
|
942
|
-
}
|
943
|
-
remove_const :LOAD if defined? LOAD
|
277
|
+
def load_default_mime_types
|
278
|
+
@__types__ = MIME::Types::Cache.load
|
279
|
+
unless @__types__
|
280
|
+
@__types__ = MIME::Types::Loader.load
|
281
|
+
MIME::Types::Cache.save(@__types__)
|
944
282
|
end
|
283
|
+
@__types__
|
284
|
+
end
|
285
|
+
end
|
945
286
|
|
946
|
-
|
947
|
-
|
948
|
-
|
287
|
+
private
|
288
|
+
def add_type_variant!(mime_type)
|
289
|
+
@type_variants[mime_type.simplified] << mime_type
|
290
|
+
end
|
949
291
|
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
end
|
292
|
+
def index_extensions!(mime_type)
|
293
|
+
mime_type.extensions.each { |ext| @extension_index[ext] << mime_type }
|
294
|
+
end
|
954
295
|
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
end
|
962
|
-
end
|
296
|
+
def prune_matches(matches, flags)
|
297
|
+
matches.delete_if { |e| not e.complete? } if flags[:complete]
|
298
|
+
matches.delete_if { |e| not e.platform? } if flags[:platform]
|
299
|
+
matches.delete_if { |e| not e.registered? } if flags[:registered]
|
300
|
+
matches
|
301
|
+
end
|
963
302
|
|
964
|
-
|
303
|
+
def match(pattern)
|
304
|
+
@type_variants.select { |k, v| k =~ pattern }.values.flatten
|
965
305
|
end
|
306
|
+
|
307
|
+
load_default_mime_types unless lazy_load?
|
966
308
|
end
|
967
309
|
|
968
310
|
# vim: ft=ruby
|