mime-types 2.99.3 → 3.4.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} +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