mime-types 2.99.3 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/{Code-of-Conduct.rdoc → Code-of-Conduct.md} +19 -20
  3. data/Contributing.md +143 -0
  4. data/History.md +240 -0
  5. data/{Licence.rdoc → Licence.md} +4 -18
  6. data/Manifest.txt +8 -25
  7. data/README.rdoc +62 -73
  8. data/Rakefile +175 -58
  9. data/lib/mime-types.rb +1 -1
  10. data/lib/mime/type.rb +213 -424
  11. data/lib/mime/type/columnar.rb +29 -62
  12. data/lib/mime/types.rb +46 -141
  13. data/lib/mime/types/_columnar.rb +136 -0
  14. data/lib/mime/types/cache.rb +51 -73
  15. data/lib/mime/types/columnar.rb +2 -147
  16. data/lib/mime/types/container.rb +96 -0
  17. data/lib/mime/types/deprecations.rb +4 -25
  18. data/lib/mime/types/full.rb +19 -0
  19. data/lib/mime/types/loader.rb +12 -141
  20. data/lib/mime/types/logger.rb +5 -1
  21. data/lib/mime/types/registry.rb +90 -0
  22. data/test/minitest_helper.rb +5 -13
  23. data/test/test_mime_type.rb +470 -456
  24. data/test/test_mime_types.rb +135 -87
  25. data/test/test_mime_types_cache.rb +82 -54
  26. data/test/test_mime_types_class.rb +118 -98
  27. data/test/test_mime_types_lazy.rb +26 -24
  28. data/test/test_mime_types_loader.rb +6 -33
  29. metadata +107 -64
  30. data/Contributing.rdoc +0 -170
  31. data/History-Types.rdoc +0 -454
  32. data/History.rdoc +0 -590
  33. data/data/mime-types.json +0 -1
  34. data/data/mime.content_type.column +0 -1980
  35. data/data/mime.docs.column +0 -1980
  36. data/data/mime.encoding.column +0 -1980
  37. data/data/mime.friendly.column +0 -1980
  38. data/data/mime.obsolete.column +0 -1980
  39. data/data/mime.registered.column +0 -1980
  40. data/data/mime.signature.column +0 -1980
  41. data/data/mime.use_instead.column +0 -1980
  42. data/data/mime.xrefs.column +0 -1980
  43. data/docs/COPYING.txt +0 -339
  44. data/docs/artistic.txt +0 -127
  45. data/lib/mime/types/loader_path.rb +0 -15
  46. data/support/apache_mime_types.rb +0 -108
  47. data/support/benchmarks/load.rb +0 -64
  48. data/support/benchmarks/load_allocations.rb +0 -83
  49. data/support/benchmarks/object_counts.rb +0 -41
  50. data/support/convert.rb +0 -158
  51. data/support/convert/columnar.rb +0 -88
  52. data/support/iana_registry.rb +0 -172
@@ -1,3 +1,3 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'mime/types'
@@ -1,4 +1,8 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ module MIME
5
+ end
2
6
 
3
7
  # The definition of one MIME content-type.
4
8
  #
@@ -53,33 +57,21 @@ class MIME::Type
53
57
  end
54
58
 
55
59
  # The released version of the mime-types library.
56
- VERSION = '2.99.3'
60
+ VERSION = '3.3.1'
57
61
 
58
62
  include Comparable
59
63
 
60
64
  # :stopdoc:
61
- MEDIA_TYPE_RE = %r{([-\w.+]+)/([-\w.+]*)}o
62
- UNREGISTERED_RE = %r{[Xx]-}o
63
- I18N_RE = %r{[^[:alnum:]]}o
64
- PLATFORM_RE = %r{#{RUBY_PLATFORM}}o
65
-
66
- DEFAULT_ENCODINGS = [ nil, :default ]
67
- BINARY_ENCODINGS = %w(base64 8bit)
68
- TEXT_ENCODINGS = %w(7bit quoted-printable)
69
- VALID_ENCODINGS = DEFAULT_ENCODINGS + BINARY_ENCODINGS + TEXT_ENCODINGS
70
-
71
- IANA_URL = 'http://www.iana.org/assignments/media-types/%s/%s'
72
- RFC_URL = 'http://rfc-editor.org/rfc/rfc%s.txt'
73
- DRAFT_URL = 'http://datatracker.ietf.org/public/idindex.cgi?command=id_details&filename=%s' # rubocop:disable Metrics/LineLength
74
- CONTACT_URL = 'http://www.iana.org/assignments/contact-people.htm#%s'
65
+ # TODO verify mime-type character restrictions; I am pretty sure that this is
66
+ # too wide open.
67
+ MEDIA_TYPE_RE = %r{([-\w.+]+)/([-\w.+]*)}.freeze
68
+ I18N_RE = /[^[:alnum:]]/.freeze
69
+ BINARY_ENCODINGS = %w(base64 8bit).freeze
70
+ ASCII_ENCODINGS = %w(7bit quoted-printable).freeze
75
71
  # :startdoc:
76
72
 
77
- if respond_to? :private_constant
78
- private_constant :MEDIA_TYPE_RE, :UNREGISTERED_RE, :I18N_RE, :PLATFORM_RE,
79
- :DEFAULT_ENCODINGS, :BINARY_ENCODINGS, :TEXT_ENCODINGS,
80
- :VALID_ENCODINGS, :IANA_URL, :RFC_URL, :DRAFT_URL,
81
- :CONTACT_URL
82
- end
73
+ private_constant :MEDIA_TYPE_RE, :I18N_RE, :BINARY_ENCODINGS,
74
+ :ASCII_ENCODINGS
83
75
 
84
76
  # Builds a MIME::Type object from the +content_type+, a MIME Content Type
85
77
  # value (e.g., 'text/plain' or 'applicaton/x-eruby'). The constructed object
@@ -88,46 +80,45 @@ class MIME::Type
88
80
  #
89
81
  # * When provided a Hash or a MIME::Type, the MIME::Type will be
90
82
  # constructed with #init_with.
91
- # * When provided an Array, the MIME::Type will be constructed only using
92
- # the first two elements of the array as the content type and
93
- # extensions.
83
+ # * When provided an Array, the MIME::Type will be constructed using
84
+ # the first element as the content type and the remaining flattened
85
+ # elements as extensions.
94
86
  # * Otherwise, the content_type will be used as a string.
95
87
  #
96
88
  # Yields the newly constructed +self+ object.
97
89
  def initialize(content_type) # :yields self:
98
90
  @friendly = {}
99
- self.obsolete = false
100
- self.registered = nil
101
- self.use_instead = nil
102
- self.signature = nil
91
+ @obsolete = @registered = false
92
+ @preferred_extension = @docs = @use_instead = nil
93
+ self.extensions = []
103
94
 
104
95
  case content_type
105
96
  when Hash
106
97
  init_with(content_type)
107
98
  when Array
108
- self.content_type = content_type[0]
109
- self.extensions = content_type[1] || []
99
+ self.content_type = content_type.shift
100
+ self.extensions = content_type.flatten
110
101
  when MIME::Type
111
102
  init_with(content_type.to_h)
112
103
  else
113
104
  self.content_type = content_type
114
105
  end
115
106
 
116
- self.extensions ||= []
117
- self.docs ||= []
118
107
  self.encoding ||= :default
119
108
  self.xrefs ||= {}
120
109
 
121
110
  yield self if block_given?
122
111
  end
123
112
 
124
- # Returns +true+ if the +other+ simplified type matches the current type.
113
+ # Indicates that a MIME type is like another type. This differs from
114
+ # <tt>==</tt> because <tt>x-</tt> prefixes are removed for this comparison.
125
115
  def like?(other)
126
- if other.respond_to?(:simplified)
127
- @simplified == other.simplified
128
- else
129
- @simplified == MIME::Type.simplified(other)
130
- end
116
+ other = if other.respond_to?(:simplified)
117
+ MIME::Type.simplified(other.simplified, remove_x_prefix: true)
118
+ else
119
+ MIME::Type.simplified(other.to_s, remove_x_prefix: true)
120
+ end
121
+ MIME::Type.simplified(simplified, remove_x_prefix: true) == other
131
122
  end
132
123
 
133
124
  # Compares the +other+ MIME::Type against the exact content type or the
@@ -135,10 +126,16 @@ class MIME::Type
135
126
  # something that can be treated as a String with #to_s). In comparisons, this
136
127
  # is done against the lowercase version of the MIME::Type.
137
128
  def <=>(other)
138
- if other.respond_to?(:content_type)
139
- @content_type.downcase <=> other.content_type.downcase
140
- elsif other.respond_to?(:to_s)
141
- @simplified <=> MIME::Type.simplified(other.to_s)
129
+ if other.nil?
130
+ -1
131
+ elsif other.respond_to?(:simplified)
132
+ simplified <=> other.simplified
133
+ else
134
+ filtered = 'silent' if other == :silent
135
+ filtered ||= 'true' if other == true
136
+ filtered ||= other.to_s
137
+
138
+ simplified <=> MIME::Type.simplified(filtered)
142
139
  end
143
140
  end
144
141
 
@@ -160,7 +157,7 @@ class MIME::Type
160
157
  # before unregistered or obsolete content types.
161
158
  def priority_compare(other)
162
159
  pc = simplified <=> other.simplified
163
- if pc.zero?
160
+ if pc.zero? || !(extensions & other.extensions).empty?
164
161
  pc = if (reg = registered?) != other.registered?
165
162
  reg ? -1 : 1 # registered < unregistered
166
163
  elsif (comp = complete?) != other.complete?
@@ -204,54 +201,74 @@ class MIME::Type
204
201
  # removed and converted to lowercase.
205
202
  #
206
203
  # text/plain => text/plain
207
- # x-chemical/x-pdb => chemical/pdb
204
+ # x-chemical/x-pdb => x-chemical/x-pdb
208
205
  # audio/QCELP => audio/qcelp
209
206
  attr_reader :simplified
210
207
  # Returns the media type of the simplified MIME::Type.
211
208
  #
212
209
  # text/plain => text
213
- # x-chemical/x-pdb => chemical
210
+ # x-chemical/x-pdb => x-chemical
211
+ # audio/QCELP => audio
214
212
  attr_reader :media_type
215
213
  # Returns the media type of the unmodified MIME::Type.
216
214
  #
217
215
  # text/plain => text
218
216
  # x-chemical/x-pdb => x-chemical
217
+ # audio/QCELP => audio
219
218
  attr_reader :raw_media_type
220
219
  # Returns the sub-type of the simplified MIME::Type.
221
220
  #
222
221
  # text/plain => plain
223
222
  # x-chemical/x-pdb => pdb
223
+ # audio/QCELP => QCELP
224
224
  attr_reader :sub_type
225
225
  # Returns the media type of the unmodified MIME::Type.
226
226
  #
227
227
  # text/plain => plain
228
228
  # x-chemical/x-pdb => x-pdb
229
+ # audio/QCELP => qcelp
229
230
  attr_reader :raw_sub_type
230
231
 
232
+ ##
231
233
  # The list of extensions which are known to be used for this MIME::Type.
232
234
  # Non-array values will be coerced into an array with #to_a. Array values
233
235
  # will be flattened, +nil+ values removed, and made unique.
234
- attr_reader :extensions
235
- def extensions=(ext) # :nodoc:
236
- @extensions = Array(ext).flatten.compact.uniq
237
- # TODO: In mime-types 3.x, we probably want to have a clue about the
238
- # container(s) we belong to so we can trigger reindexing when this is done.
236
+ #
237
+ # :attr_accessor: extensions
238
+ def extensions
239
+ @extensions.to_a
240
+ end
241
+
242
+ ##
243
+ def extensions=(value) # :nodoc:
244
+ @extensions = Set[*Array(value).flatten.compact].freeze
245
+ MIME::Types.send(:reindex_extensions, self)
239
246
  end
240
247
 
241
248
  # Merge the +extensions+ provided into this MIME::Type. The extensions added
242
249
  # will be merged uniquely.
243
250
  def add_extensions(*extensions)
244
- self.extensions = self.extensions + extensions
251
+ self.extensions += extensions
245
252
  end
246
253
 
247
254
  ##
248
- # The preferred extension for this MIME type, if one is set.
255
+ # The preferred extension for this MIME type. If one is not set and there are
256
+ # exceptions defined, the first extension will be used.
249
257
  #
250
- # :attr_reader: preferred_extension
258
+ # When setting #preferred_extensions, if #extensions does not contain this
259
+ # extension, this will be added to #xtensions.
260
+ #
261
+ # :attr_accessor: preferred_extension
251
262
 
252
263
  ##
253
264
  def preferred_extension
254
- extensions.first
265
+ @preferred_extension || extensions.first
266
+ end
267
+
268
+ ##
269
+ def preferred_extension=(value) # :nodoc:
270
+ add_extensions(value) if value
271
+ @preferred_extension = value
255
272
  end
256
273
 
257
274
  ##
@@ -270,60 +287,41 @@ class MIME::Type
270
287
 
271
288
  ##
272
289
  attr_reader :encoding
290
+
291
+ ##
273
292
  def encoding=(enc) # :nodoc:
274
- if DEFAULT_ENCODINGS.include?(enc)
293
+ if enc.nil? or enc == :default
275
294
  @encoding = default_encoding
276
- elsif BINARY_ENCODINGS.include?(enc) or TEXT_ENCODINGS.include?(enc)
295
+ elsif BINARY_ENCODINGS.include?(enc) or ASCII_ENCODINGS.include?(enc)
277
296
  @encoding = enc
278
297
  else
279
298
  fail InvalidEncoding, enc
280
299
  end
281
300
  end
282
301
 
283
- # Returns +nil+ and assignments are ignored. Prior to mime-types 2.99, this
284
- # would return the regular expression for the operating system indicated if
285
- # the MIME::Type is a system-specific MIME::Type,
286
- #
287
- # This information about MIME content types is deprecated and will be removed
288
- # in mime-types 3.
289
- def system
290
- MIME::Types.deprecated(self, __method__)
291
- nil
292
- end
293
-
294
- def system=(_os) # :nodoc:
295
- MIME::Types.deprecated(self, __method__)
296
- end
297
-
298
302
  # Returns the default encoding for the MIME::Type based on the media type.
299
303
  def default_encoding
300
- (@media_type == 'text') ? 'quoted-printable' : 'base64'
304
+ @media_type == 'text' ? 'quoted-printable' : 'base64'
301
305
  end
302
306
 
303
307
  ##
304
- # Returns the media type or types that should be used instead of this
305
- # media type, if it is obsolete. If there is no replacement media type, or
306
- # it is not obsolete, +nil+ will be returned.
308
+ # Returns the media type or types that should be used instead of this media
309
+ # type, if it is obsolete. If there is no replacement media type, or it is
310
+ # not obsolete, +nil+ will be returned.
307
311
  #
308
312
  # :attr_accessor: use_instead
309
313
 
310
314
  ##
311
315
  def use_instead
312
- return nil unless obsolete?
313
- @use_instead
316
+ obsolete? ? @use_instead : nil
314
317
  end
315
318
 
316
319
  ##
317
320
  attr_writer :use_instead
318
321
 
319
322
  # Returns +true+ if the media type is obsolete.
320
- def obsolete?
321
- !!@obsolete
322
- end
323
-
324
- def obsolete=(v) # :nodoc:
325
- @obsolete = !!v
326
- end
323
+ attr_accessor :obsolete
324
+ alias obsolete? obsolete
327
325
 
328
326
  # The documentation for this MIME::Type.
329
327
  attr_accessor :docs
@@ -333,18 +331,19 @@ class MIME::Type
333
331
  # call-seq:
334
332
  # text_plain.friendly # => "Text File"
335
333
  # text_plain.friendly('en') # => "Text File"
336
- def friendly(lang = 'en'.freeze)
334
+ def friendly(lang = 'en')
337
335
  @friendly ||= {}
338
336
 
339
337
  case lang
340
- when String
341
- @friendly[lang]
338
+ when String, Symbol
339
+ @friendly[lang.to_s]
342
340
  when Array
343
- @friendly.merge!(Hash[*lang])
341
+ @friendly.update(Hash[*lang])
344
342
  when Hash
345
- @friendly.merge!(lang)
343
+ @friendly.update(lang)
346
344
  else
347
- fail ArgumentError
345
+ fail ArgumentError,
346
+ "Expected a language or translation set, not #{lang.inspect}"
348
347
  end
349
348
  end
350
349
 
@@ -359,50 +358,6 @@ class MIME::Type
359
358
  # # from application/x-msword
360
359
  attr_reader :i18n_key
361
360
 
362
- ##
363
- # Returns an empty array and warns that this method has been deprecated.
364
- # Assignments are ignored. Prior to mime-types 2.99, this was the encoded
365
- # references URL list for this MIME::Type.
366
- #
367
- # This was previously called #url.
368
- #
369
- # #references has been deprecated and both versions (#references and #url)
370
- # will be removed in mime-types 3.
371
- #
372
- # :attr_accessor: references
373
-
374
- ##
375
- def references(*)
376
- MIME::Types.deprecated(self, __method__)
377
- []
378
- end
379
-
380
- ##
381
- def references=(_r) # :nodoc:
382
- MIME::Types.deprecated(self, __method__)
383
- end
384
-
385
- ##
386
- # Returns an empty array and warns that this method has been deprecated.
387
- # Assignments are ignored. Prior to mime-types 2.99, this was the encoded
388
- # references URL list for this MIME::Type. See #urls for more information.
389
- #
390
- # #url has been deprecated and both versions (#references and #url) will be
391
- # removed in mime-types 3.
392
- #
393
- # :attr_accessor: url
394
-
395
- ##
396
- def url
397
- MIME::Types.deprecated(self, __method__)
398
- []
399
- end
400
-
401
- ##
402
- def url=(_r) # :nodoc:
403
- MIME::Types.deprecated(self, __method__)
404
- end
405
-
406
361
  ##
407
362
  # The cross-references list for this MIME::Type.
408
363
  #
@@ -412,134 +367,39 @@ class MIME::Type
412
367
  attr_reader :xrefs
413
368
 
414
369
  ##
415
- def xrefs=(x) # :nodoc:
416
- @xrefs = MIME::Types::Container.new.merge(x)
417
- @xrefs.each_value(&:sort!)
418
- @xrefs.each_value(&:uniq!)
419
- end
420
-
421
- # Returns an empty array. Prior to mime-types 2.99, this returned the decoded
422
- # URL list for this MIME::Type.
423
- #
424
- # The special URL value IANA was translated into:
425
- # http://www.iana.org/assignments/media-types/<mediatype>/<subtype>
426
- #
427
- # The special URL value RFC### was translated into:
428
- # http://www.rfc-editor.org/rfc/rfc###.txt
429
- #
430
- # The special URL value DRAFT:name was translated into:
431
- # https://datatracker.ietf.org/public/idindex.cgi?
432
- # command=id_detail&filename=<name>
433
- #
434
- # The special URL value [token] was translated into:
435
- # http://www.iana.org/assignments/contact-people.htm#<token>
436
- #
437
- # These values were accessible through #urls, which always returns an array.
438
- #
439
- # This method is deprecated and will be removed in mime-types 3.
440
- def urls
441
- MIME::Types.deprecated(self, __method__)
442
- []
370
+ def xrefs=(xrefs) # :nodoc:
371
+ @xrefs = MIME::Types::Container.new(xrefs)
443
372
  end
444
373
 
445
374
  # The decoded cross-reference URL list for this MIME::Type.
446
375
  def xref_urls
447
- xrefs.flat_map { |(type, values)|
448
- case type
449
- when 'rfc'.freeze
450
- values.map { |data| 'http://www.iana.org/go/%s'.freeze % data }
451
- when 'draft'.freeze
452
- values.map { |data|
453
- 'http://www.iana.org/go/%s'.freeze % data.sub(/\ARFC/, 'draft')
454
- }
455
- when 'rfc-errata'.freeze
456
- values.map { |data|
457
- 'http://www.rfc-editor.org/errata_search.php?eid=%s'.freeze % data
458
- }
459
- when 'person'.freeze
460
- values.map { |data|
461
- 'http://www.iana.org/assignments/media-types/media-types.xhtml#%s'.freeze % data # rubocop:disable Metrics/LineLength
462
- }
463
- when 'template'.freeze
464
- values.map { |data|
465
- 'http://www.iana.org/assignments/media-types/%s'.freeze % data
466
- }
467
- else # 'uri', 'text', etc.
468
- values
469
- end
376
+ xrefs.flat_map { |type, values|
377
+ name = :"xref_url_for_#{type.tr('-', '_')}"
378
+ respond_to?(name, true) and xref_map(values, name) or values.to_a
470
379
  }
471
380
  end
472
381
 
473
- ##
474
- # Prior to BCP 178 (RFC 6648), it could be assumed that MIME content types
475
- # that start with <tt>x-</tt> were unregistered MIME. Per this BCP, this
476
- # assumption is no longer being made by default in this library.
477
- #
478
- # There are three possible registration states for a MIME::Type:
479
- # - Explicitly registered, like application/x-www-url-encoded.
480
- # - Explicitly not registered, like image/webp.
481
- # - Unspecified, in which case the media-type and the content-type will be
482
- # scanned to see if they start with <tt>x-</tt>, indicating that they
483
- # are assumed unregistered.
484
- #
485
- # In mime-types 3, only a MIME content type that is explicitly registered
486
- # will be used; there will be assumption that <tt>x-</tt> types are
487
- # unregistered.
488
- def registered?
489
- if @registered.nil?
490
- (@raw_media_type !~ UNREGISTERED_RE) and
491
- (@raw_sub_type !~ UNREGISTERED_RE)
492
- else
493
- !!@registered
494
- end
495
- end
496
-
497
- def registered=(v) # :nodoc:
498
- @registered = v.nil? ? v : !!v
499
- end
382
+ # Indicates whether the MIME type has been registered with IANA.
383
+ attr_accessor :registered
384
+ alias registered? registered
500
385
 
501
386
  # MIME types can be specified to be sent across a network in particular
502
387
  # formats. This method returns +true+ when the MIME::Type encoding is set
503
388
  # to <tt>base64</tt>.
504
389
  def binary?
505
- BINARY_ENCODINGS.include?(@encoding)
390
+ BINARY_ENCODINGS.include?(encoding)
506
391
  end
507
392
 
508
393
  # MIME types can be specified to be sent across a network in particular
509
394
  # formats. This method returns +false+ when the MIME::Type encoding is
510
395
  # set to <tt>base64</tt>.
511
396
  def ascii?
512
- !binary?
513
- end
514
-
515
- # Returns +true+ when the simplified MIME::Type is one of the known digital
516
- # signature types.
517
- def signature?
518
- !!@signature
397
+ ASCII_ENCODINGS.include?(encoding)
519
398
  end
520
399
 
521
- def signature=(v) # :nodoc:
522
- @signature = !!v
523
- end
524
-
525
- # Returns +false+. Prior to mime-types 2.99, would return +true+ if the
526
- # MIME::Type is specific to an operating system.
527
- #
528
- # This method is deprecated and will be removed in mime-types 3.
529
- def system?(*)
530
- MIME::Types.deprecated(self, __method__)
531
- false
532
- end
533
-
534
- # Returns +false+. Prior to mime-types 2.99, would return +true+ if the
535
- # MIME::Type is specific to the current operating system as represented by
536
- # RUBY_PLATFORM.
537
- #
538
- # This method is deprecated and will be removed in mime-types 3.
539
- def platform?(*)
540
- MIME::Types.deprecated(self, __method__)
541
- false
542
- end
400
+ # Indicateswhether the MIME type is declared as a signature type.
401
+ attr_accessor :signature
402
+ alias signature? signature
543
403
 
544
404
  # Returns +true+ if the MIME::Type specifies an extension list,
545
405
  # indicating that it is a complete MIME::Type.
@@ -560,41 +420,14 @@ class MIME::Type
560
420
  content_type
561
421
  end
562
422
 
563
- # Returns the MIME::Type as an array suitable for use with
564
- # MIME::Type.from_array.
565
- #
566
- # This method is deprecated and will be removed in mime-types 3.
567
- def to_a
568
- MIME::Types.deprecated(self, __method__)
569
- [ @content_type, @extensions, @encoding, nil, obsolete?, @docs, [],
570
- registered? ]
571
- end
572
-
573
- # Returns the MIME::Type as an array suitable for use with
574
- # MIME::Type.from_hash.
575
- #
576
- # This method is deprecated and will be removed in mime-types 3.
577
- def to_hash
578
- MIME::Types.deprecated(self, __method__)
579
- { 'Content-Type' => @content_type,
580
- 'Content-Transfer-Encoding' => @encoding,
581
- 'Extensions' => @extensions,
582
- 'System' => nil,
583
- 'Obsolete' => obsolete?,
584
- 'Docs' => @docs,
585
- 'URL' => [],
586
- 'Registered' => registered?,
587
- }
588
- end
589
-
590
423
  # Converts the MIME::Type to a JSON string.
591
424
  def to_json(*args)
592
425
  require 'json'
593
426
  to_h.to_json(*args)
594
427
  end
595
428
 
596
- # Converts the MIME::Type to a hash suitable for use in JSON. The output
597
- # of this method can also be used to initialize a MIME::Type.
429
+ # Converts the MIME::Type to a hash. The output of this method can also be
430
+ # used to initialize a MIME::Type.
598
431
  def to_h
599
432
  encode_with({})
600
433
  end
@@ -605,18 +438,26 @@ class MIME::Type
605
438
  #
606
439
  # This method should be considered a private implementation detail.
607
440
  def encode_with(coder)
608
- coder['content-type'] = @content_type
609
- coder['docs'] = @docs unless @docs.nil? or @docs.empty?
610
- coder['friendly'] = @friendly unless @friendly.empty?
611
- coder['encoding'] = @encoding
612
- coder['extensions'] = @extensions unless @extensions.empty?
441
+ coder['content-type'] = @content_type
442
+ coder['docs'] = @docs unless @docs.nil? or @docs.empty?
443
+ coder['friendly'] = @friendly unless @friendly.nil? or @friendly.empty?
444
+ coder['encoding'] = @encoding
445
+ coder['extensions'] = @extensions.to_a unless @extensions.empty?
446
+ coder['preferred-extension'] = @preferred_extension if @preferred_extension
613
447
  if obsolete?
614
- coder['obsolete'] = obsolete?
615
- coder['use-instead'] = use_instead if use_instead
448
+ coder['obsolete'] = obsolete?
449
+ coder['use-instead'] = use_instead if use_instead
450
+ end
451
+ unless xrefs.empty?
452
+ {}.tap do |hash|
453
+ xrefs.each do |k, v|
454
+ hash[k] = v.to_a.sort
455
+ end
456
+ coder['xrefs'] = hash
457
+ end
616
458
  end
617
- coder['xrefs'] = xrefs unless xrefs.empty?
618
- coder['registered'] = registered?
619
- coder['signature'] = signature? if signature?
459
+ coder['registered'] = registered?
460
+ coder['signature'] = signature? if signature?
620
461
  coder
621
462
  end
622
463
 
@@ -625,161 +466,68 @@ class MIME::Type
625
466
  #
626
467
  # This method should be considered a private implementation detail.
627
468
  def init_with(coder)
628
- self.content_type = coder['content-type']
629
- self.docs = coder['docs'] || []
469
+ self.content_type = coder['content-type']
470
+ self.docs = coder['docs'] || ''
471
+ self.encoding = coder['encoding']
472
+ self.extensions = coder['extensions'] || []
473
+ self.preferred_extension = coder['preferred-extension']
474
+ self.obsolete = coder['obsolete'] || false
475
+ self.registered = coder['registered'] || false
476
+ self.signature = coder['signature']
477
+ self.xrefs = coder['xrefs'] || {}
478
+ self.use_instead = coder['use-instead']
479
+
630
480
  friendly(coder['friendly'] || {})
631
- self.encoding = coder['encoding']
632
- self.extensions = coder['extensions'] || []
633
- self.obsolete = coder['obsolete']
634
- self.registered = coder['registered']
635
- self.signature = coder['signature']
636
- self.xrefs = coder['xrefs'] || {}
637
- self.use_instead = coder['use-instead']
638
481
  end
639
482
 
640
- class << self
641
- # The MIME types main- and sub-label can both start with <tt>x-</tt>,
642
- # which indicates that it is a non-registered name. Of course, after
643
- # registration this flag may disappear, adds to the confusing
644
- # proliferation of MIME types. The simplified +content_type+ string has the
645
- # <tt>x-</tt> removed and is translated to lowercase.
646
- def simplified(content_type)
647
- matchdata = case content_type
648
- when MatchData
649
- content_type
650
- else
651
- MEDIA_TYPE_RE.match(content_type)
652
- end
653
-
654
- return unless matchdata
483
+ def inspect # :nodoc:
484
+ # We are intentionally lying here because MIME::Type::Columnar is an
485
+ # implementation detail.
486
+ "#<MIME::Type: #{self}>"
487
+ end
655
488
 
656
- matchdata.captures.map { |e|
657
- e.downcase!
658
- e.gsub!(UNREGISTERED_RE, ''.freeze)
659
- e
660
- }.join('/'.freeze)
489
+ class << self
490
+ # MIME media types are case-insensitive, but are typically presented in a
491
+ # case-preserving format in the type registry. This method converts
492
+ # +content_type+ to lowercase.
493
+ #
494
+ # In previous versions of mime-types, this would also remove any extension
495
+ # prefix (<tt>x-</tt>). This is no longer default behaviour, but may be
496
+ # provided by providing a truth value to +remove_x_prefix+.
497
+ def simplified(content_type, remove_x_prefix: false)
498
+ simplify_matchdata(match(content_type), remove_x_prefix)
661
499
  end
662
500
 
663
501
  # Converts a provided +content_type+ into a translation key suitable for
664
502
  # use with the I18n library.
665
503
  def i18n_key(content_type)
666
- matchdata = case content_type
667
- when MatchData
668
- content_type
669
- else
670
- MEDIA_TYPE_RE.match(content_type)
671
- end
672
-
673
- return unless matchdata
674
-
675
- matchdata.captures.map { |e|
676
- e.downcase!
677
- e.gsub!(UNREGISTERED_RE, ''.freeze)
678
- e.gsub!(I18N_RE, '-'.freeze)
679
- e
680
- }.join('.'.freeze)
504
+ simplify_matchdata(match(content_type), joiner: '.') { |e|
505
+ e.gsub!(I18N_RE, '-')
506
+ }
681
507
  end
682
508
 
683
- # Creates a MIME::Type from an +args+ array in the form of:
684
- # [ type-name, [ extensions ], encoding, system ]
685
- #
686
- # +extensions+, and +encoding+ are optional; +system+ is ignored.
687
- #
688
- # MIME::Type.from_array('application/x-ruby', %w(rb), '8bit')
689
- # MIME::Type.from_array([ 'application/x-ruby', [ 'rb' ], '8bit' ])
690
- #
691
- # These are equivalent to:
692
- #
693
- # MIME::Type.new('application/x-ruby') do |t|
694
- # t.extensions = %w(rb)
695
- # t.encoding = '8bit'
696
- # end
697
- #
698
- # It will yield the type (+t+) if a block is given.
699
- #
700
- # This method is deprecated and will be removed in mime-types 3.
701
- def from_array(*args) # :yields t:
702
- MIME::Types.deprecated(self, __method__)
703
-
704
- # Dereferences the array one level, if necessary.
705
- args = args.first if args.first.kind_of? Array
706
-
707
- unless args.size.between?(1, 8)
708
- fail ArgumentError,
709
- 'Array provided must contain between one and eight elements.'
710
- end
711
-
712
- MIME::Type.new(args.shift) do |t|
713
- t.extensions, t.encoding, _system, t.obsolete, t.docs, _references,
714
- t.registered = *args
715
- yield t if block_given?
509
+ # Return a +MatchData+ object of the +content_type+ against pattern of
510
+ # media types.
511
+ def match(content_type)
512
+ case content_type
513
+ when MatchData
514
+ content_type
515
+ else
516
+ MEDIA_TYPE_RE.match(content_type)
716
517
  end
717
518
  end
718
519
 
719
- # Creates a MIME::Type from a +hash+. Keys are case-insensitive, dashes
720
- # may be replaced with underscores, and the internal Symbol of the
721
- # lowercase-underscore version can be used as well. That is,
722
- # Content-Type can be provided as content-type, Content_Type,
723
- # content_type, or :content_type.
724
- #
725
- # Known keys are <tt>Content-Type</tt>,
726
- # <tt>Content-Transfer-Encoding</tt>, <tt>Extensions</tt>, and
727
- # <tt>System</tt>. +System+ is ignored.
728
- #
729
- # MIME::Type.from_hash('Content-Type' => 'text/x-yaml',
730
- # 'Content-Transfer-Encoding' => '8bit',
731
- # 'System' => 'linux',
732
- # 'Extensions' => ['yaml', 'yml'])
733
- #
734
- # This is equivalent to:
735
- #
736
- # MIME::Type.new('text/x-yaml') do |t|
737
- # t.encoding = '8bit'
738
- # t.system = 'linux'
739
- # t.extensions = ['yaml', 'yml']
740
- # end
741
- #
742
- # It will yield the constructed type +t+ if a block has been provided.
743
- #
744
- #
745
- # This method is deprecated and will be removed in mime-types 3.
746
- def from_hash(hash) # :yields t:
747
- MIME::Types.deprecated(self, __method__)
748
- type = {}
749
- hash.each_pair do |k, v|
750
- type[k.to_s.tr('A-Z', 'a-z').gsub(/-/, '_').to_sym] = v
751
- end
520
+ private
752
521
 
753
- MIME::Type.new(type[:content_type]) do |t|
754
- t.extensions = type[:extensions]
755
- t.encoding = type[:content_transfer_encoding]
756
- t.obsolete = type[:obsolete]
757
- t.docs = type[:docs]
758
- t.url = type[:url]
759
- t.registered = type[:registered]
760
-
761
- yield t if block_given?
762
- end
763
- end
522
+ def simplify_matchdata(matchdata, remove_x = false, joiner: '/')
523
+ return nil unless matchdata
764
524
 
765
- # Essentially a copy constructor for +mime_type+.
766
- #
767
- # MIME::Type.from_mime_type(plaintext)
768
- #
769
- # is equivalent to:
770
- #
771
- # MIME::Type.new(plaintext.content_type.dup) do |t|
772
- # t.extensions = plaintext.extensions.dup
773
- # t.system = plaintext.system.dup
774
- # t.encoding = plaintext.encoding.dup
775
- # end
776
- #
777
- # It will yield the type (+t+) if a block is given.
778
- #
779
- # This method is deprecated and will be removed in mime-types 3.
780
- def from_mime_type(mime_type) # :yields the new MIME::Type:
781
- MIME::Types.deprecated(self, __method__)
782
- new(mime_type)
525
+ matchdata.captures.map { |e|
526
+ e.downcase!
527
+ e.sub!(/^x-/, '') if remove_x
528
+ yield e if block_given?
529
+ e
530
+ }.join(joiner)
783
531
  end
784
532
  end
785
533
 
@@ -789,10 +537,51 @@ class MIME::Type
789
537
  match = MEDIA_TYPE_RE.match(type_string)
790
538
  fail InvalidContentType, type_string if match.nil?
791
539
 
792
- @content_type = type_string
540
+ @content_type = intern_string(type_string)
793
541
  @raw_media_type, @raw_sub_type = match.captures
794
- @simplified = MIME::Type.simplified(match)
795
- @i18n_key = MIME::Type.i18n_key(match)
542
+ @simplified = intern_string(MIME::Type.simplified(match))
543
+ @i18n_key = intern_string(MIME::Type.i18n_key(match))
796
544
  @media_type, @sub_type = MEDIA_TYPE_RE.match(@simplified).captures
545
+
546
+ @raw_media_type = intern_string(@raw_media_type)
547
+ @raw_sub_type = intern_string(@raw_sub_type)
548
+ @media_type = intern_string(@media_type)
549
+ @sub_type = intern_string(@sub_type)
550
+ end
551
+
552
+ if String.method_defined?(:-@)
553
+ def intern_string(string)
554
+ -string
555
+ end
556
+ else
557
+ # MRI 2.2 and older don't have a method for string interning,
558
+ # so we simply freeze them for keeping a similar interface
559
+ def intern_string(string)
560
+ string.freeze
561
+ end
562
+ end
563
+
564
+ def xref_map(values, helper)
565
+ values.map { |value| send(helper, value) }
566
+ end
567
+
568
+ def xref_url_for_rfc(value)
569
+ 'http://www.iana.org/go/%s' % value
570
+ end
571
+
572
+ def xref_url_for_draft(value)
573
+ 'http://www.iana.org/go/%s' % value.sub(/\ARFC/, 'draft')
574
+ end
575
+
576
+ def xref_url_for_rfc_errata(value)
577
+ 'http://www.rfc-editor.org/errata_search.php?eid=%s' % value
578
+ end
579
+
580
+ def xref_url_for_person(value)
581
+ 'http://www.iana.org/assignments/media-types/media-types.xhtml#%s' % value
582
+ end
583
+
584
+ def xref_url_for_template(value)
585
+ 'http://www.iana.org/assignments/media-types/%s' % value
797
586
  end
798
587
  end