mime-types 2.99.3 → 3.3.1

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.
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