mime-types 3.3.1 → 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} +11 -12
- data/Manifest.txt +8 -5
- data/README.md +200 -0
- data/Rakefile +118 -201
- data/SECURITY.md +7 -0
- data/lib/mime/type/columnar.rb +17 -4
- data/lib/mime/type.rb +293 -134
- data/lib/mime/types/_columnar.rb +72 -24
- data/lib/mime/types/cache.rb +8 -12
- data/lib/mime/types/columnar.rb +1 -1
- data/lib/mime/types/container.rb +49 -19
- data/lib/mime/types/deprecations.rb +51 -27
- data/lib/mime/types/full.rb +2 -2
- data/lib/mime/types/loader.rb +29 -16
- data/lib/mime/types/logger.rb +38 -9
- data/lib/mime/types/registry.rb +10 -8
- data/lib/mime/types/version.rb +14 -0
- data/lib/mime/types.rb +45 -33
- data/lib/mime-types.rb +1 -1
- data/test/minitest_helper.rb +6 -9
- data/test/test_mime_type.rb +337 -288
- data/test/test_mime_types.rb +79 -75
- data/test/test_mime_types_cache.rb +38 -38
- data/test/test_mime_types_class.rb +70 -59
- data/test/test_mime_types_lazy.rb +16 -16
- data/test/test_mime_types_loader.rb +14 -14
- metadata +54 -122
- data/Code-of-Conduct.md +0 -73
- data/Contributing.md +0 -143
- data/History.md +0 -240
- data/README.rdoc +0 -193
data/lib/mime/type.rb
CHANGED
|
@@ -4,33 +4,71 @@
|
|
|
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[
|
|
13
|
-
# # returns [text/plain, text/plain]
|
|
14
|
+
# plaintext = MIME::Types["text/plain"] # => [ text/plain ]
|
|
14
15
|
# text = plaintext.first
|
|
15
|
-
#
|
|
16
|
-
#
|
|
16
|
+
# puts text.media_type # => "text"
|
|
17
|
+
# puts text.sub_type # => "plain"
|
|
17
18
|
#
|
|
18
|
-
# puts text.extensions.join(" ") # =>
|
|
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"
|
|
19
23
|
#
|
|
20
|
-
# puts text.encoding # =>
|
|
24
|
+
# puts text.encoding # => quoted-printable
|
|
25
|
+
# puts text.default_encoding # => quoted-printable
|
|
21
26
|
# puts text.binary? # => false
|
|
22
27
|
# puts text.ascii? # => true
|
|
23
|
-
# puts text
|
|
24
|
-
# puts
|
|
28
|
+
# puts text.obsolete? # => false
|
|
29
|
+
# puts text.registered? # => true
|
|
30
|
+
# puts text.provisional? # => false
|
|
31
|
+
# puts text.complete? # => true
|
|
32
|
+
#
|
|
33
|
+
# puts text # => "text/plain"
|
|
34
|
+
#
|
|
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
|
|
39
|
+
#
|
|
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"
|
|
42
|
+
#
|
|
43
|
+
# puts text.like?("text/x-plain") # => true
|
|
44
|
+
# puts text.like?(MIME::Type.new("content-type" => "x-text/x-plain")) # => true
|
|
45
|
+
#
|
|
46
|
+
# puts text.xrefs.inspect # => { "rfc" => [ "rfc2046", "rfc3676", "rfc5147" ] }
|
|
47
|
+
# puts text.xref_urls # => [ "http://www.iana.org/go/rfc2046",
|
|
48
|
+
# # "http://www.iana.org/go/rfc3676",
|
|
49
|
+
# # "http://www.iana.org/go/rfc5147" ]
|
|
50
|
+
#
|
|
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"
|
|
56
|
+
# puts xtext.complete? # => false
|
|
57
|
+
#
|
|
58
|
+
# puts MIME::Types.any? { |type| type.content_type == "text/plain" } # => true
|
|
59
|
+
# puts MIME::Types.all?(&:registered?) # => false
|
|
25
60
|
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# puts
|
|
30
|
-
#
|
|
61
|
+
# # Various string representations of MIME types
|
|
62
|
+
# qcelp = MIME::Types["audio/QCELP"].first # => audio/QCELP
|
|
63
|
+
# puts qcelp.content_type # => "audio/QCELP"
|
|
64
|
+
# puts qcelp.simplified # => "audio/qcelp"
|
|
65
|
+
#
|
|
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"
|
|
31
69
|
class MIME::Type
|
|
32
70
|
# Reflects a MIME content-type specification that is not correctly
|
|
33
|
-
# formatted (it
|
|
71
|
+
# formatted (it is not +type+/+subtype+).
|
|
34
72
|
class InvalidContentType < ArgumentError
|
|
35
73
|
# :stopdoc:
|
|
36
74
|
def initialize(type_string)
|
|
@@ -56,51 +94,70 @@ class MIME::Type
|
|
|
56
94
|
# :startdoc:
|
|
57
95
|
end
|
|
58
96
|
|
|
59
|
-
# The released version of the mime-types library.
|
|
60
|
-
VERSION = '3.3.1'
|
|
61
|
-
|
|
62
97
|
include Comparable
|
|
63
98
|
|
|
64
99
|
# :stopdoc:
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
|
109
|
+
I18N_RE = /[^[:alnum:]]/.freeze
|
|
110
|
+
BINARY_ENCODINGS = %w[base64 8bit].freeze
|
|
111
|
+
ASCII_ENCODINGS = %w[7bit quoted-printable].freeze
|
|
71
112
|
# :startdoc:
|
|
72
113
|
|
|
73
114
|
private_constant :MEDIA_TYPE_RE, :I18N_RE, :BINARY_ENCODINGS,
|
|
74
|
-
|
|
115
|
+
:ASCII_ENCODINGS
|
|
75
116
|
|
|
76
117
|
# Builds a MIME::Type object from the +content_type+, a MIME Content Type
|
|
77
|
-
# value (e.g.,
|
|
118
|
+
# value (e.g., "text/plain" or "application/x-eruby"). The constructed object
|
|
78
119
|
# is yielded to an optional block for additional configuration, such as
|
|
79
120
|
# associating extensions and encoding information.
|
|
80
121
|
#
|
|
81
122
|
# * When provided a Hash or a MIME::Type, the MIME::Type will be
|
|
82
123
|
# constructed with #init_with.
|
|
124
|
+
#
|
|
125
|
+
# There are two deprecated initialization forms:
|
|
126
|
+
#
|
|
83
127
|
# * When provided an Array, the MIME::Type will be constructed using
|
|
84
128
|
# the first element as the content type and the remaining flattened
|
|
85
129
|
# elements as extensions.
|
|
86
130
|
# * Otherwise, the content_type will be used as a string.
|
|
87
131
|
#
|
|
88
132
|
# Yields the newly constructed +self+ object.
|
|
89
|
-
def initialize(content_type) # :yields self
|
|
133
|
+
def initialize(content_type) # :yields: self
|
|
90
134
|
@friendly = {}
|
|
91
|
-
@obsolete = @registered = false
|
|
92
|
-
@preferred_extension = @docs = @use_instead = nil
|
|
135
|
+
@obsolete = @registered = @provisional = false
|
|
136
|
+
@preferred_extension = @docs = @use_instead = @__sort_priority = nil
|
|
137
|
+
|
|
93
138
|
self.extensions = []
|
|
94
139
|
|
|
95
140
|
case content_type
|
|
96
141
|
when Hash
|
|
97
142
|
init_with(content_type)
|
|
98
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
|
+
)
|
|
99
150
|
self.content_type = content_type.shift
|
|
100
151
|
self.extensions = content_type.flatten
|
|
101
152
|
when MIME::Type
|
|
102
153
|
init_with(content_type.to_h)
|
|
103
154
|
else
|
|
155
|
+
MIME::Types.deprecated(
|
|
156
|
+
class: MIME::Type,
|
|
157
|
+
method: :new,
|
|
158
|
+
pre: "when called with a String",
|
|
159
|
+
once: true
|
|
160
|
+
)
|
|
104
161
|
self.content_type = content_type
|
|
105
162
|
end
|
|
106
163
|
|
|
@@ -108,16 +165,19 @@ class MIME::Type
|
|
|
108
165
|
self.xrefs ||= {}
|
|
109
166
|
|
|
110
167
|
yield self if block_given?
|
|
168
|
+
|
|
169
|
+
update_sort_priority
|
|
111
170
|
end
|
|
112
171
|
|
|
113
172
|
# Indicates that a MIME type is like another type. This differs from
|
|
114
173
|
# <tt>==</tt> because <tt>x-</tt> prefixes are removed for this comparison.
|
|
115
174
|
def like?(other)
|
|
116
|
-
other =
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
175
|
+
other =
|
|
176
|
+
if other.respond_to?(:simplified)
|
|
177
|
+
MIME::Type.simplified(other.simplified, remove_x_prefix: true)
|
|
178
|
+
else
|
|
179
|
+
MIME::Type.simplified(other.to_s, remove_x_prefix: true)
|
|
180
|
+
end
|
|
121
181
|
MIME::Type.simplified(simplified, remove_x_prefix: true) == other
|
|
122
182
|
end
|
|
123
183
|
|
|
@@ -125,65 +185,93 @@ class MIME::Type
|
|
|
125
185
|
# simplified type (the simplified type will be used if comparing against
|
|
126
186
|
# something that can be treated as a String with #to_s). In comparisons, this
|
|
127
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.
|
|
128
193
|
def <=>(other)
|
|
129
|
-
if other.
|
|
130
|
-
|
|
131
|
-
|
|
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
|
|
132
205
|
simplified <=> other.simplified
|
|
133
206
|
else
|
|
134
|
-
|
|
135
|
-
filtered ||= 'true' if other == true
|
|
136
|
-
filtered ||= other.to_s
|
|
137
|
-
|
|
138
|
-
simplified <=> MIME::Type.simplified(filtered)
|
|
207
|
+
cmp
|
|
139
208
|
end
|
|
140
209
|
end
|
|
141
210
|
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
# comparisons involved are:
|
|
145
|
-
#
|
|
146
|
-
# 1. self.simplified <=> other.simplified (ensures that we
|
|
147
|
-
# don't try to compare different types)
|
|
148
|
-
# 2. IANA-registered definitions < other definitions.
|
|
149
|
-
# 3. Complete definitions < incomplete definitions.
|
|
150
|
-
# 4. Current definitions < obsolete definitions.
|
|
151
|
-
# 5. Obselete with use-instead names < obsolete without.
|
|
152
|
-
# 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.
|
|
153
213
|
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
def
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
1
|
|
170
|
-
elsif oui.nil?
|
|
171
|
-
-1
|
|
172
|
-
else
|
|
173
|
-
ui <=> oui
|
|
174
|
-
end
|
|
175
|
-
else
|
|
176
|
-
0
|
|
177
|
-
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
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
osp = other.__sort_priority
|
|
226
|
+
|
|
227
|
+
if exts.include?(other.preferred_extension) && osp & 0b1000 != 0
|
|
228
|
+
osp = osp & 0b11110111 | 0b0111
|
|
178
229
|
end
|
|
179
230
|
|
|
180
|
-
|
|
231
|
+
if (cmp = tsp <=> osp) == 0
|
|
232
|
+
simplified <=> other.simplified
|
|
233
|
+
else
|
|
234
|
+
cmp
|
|
235
|
+
end
|
|
181
236
|
end
|
|
182
237
|
|
|
183
238
|
# Returns +true+ if the +other+ object is a MIME::Type and the content types
|
|
184
239
|
# match.
|
|
185
240
|
def eql?(other)
|
|
186
|
-
other.
|
|
241
|
+
other.is_a?(MIME::Type) && (self == other)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Returns a hash based on the #simplified value.
|
|
245
|
+
#
|
|
246
|
+
# This maintains the invariant that two #eql? instances must have the same
|
|
247
|
+
# #hash (although having the same #hash does *not* imply that the objects are
|
|
248
|
+
# #eql?).
|
|
249
|
+
#
|
|
250
|
+
# To see why, suppose a MIME::Type instance +a+ is compared to another object
|
|
251
|
+
# +b+, and that <code>a.eql?(b)</code> is true. By the definition of #eql?,
|
|
252
|
+
# we know the following:
|
|
253
|
+
#
|
|
254
|
+
# 1. +b+ is a MIME::Type instance itself.
|
|
255
|
+
# 2. <code>a == b</code> is true.
|
|
256
|
+
#
|
|
257
|
+
# Due to the first point, we know that +b+ should respond to the #simplified
|
|
258
|
+
# method. Thus, per the definition of #<=>, we know that +a.simplified+ must
|
|
259
|
+
# be equal to +b.simplified+, as compared by the <=> method corresponding to
|
|
260
|
+
# +a.simplified+.
|
|
261
|
+
#
|
|
262
|
+
# Presumably, if <code>a.simplified <=> b.simplified</code> is +0+, then
|
|
263
|
+
# +a.simplified+ has the same hash as +b.simplified+. So we assume it is
|
|
264
|
+
# suitable for #hash to delegate to #simplified in service of the #eql?
|
|
265
|
+
# invariant.
|
|
266
|
+
def hash
|
|
267
|
+
simplified.hash
|
|
268
|
+
end
|
|
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
|
|
187
275
|
end
|
|
188
276
|
|
|
189
277
|
# Returns the whole MIME content-type string.
|
|
@@ -197,8 +285,7 @@ class MIME::Type
|
|
|
197
285
|
# audio/QCELP => audio/QCELP
|
|
198
286
|
attr_reader :content_type
|
|
199
287
|
# A simplified form of the MIME content-type string, suitable for
|
|
200
|
-
# case-insensitive comparison, with
|
|
201
|
-
# removed and converted to lowercase.
|
|
288
|
+
# case-insensitive comparison, with the content_type converted to lowercase.
|
|
202
289
|
#
|
|
203
290
|
# text/plain => text/plain
|
|
204
291
|
# x-chemical/x-pdb => x-chemical/x-pdb
|
|
@@ -241,6 +328,7 @@ class MIME::Type
|
|
|
241
328
|
|
|
242
329
|
##
|
|
243
330
|
def extensions=(value) # :nodoc:
|
|
331
|
+
clear_sort_priority
|
|
244
332
|
@extensions = Set[*Array(value).flatten.compact].freeze
|
|
245
333
|
MIME::Types.send(:reindex_extensions, self)
|
|
246
334
|
end
|
|
@@ -256,7 +344,7 @@ class MIME::Type
|
|
|
256
344
|
# exceptions defined, the first extension will be used.
|
|
257
345
|
#
|
|
258
346
|
# When setting #preferred_extensions, if #extensions does not contain this
|
|
259
|
-
# extension, this will be added to #
|
|
347
|
+
# extension, this will be added to #extensions.
|
|
260
348
|
#
|
|
261
349
|
# :attr_accessor: preferred_extension
|
|
262
350
|
|
|
@@ -280,7 +368,7 @@ class MIME::Type
|
|
|
280
368
|
# provided is invalid.
|
|
281
369
|
#
|
|
282
370
|
# If the encoding is not provided on construction, this will be either
|
|
283
|
-
#
|
|
371
|
+
# "quoted-printable" (for text/* media types) and "base64" for eveything
|
|
284
372
|
# else.
|
|
285
373
|
#
|
|
286
374
|
# :attr_accessor: encoding
|
|
@@ -290,9 +378,9 @@ class MIME::Type
|
|
|
290
378
|
|
|
291
379
|
##
|
|
292
380
|
def encoding=(enc) # :nodoc:
|
|
293
|
-
if enc.nil?
|
|
381
|
+
if enc.nil? || (enc == :default)
|
|
294
382
|
@encoding = default_encoding
|
|
295
|
-
elsif BINARY_ENCODINGS.include?(enc)
|
|
383
|
+
elsif BINARY_ENCODINGS.include?(enc) || ASCII_ENCODINGS.include?(enc)
|
|
296
384
|
@encoding = enc
|
|
297
385
|
else
|
|
298
386
|
fail InvalidEncoding, enc
|
|
@@ -301,7 +389,7 @@ class MIME::Type
|
|
|
301
389
|
|
|
302
390
|
# Returns the default encoding for the MIME::Type based on the media type.
|
|
303
391
|
def default_encoding
|
|
304
|
-
@media_type ==
|
|
392
|
+
(@media_type == "text") ? "quoted-printable" : "base64"
|
|
305
393
|
end
|
|
306
394
|
|
|
307
395
|
##
|
|
@@ -320,8 +408,16 @@ class MIME::Type
|
|
|
320
408
|
attr_writer :use_instead
|
|
321
409
|
|
|
322
410
|
# Returns +true+ if the media type is obsolete.
|
|
323
|
-
|
|
324
|
-
|
|
411
|
+
#
|
|
412
|
+
# :attr_accessor: obsolete
|
|
413
|
+
attr_reader :obsolete
|
|
414
|
+
alias_method :obsolete?, :obsolete
|
|
415
|
+
|
|
416
|
+
##
|
|
417
|
+
def obsolete=(value)
|
|
418
|
+
clear_sort_priority
|
|
419
|
+
@obsolete = !!value
|
|
420
|
+
end
|
|
325
421
|
|
|
326
422
|
# The documentation for this MIME::Type.
|
|
327
423
|
attr_accessor :docs
|
|
@@ -330,8 +426,8 @@ class MIME::Type
|
|
|
330
426
|
#
|
|
331
427
|
# call-seq:
|
|
332
428
|
# text_plain.friendly # => "Text File"
|
|
333
|
-
# text_plain.friendly(
|
|
334
|
-
def friendly(lang =
|
|
429
|
+
# text_plain.friendly("en") # => "Text File"
|
|
430
|
+
def friendly(lang = "en")
|
|
335
431
|
@friendly ||= {}
|
|
336
432
|
|
|
337
433
|
case lang
|
|
@@ -343,7 +439,7 @@ class MIME::Type
|
|
|
343
439
|
@friendly.update(lang)
|
|
344
440
|
else
|
|
345
441
|
fail ArgumentError,
|
|
346
|
-
|
|
442
|
+
"Expected a language or translation set, not #{lang.inspect}"
|
|
347
443
|
end
|
|
348
444
|
end
|
|
349
445
|
|
|
@@ -374,14 +470,38 @@ class MIME::Type
|
|
|
374
470
|
# The decoded cross-reference URL list for this MIME::Type.
|
|
375
471
|
def xref_urls
|
|
376
472
|
xrefs.flat_map { |type, values|
|
|
377
|
-
name = :"xref_url_for_#{type.tr(
|
|
378
|
-
respond_to?(name, true)
|
|
473
|
+
name = :"xref_url_for_#{type.tr("-", "_")}"
|
|
474
|
+
respond_to?(name, true) && xref_map(values, name) || values.to_a
|
|
379
475
|
}
|
|
380
476
|
end
|
|
381
477
|
|
|
382
478
|
# Indicates whether the MIME type has been registered with IANA.
|
|
383
|
-
|
|
384
|
-
|
|
479
|
+
#
|
|
480
|
+
# :attr_accessor: registered
|
|
481
|
+
attr_reader :registered
|
|
482
|
+
alias_method :registered?, :registered
|
|
483
|
+
|
|
484
|
+
##
|
|
485
|
+
def registered=(value)
|
|
486
|
+
clear_sort_priority
|
|
487
|
+
@registered = !!value
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Indicates whether the MIME type's registration with IANA is provisional.
|
|
491
|
+
#
|
|
492
|
+
# :attr_accessor: provisional
|
|
493
|
+
attr_reader :provisional
|
|
494
|
+
|
|
495
|
+
##
|
|
496
|
+
def provisional=(value)
|
|
497
|
+
clear_sort_priority
|
|
498
|
+
@provisional = !!value
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Indicates whether the MIME type's registration with IANA is provisional.
|
|
502
|
+
def provisional?
|
|
503
|
+
registered? && @provisional
|
|
504
|
+
end
|
|
385
505
|
|
|
386
506
|
# MIME types can be specified to be sent across a network in particular
|
|
387
507
|
# formats. This method returns +true+ when the MIME::Type encoding is set
|
|
@@ -399,7 +519,7 @@ class MIME::Type
|
|
|
399
519
|
|
|
400
520
|
# Indicateswhether the MIME type is declared as a signature type.
|
|
401
521
|
attr_accessor :signature
|
|
402
|
-
|
|
522
|
+
alias_method :signature?, :signature
|
|
403
523
|
|
|
404
524
|
# Returns +true+ if the MIME::Type specifies an extension list,
|
|
405
525
|
# indicating that it is a complete MIME::Type.
|
|
@@ -415,14 +535,14 @@ class MIME::Type
|
|
|
415
535
|
# Returns the MIME::Type as a string for implicit conversions. This allows
|
|
416
536
|
# MIME::Type objects to appear on either side of a comparison.
|
|
417
537
|
#
|
|
418
|
-
#
|
|
538
|
+
# "text/plain" == MIME::Type.new("content-type" => "text/plain")
|
|
419
539
|
def to_str
|
|
420
540
|
content_type
|
|
421
541
|
end
|
|
422
542
|
|
|
423
543
|
# Converts the MIME::Type to a JSON string.
|
|
424
544
|
def to_json(*args)
|
|
425
|
-
require
|
|
545
|
+
require "json"
|
|
426
546
|
to_h.to_json(*args)
|
|
427
547
|
end
|
|
428
548
|
|
|
@@ -438,26 +558,28 @@ class MIME::Type
|
|
|
438
558
|
#
|
|
439
559
|
# This method should be considered a private implementation detail.
|
|
440
560
|
def encode_with(coder)
|
|
441
|
-
coder[
|
|
442
|
-
coder[
|
|
443
|
-
coder[
|
|
444
|
-
coder[
|
|
445
|
-
coder[
|
|
446
|
-
coder[
|
|
561
|
+
coder["content-type"] = @content_type
|
|
562
|
+
coder["docs"] = @docs unless @docs.nil? || @docs.empty?
|
|
563
|
+
coder["friendly"] = @friendly unless @friendly.nil? || @friendly.empty?
|
|
564
|
+
coder["encoding"] = @encoding
|
|
565
|
+
coder["extensions"] = @extensions.to_a unless @extensions.empty?
|
|
566
|
+
coder["preferred-extension"] = @preferred_extension if @preferred_extension
|
|
447
567
|
if obsolete?
|
|
448
|
-
coder[
|
|
449
|
-
coder[
|
|
568
|
+
coder["obsolete"] = obsolete?
|
|
569
|
+
coder["use-instead"] = use_instead if use_instead
|
|
450
570
|
end
|
|
451
571
|
unless xrefs.empty?
|
|
452
572
|
{}.tap do |hash|
|
|
453
573
|
xrefs.each do |k, v|
|
|
454
574
|
hash[k] = v.to_a.sort
|
|
455
575
|
end
|
|
456
|
-
coder[
|
|
576
|
+
coder["xrefs"] = hash
|
|
457
577
|
end
|
|
458
578
|
end
|
|
459
|
-
coder[
|
|
460
|
-
coder[
|
|
579
|
+
coder["registered"] = registered?
|
|
580
|
+
coder["provisional"] = provisional? if provisional?
|
|
581
|
+
coder["signature"] = signature? if signature?
|
|
582
|
+
coder["sort-priority"] = __sort_priority || 0b11111111
|
|
461
583
|
coder
|
|
462
584
|
end
|
|
463
585
|
|
|
@@ -466,18 +588,22 @@ class MIME::Type
|
|
|
466
588
|
#
|
|
467
589
|
# This method should be considered a private implementation detail.
|
|
468
590
|
def init_with(coder)
|
|
469
|
-
|
|
470
|
-
self.
|
|
471
|
-
self.
|
|
472
|
-
self.
|
|
473
|
-
self.
|
|
474
|
-
self.
|
|
475
|
-
self.
|
|
476
|
-
self.
|
|
477
|
-
self.
|
|
478
|
-
self.
|
|
591
|
+
@__sort_priority = 0
|
|
592
|
+
self.content_type = coder["content-type"]
|
|
593
|
+
self.docs = coder["docs"] || ""
|
|
594
|
+
self.encoding = coder["encoding"]
|
|
595
|
+
self.extensions = coder["extensions"] || []
|
|
596
|
+
self.preferred_extension = coder["preferred-extension"]
|
|
597
|
+
self.obsolete = coder["obsolete"] || false
|
|
598
|
+
self.registered = coder["registered"] || false
|
|
599
|
+
self.provisional = coder["provisional"] || false
|
|
600
|
+
self.signature = coder["signature"]
|
|
601
|
+
self.xrefs = coder["xrefs"] || {}
|
|
602
|
+
self.use_instead = coder["use-instead"]
|
|
603
|
+
|
|
604
|
+
friendly(coder["friendly"] || {})
|
|
479
605
|
|
|
480
|
-
|
|
606
|
+
update_sort_priority
|
|
481
607
|
end
|
|
482
608
|
|
|
483
609
|
def inspect # :nodoc:
|
|
@@ -501,8 +627,8 @@ class MIME::Type
|
|
|
501
627
|
# Converts a provided +content_type+ into a translation key suitable for
|
|
502
628
|
# use with the I18n library.
|
|
503
629
|
def i18n_key(content_type)
|
|
504
|
-
simplify_matchdata(match(content_type), joiner:
|
|
505
|
-
e.gsub!(I18N_RE,
|
|
630
|
+
simplify_matchdata(match(content_type), joiner: ".") { |e|
|
|
631
|
+
e.gsub!(I18N_RE, "-")
|
|
506
632
|
}
|
|
507
633
|
end
|
|
508
634
|
|
|
@@ -519,12 +645,12 @@ class MIME::Type
|
|
|
519
645
|
|
|
520
646
|
private
|
|
521
647
|
|
|
522
|
-
def simplify_matchdata(matchdata, remove_x = false, joiner:
|
|
648
|
+
def simplify_matchdata(matchdata, remove_x = false, joiner: "/")
|
|
523
649
|
return nil unless matchdata
|
|
524
650
|
|
|
525
651
|
matchdata.captures.map { |e|
|
|
526
652
|
e.downcase!
|
|
527
|
-
e.sub!(/^x-/,
|
|
653
|
+
e.sub!(/^x-/, "") if remove_x
|
|
528
654
|
yield e if block_given?
|
|
529
655
|
e
|
|
530
656
|
}.join(joiner)
|
|
@@ -533,15 +659,46 @@ class MIME::Type
|
|
|
533
659
|
|
|
534
660
|
private
|
|
535
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
|
+
|
|
536
693
|
def content_type=(type_string)
|
|
537
694
|
match = MEDIA_TYPE_RE.match(type_string)
|
|
538
695
|
fail InvalidContentType, type_string if match.nil?
|
|
539
696
|
|
|
540
|
-
@content_type
|
|
697
|
+
@content_type = intern_string(type_string)
|
|
541
698
|
@raw_media_type, @raw_sub_type = match.captures
|
|
542
|
-
@simplified
|
|
543
|
-
@i18n_key
|
|
544
|
-
@media_type, @sub_type
|
|
699
|
+
@simplified = intern_string(MIME::Type.simplified(match))
|
|
700
|
+
@i18n_key = intern_string(MIME::Type.i18n_key(match))
|
|
701
|
+
@media_type, @sub_type = MEDIA_TYPE_RE.match(@simplified).captures
|
|
545
702
|
|
|
546
703
|
@raw_media_type = intern_string(@raw_media_type)
|
|
547
704
|
@raw_sub_type = intern_string(@raw_sub_type)
|
|
@@ -554,7 +711,7 @@ class MIME::Type
|
|
|
554
711
|
-string
|
|
555
712
|
end
|
|
556
713
|
else
|
|
557
|
-
# MRI 2.2 and older
|
|
714
|
+
# MRI 2.2 and older do not have a method for string interning,
|
|
558
715
|
# so we simply freeze them for keeping a similar interface
|
|
559
716
|
def intern_string(string)
|
|
560
717
|
string.freeze
|
|
@@ -566,22 +723,24 @@ class MIME::Type
|
|
|
566
723
|
end
|
|
567
724
|
|
|
568
725
|
def xref_url_for_rfc(value)
|
|
569
|
-
|
|
726
|
+
"http://www.iana.org/go/%s" % value
|
|
570
727
|
end
|
|
571
728
|
|
|
572
729
|
def xref_url_for_draft(value)
|
|
573
|
-
|
|
730
|
+
"http://www.iana.org/go/%s" % value.sub(/\ARFC/, "draft")
|
|
574
731
|
end
|
|
575
732
|
|
|
576
733
|
def xref_url_for_rfc_errata(value)
|
|
577
|
-
|
|
734
|
+
"http://www.rfc-editor.org/errata_search.php?eid=%s" % value
|
|
578
735
|
end
|
|
579
736
|
|
|
580
737
|
def xref_url_for_person(value)
|
|
581
|
-
|
|
738
|
+
"http://www.iana.org/assignments/media-types/media-types.xhtml#%s" % value
|
|
582
739
|
end
|
|
583
740
|
|
|
584
741
|
def xref_url_for_template(value)
|
|
585
|
-
|
|
742
|
+
"http://www.iana.org/assignments/media-types/%s" % value
|
|
586
743
|
end
|
|
587
744
|
end
|
|
745
|
+
|
|
746
|
+
require "mime/types/version"
|