mime-types 3.5.2 → 3.7.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +413 -0
- data/CODE_OF_CONDUCT.md +128 -0
- data/CONTRIBUTING.md +93 -0
- data/CONTRIBUTORS.md +52 -0
- data/{Licence.md → LICENCE.md} +9 -10
- data/Manifest.txt +8 -6
- data/README.md +200 -0
- data/Rakefile +66 -94
- data/SECURITY.md +7 -0
- data/lib/mime/type/columnar.rb +14 -1
- data/lib/mime/type.rb +178 -92
- data/lib/mime/types/_columnar.rb +52 -5
- data/lib/mime/types/container.rb +45 -15
- data/lib/mime/types/deprecations.rb +39 -19
- data/lib/mime/types/loader.rb +2 -2
- data/lib/mime/types/logger.rb +34 -3
- data/lib/mime/types/registry.rb +6 -4
- data/lib/mime/types/version.rb +14 -0
- data/lib/mime/types.rb +20 -10
- data/test/minitest_helper.rb +3 -3
- data/test/test_mime_type.rb +69 -67
- data/test/test_mime_types.rb +20 -20
- data/test/test_mime_types_class.rb +13 -7
- metadata +54 -88
- data/.standard.yml +0 -4
- data/Code-of-Conduct.md +0 -73
- data/Contributing.md +0 -133
- data/History.md +0 -335
- data/README.rdoc +0 -194
data/lib/mime/type.rb
CHANGED
|
@@ -4,20 +4,22 @@
|
|
|
4
4
|
module MIME
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
+
require "mime/types/deprecations"
|
|
8
|
+
|
|
7
9
|
# The definition of one MIME content-type.
|
|
8
10
|
#
|
|
9
11
|
# == Usage
|
|
10
|
-
# require
|
|
12
|
+
# require "mime/types"
|
|
11
13
|
#
|
|
12
|
-
# plaintext = MIME::Types[
|
|
14
|
+
# plaintext = MIME::Types["text/plain"] # => [ text/plain ]
|
|
13
15
|
# text = plaintext.first
|
|
14
|
-
# puts text.media_type # =>
|
|
15
|
-
# puts text.sub_type # =>
|
|
16
|
+
# puts text.media_type # => "text"
|
|
17
|
+
# puts text.sub_type # => "plain"
|
|
16
18
|
#
|
|
17
|
-
# puts text.extensions.join(
|
|
18
|
-
# puts text.preferred_extension # =>
|
|
19
|
-
# puts text.friendly # =>
|
|
20
|
-
# puts text.i18n_key # =>
|
|
19
|
+
# puts text.extensions.join(" ") # => "txt asc c cc h hh cpp hpp dat hlp"
|
|
20
|
+
# puts text.preferred_extension # => "txt"
|
|
21
|
+
# puts text.friendly # => "Text Document"
|
|
22
|
+
# puts text.i18n_key # => "text.plain"
|
|
21
23
|
#
|
|
22
24
|
# puts text.encoding # => quoted-printable
|
|
23
25
|
# puts text.default_encoding # => quoted-printable
|
|
@@ -28,45 +30,45 @@ end
|
|
|
28
30
|
# puts text.provisional? # => false
|
|
29
31
|
# puts text.complete? # => true
|
|
30
32
|
#
|
|
31
|
-
# puts text # =>
|
|
33
|
+
# puts text # => "text/plain"
|
|
32
34
|
#
|
|
33
|
-
# puts text ==
|
|
34
|
-
# puts
|
|
35
|
-
# puts text ==
|
|
36
|
-
# puts
|
|
35
|
+
# puts text == "text/plain" # => true
|
|
36
|
+
# puts "text/plain" == text # => true
|
|
37
|
+
# puts text == "text/x-plain" # => false
|
|
38
|
+
# puts "text/x-plain" == text # => false
|
|
37
39
|
#
|
|
38
|
-
# puts MIME::Type.simplified(
|
|
39
|
-
# puts MIME::Type.i18n_key(
|
|
40
|
+
# puts MIME::Type.simplified("x-appl/x-zip") # => "x-appl/x-zip"
|
|
41
|
+
# puts MIME::Type.i18n_key("x-appl/x-zip") # => "x-appl.x-zip"
|
|
40
42
|
#
|
|
41
|
-
# puts text.like?(
|
|
42
|
-
# puts text.like?(MIME::Type.new(
|
|
43
|
+
# puts text.like?("text/x-plain") # => true
|
|
44
|
+
# puts text.like?(MIME::Type.new("content-type" => "x-text/x-plain")) # => true
|
|
43
45
|
#
|
|
44
46
|
# puts text.xrefs.inspect # => { "rfc" => [ "rfc2046", "rfc3676", "rfc5147" ] }
|
|
45
47
|
# puts text.xref_urls # => [ "http://www.iana.org/go/rfc2046",
|
|
46
48
|
# # "http://www.iana.org/go/rfc3676",
|
|
47
49
|
# # "http://www.iana.org/go/rfc5147" ]
|
|
48
50
|
#
|
|
49
|
-
# xtext = MIME::Type.new(
|
|
50
|
-
# puts xtext.media_type # =>
|
|
51
|
-
# puts xtext.raw_media_type # =>
|
|
52
|
-
# puts xtext.sub_type # =>
|
|
53
|
-
# puts xtext.raw_sub_type # =>
|
|
51
|
+
# xtext = MIME::Type.new("x-text/x-plain")
|
|
52
|
+
# puts xtext.media_type # => "text"
|
|
53
|
+
# puts xtext.raw_media_type # => "x-text"
|
|
54
|
+
# puts xtext.sub_type # => "plain"
|
|
55
|
+
# puts xtext.raw_sub_type # => "x-plain"
|
|
54
56
|
# puts xtext.complete? # => false
|
|
55
57
|
#
|
|
56
|
-
# puts MIME::Types.any? { |type| type.content_type ==
|
|
58
|
+
# puts MIME::Types.any? { |type| type.content_type == "text/plain" } # => true
|
|
57
59
|
# puts MIME::Types.all?(&:registered?) # => false
|
|
58
60
|
#
|
|
59
61
|
# # Various string representations of MIME types
|
|
60
|
-
# qcelp = MIME::Types[
|
|
61
|
-
# puts qcelp.content_type # =>
|
|
62
|
-
# puts qcelp.simplified # =>
|
|
62
|
+
# qcelp = MIME::Types["audio/QCELP"].first # => audio/QCELP
|
|
63
|
+
# puts qcelp.content_type # => "audio/QCELP"
|
|
64
|
+
# puts qcelp.simplified # => "audio/qcelp"
|
|
63
65
|
#
|
|
64
|
-
# xwingz = MIME::Types[
|
|
65
|
-
# puts xwingz.content_type # =>
|
|
66
|
-
# puts xwingz.simplified # =>
|
|
66
|
+
# xwingz = MIME::Types["application/x-Wingz"].first # => application/x-Wingz
|
|
67
|
+
# puts xwingz.content_type # => "application/x-Wingz"
|
|
68
|
+
# puts xwingz.simplified # => "application/x-wingz"
|
|
67
69
|
class MIME::Type
|
|
68
70
|
# Reflects a MIME content-type specification that is not correctly
|
|
69
|
-
# formatted (it
|
|
71
|
+
# formatted (it is not +type+/+subtype+).
|
|
70
72
|
class InvalidContentType < ArgumentError
|
|
71
73
|
# :stopdoc:
|
|
72
74
|
def initialize(type_string)
|
|
@@ -92,15 +94,18 @@ class MIME::Type
|
|
|
92
94
|
# :startdoc:
|
|
93
95
|
end
|
|
94
96
|
|
|
95
|
-
# The released version of the mime-types library.
|
|
96
|
-
VERSION = "3.5.2"
|
|
97
|
-
|
|
98
97
|
include Comparable
|
|
99
98
|
|
|
100
99
|
# :stopdoc:
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
|
|
100
|
+
# Full conformance with RFC 6838 §4.2 (the recommendation for < 64 characters is not
|
|
101
|
+
# enforced or reported because MIME::Types mostly deals with registered data). RFC 4288
|
|
102
|
+
# §4.2 does not restrict the first character to alphanumeric, but the total length of
|
|
103
|
+
# each part is limited to 127 characters. RFCC 2045 §5.1 does not restrict the character
|
|
104
|
+
# composition except for whitespace, but MIME::Type was always more strict than this.
|
|
105
|
+
restricted_name_first = "[0-9a-zA-Z]"
|
|
106
|
+
restricted_name_chars = "[-!#{$&}^_.+0-9a-zA-Z]{0,126}"
|
|
107
|
+
restricted_name = "#{restricted_name_first}#{restricted_name_chars}"
|
|
108
|
+
MEDIA_TYPE_RE = %r{(#{restricted_name})/(#{restricted_name})}.freeze
|
|
104
109
|
I18N_RE = /[^[:alnum:]]/.freeze
|
|
105
110
|
BINARY_ENCODINGS = %w[base64 8bit].freeze
|
|
106
111
|
ASCII_ENCODINGS = %w[7bit quoted-printable].freeze
|
|
@@ -110,12 +115,15 @@ class MIME::Type
|
|
|
110
115
|
:ASCII_ENCODINGS
|
|
111
116
|
|
|
112
117
|
# Builds a MIME::Type object from the +content_type+, a MIME Content Type
|
|
113
|
-
# value (e.g.,
|
|
118
|
+
# value (e.g., "text/plain" or "application/x-eruby"). The constructed object
|
|
114
119
|
# is yielded to an optional block for additional configuration, such as
|
|
115
120
|
# associating extensions and encoding information.
|
|
116
121
|
#
|
|
117
122
|
# * When provided a Hash or a MIME::Type, the MIME::Type will be
|
|
118
123
|
# constructed with #init_with.
|
|
124
|
+
#
|
|
125
|
+
# There are two deprecated initialization forms:
|
|
126
|
+
#
|
|
119
127
|
# * When provided an Array, the MIME::Type will be constructed using
|
|
120
128
|
# the first element as the content type and the remaining flattened
|
|
121
129
|
# elements as extensions.
|
|
@@ -125,18 +133,31 @@ class MIME::Type
|
|
|
125
133
|
def initialize(content_type) # :yields: self
|
|
126
134
|
@friendly = {}
|
|
127
135
|
@obsolete = @registered = @provisional = false
|
|
128
|
-
@preferred_extension = @docs = @use_instead = nil
|
|
136
|
+
@preferred_extension = @docs = @use_instead = @__sort_priority = nil
|
|
137
|
+
|
|
129
138
|
self.extensions = []
|
|
130
139
|
|
|
131
140
|
case content_type
|
|
132
141
|
when Hash
|
|
133
142
|
init_with(content_type)
|
|
134
143
|
when Array
|
|
144
|
+
MIME::Types.deprecated(
|
|
145
|
+
class: MIME::Type,
|
|
146
|
+
method: :new,
|
|
147
|
+
pre: "when called with an Array",
|
|
148
|
+
once: true
|
|
149
|
+
)
|
|
135
150
|
self.content_type = content_type.shift
|
|
136
151
|
self.extensions = content_type.flatten
|
|
137
152
|
when MIME::Type
|
|
138
153
|
init_with(content_type.to_h)
|
|
139
154
|
else
|
|
155
|
+
MIME::Types.deprecated(
|
|
156
|
+
class: MIME::Type,
|
|
157
|
+
method: :new,
|
|
158
|
+
pre: "when called with a String",
|
|
159
|
+
once: true
|
|
160
|
+
)
|
|
140
161
|
self.content_type = content_type
|
|
141
162
|
end
|
|
142
163
|
|
|
@@ -144,6 +165,8 @@ class MIME::Type
|
|
|
144
165
|
self.xrefs ||= {}
|
|
145
166
|
|
|
146
167
|
yield self if block_given?
|
|
168
|
+
|
|
169
|
+
update_sort_priority
|
|
147
170
|
end
|
|
148
171
|
|
|
149
172
|
# Indicates that a MIME type is like another type. This differs from
|
|
@@ -162,60 +185,54 @@ class MIME::Type
|
|
|
162
185
|
# simplified type (the simplified type will be used if comparing against
|
|
163
186
|
# something that can be treated as a String with #to_s). In comparisons, this
|
|
164
187
|
# is done against the lowercase version of the MIME::Type.
|
|
188
|
+
#
|
|
189
|
+
# Note that this implementation of #<=> is deprecated and will be changed
|
|
190
|
+
# in the next major version to be the same as #priority_compare.
|
|
191
|
+
#
|
|
192
|
+
# Note that MIME::Types no longer compare against nil.
|
|
165
193
|
def <=>(other)
|
|
166
|
-
if other.
|
|
167
|
-
|
|
168
|
-
|
|
194
|
+
return priority_compare(other) if other.is_a?(MIME::Type)
|
|
195
|
+
simplified <=> other
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Compares the +other+ MIME::Type using a pre-computed sort priority value,
|
|
199
|
+
# then the simplified representation for an alphabetical sort.
|
|
200
|
+
#
|
|
201
|
+
# For the next major version of MIME::Types, this method will become #<=> and
|
|
202
|
+
# #priority_compare will be removed.
|
|
203
|
+
def priority_compare(other)
|
|
204
|
+
if (cmp = __sort_priority <=> other.__sort_priority) == 0
|
|
169
205
|
simplified <=> other.simplified
|
|
170
206
|
else
|
|
171
|
-
|
|
172
|
-
filtered ||= "true" if other == true
|
|
173
|
-
filtered ||= other.to_s
|
|
174
|
-
|
|
175
|
-
simplified <=> MIME::Type.simplified(filtered)
|
|
207
|
+
cmp
|
|
176
208
|
end
|
|
177
209
|
end
|
|
178
210
|
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
# comparisons involved are:
|
|
182
|
-
#
|
|
183
|
-
# 1. self.simplified <=> other.simplified (ensures that we
|
|
184
|
-
# don't try to compare different types)
|
|
185
|
-
# 2. IANA-registered definitions < other definitions.
|
|
186
|
-
# 3. Complete definitions < incomplete definitions.
|
|
187
|
-
# 4. Current definitions < obsolete definitions.
|
|
188
|
-
# 5. Obselete with use-instead names < obsolete without.
|
|
189
|
-
# 6. Obsolete use-instead definitions are compared.
|
|
211
|
+
# Uses a modified pre-computed sort priority value based on whether one of the provided
|
|
212
|
+
# extensions is the preferred extension for a type.
|
|
190
213
|
#
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
def
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
|
214
|
+
# This is an internal function. If an extension provided is a preferred extension either
|
|
215
|
+
# for this instance or the compared instance, the corresponding extension has its top
|
|
216
|
+
# _extension_ bit cleared from its sort priority. That means that a type with between
|
|
217
|
+
# 0 and 8 extensions will be treated as if it had 9 extensions.
|
|
218
|
+
def __extension_priority_compare(other, exts) # :nodoc:
|
|
219
|
+
tsp = __sort_priority
|
|
220
|
+
|
|
221
|
+
if exts.include?(preferred_extension) && tsp & 0b1000 != 0
|
|
222
|
+
tsp = tsp & 0b11110111 | 0b0111
|
|
216
223
|
end
|
|
217
224
|
|
|
218
|
-
|
|
225
|
+
osp = other.__sort_priority
|
|
226
|
+
|
|
227
|
+
if exts.include?(other.preferred_extension) && osp & 0b1000 != 0
|
|
228
|
+
osp = osp & 0b11110111 | 0b0111
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
if (cmp = tsp <=> osp) == 0
|
|
232
|
+
simplified <=> other.simplified
|
|
233
|
+
else
|
|
234
|
+
cmp
|
|
235
|
+
end
|
|
219
236
|
end
|
|
220
237
|
|
|
221
238
|
# Returns +true+ if the +other+ object is a MIME::Type and the content types
|
|
@@ -243,13 +260,20 @@ class MIME::Type
|
|
|
243
260
|
# +a.simplified+.
|
|
244
261
|
#
|
|
245
262
|
# Presumably, if <code>a.simplified <=> b.simplified</code> is +0+, then
|
|
246
|
-
# +a.simplified+ has the same hash as +b.simplified+. So we assume it
|
|
263
|
+
# +a.simplified+ has the same hash as +b.simplified+. So we assume it is
|
|
247
264
|
# suitable for #hash to delegate to #simplified in service of the #eql?
|
|
248
265
|
# invariant.
|
|
249
266
|
def hash
|
|
250
267
|
simplified.hash
|
|
251
268
|
end
|
|
252
269
|
|
|
270
|
+
# The computed sort priority value. This is _not_ intended to be used by most
|
|
271
|
+
# callers.
|
|
272
|
+
def __sort_priority # :nodoc:
|
|
273
|
+
update_sort_priority if !instance_variable_defined?(:@__sort_priority) || @__sort_priority.nil?
|
|
274
|
+
@__sort_priority
|
|
275
|
+
end
|
|
276
|
+
|
|
253
277
|
# Returns the whole MIME content-type string.
|
|
254
278
|
#
|
|
255
279
|
# The content type is a presentation value from the MIME type registry and
|
|
@@ -304,6 +328,7 @@ class MIME::Type
|
|
|
304
328
|
|
|
305
329
|
##
|
|
306
330
|
def extensions=(value) # :nodoc:
|
|
331
|
+
clear_sort_priority
|
|
307
332
|
@extensions = Set[*Array(value).flatten.compact].freeze
|
|
308
333
|
MIME::Types.send(:reindex_extensions, self)
|
|
309
334
|
end
|
|
@@ -319,7 +344,7 @@ class MIME::Type
|
|
|
319
344
|
# exceptions defined, the first extension will be used.
|
|
320
345
|
#
|
|
321
346
|
# When setting #preferred_extensions, if #extensions does not contain this
|
|
322
|
-
# extension, this will be added to #
|
|
347
|
+
# extension, this will be added to #extensions.
|
|
323
348
|
#
|
|
324
349
|
# :attr_accessor: preferred_extension
|
|
325
350
|
|
|
@@ -343,7 +368,7 @@ class MIME::Type
|
|
|
343
368
|
# provided is invalid.
|
|
344
369
|
#
|
|
345
370
|
# If the encoding is not provided on construction, this will be either
|
|
346
|
-
#
|
|
371
|
+
# "quoted-printable" (for text/* media types) and "base64" for eveything
|
|
347
372
|
# else.
|
|
348
373
|
#
|
|
349
374
|
# :attr_accessor: encoding
|
|
@@ -383,9 +408,17 @@ class MIME::Type
|
|
|
383
408
|
attr_writer :use_instead
|
|
384
409
|
|
|
385
410
|
# Returns +true+ if the media type is obsolete.
|
|
386
|
-
|
|
411
|
+
#
|
|
412
|
+
# :attr_accessor: obsolete
|
|
413
|
+
attr_reader :obsolete
|
|
387
414
|
alias_method :obsolete?, :obsolete
|
|
388
415
|
|
|
416
|
+
##
|
|
417
|
+
def obsolete=(value)
|
|
418
|
+
clear_sort_priority
|
|
419
|
+
@obsolete = !!value
|
|
420
|
+
end
|
|
421
|
+
|
|
389
422
|
# The documentation for this MIME::Type.
|
|
390
423
|
attr_accessor :docs
|
|
391
424
|
|
|
@@ -393,7 +426,7 @@ class MIME::Type
|
|
|
393
426
|
#
|
|
394
427
|
# call-seq:
|
|
395
428
|
# text_plain.friendly # => "Text File"
|
|
396
|
-
# text_plain.friendly(
|
|
429
|
+
# text_plain.friendly("en") # => "Text File"
|
|
397
430
|
def friendly(lang = "en")
|
|
398
431
|
@friendly ||= {}
|
|
399
432
|
|
|
@@ -443,11 +476,27 @@ class MIME::Type
|
|
|
443
476
|
end
|
|
444
477
|
|
|
445
478
|
# Indicates whether the MIME type has been registered with IANA.
|
|
446
|
-
|
|
479
|
+
#
|
|
480
|
+
# :attr_accessor: registered
|
|
481
|
+
attr_reader :registered
|
|
447
482
|
alias_method :registered?, :registered
|
|
448
483
|
|
|
484
|
+
##
|
|
485
|
+
def registered=(value)
|
|
486
|
+
clear_sort_priority
|
|
487
|
+
@registered = !!value
|
|
488
|
+
end
|
|
489
|
+
|
|
449
490
|
# Indicates whether the MIME type's registration with IANA is provisional.
|
|
450
|
-
|
|
491
|
+
#
|
|
492
|
+
# :attr_accessor: provisional
|
|
493
|
+
attr_reader :provisional
|
|
494
|
+
|
|
495
|
+
##
|
|
496
|
+
def provisional=(value)
|
|
497
|
+
clear_sort_priority
|
|
498
|
+
@provisional = !!value
|
|
499
|
+
end
|
|
451
500
|
|
|
452
501
|
# Indicates whether the MIME type's registration with IANA is provisional.
|
|
453
502
|
def provisional?
|
|
@@ -486,7 +535,7 @@ class MIME::Type
|
|
|
486
535
|
# Returns the MIME::Type as a string for implicit conversions. This allows
|
|
487
536
|
# MIME::Type objects to appear on either side of a comparison.
|
|
488
537
|
#
|
|
489
|
-
#
|
|
538
|
+
# "text/plain" == MIME::Type.new("content-type" => "text/plain")
|
|
490
539
|
def to_str
|
|
491
540
|
content_type
|
|
492
541
|
end
|
|
@@ -530,6 +579,7 @@ class MIME::Type
|
|
|
530
579
|
coder["registered"] = registered?
|
|
531
580
|
coder["provisional"] = provisional? if provisional?
|
|
532
581
|
coder["signature"] = signature? if signature?
|
|
582
|
+
coder["sort-priority"] = __sort_priority || 0b11111111
|
|
533
583
|
coder
|
|
534
584
|
end
|
|
535
585
|
|
|
@@ -538,6 +588,7 @@ class MIME::Type
|
|
|
538
588
|
#
|
|
539
589
|
# This method should be considered a private implementation detail.
|
|
540
590
|
def init_with(coder)
|
|
591
|
+
@__sort_priority = 0
|
|
541
592
|
self.content_type = coder["content-type"]
|
|
542
593
|
self.docs = coder["docs"] || ""
|
|
543
594
|
self.encoding = coder["encoding"]
|
|
@@ -551,6 +602,8 @@ class MIME::Type
|
|
|
551
602
|
self.use_instead = coder["use-instead"]
|
|
552
603
|
|
|
553
604
|
friendly(coder["friendly"] || {})
|
|
605
|
+
|
|
606
|
+
update_sort_priority
|
|
554
607
|
end
|
|
555
608
|
|
|
556
609
|
def inspect # :nodoc:
|
|
@@ -606,6 +659,37 @@ class MIME::Type
|
|
|
606
659
|
|
|
607
660
|
private
|
|
608
661
|
|
|
662
|
+
def clear_sort_priority
|
|
663
|
+
@__sort_priority = nil
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
# Update the __sort_priority value. Lower numbers sort better, so the
|
|
667
|
+
# bitmapping may seem a little odd. The _best_ sort priority is 0.
|
|
668
|
+
#
|
|
669
|
+
# | bit | meaning | details |
|
|
670
|
+
# | --- | --------------- | --------- |
|
|
671
|
+
# | 7 | obsolete | 1 if true |
|
|
672
|
+
# | 6 | provisional | 1 if true |
|
|
673
|
+
# | 5 | registered | 0 if true |
|
|
674
|
+
# | 4 | complete | 0 if true |
|
|
675
|
+
# | 3 | # of extensions | see below |
|
|
676
|
+
# | 2 | # of extensions | see below |
|
|
677
|
+
# | 1 | # of extensions | see below |
|
|
678
|
+
# | 0 | # of extensions | see below |
|
|
679
|
+
#
|
|
680
|
+
# The # of extensions is marked as the number of extensions subtracted from
|
|
681
|
+
# 16, to a minimum of 0.
|
|
682
|
+
def update_sort_priority
|
|
683
|
+
extension_count = @extensions.length
|
|
684
|
+
obsolete = (instance_variable_defined?(:@obsolete) && @obsolete) ? 1 << 7 : 0
|
|
685
|
+
provisional = (instance_variable_defined?(:@provisional) && @provisional) ? 1 << 6 : 0
|
|
686
|
+
registered = (instance_variable_defined?(:@registered) && @registered) ? 0 : 1 << 5
|
|
687
|
+
complete = extension_count.nonzero? ? 0 : 1 << 4
|
|
688
|
+
extension_count = [0, 16 - extension_count].max
|
|
689
|
+
|
|
690
|
+
@__sort_priority = obsolete | registered | provisional | complete | extension_count
|
|
691
|
+
end
|
|
692
|
+
|
|
609
693
|
def content_type=(type_string)
|
|
610
694
|
match = MEDIA_TYPE_RE.match(type_string)
|
|
611
695
|
fail InvalidContentType, type_string if match.nil?
|
|
@@ -627,7 +711,7 @@ class MIME::Type
|
|
|
627
711
|
-string
|
|
628
712
|
end
|
|
629
713
|
else
|
|
630
|
-
# MRI 2.2 and older
|
|
714
|
+
# MRI 2.2 and older do not have a method for string interning,
|
|
631
715
|
# so we simply freeze them for keeping a similar interface
|
|
632
716
|
def intern_string(string)
|
|
633
717
|
string.freeze
|
|
@@ -658,3 +742,5 @@ class MIME::Type
|
|
|
658
742
|
"http://www.iana.org/assignments/media-types/%s" % value
|
|
659
743
|
end
|
|
660
744
|
end
|
|
745
|
+
|
|
746
|
+
require "mime/types/version"
|
data/lib/mime/types/_columnar.rb
CHANGED
|
@@ -18,6 +18,10 @@ module MIME::Types::Columnar
|
|
|
18
18
|
obj.instance_variable_set(:@__files__, Set.new)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
def __fully_loaded? # :nodoc:
|
|
22
|
+
@__files__.size == 10
|
|
23
|
+
end
|
|
24
|
+
|
|
21
25
|
# Load the first column data file (type and extensions).
|
|
22
26
|
def load_base_data(path) # :nodoc:
|
|
23
27
|
@__root__ = path
|
|
@@ -26,13 +30,16 @@ module MIME::Types::Columnar
|
|
|
26
30
|
line = line.split
|
|
27
31
|
content_type = line.shift
|
|
28
32
|
extensions = line
|
|
29
|
-
# content_type, *extensions = line.split
|
|
30
33
|
|
|
31
34
|
type = MIME::Type::Columnar.new(self, content_type, extensions)
|
|
32
35
|
@__mime_data__ << type
|
|
33
36
|
add(type)
|
|
34
37
|
end
|
|
35
38
|
|
|
39
|
+
each_file_byte("spri") do |type, byte|
|
|
40
|
+
type.instance_variable_set(:@__sort_priority, byte)
|
|
41
|
+
end
|
|
42
|
+
|
|
36
43
|
self
|
|
37
44
|
end
|
|
38
45
|
|
|
@@ -60,10 +67,29 @@ module MIME::Types::Columnar
|
|
|
60
67
|
end
|
|
61
68
|
end
|
|
62
69
|
|
|
70
|
+
def each_file_byte(name)
|
|
71
|
+
LOAD_MUTEX.synchronize do
|
|
72
|
+
next if @__files__.include?(name)
|
|
73
|
+
|
|
74
|
+
i = -1
|
|
75
|
+
|
|
76
|
+
filename = File.join(@__root__, "mime.#{name}.column")
|
|
77
|
+
|
|
78
|
+
next unless File.exist?(filename)
|
|
79
|
+
|
|
80
|
+
IO.binread(filename).unpack("C*").each do |byte|
|
|
81
|
+
(type = @__mime_data__[i += 1]) || next
|
|
82
|
+
yield type, byte
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@__files__ << name
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
63
89
|
def load_encoding
|
|
64
90
|
each_file_line("encoding") do |type, line|
|
|
65
91
|
pool ||= {}
|
|
66
|
-
type.instance_variable_set(:@encoding,
|
|
92
|
+
type.instance_variable_set(:@encoding, pool[line] ||= line)
|
|
67
93
|
end
|
|
68
94
|
end
|
|
69
95
|
|
|
@@ -91,7 +117,7 @@ module MIME::Types::Columnar
|
|
|
91
117
|
|
|
92
118
|
def load_xrefs
|
|
93
119
|
each_file_line("xrefs") { |type, line|
|
|
94
|
-
type.instance_variable_set(:@xrefs, dict(line,
|
|
120
|
+
type.instance_variable_set(:@xrefs, dict(line, transform: :array))
|
|
95
121
|
}
|
|
96
122
|
end
|
|
97
123
|
|
|
@@ -107,18 +133,39 @@ module MIME::Types::Columnar
|
|
|
107
133
|
end
|
|
108
134
|
end
|
|
109
135
|
|
|
110
|
-
def dict(line,
|
|
136
|
+
def dict(line, transform: nil)
|
|
111
137
|
if line == "-"
|
|
112
138
|
{}
|
|
113
139
|
else
|
|
114
140
|
line.split("|").each_with_object({}) { |l, h|
|
|
115
141
|
k, v = l.split("^")
|
|
116
142
|
v = nil if v.empty?
|
|
117
|
-
|
|
143
|
+
|
|
144
|
+
if transform
|
|
145
|
+
send(:"dict_#{transform}", h, k, v)
|
|
146
|
+
else
|
|
147
|
+
h[k] = v
|
|
148
|
+
end
|
|
118
149
|
}
|
|
119
150
|
end
|
|
120
151
|
end
|
|
121
152
|
|
|
153
|
+
def dict_extension_priority(h, k, v)
|
|
154
|
+
return if v.nil?
|
|
155
|
+
|
|
156
|
+
v = v.to_i if v.is_a?(String)
|
|
157
|
+
v = v.trunc if v.is_a?(Float)
|
|
158
|
+
v = [[-20, v].max, 20].min
|
|
159
|
+
|
|
160
|
+
return if v.zero?
|
|
161
|
+
|
|
162
|
+
h[k] = v
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def dict_array(h, k, v)
|
|
166
|
+
h[k] = Array(v)
|
|
167
|
+
end
|
|
168
|
+
|
|
122
169
|
def arr(line)
|
|
123
170
|
if line == "-"
|
|
124
171
|
[]
|
data/lib/mime/types/container.rb
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "set"
|
|
4
|
-
require "forwardable"
|
|
5
4
|
|
|
6
5
|
# MIME::Types requires a serializable keyed container that returns an empty Set
|
|
7
6
|
# on a key miss. Hash#default_value cannot be used because, while it traverses
|
|
8
|
-
# the Marshal format correctly, it
|
|
7
|
+
# the Marshal format correctly, it will not survive any other serialization
|
|
9
8
|
# format (plus, a default of a mutable object resuls in a shared mess).
|
|
10
9
|
# Hash#default_proc cannot be used without a wrapper because it prevents
|
|
11
|
-
# Marshal serialization (and
|
|
10
|
+
# Marshal serialization (and does not survive the round-trip).
|
|
12
11
|
class MIME::Types::Container # :nodoc:
|
|
13
|
-
extend Forwardable
|
|
14
|
-
|
|
15
12
|
def initialize(hash = {})
|
|
16
13
|
@container = {}
|
|
17
14
|
merge!(hash)
|
|
@@ -47,16 +44,49 @@ class MIME::Types::Container # :nodoc:
|
|
|
47
44
|
container
|
|
48
45
|
end
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
def ==(other)
|
|
48
|
+
container == other
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def count(*args, &block)
|
|
52
|
+
if args.size == 0
|
|
53
|
+
container.count
|
|
54
|
+
elsif block
|
|
55
|
+
container.count(&block)
|
|
56
|
+
else
|
|
57
|
+
container.count(args.first)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def each_pair(&block)
|
|
62
|
+
container.each_pair(&block)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
alias_method :each, :each_pair
|
|
66
|
+
|
|
67
|
+
def each_value(&block)
|
|
68
|
+
container.each_value(&block)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def empty?
|
|
72
|
+
container.empty?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def flat_map(&block)
|
|
76
|
+
container.flat_map(&block)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def keys
|
|
80
|
+
container.keys
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def values
|
|
84
|
+
container.values
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def select(&block)
|
|
88
|
+
container.select(&block)
|
|
89
|
+
end
|
|
60
90
|
|
|
61
91
|
def add(key, value)
|
|
62
92
|
(container[key] ||= Set.new).add(value)
|