mime-types 1.16 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/mime/types.rb CHANGED
@@ -1,751 +1,233 @@
1
- # vim: ft=ruby encoding=utf-8
2
- #--
3
- # MIME::Types
4
- # A Ruby implementation of a MIME Types information library. Based in spirit
5
- # on the Perl MIME::Types information library by Mark Overmeer.
6
- # http://rubyforge.org/projects/mime-types/
7
- #
8
- # Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl
9
- # Artistic licence. See Licence.txt for more information.
10
- #
11
- # Copyright 2003 - 2009 Austin Ziegler
12
- #++
1
+ # frozen_string_literal: true
13
2
 
14
- # The namespace for MIME applications, tools, and libraries.
3
+ ##
15
4
  module MIME
16
- # Reflects a MIME Content-Type which is in invalid format (e.g., it isn't
17
- # in the form of type/subtype).
18
- class InvalidContentType < RuntimeError; end
19
-
20
- # The definition of one MIME content-type.
21
- #
22
- # == Usage
23
- # require 'mime/types'
24
- #
25
- # plaintext = MIME::Types['text/plain']
26
- # print plaintext.media_type # => 'text'
27
- # print plaintext.sub_type # => 'plain'
28
- #
29
- # puts plaintext.extensions.join(" ") # => 'asc txt c cc h hh cpp'
30
- #
31
- # puts plaintext.encoding # => 8bit
32
- # puts plaintext.binary? # => false
33
- # puts plaintext.ascii? # => true
34
- # puts plaintext == 'text/plain' # => true
35
- # puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
36
- #
37
- class Type
38
- VERSION = '1.16'
39
-
40
- include Comparable
41
-
42
- MEDIA_TYPE_RE = %r{([-\w.+]+)/([-\w.+]*)}o
43
- UNREG_RE = %r{[Xx]-}o
44
- ENCODING_RE = %r{(?:base64|7bit|8bit|quoted\-printable)}o
45
- PLATFORM_RE = %r|#{RUBY_PLATFORM}|o
46
-
47
- SIGNATURES = %w(application/pgp-keys application/pgp
48
- application/pgp-signature application/pkcs10
49
- application/pkcs7-mime application/pkcs7-signature
50
- text/vcard)
51
-
52
- IANA_URL = "http://www.iana.org/assignments/media-types/%s/%s"
53
- RFC_URL = "http://rfc-editor.org/rfc/rfc%s.txt"
54
- DRAFT_URL = "http://datatracker.ietf.org/public/idindex.cgi?command=id_details&filename=%s"
55
- LTSW_URL = "http://www.ltsw.se/knbase/internet/%s.htp"
56
- CONTACT_URL = "http://www.iana.org/assignments/contact-people.htm#%s"
57
-
58
- # Returns +true+ if the simplified type matches the current
59
- def like?(other)
60
- if other.respond_to?(:simplified)
61
- @simplified == other.simplified
62
- else
63
- @simplified == Type.simplified(other)
64
- end
65
- end
66
-
67
- # Compares the MIME::Type against the exact content type or the
68
- # simplified type (the simplified type will be used if comparing against
69
- # something that can be treated as a String with #to_s). In comparisons,
70
- # this is done against the lowercase version of the MIME::Type.
71
- def <=>(other)
72
- if other.respond_to?(:content_type)
73
- @content_type.downcase <=> other.content_type.downcase
74
- elsif other.respond_to?(:to_s)
75
- @simplified <=> Type.simplified(other.to_s)
76
- else
77
- @content_type.downcase <=> other.downcase
78
- end
79
- end
80
-
81
- # Compares the MIME::Type based on how reliable it is before doing a
82
- # normal <=> comparison. Used by MIME::Types#[] to sort types. The
83
- # comparisons involved are:
84
- #
85
- # 1. self.simplified <=> other.simplified (ensures that we
86
- # don't try to compare different types)
87
- # 2. IANA-registered definitions > other definitions.
88
- # 3. Generic definitions > platform definitions.
89
- # 3. Complete definitions > incomplete definitions.
90
- # 4. Current definitions > obsolete definitions.
91
- # 5. Obselete with use-instead references > obsolete without.
92
- # 6. Obsolete use-instead definitions are compared.
93
- def priority_compare(other)
94
- pc = simplified <=> other.simplified
95
-
96
- if pc.zero? and registered? != other.registered?
97
- pc = registered? ? -1 : 1
98
- end
99
-
100
- if pc.zero? and platform? != other.platform?
101
- pc = platform? ? 1 : -1
102
- end
103
-
104
- if pc.zero? and complete? != other.complete?
105
- pc = complete? ? -1 : 1
106
- end
107
-
108
- if pc.zero? and obsolete? != other.obsolete?
109
- pc = obsolete? ? 1 : -1
110
- end
111
-
112
- if pc.zero? and obsolete? and (use_instead != other.use_instead)
113
- pc = if use_instead.nil?
114
- -1
115
- elsif other.use_instead.nil?
116
- 1
117
- else
118
- use_instead <=> other.use_instead
119
- end
120
- end
121
-
122
- pc
123
- end
124
-
125
- # Returns +true+ if the other object is a MIME::Type and the content
126
- # types match.
127
- def eql?(other)
128
- other.kind_of?(MIME::Type) and self == other
129
- end
130
-
131
- # Returns the whole MIME content-type string.
132
- #
133
- # text/plain => text/plain
134
- # x-chemical/x-pdb => x-chemical/x-pdb
135
- attr_reader :content_type
136
- # Returns the media type of the simplified MIME type.
137
- #
138
- # text/plain => text
139
- # x-chemical/x-pdb => chemical
140
- attr_reader :media_type
141
- # Returns the media type of the unmodified MIME type.
142
- #
143
- # text/plain => text
144
- # x-chemical/x-pdb => x-chemical
145
- attr_reader :raw_media_type
146
- # Returns the sub-type of the simplified MIME type.
147
- #
148
- # text/plain => plain
149
- # x-chemical/x-pdb => pdb
150
- attr_reader :sub_type
151
- # Returns the media type of the unmodified MIME type.
152
- #
153
- # text/plain => plain
154
- # x-chemical/x-pdb => x-pdb
155
- attr_reader :raw_sub_type
156
- # The MIME types main- and sub-label can both start with <tt>x-</tt>,
157
- # which indicates that it is a non-registered name. Of course, after
158
- # registration this flag can disappear, adds to the confusing
159
- # proliferation of MIME types. The simplified string has the <tt>x-</tt>
160
- # removed and are translated to lowercase.
161
- #
162
- # text/plain => text/plain
163
- # x-chemical/x-pdb => chemical/pdb
164
- attr_reader :simplified
165
- # The list of extensions which are known to be used for this MIME::Type.
166
- # Non-array values will be coerced into an array with #to_a. Array
167
- # values will be flattened and +nil+ values removed.
168
- attr_accessor :extensions
169
- remove_method :extensions= ;
170
- def extensions=(ext) #:nodoc:
171
- @extensions = [ext].flatten.compact
172
- end
173
-
174
- # The encoding (7bit, 8bit, quoted-printable, or base64) required to
175
- # transport the data of this content type safely across a network, which
176
- # roughly corresponds to Content-Transfer-Encoding. A value of +nil+ or
177
- # <tt>:default</tt> will reset the #encoding to the #default_encoding
178
- # for the MIME::Type. Raises ArgumentError if the encoding provided is
179
- # invalid.
180
- #
181
- # If the encoding is not provided on construction, this will be either
182
- # 'quoted-printable' (for text/* media types) and 'base64' for eveything
183
- # else.
184
- attr_accessor :encoding
185
- remove_method :encoding= ;
186
- def encoding=(enc) #:nodoc:
187
- if enc.nil? or enc == :default
188
- @encoding = self.default_encoding
189
- elsif enc =~ ENCODING_RE
190
- @encoding = enc
191
- else
192
- raise ArgumentError, "The encoding must be nil, :default, base64, 7bit, 8bit, or quoted-printable."
193
- end
194
- end
195
-
196
- # The regexp for the operating system that this MIME::Type is specific
197
- # to.
198
- attr_accessor :system
199
- remove_method :system= ;
200
- def system=(os) #:nodoc:
201
- if os.nil? or os.kind_of?(Regexp)
202
- @system = os
203
- else
204
- @system = %r|#{os}|
205
- end
206
- end
207
- # Returns the default encoding for the MIME::Type based on the media
208
- # type.
209
- attr_reader :default_encoding
210
- remove_method :default_encoding
211
- def default_encoding
212
- (@media_type == 'text') ? 'quoted-printable' : 'base64'
213
- end
214
-
215
- # Returns the media type or types that should be used instead of this
216
- # media type, if it is obsolete. If there is no replacement media type,
217
- # or it is not obsolete, +nil+ will be returned.
218
- attr_reader :use_instead
219
- remove_method :use_instead
220
- def use_instead
221
- return nil unless @obsolete
222
- @use_instead
223
- end
224
-
225
- # Returns +true+ if the media type is obsolete.
226
- def obsolete?
227
- @obsolete ? true : false
228
- end
229
- # Sets the obsolescence indicator for this media type.
230
- attr_writer :obsolete
231
-
232
- # The documentation for this MIME::Type. Documentation about media
233
- # types will be found on a media type definition as a comment.
234
- # Documentation will be found through #docs.
235
- attr_accessor :docs
236
- remove_method :docs= ;
237
- def docs=(d)
238
- if d
239
- a = d.scan(%r{use-instead:#{MEDIA_TYPE_RE}})
240
-
241
- if a.empty?
242
- @use_instead = nil
243
- else
244
- @use_instead = a.map { |el| "#{el[0]}/#{el[1]}" }
245
- end
246
- end
247
- @docs = d
248
- end
249
-
250
- # The encoded URL list for this MIME::Type. See #urls for more
251
- # information.
252
- attr_accessor :url
253
- # The decoded URL list for this MIME::Type.
254
- # The special URL value IANA will be translated into:
255
- # http://www.iana.org/assignments/media-types/<mediatype>/<subtype>
256
- #
257
- # The special URL value RFC### will be translated into:
258
- # http://www.rfc-editor.org/rfc/rfc###.txt
259
- #
260
- # The special URL value DRAFT:name will be translated into:
261
- # https://datatracker.ietf.org/public/idindex.cgi?
262
- # command=id_detail&filename=<name>
263
- #
264
- # The special URL value LTSW will be translated into:
265
- # http://www.ltsw.se/knbase/internet/<mediatype>.htp
266
- #
267
- # The special URL value [token] will be translated into:
268
- # http://www.iana.org/assignments/contact-people.htm#<token>
269
- #
270
- # These values will be accessible through #urls, which always returns an
271
- # array.
272
- def urls
273
- @url.map do |el|
274
- case el
275
- when %r{^IANA$}
276
- IANA_URL % [ @media_type, @sub_type ]
277
- when %r{^RFC(\d+)$}
278
- RFC_URL % $1
279
- when %r{^DRAFT:(.+)$}
280
- DRAFT_URL % $1
281
- when %r{^LTSW$}
282
- LTSW_URL % @media_type
283
- when %r<^\{([^=]+)=([^\]]+)\}>
284
- [$1, $2]
285
- when %r{^\[([^=]+)=([^\]]+)\]}
286
- [$1, CONTACT_URL % $2]
287
- when %r{^\[([^\]]+)\]}
288
- CONTACT_URL % $1
289
- else
290
- el
291
- end
292
- end
293
- end
294
-
295
- class << self
296
- # The MIME types main- and sub-label can both start with <tt>x-</tt>,
297
- # which indicates that it is a non-registered name. Of course, after
298
- # registration this flag can disappear, adds to the confusing
299
- # proliferation of MIME types. The simplified string has the
300
- # <tt>x-</tt> removed and are translated to lowercase.
301
- def simplified(content_type)
302
- matchdata = MEDIA_TYPE_RE.match(content_type)
303
-
304
- if matchdata.nil?
305
- simplified = nil
306
- else
307
- media_type = matchdata.captures[0].downcase.gsub(UNREG_RE, '')
308
- subtype = matchdata.captures[1].downcase.gsub(UNREG_RE, '')
309
- simplified = "#{media_type}/#{subtype}"
310
- end
311
- simplified
312
- end
313
-
314
- # Creates a MIME::Type from an array in the form of:
315
- # [type-name, [extensions], encoding, system]
316
- #
317
- # +extensions+, +encoding+, and +system+ are optional.
318
- #
319
- # MIME::Type.from_array("application/x-ruby", ['rb'], '8bit')
320
- # MIME::Type.from_array(["application/x-ruby", ['rb'], '8bit'])
321
- #
322
- # These are equivalent to:
323
- #
324
- # MIME::Type.new('application/x-ruby') do |t|
325
- # t.extensions = %w(rb)
326
- # t.encoding = '8bit'
327
- # end
328
- def from_array(*args) #:yields MIME::Type.new:
329
- # Dereferences the array one level, if necessary.
330
- args = args[0] if args[0].kind_of?(Array)
331
-
332
- if args.size.between?(1, 8)
333
- m = MIME::Type.new(args[0]) do |t|
334
- t.extensions = args[1] if args.size > 1
335
- t.encoding = args[2] if args.size > 2
336
- t.system = args[3] if args.size > 3
337
- t.obsolete = args[4] if args.size > 4
338
- t.docs = args[5] if args.size > 5
339
- t.url = args[6] if args.size > 6
340
- t.registered = args[7] if args.size > 7
341
- end
342
- yield m if block_given?
343
- else
344
- raise ArgumentError, "Array provided must contain between one and eight elements."
345
- end
346
- m
347
- end
348
-
349
- # Creates a MIME::Type from a hash. Keys are case-insensitive,
350
- # dashes may be replaced with underscores, and the internal Symbol
351
- # of the lowercase-underscore version can be used as well. That is,
352
- # Content-Type can be provided as content-type, Content_Type,
353
- # content_type, or :content_type.
354
- #
355
- # Known keys are <tt>Content-Type</tt>,
356
- # <tt>Content-Transfer-Encoding</tt>, <tt>Extensions</tt>, and
357
- # <tt>System</tt>.
358
- #
359
- # MIME::Type.from_hash('Content-Type' => 'text/x-yaml',
360
- # 'Content-Transfer-Encoding' => '8bit',
361
- # 'System' => 'linux',
362
- # 'Extensions' => ['yaml', 'yml'])
363
- #
364
- # This is equivalent to:
365
- #
366
- # MIME::Type.new('text/x-yaml') do |t|
367
- # t.encoding = '8bit'
368
- # t.system = 'linux'
369
- # t.extensions = ['yaml', 'yml']
370
- # end
371
- def from_hash(hash) #:yields MIME::Type.new:
372
- type = {}
373
- hash.each_pair do |k, v|
374
- type[k.to_s.tr('A-Z', 'a-z').gsub(/-/, '_').to_sym] = v
375
- end
5
+ ##
6
+ class Types
7
+ end
8
+ end
376
9
 
377
- m = MIME::Type.new(type[:content_type]) do |t|
378
- t.extensions = type[:extensions]
379
- t.encoding = type[:content_transfer_encoding]
380
- t.system = type[:system]
381
- t.obsolete = type[:obsolete]
382
- t.docs = type[:docs]
383
- t.url = type[:url]
384
- t.registered = type[:registered]
385
- end
10
+ require "mime/type"
386
11
 
387
- yield m if block_given?
388
- m
389
- end
12
+ # MIME::Types is a registry of MIME types. It is both a class (created with
13
+ # MIME::Types.new) and a default registry (loaded automatically or through
14
+ # interactions with MIME::Types.[] and MIME::Types.type_for).
15
+ #
16
+ # == The Default mime-types Registry
17
+ #
18
+ # The default mime-types registry is loaded automatically when the library
19
+ # is required (<tt>require 'mime/types'</tt>), but it may be lazily loaded
20
+ # (loaded on first use) with the use of the environment variable
21
+ # +RUBY_MIME_TYPES_LAZY_LOAD+ having any value other than +false+. The
22
+ # initial startup is about 14× faster (~10 ms vs ~140 ms), but the
23
+ # registry will be loaded at some point in the future.
24
+ #
25
+ # The default mime-types registry can also be loaded from a Marshal cache
26
+ # file specific to the version of MIME::Types being loaded. This will be
27
+ # handled automatically with the use of a file referred to in the
28
+ # environment variable +RUBY_MIME_TYPES_CACHE+. MIME::Types will attempt to
29
+ # load the registry from this cache file (MIME::Type::Cache.load); if it
30
+ # cannot be loaded (because the file does not exist, there is an error, or
31
+ # the data is for a different version of mime-types), the default registry
32
+ # will be loaded from the normal JSON version and then the cache file will
33
+ # be *written* to the location indicated by +RUBY_MIME_TYPES_CACHE+. Cache
34
+ # file loads just over 4½× faster (~30 ms vs ~140 ms).
35
+ # loads.
36
+ #
37
+ # Notes:
38
+ # * The loading of the default registry is *not* atomic; when using a
39
+ # multi-threaded environment, it is recommended that lazy loading is not
40
+ # used and mime-types is loaded as early as possible.
41
+ # * Cache files should be specified per application in a multiprocess
42
+ # environment and should be initialized during deployment or before
43
+ # forking to minimize the chance that the multiple processes will be
44
+ # trying to write to the same cache file at the same time, or that two
45
+ # applications that are on different versions of mime-types would be
46
+ # thrashing the cache.
47
+ # * Unless cache files are preinitialized, the application using the
48
+ # mime-types cache file must have read/write permission to the cache file.
49
+ #
50
+ # == Usage
51
+ # require 'mime/types'
52
+ #
53
+ # plaintext = MIME::Types['text/plain']
54
+ # print plaintext.media_type # => 'text'
55
+ # print plaintext.sub_type # => 'plain'
56
+ #
57
+ # puts plaintext.extensions.join(" ") # => 'asc txt c cc h hh cpp'
58
+ #
59
+ # puts plaintext.encoding # => 8bit
60
+ # puts plaintext.binary? # => false
61
+ # puts plaintext.ascii? # => true
62
+ # puts plaintext.obsolete? # => false
63
+ # puts plaintext.registered? # => true
64
+ # puts plaintext.provisional? # => false
65
+ # puts plaintext == 'text/plain' # => true
66
+ # puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
67
+ #
68
+ class MIME::Types
69
+ # The release version of Ruby MIME::Types
70
+ VERSION = MIME::Type::VERSION
390
71
 
391
- # Essentially a copy constructor.
392
- #
393
- # MIME::Type.from_mime_type(plaintext)
394
- #
395
- # is equivalent to:
396
- #
397
- # MIME::Type.new(plaintext.content_type.dup) do |t|
398
- # t.extensions = plaintext.extensions.dup
399
- # t.system = plaintext.system.dup
400
- # t.encoding = plaintext.encoding.dup
401
- # end
402
- def from_mime_type(mime_type) #:yields the new MIME::Type:
403
- m = MIME::Type.new(mime_type.content_type.dup) do |t|
404
- t.extensions = mime_type.extensions.map { |e| e.dup }
405
- t.url = mime_type.url && mime_type.url.map { |e| e.dup }
72
+ include Enumerable
406
73
 
407
- mime_type.system && t.system = mime_type.system.dup
408
- mime_type.encoding && t.encoding = mime_type.encoding.dup
74
+ # Creates a new MIME::Types registry.
75
+ def initialize
76
+ @type_variants = Container.new
77
+ @extension_index = Container.new
78
+ end
409
79
 
410
- t.obsolete = mime_type.obsolete?
411
- t.registered = mime_type.registered?
80
+ # Returns the number of known type variants.
81
+ def count
82
+ @type_variants.values.inject(0) { |a, e| a + e.size }
83
+ end
412
84
 
413
- mime_type.docs && t.docs = mime_type.docs.dup
414
-
415
- end
85
+ def inspect # :nodoc:
86
+ "#<#{self.class}: #{count} variants, #{@extension_index.count} extensions>"
87
+ end
416
88
 
417
- yield m if block_given?
418
- end
89
+ # Iterates through the type variants.
90
+ def each
91
+ if block_given?
92
+ @type_variants.each_value { |tv| tv.each { |t| yield t } }
93
+ else
94
+ enum_for(:each)
419
95
  end
96
+ end
420
97
 
421
- # Builds a MIME::Type object from the provided MIME Content Type value
422
- # (e.g., 'text/plain' or 'applicaton/x-eruby'). The constructed object
423
- # is yielded to an optional block for additional configuration, such as
424
- # associating extensions and encoding information.
425
- def initialize(content_type) #:yields self:
426
- matchdata = MEDIA_TYPE_RE.match(content_type)
427
-
428
- if matchdata.nil?
429
- raise InvalidContentType, "Invalid Content-Type provided ('#{content_type}')"
430
- end
431
-
432
- @content_type = content_type
433
- @raw_media_type = matchdata.captures[0]
434
- @raw_sub_type = matchdata.captures[1]
435
-
436
- @simplified = MIME::Type.simplified(@content_type)
437
- matchdata = MEDIA_TYPE_RE.match(@simplified)
438
- @media_type = matchdata.captures[0]
439
- @sub_type = matchdata.captures[1]
440
-
441
- self.extensions = nil
442
- self.encoding = :default
443
- self.system = nil
444
- self.registered = true
445
- self.url = nil
446
- self.obsolete = nil
447
- self.docs = nil
448
-
449
- yield self if block_given?
450
- end
98
+ @__types__ = nil
451
99
 
452
- # MIME content-types which are not regestered by IANA nor defined in
453
- # RFCs are required to start with <tt>x-</tt>. This counts as well for
454
- # a new media type as well as a new sub-type of an existing media
455
- # type. If either the media-type or the content-type begins with
456
- # <tt>x-</tt>, this method will return +false+.
457
- def registered?
458
- if (@raw_media_type =~ UNREG_RE) || (@raw_sub_type =~ UNREG_RE)
459
- false
100
+ # Returns a list of MIME::Type objects, which may be empty. The optional
101
+ # flag parameters are <tt>:complete</tt> (finds only complete MIME::Type
102
+ # objects) and <tt>:registered</tt> (finds only MIME::Types that are
103
+ # registered). It is possible for multiple matches to be returned for
104
+ # either type (in the example below, 'text/plain' returns two values --
105
+ # one for the general case, and one for VMS systems).
106
+ #
107
+ # puts "\nMIME::Types['text/plain']"
108
+ # MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
109
+ #
110
+ # puts "\nMIME::Types[/^image/, complete: true]"
111
+ # MIME::Types[/^image/, :complete => true].each do |t|
112
+ # puts t.to_a.join(", ")
113
+ # end
114
+ #
115
+ # If multiple type definitions are returned, returns them sorted as
116
+ # follows:
117
+ # 1. Complete definitions sort before incomplete ones;
118
+ # 2. IANA-registered definitions sort before LTSW-recorded
119
+ # definitions.
120
+ # 3. Current definitions sort before obsolete ones;
121
+ # 4. Obsolete definitions with use-instead clauses sort before those
122
+ # without;
123
+ # 5. Obsolete definitions use-instead clauses are compared.
124
+ # 6. Sort on name.
125
+ def [](type_id, complete: false, registered: false)
126
+ matches =
127
+ case type_id
128
+ when MIME::Type
129
+ @type_variants[type_id.simplified]
130
+ when Regexp
131
+ match(type_id)
460
132
  else
461
- @registered
133
+ @type_variants[MIME::Type.simplified(type_id)]
462
134
  end
463
- end
464
- attr_writer :registered #:nodoc:
465
-
466
- # MIME types can be specified to be sent across a network in particular
467
- # formats. This method returns +true+ when the MIME type encoding is set
468
- # to <tt>base64</tt>.
469
- def binary?
470
- @encoding == 'base64'
471
- end
472
-
473
- # MIME types can be specified to be sent across a network in particular
474
- # formats. This method returns +false+ when the MIME type encoding is
475
- # set to <tt>base64</tt>.
476
- def ascii?
477
- not binary?
478
- end
479
-
480
- # Returns +true+ when the simplified MIME type is in the list of known
481
- # digital signatures.
482
- def signature?
483
- SIGNATURES.include?(@simplified.downcase)
484
- end
485
-
486
- # Returns +true+ if the MIME::Type is specific to an operating system.
487
- def system?
488
- not @system.nil?
489
- end
490
-
491
- # Returns +true+ if the MIME::Type is specific to the current operating
492
- # system as represented by RUBY_PLATFORM.
493
- def platform?
494
- system? and (RUBY_PLATFORM =~ @system)
495
- end
496
-
497
- # Returns +true+ if the MIME::Type specifies an extension list,
498
- # indicating that it is a complete MIME::Type.
499
- def complete?
500
- not @extensions.empty?
501
- end
502
-
503
- # Returns the MIME type as a string.
504
- def to_s
505
- @content_type
506
- end
507
-
508
- # Returns the MIME type as a string for implicit conversions.
509
- def to_str
510
- @content_type
511
- end
512
-
513
- # Returns the MIME type as an array suitable for use with
514
- # MIME::Type.from_array.
515
- def to_a
516
- [ @content_type, @extensions, @encoding, @system, @obsolete, @docs,
517
- @url, registered? ]
518
- end
519
135
 
520
- # Returns the MIME type as an array suitable for use with
521
- # MIME::Type.from_hash.
522
- def to_hash
523
- { 'Content-Type' => @content_type,
524
- 'Content-Transfer-Encoding' => @encoding,
525
- 'Extensions' => @extensions,
526
- 'System' => @system,
527
- 'Obsolete' => @obsolete,
528
- 'Docs' => @docs,
529
- 'URL' => @url,
530
- 'Registered' => registered?,
531
- }
532
- end
136
+ prune_matches(matches, complete, registered).sort { |a, b|
137
+ a.priority_compare(b)
138
+ }
533
139
  end
534
140
 
535
- # = MIME::Types
536
- # MIME types are used in MIME-compliant communications, as in e-mail or
537
- # HTTP traffic, to indicate the type of content which is transmitted.
538
- # MIME::Types provides the ability for detailed information about MIME
539
- # entities (provided as a set of MIME::Type objects) to be determined and
540
- # used programmatically. There are many types defined by RFCs and vendors,
541
- # so the list is long but not complete; don't hesitate to ask to add
542
- # additional information. This library follows the IANA collection of MIME
543
- # types (see below for reference).
544
- #
545
- # == Description
546
- # MIME types are used in MIME entities, as in email or HTTP traffic. It is
547
- # useful at times to have information available about MIME types (or,
548
- # inversely, about files). A MIME::Type stores the known information about
549
- # one MIME type.
550
- #
551
- # == Usage
552
- # require 'mime/types'
553
- #
554
- # plaintext = MIME::Types['text/plain']
555
- # print plaintext.media_type # => 'text'
556
- # print plaintext.sub_type # => 'plain'
557
- #
558
- # puts plaintext.extensions.join(" ") # => 'asc txt c cc h hh cpp'
141
+ # Return the list of MIME::Types which belongs to the file based on its
142
+ # filename extension. If there is no extension, the filename will be used
143
+ # as the matching criteria on its own.
559
144
  #
560
- # puts plaintext.encoding # => 8bit
561
- # puts plaintext.binary? # => false
562
- # puts plaintext.ascii? # => true
563
- # puts plaintext.obsolete? # => false
564
- # puts plaintext.registered? # => true
565
- # puts plaintext == 'text/plain' # => true
566
- # puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
145
+ # This will always return a merged, flatten, priority sorted, unique array.
567
146
  #
568
- # This module is built to conform to the MIME types of RFCs 2045 and 2231.
569
- # It follows the official IANA registry at
570
- # http://www.iana.org/assignments/media-types/ and
571
- # ftp://ftp.iana.org/assignments/media-types with some unofficial types
572
- # added from the the collection at
573
- # http://www.ltsw.se/knbase/internet/mime.htp
574
- #
575
- # This is originally based on Perl MIME::Types by Mark Overmeer.
576
- #
577
- # = Author
578
- # Copyright:: Copyright (c) 2002 - 2009 by Austin Ziegler
579
- # <austin@rubyforge.org>
580
- # Version:: 1.16
581
- # Based On:: Perl
582
- # MIME::Types[http://search.cpan.org/author/MARKOV/MIME-Types-1.27/MIME/Types.pm],
583
- # Copyright (c) 2001 - 2009 by Mark Overmeer
584
- # <mimetypes@overmeer.net>.
585
- # Licence:: Ruby's, Perl Artistic, or GPL version 2 (or later)
586
- # See Also:: http://www.iana.org/assignments/media-types/
587
- # http://www.ltsw.se/knbase/internet/mime.htp
588
- #
589
- class Types
590
- # The released version of Ruby MIME::Types
591
- VERSION = '1.16'
592
-
593
- # The data version.
594
- attr_reader :data_version
595
-
596
- def initialize(data_version = nil)
597
- @type_variants = Hash.new { |h, k| h[k] = [] }
598
- @extension_index = Hash.new { |h, k| h[k] = [] }
599
- end
600
-
601
- def add_type_variant(mime_type) #:nodoc:
602
- @type_variants[mime_type.simplified] << mime_type
603
- end
604
-
605
- def index_extensions(mime_type) #:nodoc:
606
- mime_type.extensions.each { |ext| @extension_index[ext] << mime_type }
607
- end
608
-
609
- @__types__ = self.new(VERSION)
147
+ # puts MIME::Types.type_for('citydesk.xml')
148
+ # => [application/xml, text/xml]
149
+ # puts MIME::Types.type_for('citydesk.gif')
150
+ # => [image/gif]
151
+ # puts MIME::Types.type_for(%w(citydesk.xml citydesk.gif))
152
+ # => [application/xml, image/gif, text/xml]
153
+ def type_for(filename)
154
+ Array(filename).flat_map { |fn|
155
+ @extension_index[fn.chomp.downcase[/\.?([^.]*?)\z/m, 1]]
156
+ }.compact.inject(Set.new, :+).sort { |a, b|
157
+ a.priority_compare(b)
158
+ }
159
+ end
160
+ alias_method :of, :type_for
610
161
 
611
- # Returns a list of MIME::Type objects, which may be empty. The optional
612
- # flag parameters are :complete (finds only complete MIME::Type objects)
613
- # and :platform (finds only MIME::Types for the current platform). It is
614
- # possible for multiple matches to be returned for either type (in the
615
- # example below, 'text/plain' returns two values -- one for the general
616
- # case, and one for VMS systems.
617
- #
618
- # puts "\nMIME::Types['text/plain']"
619
- # MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
620
- #
621
- # puts "\nMIME::Types[/^image/, :complete => true]"
622
- # MIME::Types[/^image/, :complete => true].each do |t|
623
- # puts t.to_a.join(", ")
624
- # end
625
- #
626
- # If multiple type definitions are returned, returns them sorted as
627
- # follows:
628
- # 1. Complete definitions sort before incomplete ones;
629
- # 2. IANA-registered definitions sort before LTSW-recorded
630
- # definitions.
631
- # 3. Generic definitions sort before platform-specific ones;
632
- # 4. Current definitions sort before obsolete ones;
633
- # 5. Obsolete definitions with use-instead clauses sort before those
634
- # without;
635
- # 6. Obsolete definitions use-instead clauses are compared.
636
- # 7. Sort on name.
637
- def [](type_id, flags = {})
638
- if type_id.kind_of?(Regexp)
639
- matches = []
640
- @type_variants.each_key do |k|
641
- matches << @type_variants[k] if k =~ type_id
642
- end
643
- matches.flatten!
644
- elsif type_id.kind_of?(MIME::Type)
645
- matches = [type_id]
162
+ # Add one or more MIME::Type objects to the set of known types. If the
163
+ # type is already known, a warning will be displayed.
164
+ #
165
+ # The last parameter may be the value <tt>:silent</tt> or +true+ which
166
+ # will suppress duplicate MIME type warnings.
167
+ def add(*types)
168
+ quiet = (types.last == :silent) || (types.last == true)
169
+
170
+ types.each do |mime_type|
171
+ case mime_type
172
+ when true, false, nil, Symbol
173
+ nil
174
+ when MIME::Types
175
+ variants = mime_type.instance_variable_get(:@type_variants)
176
+ add(*variants.values.inject(Set.new, :+).to_a, quiet)
177
+ when Array
178
+ add(*mime_type, quiet)
646
179
  else
647
- matches = @type_variants[MIME::Type.simplified(type_id)]
180
+ add_type(mime_type, quiet)
648
181
  end
649
-
650
- matches.delete_if { |e| not e.complete? } if flags[:complete]
651
- matches.delete_if { |e| not e.platform? } if flags[:platform]
652
-
653
- matches.sort { |a, b| a.priority_compare(b) }
654
182
  end
183
+ end
655
184
 
656
- # Return the list of MIME::Types which belongs to the file based on its
657
- # filename extension. If +platform+ is +true+, then only file types that
658
- # are specific to the current platform will be returned.
659
- #
660
- # puts "MIME::Types.type_for('citydesk.xml')
661
- # => "#{MIME::Types.type_for('citydesk.xml')}"
662
- # puts "MIME::Types.type_for('citydesk.gif')
663
- # => "#{MIME::Types.type_for('citydesk.gif')}"
664
- def type_for(filename, platform = false)
665
- ext = filename.chomp.downcase.gsub(/.*\./o, '')
666
- list = @extension_index[ext]
667
- list.delete_if { |e| not e.platform? } if platform
668
- list
185
+ # Add a single MIME::Type object to the set of known types. If the +type+ is
186
+ # already known, a warning will be displayed. The +quiet+ parameter may be a
187
+ # truthy value to suppress that warning.
188
+ def add_type(type, quiet = false)
189
+ if !quiet && @type_variants[type.simplified].include?(type)
190
+ MIME::Types.logger.debug <<-WARNING.chomp.strip
191
+ Type #{type} is already registered as a variant of #{type.simplified}.
192
+ WARNING
669
193
  end
670
194
 
671
- # A synonym for MIME::Types.type_for
672
- def of(filename, platform = false)
673
- type_for(filename, platform)
674
- end
195
+ add_type_variant!(type)
196
+ index_extensions!(type)
197
+ end
675
198
 
676
- # Add one or more MIME::Type objects to the set of known types. Each
677
- # type should be experimental (e.g., 'application/x-ruby'). If the type
678
- # is already known, a warning will be displayed.
679
- #
680
- # <b>Please inform the maintainer of this module when registered types
681
- # are missing.</b>
682
- def add(*types)
683
- types.each do |mime_type|
684
- if @type_variants.include?(mime_type.simplified)
685
- if @type_variants[mime_type.simplified].include?(mime_type)
686
- warn "Type #{mime_type} already registered as a variant of #{mime_type.simplified}."
687
- end
688
- end
689
- add_type_variant(mime_type)
690
- index_extensions(mime_type)
691
- end
692
- end
199
+ private
693
200
 
694
- class << self
695
- def add_type_variant(mime_type) #:nodoc:
696
- @__types__.add_type_variant(mime_type)
697
- end
201
+ def add_type_variant!(mime_type)
202
+ @type_variants.add(mime_type.simplified, mime_type)
203
+ end
698
204
 
699
- def index_extensions(mime_type) #:nodoc:
700
- @__types__.index_extensions(mime_type)
701
- end
205
+ def reindex_extensions!(mime_type)
206
+ return unless @type_variants[mime_type.simplified].include?(mime_type)
702
207
 
703
- # Returns a list of MIME::Type objects, which may be empty. The
704
- # optional flag parameters are :complete (finds only complete
705
- # MIME::Type objects) and :platform (finds only MIME::Types for the
706
- # current platform). It is possible for multiple matches to be
707
- # returned for either type (in the example below, 'text/plain' returns
708
- # two values -- one for the general case, and one for VMS systems.
709
- #
710
- # puts "\nMIME::Types['text/plain']"
711
- # MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
712
- #
713
- # puts "\nMIME::Types[/^image/, :complete => true]"
714
- # MIME::Types[/^image/, :complete => true].each do |t|
715
- # puts t.to_a.join(", ")
716
- # end
717
- def [](type_id, flags = {})
718
- @__types__[type_id, flags]
719
- end
208
+ index_extensions!(mime_type)
209
+ end
720
210
 
721
- # Return the list of MIME::Types which belongs to the file based on
722
- # its filename extension. If +platform+ is +true+, then only file
723
- # types that are specific to the current platform will be returned.
724
- #
725
- # puts "MIME::Types.type_for('citydesk.xml')
726
- # => "#{MIME::Types.type_for('citydesk.xml')}"
727
- # puts "MIME::Types.type_for('citydesk.gif')
728
- # => "#{MIME::Types.type_for('citydesk.gif')}"
729
- def type_for(filename, platform = false)
730
- @__types__.type_for(filename, platform)
731
- end
211
+ def index_extensions!(mime_type)
212
+ mime_type.extensions.each { |ext| @extension_index.add(ext, mime_type) }
213
+ end
732
214
 
733
- # A synonym for MIME::Types.type_for
734
- def of(filename, platform = false)
735
- @__types__.type_for(filename, platform)
736
- end
215
+ def prune_matches(matches, complete, registered)
216
+ matches.delete_if { |e| !e.complete? } if complete
217
+ matches.delete_if { |e| !e.registered? } if registered
218
+ matches
219
+ end
737
220
 
738
- # Add one or more MIME::Type objects to the set of known types. Each
739
- # type should be experimental (e.g., 'application/x-ruby'). If the
740
- # type is already known, a warning will be displayed.
741
- #
742
- # <b>Please inform the maintainer of this module when registered types
743
- # are missing.</b>
744
- def add(*types)
745
- @__types__.add(*types)
746
- end
747
- end
221
+ def match(pattern)
222
+ @type_variants.select { |k, _|
223
+ k =~ pattern
224
+ }.values.inject(Set.new, :+)
748
225
  end
749
226
  end
750
227
 
751
- load File.join(File.dirname(__FILE__), 'types.rb.data')
228
+ require "mime/types/cache"
229
+ require "mime/types/container"
230
+ require "mime/types/loader"
231
+ require "mime/types/logger"
232
+ require "mime/types/_columnar"
233
+ require "mime/types/registry"