mime-types 2.99.3 → 3.4.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} +29 -30
  3. data/Contributing.md +132 -0
  4. data/History.md +269 -0
  5. data/{Licence.rdoc → Licence.md} +4 -18
  6. data/Manifest.txt +8 -25
  7. data/README.rdoc +63 -73
  8. data/Rakefile +200 -97
  9. data/lib/mime/type/columnar.rb +30 -63
  10. data/lib/mime/type.rb +294 -458
  11. data/lib/mime/types/_columnar.rb +137 -0
  12. data/lib/mime/types/cache.rb +52 -74
  13. data/lib/mime/types/columnar.rb +2 -147
  14. data/lib/mime/types/container.rb +96 -0
  15. data/lib/mime/types/deprecations.rb +17 -34
  16. data/lib/mime/types/full.rb +19 -0
  17. data/lib/mime/types/loader.rb +36 -152
  18. data/lib/mime/types/logger.rb +7 -5
  19. data/lib/mime/types/registry.rb +90 -0
  20. data/lib/mime/types.rb +55 -148
  21. data/lib/mime-types.rb +2 -2
  22. data/test/minitest_helper.rb +8 -18
  23. data/test/test_mime_type.rb +489 -464
  24. data/test/test_mime_types.rb +139 -91
  25. data/test/test_mime_types_cache.rb +85 -57
  26. data/test/test_mime_types_class.rb +120 -100
  27. data/test/test_mime_types_lazy.rb +30 -28
  28. data/test/test_mime_types_loader.rb +18 -45
  29. metadata +92 -77
  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/columnar.rb +0 -88
  51. data/support/convert.rb +0 -158
  52. data/support/iana_registry.rb +0 -172
data/lib/mime/type.rb CHANGED
@@ -1,29 +1,69 @@
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
  #
5
9
  # == Usage
6
10
  # require 'mime/types'
7
11
  #
8
- # plaintext = MIME::Types['text/plain'].first
9
- # # returns [text/plain, text/plain]
12
+ # plaintext = MIME::Types['text/plain'] # => [ text/plain ]
10
13
  # text = plaintext.first
11
- # print text.media_type # => 'text'
12
- # print text.sub_type # => 'plain'
14
+ # puts text.media_type # => 'text'
15
+ # puts text.sub_type # => 'plain'
13
16
  #
14
- # puts text.extensions.join(" ") # => 'asc txt c cc h hh cpp'
17
+ # puts text.extensions.join(' ') # => 'txt asc c cc h hh cpp hpp dat hlp'
18
+ # puts text.preferred_extension # => 'txt'
19
+ # puts text.friendly # => 'Text Document'
20
+ # puts text.i18n_key # => 'text.plain'
15
21
  #
16
- # puts text.encoding # => 8bit
22
+ # puts text.encoding # => quoted-printable
23
+ # puts text.default_encoding # => quoted-printable
17
24
  # puts text.binary? # => false
18
25
  # puts text.ascii? # => true
26
+ # puts text.obsolete? # => false
27
+ # puts text.registered? # => true
28
+ # puts text.provisional? # => false
29
+ # puts text.complete? # => true
30
+ #
31
+ # puts text # => 'text/plain'
32
+ #
19
33
  # puts text == 'text/plain' # => true
20
- # puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
34
+ # puts 'text/plain' == text # => true
35
+ # puts text == 'text/x-plain' # => false
36
+ # puts 'text/x-plain' == text # => false
37
+ #
38
+ # puts MIME::Type.simplified('x-appl/x-zip') # => 'x-appl/x-zip'
39
+ # puts MIME::Type.i18n_key('x-appl/x-zip') # => 'x-appl.x-zip'
40
+ #
41
+ # puts text.like?('text/x-plain') # => true
42
+ # puts text.like?(MIME::Type.new('x-text/x-plain')) # => true
43
+ #
44
+ # puts text.xrefs.inspect # => { "rfc" => [ "rfc2046", "rfc3676", "rfc5147" ] }
45
+ # puts text.xref_urls # => [ "http://www.iana.org/go/rfc2046",
46
+ # # "http://www.iana.org/go/rfc3676",
47
+ # # "http://www.iana.org/go/rfc5147" ]
48
+ #
49
+ # xtext = MIME::Type.new('x-text/x-plain')
50
+ # puts xtext.media_type # => 'text'
51
+ # puts xtext.raw_media_type # => 'x-text'
52
+ # puts xtext.sub_type # => 'plain'
53
+ # puts xtext.raw_sub_type # => 'x-plain'
54
+ # puts xtext.complete? # => false
55
+ #
56
+ # puts MIME::Types.any? { |type| type.content_type == 'text/plain' } # => true
57
+ # puts MIME::Types.all?(&:registered?) # => false
58
+ #
59
+ # # Various string representations of MIME types
60
+ # qcelp = MIME::Types['audio/QCELP'].first # => audio/QCELP
61
+ # puts qcelp.content_type # => 'audio/QCELP'
62
+ # puts qcelp.simplified # => 'audio/qcelp'
21
63
  #
22
- # puts MIME::Types.any? { |type|
23
- # type.content_type == 'text/plain'
24
- # } # => true
25
- # puts MIME::Types.all?(&:registered?)
26
- # # => false
64
+ # xwingz = MIME::Types['application/x-Wingz'].first # => application/x-Wingz
65
+ # puts xwingz.content_type # => 'application/x-Wingz'
66
+ # puts xwingz.simplified # => 'application/x-wingz'
27
67
  class MIME::Type
28
68
  # Reflects a MIME content-type specification that is not correctly
29
69
  # formatted (it isn't +type+/+subtype+).
@@ -53,81 +93,69 @@ class MIME::Type
53
93
  end
54
94
 
55
95
  # The released version of the mime-types library.
56
- VERSION = '2.99.3'
96
+ VERSION = "3.4.1"
57
97
 
58
98
  include Comparable
59
99
 
60
100
  # :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'
101
+ # TODO verify mime-type character restrictions; I am pretty sure that this is
102
+ # too wide open.
103
+ MEDIA_TYPE_RE = %r{([-\w.+]+)/([-\w.+]*)}.freeze
104
+ I18N_RE = /[^[:alnum:]]/.freeze
105
+ BINARY_ENCODINGS = %w[base64 8bit].freeze
106
+ ASCII_ENCODINGS = %w[7bit quoted-printable].freeze
75
107
  # :startdoc:
76
108
 
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
109
+ private_constant :MEDIA_TYPE_RE, :I18N_RE, :BINARY_ENCODINGS,
110
+ :ASCII_ENCODINGS
83
111
 
84
112
  # Builds a MIME::Type object from the +content_type+, a MIME Content Type
85
- # value (e.g., 'text/plain' or 'applicaton/x-eruby'). The constructed object
113
+ # value (e.g., 'text/plain' or 'application/x-eruby'). The constructed object
86
114
  # is yielded to an optional block for additional configuration, such as
87
115
  # associating extensions and encoding information.
88
116
  #
89
117
  # * When provided a Hash or a MIME::Type, the MIME::Type will be
90
118
  # 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.
119
+ # * When provided an Array, the MIME::Type will be constructed using
120
+ # the first element as the content type and the remaining flattened
121
+ # elements as extensions.
94
122
  # * Otherwise, the content_type will be used as a string.
95
123
  #
96
124
  # Yields the newly constructed +self+ object.
97
- def initialize(content_type) # :yields self:
125
+ def initialize(content_type) # :yields: self
98
126
  @friendly = {}
99
- self.obsolete = false
100
- self.registered = nil
101
- self.use_instead = nil
102
- self.signature = nil
127
+ @obsolete = @registered = @provisional = false
128
+ @preferred_extension = @docs = @use_instead = nil
129
+ self.extensions = []
103
130
 
104
131
  case content_type
105
132
  when Hash
106
133
  init_with(content_type)
107
134
  when Array
108
- self.content_type = content_type[0]
109
- self.extensions = content_type[1] || []
135
+ self.content_type = content_type.shift
136
+ self.extensions = content_type.flatten
110
137
  when MIME::Type
111
138
  init_with(content_type.to_h)
112
139
  else
113
140
  self.content_type = content_type
114
141
  end
115
142
 
116
- self.extensions ||= []
117
- self.docs ||= []
118
143
  self.encoding ||= :default
119
144
  self.xrefs ||= {}
120
145
 
121
146
  yield self if block_given?
122
147
  end
123
148
 
124
- # Returns +true+ if the +other+ simplified type matches the current type.
149
+ # Indicates that a MIME type is like another type. This differs from
150
+ # <tt>==</tt> because <tt>x-</tt> prefixes are removed for this comparison.
125
151
  def like?(other)
126
- if other.respond_to?(:simplified)
127
- @simplified == other.simplified
128
- else
129
- @simplified == MIME::Type.simplified(other)
130
- end
152
+ other =
153
+ if other.respond_to?(:simplified)
154
+ MIME::Type.simplified(other.simplified, remove_x_prefix: true)
155
+ else
156
+ MIME::Type.simplified(other.to_s, remove_x_prefix: true)
157
+ end
158
+ MIME::Type.simplified(simplified, remove_x_prefix: true) == other
131
159
  end
132
160
 
133
161
  # Compares the +other+ MIME::Type against the exact content type or the
@@ -135,10 +163,16 @@ class MIME::Type
135
163
  # something that can be treated as a String with #to_s). In comparisons, this
136
164
  # is done against the lowercase version of the MIME::Type.
137
165
  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)
166
+ if other.nil?
167
+ -1
168
+ elsif other.respond_to?(:simplified)
169
+ simplified <=> other.simplified
170
+ else
171
+ filtered = "silent" if other == :silent
172
+ filtered ||= "true" if other == true
173
+ filtered ||= other.to_s
174
+
175
+ simplified <=> MIME::Type.simplified(filtered)
142
176
  end
143
177
  end
144
178
 
@@ -160,24 +194,25 @@ class MIME::Type
160
194
  # before unregistered or obsolete content types.
161
195
  def priority_compare(other)
162
196
  pc = simplified <=> other.simplified
163
- if pc.zero?
164
- pc = if (reg = registered?) != other.registered?
165
- reg ? -1 : 1 # registered < unregistered
166
- elsif (comp = complete?) != other.complete?
167
- comp ? -1 : 1 # complete < incomplete
168
- elsif (obs = obsolete?) != other.obsolete?
169
- obs ? 1 : -1 # current < obsolete
170
- elsif obs and ((ui = use_instead) != (oui = other.use_instead))
171
- if ui.nil?
172
- 1
173
- elsif oui.nil?
174
- -1
175
- else
176
- ui <=> oui
177
- end
178
- else
179
- 0
180
- end
197
+ if pc.zero? || !(extensions & other.extensions).empty?
198
+ pc =
199
+ if (reg = registered?) != other.registered?
200
+ reg ? -1 : 1 # registered < unregistered
201
+ elsif (comp = complete?) != other.complete?
202
+ comp ? -1 : 1 # complete < incomplete
203
+ elsif (obs = obsolete?) != other.obsolete?
204
+ obs ? 1 : -1 # current < obsolete
205
+ elsif obs && ((ui = use_instead) != (oui = other.use_instead))
206
+ if ui.nil?
207
+ 1
208
+ elsif oui.nil?
209
+ -1
210
+ else
211
+ ui <=> oui
212
+ end
213
+ else
214
+ 0
215
+ end
181
216
  end
182
217
 
183
218
  pc
@@ -186,7 +221,7 @@ class MIME::Type
186
221
  # Returns +true+ if the +other+ object is a MIME::Type and the content types
187
222
  # match.
188
223
  def eql?(other)
189
- other.kind_of?(MIME::Type) and self == other
224
+ other.is_a?(MIME::Type) && (self == other)
190
225
  end
191
226
 
192
227
  # Returns the whole MIME content-type string.
@@ -200,58 +235,77 @@ class MIME::Type
200
235
  # audio/QCELP => audio/QCELP
201
236
  attr_reader :content_type
202
237
  # A simplified form of the MIME content-type string, suitable for
203
- # case-insensitive comparison, with any extension markers (<tt>x-</tt)
204
- # removed and converted to lowercase.
238
+ # case-insensitive comparison, with the content_type converted to lowercase.
205
239
  #
206
240
  # text/plain => text/plain
207
- # x-chemical/x-pdb => chemical/pdb
241
+ # x-chemical/x-pdb => x-chemical/x-pdb
208
242
  # audio/QCELP => audio/qcelp
209
243
  attr_reader :simplified
210
244
  # Returns the media type of the simplified MIME::Type.
211
245
  #
212
246
  # text/plain => text
213
- # x-chemical/x-pdb => chemical
247
+ # x-chemical/x-pdb => x-chemical
248
+ # audio/QCELP => audio
214
249
  attr_reader :media_type
215
250
  # Returns the media type of the unmodified MIME::Type.
216
251
  #
217
252
  # text/plain => text
218
253
  # x-chemical/x-pdb => x-chemical
254
+ # audio/QCELP => audio
219
255
  attr_reader :raw_media_type
220
256
  # Returns the sub-type of the simplified MIME::Type.
221
257
  #
222
258
  # text/plain => plain
223
259
  # x-chemical/x-pdb => pdb
260
+ # audio/QCELP => QCELP
224
261
  attr_reader :sub_type
225
262
  # Returns the media type of the unmodified MIME::Type.
226
263
  #
227
264
  # text/plain => plain
228
265
  # x-chemical/x-pdb => x-pdb
266
+ # audio/QCELP => qcelp
229
267
  attr_reader :raw_sub_type
230
268
 
269
+ ##
231
270
  # The list of extensions which are known to be used for this MIME::Type.
232
271
  # Non-array values will be coerced into an array with #to_a. Array values
233
272
  # 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.
273
+ #
274
+ # :attr_accessor: extensions
275
+ def extensions
276
+ @extensions.to_a
277
+ end
278
+
279
+ ##
280
+ def extensions=(value) # :nodoc:
281
+ @extensions = Set[*Array(value).flatten.compact].freeze
282
+ MIME::Types.send(:reindex_extensions, self)
239
283
  end
240
284
 
241
285
  # Merge the +extensions+ provided into this MIME::Type. The extensions added
242
286
  # will be merged uniquely.
243
287
  def add_extensions(*extensions)
244
- self.extensions = self.extensions + extensions
288
+ self.extensions += extensions
245
289
  end
246
290
 
247
291
  ##
248
- # The preferred extension for this MIME type, if one is set.
292
+ # The preferred extension for this MIME type. If one is not set and there are
293
+ # exceptions defined, the first extension will be used.
294
+ #
295
+ # When setting #preferred_extensions, if #extensions does not contain this
296
+ # extension, this will be added to #xtensions.
249
297
  #
250
- # :attr_reader: preferred_extension
298
+ # :attr_accessor: preferred_extension
251
299
 
252
300
  ##
253
301
  def preferred_extension
254
- extensions.first
302
+ @preferred_extension || extensions.first
303
+ end
304
+
305
+ ##
306
+ def preferred_extension=(value) # :nodoc:
307
+ add_extensions(value) if value
308
+ @preferred_extension = value
255
309
  end
256
310
 
257
311
  ##
@@ -270,60 +324,41 @@ class MIME::Type
270
324
 
271
325
  ##
272
326
  attr_reader :encoding
327
+
328
+ ##
273
329
  def encoding=(enc) # :nodoc:
274
- if DEFAULT_ENCODINGS.include?(enc)
330
+ if enc.nil? || (enc == :default)
275
331
  @encoding = default_encoding
276
- elsif BINARY_ENCODINGS.include?(enc) or TEXT_ENCODINGS.include?(enc)
332
+ elsif BINARY_ENCODINGS.include?(enc) || ASCII_ENCODINGS.include?(enc)
277
333
  @encoding = enc
278
334
  else
279
335
  fail InvalidEncoding, enc
280
336
  end
281
337
  end
282
338
 
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
339
  # Returns the default encoding for the MIME::Type based on the media type.
299
340
  def default_encoding
300
- (@media_type == 'text') ? 'quoted-printable' : 'base64'
341
+ @media_type == "text" ? "quoted-printable" : "base64"
301
342
  end
302
343
 
303
344
  ##
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.
345
+ # Returns the media type or types that should be used instead of this media
346
+ # type, if it is obsolete. If there is no replacement media type, or it is
347
+ # not obsolete, +nil+ will be returned.
307
348
  #
308
349
  # :attr_accessor: use_instead
309
350
 
310
351
  ##
311
352
  def use_instead
312
- return nil unless obsolete?
313
- @use_instead
353
+ obsolete? ? @use_instead : nil
314
354
  end
315
355
 
316
356
  ##
317
357
  attr_writer :use_instead
318
358
 
319
359
  # 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
360
+ attr_accessor :obsolete
361
+ alias_method :obsolete?, :obsolete
327
362
 
328
363
  # The documentation for this MIME::Type.
329
364
  attr_accessor :docs
@@ -333,18 +368,19 @@ class MIME::Type
333
368
  # call-seq:
334
369
  # text_plain.friendly # => "Text File"
335
370
  # text_plain.friendly('en') # => "Text File"
336
- def friendly(lang = 'en'.freeze)
371
+ def friendly(lang = "en")
337
372
  @friendly ||= {}
338
373
 
339
374
  case lang
340
- when String
341
- @friendly[lang]
375
+ when String, Symbol
376
+ @friendly[lang.to_s]
342
377
  when Array
343
- @friendly.merge!(Hash[*lang])
378
+ @friendly.update(Hash[*lang])
344
379
  when Hash
345
- @friendly.merge!(lang)
380
+ @friendly.update(lang)
346
381
  else
347
- fail ArgumentError
382
+ fail ArgumentError,
383
+ "Expected a language or translation set, not #{lang.inspect}"
348
384
  end
349
385
  end
350
386
 
@@ -359,50 +395,6 @@ class MIME::Type
359
395
  # # from application/x-msword
360
396
  attr_reader :i18n_key
361
397
 
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
398
  ##
407
399
  # The cross-references list for this MIME::Type.
408
400
  #
@@ -412,134 +404,47 @@ class MIME::Type
412
404
  attr_reader :xrefs
413
405
 
414
406
  ##
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
- []
407
+ def xrefs=(xrefs) # :nodoc:
408
+ @xrefs = MIME::Types::Container.new(xrefs)
443
409
  end
444
410
 
445
411
  # The decoded cross-reference URL list for this MIME::Type.
446
412
  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
413
+ xrefs.flat_map { |type, values|
414
+ name = :"xref_url_for_#{type.tr("-", "_")}"
415
+ respond_to?(name, true) && xref_map(values, name) || values.to_a
470
416
  }
471
417
  end
472
418
 
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
419
+ # Indicates whether the MIME type has been registered with IANA.
420
+ attr_accessor :registered
421
+ alias_method :registered?, :registered
496
422
 
497
- def registered=(v) # :nodoc:
498
- @registered = v.nil? ? v : !!v
423
+ # Indicates whether the MIME type's registration with IANA is provisional.
424
+ attr_accessor :provisional
425
+
426
+ # Indicates whether the MIME type's registration with IANA is provisional.
427
+ def provisional?
428
+ registered? && @provisional
499
429
  end
500
430
 
501
431
  # MIME types can be specified to be sent across a network in particular
502
432
  # formats. This method returns +true+ when the MIME::Type encoding is set
503
433
  # to <tt>base64</tt>.
504
434
  def binary?
505
- BINARY_ENCODINGS.include?(@encoding)
435
+ BINARY_ENCODINGS.include?(encoding)
506
436
  end
507
437
 
508
438
  # MIME types can be specified to be sent across a network in particular
509
439
  # formats. This method returns +false+ when the MIME::Type encoding is
510
440
  # set to <tt>base64</tt>.
511
441
  def ascii?
512
- !binary?
442
+ ASCII_ENCODINGS.include?(encoding)
513
443
  end
514
444
 
515
- # Returns +true+ when the simplified MIME::Type is one of the known digital
516
- # signature types.
517
- def signature?
518
- !!@signature
519
- end
520
-
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
445
+ # Indicateswhether the MIME type is declared as a signature type.
446
+ attr_accessor :signature
447
+ alias_method :signature?, :signature
543
448
 
544
449
  # Returns +true+ if the MIME::Type specifies an extension list,
545
450
  # indicating that it is a complete MIME::Type.
@@ -560,41 +465,14 @@ class MIME::Type
560
465
  content_type
561
466
  end
562
467
 
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
468
  # Converts the MIME::Type to a JSON string.
591
469
  def to_json(*args)
592
- require 'json'
470
+ require "json"
593
471
  to_h.to_json(*args)
594
472
  end
595
473
 
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.
474
+ # Converts the MIME::Type to a hash. The output of this method can also be
475
+ # used to initialize a MIME::Type.
598
476
  def to_h
599
477
  encode_with({})
600
478
  end
@@ -605,18 +483,27 @@ class MIME::Type
605
483
  #
606
484
  # This method should be considered a private implementation detail.
607
485
  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?
486
+ coder["content-type"] = @content_type
487
+ coder["docs"] = @docs unless @docs.nil? || @docs.empty?
488
+ coder["friendly"] = @friendly unless @friendly.nil? || @friendly.empty?
489
+ coder["encoding"] = @encoding
490
+ coder["extensions"] = @extensions.to_a unless @extensions.empty?
491
+ coder["preferred-extension"] = @preferred_extension if @preferred_extension
613
492
  if obsolete?
614
- coder['obsolete'] = obsolete?
615
- coder['use-instead'] = use_instead if use_instead
493
+ coder["obsolete"] = obsolete?
494
+ coder["use-instead"] = use_instead if use_instead
616
495
  end
617
- coder['xrefs'] = xrefs unless xrefs.empty?
618
- coder['registered'] = registered?
619
- coder['signature'] = signature? if signature?
496
+ unless xrefs.empty?
497
+ {}.tap do |hash|
498
+ xrefs.each do |k, v|
499
+ hash[k] = v.to_a.sort
500
+ end
501
+ coder["xrefs"] = hash
502
+ end
503
+ end
504
+ coder["registered"] = registered?
505
+ coder["provisional"] = provisional? if provisional?
506
+ coder["signature"] = signature? if signature?
620
507
  coder
621
508
  end
622
509
 
@@ -625,174 +512,123 @@ class MIME::Type
625
512
  #
626
513
  # This method should be considered a private implementation detail.
627
514
  def init_with(coder)
628
- self.content_type = coder['content-type']
629
- self.docs = coder['docs'] || []
630
- 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']
515
+ self.content_type = coder["content-type"]
516
+ self.docs = coder["docs"] || ""
517
+ self.encoding = coder["encoding"]
518
+ self.extensions = coder["extensions"] || []
519
+ self.preferred_extension = coder["preferred-extension"]
520
+ self.obsolete = coder["obsolete"] || false
521
+ self.registered = coder["registered"] || false
522
+ self.provisional = coder["provisional"] || false
523
+ self.signature = coder["signature"]
524
+ self.xrefs = coder["xrefs"] || {}
525
+ self.use_instead = coder["use-instead"]
526
+
527
+ friendly(coder["friendly"] || {})
638
528
  end
639
529
 
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
530
+ def inspect # :nodoc:
531
+ # We are intentionally lying here because MIME::Type::Columnar is an
532
+ # implementation detail.
533
+ "#<MIME::Type: #{self}>"
534
+ end
655
535
 
656
- matchdata.captures.map { |e|
657
- e.downcase!
658
- e.gsub!(UNREGISTERED_RE, ''.freeze)
659
- e
660
- }.join('/'.freeze)
536
+ class << self
537
+ # MIME media types are case-insensitive, but are typically presented in a
538
+ # case-preserving format in the type registry. This method converts
539
+ # +content_type+ to lowercase.
540
+ #
541
+ # In previous versions of mime-types, this would also remove any extension
542
+ # prefix (<tt>x-</tt>). This is no longer default behaviour, but may be
543
+ # provided by providing a truth value to +remove_x_prefix+.
544
+ def simplified(content_type, remove_x_prefix: false)
545
+ simplify_matchdata(match(content_type), remove_x_prefix)
661
546
  end
662
547
 
663
548
  # Converts a provided +content_type+ into a translation key suitable for
664
549
  # use with the I18n library.
665
550
  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
551
+ simplify_matchdata(match(content_type), joiner: ".") { |e|
552
+ e.gsub!(I18N_RE, "-")
553
+ }
554
+ end
555
+
556
+ # Return a +MatchData+ object of the +content_type+ against pattern of
557
+ # media types.
558
+ def match(content_type)
559
+ case content_type
560
+ when MatchData
561
+ content_type
562
+ else
563
+ MEDIA_TYPE_RE.match(content_type)
564
+ end
565
+ end
566
+
567
+ private
672
568
 
673
- return unless matchdata
569
+ def simplify_matchdata(matchdata, remove_x = false, joiner: "/")
570
+ return nil unless matchdata
674
571
 
675
572
  matchdata.captures.map { |e|
676
573
  e.downcase!
677
- e.gsub!(UNREGISTERED_RE, ''.freeze)
678
- e.gsub!(I18N_RE, '-'.freeze)
574
+ e.sub!(/^x-/, "") if remove_x
575
+ yield e if block_given?
679
576
  e
680
- }.join('.'.freeze)
577
+ }.join(joiner)
681
578
  end
579
+ end
682
580
 
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__)
581
+ private
703
582
 
704
- # Dereferences the array one level, if necessary.
705
- args = args.first if args.first.kind_of? Array
583
+ def content_type=(type_string)
584
+ match = MEDIA_TYPE_RE.match(type_string)
585
+ fail InvalidContentType, type_string if match.nil?
706
586
 
707
- unless args.size.between?(1, 8)
708
- fail ArgumentError,
709
- 'Array provided must contain between one and eight elements.'
710
- end
587
+ @content_type = intern_string(type_string)
588
+ @raw_media_type, @raw_sub_type = match.captures
589
+ @simplified = intern_string(MIME::Type.simplified(match))
590
+ @i18n_key = intern_string(MIME::Type.i18n_key(match))
591
+ @media_type, @sub_type = MEDIA_TYPE_RE.match(@simplified).captures
711
592
 
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?
716
- end
717
- end
593
+ @raw_media_type = intern_string(@raw_media_type)
594
+ @raw_sub_type = intern_string(@raw_sub_type)
595
+ @media_type = intern_string(@media_type)
596
+ @sub_type = intern_string(@sub_type)
597
+ end
718
598
 
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
599
+ if String.method_defined?(:-@)
600
+ def intern_string(string)
601
+ -string
602
+ end
603
+ else
604
+ # MRI 2.2 and older don't have a method for string interning,
605
+ # so we simply freeze them for keeping a similar interface
606
+ def intern_string(string)
607
+ string.freeze
608
+ end
609
+ end
752
610
 
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]
611
+ def xref_map(values, helper)
612
+ values.map { |value| send(helper, value) }
613
+ end
760
614
 
761
- yield t if block_given?
762
- end
763
- end
615
+ def xref_url_for_rfc(value)
616
+ "http://www.iana.org/go/%s" % value
617
+ end
764
618
 
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)
783
- end
619
+ def xref_url_for_draft(value)
620
+ "http://www.iana.org/go/%s" % value.sub(/\ARFC/, "draft")
784
621
  end
785
622
 
786
- private
623
+ def xref_url_for_rfc_errata(value)
624
+ "http://www.rfc-editor.org/errata_search.php?eid=%s" % value
625
+ end
787
626
 
788
- def content_type=(type_string)
789
- match = MEDIA_TYPE_RE.match(type_string)
790
- fail InvalidContentType, type_string if match.nil?
627
+ def xref_url_for_person(value)
628
+ "http://www.iana.org/assignments/media-types/media-types.xhtml#%s" % value
629
+ end
791
630
 
792
- @content_type = type_string
793
- @raw_media_type, @raw_sub_type = match.captures
794
- @simplified = MIME::Type.simplified(match)
795
- @i18n_key = MIME::Type.i18n_key(match)
796
- @media_type, @sub_type = MEDIA_TYPE_RE.match(@simplified).captures
631
+ def xref_url_for_template(value)
632
+ "http://www.iana.org/assignments/media-types/%s" % value
797
633
  end
798
634
  end