mime-types 3.6.2 → 3.7.0.pre2
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 +33 -1
- data/CONTRIBUTORS.md +1 -0
- data/Rakefile +10 -1
- data/lib/mime/type/columnar.rb +16 -1
- data/lib/mime/type.rb +114 -52
- data/lib/mime/types/_columnar.rb +59 -4
- data/lib/mime/types/version.rb +1 -1
- data/lib/mime/types.rb +20 -7
- data/test/test_mime_type.rb +32 -34
- data/test/test_mime_types.rb +10 -5
- data/test/test_mime_types_class.rb +10 -4
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e25ed719cc7aaa5bebf7b6a4c701a9269aee07a7826d57f51b0e304c3cef489e
|
4
|
+
data.tar.gz: c7c7df7e30a4a6e03b60a4c3d19009a18a8cc4a263a9bc0e9d7317c1fa22868c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f45853a6237e1773122595b9055112b053743daf726d209bbeabadda70dfb3248120db2a45807246739e87961efaebc35bedfd1e0418820f7c511fddc906633
|
7
|
+
data.tar.gz: 0da2dad77c9d62eb54bbbd5a830593d6e1e392c1c1f4b141aa242b9cff512f3918504baf29b2cbb4f18f90a9103cf024b1a85b834557a0430fb84ddce46e88ba
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,40 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 3.7.0.pre2 / YYYY-MM-DD
|
4
|
+
|
5
|
+
- Deprecated `MIME::Type#priority_compare`. In a future release, this will be
|
6
|
+
will be renamed to `MIME::Type#<=>`. This method is used in tight loops, so
|
7
|
+
there is no warning message for either `MIME::Type#priority_compare` or
|
8
|
+
`MIME::Type#<=>`.
|
9
|
+
|
10
|
+
- Improved the performance of sorting by eliminating the complex comparison flow
|
11
|
+
from `MIME::Type#priority_compare`. The old version shows under 600 i/s, and
|
12
|
+
the new version shows over 900 i/s. In sorting the full set of MIME data,
|
13
|
+
there are three differences between the old and new versions; after
|
14
|
+
comparison, these differences are considered acceptable.
|
15
|
+
|
16
|
+
- Simplified the default compare implementation (`MIME::Type#<=>`) to use the
|
17
|
+
new `MIME::Type#priority_compare` operation and simplify the fallback to
|
18
|
+
`String` comparison. This _may_ result in exceptions where there had been
|
19
|
+
none, as explicit support for several special values (which should have caused
|
20
|
+
errors in any case) have been removed.
|
21
|
+
|
22
|
+
- When sorting the result of `MIME::Types#type_for`, provided a priority boost
|
23
|
+
if one of the target extensions is the type's preferred extension. This means
|
24
|
+
that for the case in [#148][issue-148], when getting the type for `foo.webm`,
|
25
|
+
the type `video/webm` will be returned before the type `audio/webm`, because
|
26
|
+
`.webm` is the preferred extension for `video/webm` but not `audio/webm`
|
27
|
+
(which has a preferred extension of `.weba`). Added tests to ensure MIME types
|
28
|
+
are retrieved in a stable order (which is alphabetical).
|
29
|
+
|
3
30
|
## 3.6.2 / 2025-03-25
|
4
31
|
|
5
32
|
- Updated the reference to the changelog in the README, fixing RubyGems metadata
|
6
33
|
on the next release. Fixed in [#189][pull-189] by nna774.
|
7
34
|
|
35
|
+
- Daniel Watkins fixed an error in the repo tag for this release because the
|
36
|
+
modified gemspec was not included in the release. Fixed in [#196][pull-196].
|
37
|
+
|
8
38
|
## 3.6.1 / 2025-03-15
|
9
39
|
|
10
40
|
- Restructure project structure to be more consistent with mime-types-data.
|
@@ -148,7 +178,7 @@ there are some validation changes and updated code with formatting.
|
|
148
178
|
|
149
179
|
## 3.3 / 2019-09-04
|
150
180
|
|
151
|
-
- 1 minor enhancement
|
181
|
+
- 1 minor enhancement:
|
152
182
|
|
153
183
|
- Jean Boussier reduced memory usage for Ruby versions 2.3 or higher by
|
154
184
|
interning various string values in each type. This is done with a
|
@@ -347,6 +377,7 @@ there are some validation changes and updated code with formatting.
|
|
347
377
|
[issue-127]: https://github.com/mime-types/ruby-mime-types/issues/127
|
348
378
|
[issue-134]: https://github.com/mime-types/ruby-mime-types/issues/134
|
349
379
|
[issue-136]: https://github.com/mime-types/ruby-mime-types/issues/136
|
380
|
+
[issue-148]: https://github.com/mime-types/ruby-mime-types/issues/148
|
350
381
|
[issue-166]: https://github.com/mime-types/ruby-mime-types/issues/166
|
351
382
|
[issue-177]: https://github.com/mime-types/ruby-mime-types/issues/177
|
352
383
|
[mime-types-data]: https://github.com/mime-types/mime-types-data
|
@@ -373,6 +404,7 @@ there are some validation changes and updated code with formatting.
|
|
373
404
|
[pull-179]: https://github.com/mime-types/ruby-mime-types/pull/179
|
374
405
|
[pull-180]: https://github.com/mime-types/ruby-mime-types/pull/180
|
375
406
|
[pull-189]: https://github.com/mime-types/ruby-mime-types/pull/189
|
407
|
+
[pull-196]: https://github.com/mime-types/ruby-mime-types/pull/196
|
376
408
|
[pull-79]: https://github.com/mime-types/ruby-mime-types/pull/79
|
377
409
|
[pull-84]: https://github.com/mime-types/ruby-mime-types/pull/84
|
378
410
|
[pull-85]: https://github.com/mime-types/ruby-mime-types/pull/85
|
data/CONTRIBUTORS.md
CHANGED
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@ require "rubygems"
|
|
2
2
|
require "hoe"
|
3
3
|
require "rake/clean"
|
4
4
|
require "minitest"
|
5
|
+
require "minitest/test_task"
|
5
6
|
|
6
7
|
Hoe.plugin :halostatue
|
7
8
|
Hoe.plugin :rubygems
|
@@ -10,6 +11,7 @@ Hoe.plugins.delete :debug
|
|
10
11
|
Hoe.plugins.delete :newb
|
11
12
|
Hoe.plugins.delete :publish
|
12
13
|
Hoe.plugins.delete :signing
|
14
|
+
Hoe.plugins.delete :test
|
13
15
|
|
14
16
|
spec = Hoe.spec "mime-types" do
|
15
17
|
developer("Austin Ziegler", "halostatue@gmail.com")
|
@@ -24,7 +26,7 @@ spec = Hoe.spec "mime-types" do
|
|
24
26
|
val.merge!({"rubygems_mfa_required" => "true"})
|
25
27
|
}
|
26
28
|
|
27
|
-
extra_deps << ["mime-types-data", "~> 3.
|
29
|
+
extra_deps << ["mime-types-data", "~> 3.2025", ">= 3.2025.0506.pre2"]
|
28
30
|
extra_deps << ["logger", ">= 0"]
|
29
31
|
|
30
32
|
extra_dev_deps << ["hoe", "~> 4.0"]
|
@@ -65,6 +67,8 @@ Minitest::TestTask.create :coverage do |t|
|
|
65
67
|
RUBY
|
66
68
|
end
|
67
69
|
|
70
|
+
task default: :test
|
71
|
+
|
68
72
|
namespace :benchmark do
|
69
73
|
task :support do
|
70
74
|
%w[lib support].each { |path|
|
@@ -174,6 +178,11 @@ namespace :convert do
|
|
174
178
|
task docs: "convert:docs:run"
|
175
179
|
end
|
176
180
|
|
181
|
+
task :version do
|
182
|
+
require "mime/types/version"
|
183
|
+
puts MIME::Types::VERSION
|
184
|
+
end
|
185
|
+
|
177
186
|
namespace :deps do
|
178
187
|
task :top, [:number] => "benchmark:support" do |_, args|
|
179
188
|
require "deps"
|
data/lib/mime/type/columnar.rb
CHANGED
@@ -15,8 +15,10 @@ require "mime/type"
|
|
15
15
|
class MIME::Type::Columnar < MIME::Type
|
16
16
|
def initialize(container, content_type, extensions) # :nodoc:
|
17
17
|
@container = container
|
18
|
+
@__priority_penalty = nil
|
18
19
|
self.content_type = content_type
|
19
|
-
|
20
|
+
@extensions = Set[*Array(extensions).flatten.compact].freeze
|
21
|
+
clear_sort_priority
|
20
22
|
end
|
21
23
|
|
22
24
|
def self.column(*methods, file: nil) # :nodoc:
|
@@ -39,6 +41,7 @@ class MIME::Type::Columnar < MIME::Type
|
|
39
41
|
:signature?, :provisional, :provisional=, :provisional?, file: "flags"
|
40
42
|
column :xrefs, :xrefs=, :xref_urls
|
41
43
|
column :use_instead, :use_instead=
|
44
|
+
column :extension_priorities, :extension_priorities=
|
42
45
|
|
43
46
|
def encode_with(coder) # :nodoc:
|
44
47
|
@container.send(:load_friendly)
|
@@ -48,9 +51,21 @@ class MIME::Type::Columnar < MIME::Type
|
|
48
51
|
@container.send(:load_use_instead)
|
49
52
|
@container.send(:load_xrefs)
|
50
53
|
@container.send(:load_preferred_extension)
|
54
|
+
@container.send(:load_extension_priorities)
|
51
55
|
super
|
52
56
|
end
|
53
57
|
|
58
|
+
def update_sort_priority
|
59
|
+
if @container.__fully_loaded?
|
60
|
+
super
|
61
|
+
else
|
62
|
+
obsolete = (@__sort_priority & (1 << 7)) != 0
|
63
|
+
registered = (@__sort_priority & (1 << 5)) == 0
|
64
|
+
|
65
|
+
@__priority_penalty = (obsolete ? 3 : 0) + (registered ? 0 : 2)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
54
69
|
class << self
|
55
70
|
undef column
|
56
71
|
end
|
data/lib/mime/type.rb
CHANGED
@@ -133,7 +133,8 @@ class MIME::Type
|
|
133
133
|
def initialize(content_type) # :yields: self
|
134
134
|
@friendly = {}
|
135
135
|
@obsolete = @registered = @provisional = false
|
136
|
-
@preferred_extension = @docs = @use_instead = nil
|
136
|
+
@preferred_extension = @docs = @use_instead = @__sort_priority = nil
|
137
|
+
|
137
138
|
self.extensions = []
|
138
139
|
|
139
140
|
case content_type
|
@@ -164,6 +165,8 @@ class MIME::Type
|
|
164
165
|
self.xrefs ||= {}
|
165
166
|
|
166
167
|
yield self if block_given?
|
168
|
+
|
169
|
+
update_sort_priority
|
167
170
|
end
|
168
171
|
|
169
172
|
# Indicates that a MIME type is like another type. This differs from
|
@@ -182,60 +185,54 @@ class MIME::Type
|
|
182
185
|
# simplified type (the simplified type will be used if comparing against
|
183
186
|
# something that can be treated as a String with #to_s). In comparisons, this
|
184
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.
|
185
193
|
def <=>(other)
|
186
|
-
if other.
|
187
|
-
|
188
|
-
|
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
|
189
205
|
simplified <=> other.simplified
|
190
206
|
else
|
191
|
-
|
192
|
-
filtered ||= "true" if other == true
|
193
|
-
filtered ||= other.to_s
|
194
|
-
|
195
|
-
simplified <=> MIME::Type.simplified(filtered)
|
207
|
+
cmp
|
196
208
|
end
|
197
209
|
end
|
198
210
|
|
199
|
-
#
|
200
|
-
#
|
201
|
-
# comparisons involved are:
|
202
|
-
#
|
203
|
-
# 1. self.simplified <=> other.simplified (ensures that we
|
204
|
-
# do not try to compare different types)
|
205
|
-
# 2. IANA-registered definitions < other definitions.
|
206
|
-
# 3. Complete definitions < incomplete definitions.
|
207
|
-
# 4. Current definitions < obsolete definitions.
|
208
|
-
# 5. Obselete with use-instead names < obsolete without.
|
209
|
-
# 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.
|
210
213
|
#
|
211
|
-
#
|
212
|
-
#
|
213
|
-
#
|
214
|
-
#
|
215
|
-
def
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
if ui.nil?
|
227
|
-
1
|
228
|
-
elsif oui.nil?
|
229
|
-
-1
|
230
|
-
else
|
231
|
-
ui <=> oui
|
232
|
-
end
|
233
|
-
else
|
234
|
-
0
|
235
|
-
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
|
236
229
|
end
|
237
230
|
|
238
|
-
|
231
|
+
if (cmp = tsp <=> osp) == 0
|
232
|
+
simplified <=> other.simplified
|
233
|
+
else
|
234
|
+
cmp
|
235
|
+
end
|
239
236
|
end
|
240
237
|
|
241
238
|
# Returns +true+ if the +other+ object is a MIME::Type and the content types
|
@@ -270,6 +267,13 @@ class MIME::Type
|
|
270
267
|
simplified.hash
|
271
268
|
end
|
272
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
|
+
|
273
277
|
# Returns the whole MIME content-type string.
|
274
278
|
#
|
275
279
|
# The content type is a presentation value from the MIME type registry and
|
@@ -324,6 +328,7 @@ class MIME::Type
|
|
324
328
|
|
325
329
|
##
|
326
330
|
def extensions=(value) # :nodoc:
|
331
|
+
clear_sort_priority
|
327
332
|
@extensions = Set[*Array(value).flatten.compact].freeze
|
328
333
|
MIME::Types.send(:reindex_extensions, self)
|
329
334
|
end
|
@@ -350,9 +355,7 @@ class MIME::Type
|
|
350
355
|
|
351
356
|
##
|
352
357
|
def preferred_extension=(value) # :nodoc:
|
353
|
-
if value
|
354
|
-
add_extensions(value)
|
355
|
-
end
|
358
|
+
add_extensions(value) if value
|
356
359
|
@preferred_extension = value
|
357
360
|
end
|
358
361
|
|
@@ -405,9 +408,17 @@ class MIME::Type
|
|
405
408
|
attr_writer :use_instead
|
406
409
|
|
407
410
|
# Returns +true+ if the media type is obsolete.
|
408
|
-
|
411
|
+
#
|
412
|
+
# :attr_accessor: obsolete
|
413
|
+
attr_reader :obsolete
|
409
414
|
alias_method :obsolete?, :obsolete
|
410
415
|
|
416
|
+
##
|
417
|
+
def obsolete=(value)
|
418
|
+
clear_sort_priority
|
419
|
+
@obsolete = !!value
|
420
|
+
end
|
421
|
+
|
411
422
|
# The documentation for this MIME::Type.
|
412
423
|
attr_accessor :docs
|
413
424
|
|
@@ -465,11 +476,27 @@ class MIME::Type
|
|
465
476
|
end
|
466
477
|
|
467
478
|
# Indicates whether the MIME type has been registered with IANA.
|
468
|
-
|
479
|
+
#
|
480
|
+
# :attr_accessor: registered
|
481
|
+
attr_reader :registered
|
469
482
|
alias_method :registered?, :registered
|
470
483
|
|
484
|
+
##
|
485
|
+
def registered=(value)
|
486
|
+
clear_sort_priority
|
487
|
+
@registered = !!value
|
488
|
+
end
|
489
|
+
|
471
490
|
# Indicates whether the MIME type's registration with IANA is provisional.
|
472
|
-
|
491
|
+
#
|
492
|
+
# :attr_accessor: provisional
|
493
|
+
attr_reader :provisional
|
494
|
+
|
495
|
+
##
|
496
|
+
def provisional=(value)
|
497
|
+
clear_sort_priority
|
498
|
+
@provisional = !!value
|
499
|
+
end
|
473
500
|
|
474
501
|
# Indicates whether the MIME type's registration with IANA is provisional.
|
475
502
|
def provisional?
|
@@ -552,6 +579,7 @@ class MIME::Type
|
|
552
579
|
coder["registered"] = registered?
|
553
580
|
coder["provisional"] = provisional? if provisional?
|
554
581
|
coder["signature"] = signature? if signature?
|
582
|
+
coder["sort-priority"] = __sort_priority || 0b11111111
|
555
583
|
coder
|
556
584
|
end
|
557
585
|
|
@@ -560,6 +588,7 @@ class MIME::Type
|
|
560
588
|
#
|
561
589
|
# This method should be considered a private implementation detail.
|
562
590
|
def init_with(coder)
|
591
|
+
@__sort_priority = 0
|
563
592
|
self.content_type = coder["content-type"]
|
564
593
|
self.docs = coder["docs"] || ""
|
565
594
|
self.encoding = coder["encoding"]
|
@@ -573,6 +602,8 @@ class MIME::Type
|
|
573
602
|
self.use_instead = coder["use-instead"]
|
574
603
|
|
575
604
|
friendly(coder["friendly"] || {})
|
605
|
+
|
606
|
+
update_sort_priority
|
576
607
|
end
|
577
608
|
|
578
609
|
def inspect # :nodoc:
|
@@ -628,6 +659,37 @@ class MIME::Type
|
|
628
659
|
|
629
660
|
private
|
630
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
|
+
|
631
693
|
def content_type=(type_string)
|
632
694
|
match = MEDIA_TYPE_RE.match(type_string)
|
633
695
|
fail InvalidContentType, type_string if match.nil?
|
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,6 +67,25 @@ 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 ||= {}
|
@@ -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,47 @@ module MIME::Types::Columnar
|
|
107
133
|
end
|
108
134
|
end
|
109
135
|
|
110
|
-
def
|
136
|
+
def load_extension_priorities
|
137
|
+
each_file_line("extpri") do |type, line|
|
138
|
+
type.instance_variable_set(:@extension_priorities, dict(line, transform: :extension_priority))
|
139
|
+
end
|
140
|
+
rescue
|
141
|
+
# This path preserves backwards compatibility.
|
142
|
+
end
|
143
|
+
|
144
|
+
def dict(line, transform: nil)
|
111
145
|
if line == "-"
|
112
146
|
{}
|
113
147
|
else
|
114
148
|
line.split("|").each_with_object({}) { |l, h|
|
115
149
|
k, v = l.split("^")
|
116
150
|
v = nil if v.empty?
|
117
|
-
|
151
|
+
|
152
|
+
if transform
|
153
|
+
send(:"dict_#{transform}", h, k, v)
|
154
|
+
else
|
155
|
+
h[k] = v
|
156
|
+
end
|
118
157
|
}
|
119
158
|
end
|
120
159
|
end
|
121
160
|
|
161
|
+
def dict_extension_priority(h, k, v)
|
162
|
+
return if v.nil?
|
163
|
+
|
164
|
+
v = v.to_i if v.is_a?(String)
|
165
|
+
v = v.trunc if v.is_a?(Float)
|
166
|
+
v = [[-20, v].max, 20].min
|
167
|
+
|
168
|
+
return if v.zero?
|
169
|
+
|
170
|
+
h[k] = v
|
171
|
+
end
|
172
|
+
|
173
|
+
def dict_array(h, k, v)
|
174
|
+
h[k] = Array(v)
|
175
|
+
end
|
176
|
+
|
122
177
|
def arr(line)
|
123
178
|
if line == "-"
|
124
179
|
[]
|
data/lib/mime/types/version.rb
CHANGED
data/lib/mime/types.rb
CHANGED
@@ -130,9 +130,8 @@ class MIME::Types
|
|
130
130
|
@type_variants[MIME::Type.simplified(type_id)]
|
131
131
|
end
|
132
132
|
|
133
|
-
prune_matches(matches, complete, registered).sort { |a, b|
|
134
|
-
|
135
|
-
}
|
133
|
+
# prune_matches(matches, complete, registered).sort { |a, b| a.priority_compare(b) }
|
134
|
+
prune_matches(matches, complete, registered).sort
|
136
135
|
end
|
137
136
|
|
138
137
|
# Return the list of MIME::Types which belongs to the file based on its
|
@@ -148,10 +147,14 @@ class MIME::Types
|
|
148
147
|
# puts MIME::Types.type_for(%w(citydesk.xml citydesk.gif))
|
149
148
|
# => [application/xml, image/gif, text/xml]
|
150
149
|
def type_for(filename)
|
151
|
-
Array(filename).
|
152
|
-
|
153
|
-
|
154
|
-
|
150
|
+
wanted = Array(filename).map { |fn| fn.chomp.downcase[/\.?([^.]*?)\z/m, 1] }
|
151
|
+
|
152
|
+
wanted
|
153
|
+
.flat_map { |ext| @extension_index[ext] }
|
154
|
+
.compact
|
155
|
+
.reduce(Set.new, :+)
|
156
|
+
.sort { |a, b|
|
157
|
+
a.__extension_priority_compare(b, wanted)
|
155
158
|
}
|
156
159
|
end
|
157
160
|
alias_method :of, :type_for
|
@@ -193,6 +196,10 @@ class MIME::Types
|
|
193
196
|
index_extensions!(type)
|
194
197
|
end
|
195
198
|
|
199
|
+
def __fully_loaded? # :nodoc:
|
200
|
+
true
|
201
|
+
end
|
202
|
+
|
196
203
|
private
|
197
204
|
|
198
205
|
def add_type_variant!(mime_type)
|
@@ -220,6 +227,12 @@ class MIME::Types
|
|
220
227
|
k =~ pattern
|
221
228
|
}.values.inject(Set.new, :+)
|
222
229
|
end
|
230
|
+
|
231
|
+
# def stable_sort(list)
|
232
|
+
# list.lazy.each_with_index.sort { |(a, ai), (b, bi)|
|
233
|
+
# a.priority_compare(b).nonzero? || ai <=> bi
|
234
|
+
# }.map(&:first)
|
235
|
+
# end
|
223
236
|
end
|
224
237
|
|
225
238
|
require "mime/types/cache"
|
data/test/test_mime_type.rb
CHANGED
@@ -175,11 +175,6 @@ describe MIME::Type do
|
|
175
175
|
refute_equal text_plain, "text/html"
|
176
176
|
assert_operator text_plain, :>, "text/html"
|
177
177
|
end
|
178
|
-
|
179
|
-
it "correctly compares against nil" do
|
180
|
-
refute_equal text_html, nil
|
181
|
-
assert_operator text_plain, :<, nil
|
182
|
-
end
|
183
178
|
end
|
184
179
|
|
185
180
|
describe "#ascii?" do
|
@@ -326,41 +321,56 @@ describe MIME::Type do
|
|
326
321
|
end
|
327
322
|
|
328
323
|
describe "#priority_compare" do
|
324
|
+
def priority(type)
|
325
|
+
priority = "OpRceXtN"
|
326
|
+
.chars
|
327
|
+
.zip(("%08b" % type.__sort_priority).chars)
|
328
|
+
.map { |e| e.join(":") }
|
329
|
+
.join(" ")
|
330
|
+
|
331
|
+
"#{type} (#{priority} / #{type.__sort_priority})"
|
332
|
+
end
|
333
|
+
|
329
334
|
def assert_priority_less(left, right)
|
330
|
-
assert_equal(-1, left.priority_compare(right))
|
335
|
+
assert_equal(-1, left.priority_compare(right), "#{priority(left)} is not less than #{priority(right)}")
|
331
336
|
end
|
332
337
|
|
333
338
|
def assert_priority_same(left, right)
|
334
|
-
assert_equal 0, left.priority_compare(right)
|
339
|
+
assert_equal 0, left.priority_compare(right), "#{priority(left)} is not equal to #{priority(right)}"
|
335
340
|
end
|
336
341
|
|
337
342
|
def assert_priority_more(left, right)
|
338
|
-
assert_equal 1, left.priority_compare(right)
|
343
|
+
assert_equal 1, left.priority_compare(right), "#{priority(left)} is not more than #{priority(right)}"
|
339
344
|
end
|
340
345
|
|
341
346
|
def assert_priority(left, middle, right)
|
342
347
|
assert_priority_less left, right
|
343
348
|
assert_priority_same left, middle
|
344
|
-
assert_priority_more right,
|
349
|
+
assert_priority_more right, middle
|
345
350
|
end
|
346
351
|
|
347
352
|
let(:text_1) { mime_type("content-type" => "text/1") }
|
348
353
|
let(:text_1p) { mime_type("content-type" => "text/1") }
|
349
354
|
let(:text_2) { mime_type("content-type" => "text/2") }
|
350
355
|
|
351
|
-
it "sorts
|
356
|
+
it "sorts based on the simplified type when the sort priorities are the same" do
|
352
357
|
assert_priority text_1, text_1p, text_2
|
353
358
|
end
|
354
359
|
|
355
|
-
it "sorts
|
356
|
-
text_1.
|
357
|
-
|
360
|
+
it "sorts obsolete types higher than non-obsolete types" do
|
361
|
+
text_1.obsolete = text_1p.obsolete = false
|
362
|
+
text_1b = mime_type(text_1) { |t| t.obsolete = true }
|
363
|
+
|
364
|
+
assert_priority_less text_1, text_1b
|
358
365
|
|
359
|
-
|
366
|
+
assert_priority text_1, text_1p, text_1b
|
367
|
+
end
|
360
368
|
|
361
|
-
|
369
|
+
it "sorts provisional types higher than non-provisional types" do
|
370
|
+
text_1.provisional = text_1p.provisional = false
|
371
|
+
text_1b = mime_type(text_1) { |t| t.provisional = true }
|
362
372
|
|
363
|
-
|
373
|
+
assert_priority text_1, text_1p, text_1b
|
364
374
|
end
|
365
375
|
|
366
376
|
it "sorts (3) based on the registration state" do
|
@@ -377,23 +387,11 @@ describe MIME::Type do
|
|
377
387
|
assert_priority text_1, text_1p, text_1b
|
378
388
|
end
|
379
389
|
|
380
|
-
it "sorts
|
381
|
-
text_1.
|
382
|
-
|
383
|
-
|
384
|
-
assert_priority text_1, text_1p, text_1b
|
385
|
-
end
|
386
|
-
|
387
|
-
it "sorts (5) based on the use-instead value" do
|
388
|
-
text_1.obsolete = text_1p.obsolete = true
|
389
|
-
text_1.use_instead = text_1p.use_instead = "abc/xyz"
|
390
|
-
text_1b = mime_type(text_1) { |t| t.use_instead = nil }
|
391
|
-
|
392
|
-
assert_priority text_1, text_1p, text_1b
|
393
|
-
|
394
|
-
text_1b.use_instead = "abc/zzz"
|
390
|
+
it "sorts based on extensions (more extensions sort lower)" do
|
391
|
+
text_1.extensions = ["foo", "bar"]
|
392
|
+
text_2.extensions = ["foo"]
|
395
393
|
|
396
|
-
|
394
|
+
assert_priority_less text_1, text_2
|
397
395
|
end
|
398
396
|
end
|
399
397
|
|
@@ -502,10 +500,10 @@ describe MIME::Type do
|
|
502
500
|
|
503
501
|
describe "#to_json" do
|
504
502
|
let(:expected_1) {
|
505
|
-
'{"content-type":"a/b","encoding":"base64","registered":false}'
|
503
|
+
'{"content-type":"a/b","encoding":"base64","registered":false,"sort-priority":48}'
|
506
504
|
}
|
507
505
|
let(:expected_2) {
|
508
|
-
'{"content-type":"a/b","encoding":"base64","registered":true,"provisional":true}'
|
506
|
+
'{"content-type":"a/b","encoding":"base64","registered":true,"provisional":true,"sort-priority":80}'
|
509
507
|
}
|
510
508
|
|
511
509
|
it "converts to JSON when requested" do
|
data/test/test_mime_types.rb
CHANGED
@@ -12,7 +12,8 @@ describe MIME::Types do
|
|
12
12
|
MIME::Type.new("content-type" => "application/x-wordperfect6.1"),
|
13
13
|
MIME::Type.new("content-type" => "application/x-www-form-urlencoded", "registered" => true),
|
14
14
|
MIME::Type.new("content-type" => "application/x-gzip", "extensions" => %w[gz]),
|
15
|
-
MIME::Type.new("content-type" => "application/gzip", "extensions" => "gz", "registered" => true)
|
15
|
+
MIME::Type.new("content-type" => "application/gzip", "extensions" => "gz", "registered" => true),
|
16
|
+
*MIME::Types.type_for("foo.webm")
|
16
17
|
)
|
17
18
|
}
|
18
19
|
end
|
@@ -33,8 +34,8 @@ describe MIME::Types do
|
|
33
34
|
end
|
34
35
|
|
35
36
|
it "is countable with an enumerator" do
|
36
|
-
assert_equal
|
37
|
-
assert_equal
|
37
|
+
assert_equal 8, mime_types.each.count
|
38
|
+
assert_equal 8, mime_types.lazy.count
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -139,7 +140,7 @@ describe MIME::Types do
|
|
139
140
|
end
|
140
141
|
|
141
142
|
it "finds multiple extensions" do
|
142
|
-
assert_equal %w[image/jpeg
|
143
|
+
assert_equal %w[text/plain image/jpeg],
|
143
144
|
mime_types.type_for(%w[foo.txt foo.jpeg])
|
144
145
|
end
|
145
146
|
|
@@ -158,11 +159,15 @@ describe MIME::Types do
|
|
158
159
|
it "handles newline characters correctly" do
|
159
160
|
assert_includes mime_types.type_for("test.pdf\n.txt"), "text/plain"
|
160
161
|
end
|
162
|
+
|
163
|
+
it "returns a stable order for types with equal priority" do
|
164
|
+
assert_equal %w[text/x-vcalendar text/x-vcard], MIME::Types[/text\/x-vca/]
|
165
|
+
end
|
161
166
|
end
|
162
167
|
|
163
168
|
describe "#count" do
|
164
169
|
it "can count the number of types inside" do
|
165
|
-
assert_equal
|
170
|
+
assert_equal 8, mime_types.count
|
166
171
|
end
|
167
172
|
end
|
168
173
|
end
|
@@ -47,7 +47,7 @@ describe MIME::Types, "registry" do
|
|
47
47
|
}
|
48
48
|
# This is this way because of a new type ending with gzip that only
|
49
49
|
# appears in some data files.
|
50
|
-
assert_equal %w[application/gzip
|
50
|
+
assert_equal %w[application/gzip multipart/x-gzip application/x-gzip], types
|
51
51
|
assert_equal 3, types.size
|
52
52
|
end
|
53
53
|
|
@@ -86,9 +86,11 @@ describe MIME::Types, "registry" do
|
|
86
86
|
assert_equal %w[image/jpeg], MIME::Types.of(["foo.jpeg", "bar.jpeg"])
|
87
87
|
end
|
88
88
|
|
89
|
-
it "finds multiple extensions" do
|
90
|
-
|
91
|
-
|
89
|
+
it "finds multiple extensions ordered by the filename list" do
|
90
|
+
result = MIME::Types.type_for(%w[foo.txt foo.jpeg])
|
91
|
+
|
92
|
+
# assert_equal %w[text/plain image/jpeg], MIME::Types.type_for(%w[foo.txt foo.jpeg])
|
93
|
+
assert_equal %w[text/plain image/jpeg], result
|
92
94
|
end
|
93
95
|
|
94
96
|
it "does not find unknown extensions" do
|
@@ -105,6 +107,10 @@ describe MIME::Types, "registry" do
|
|
105
107
|
assert_includes MIME::Types.type_for("test.pdf\n.txt"), "text/plain"
|
106
108
|
assert_includes MIME::Types.type_for("test.txt\n.pdf"), "application/pdf"
|
107
109
|
end
|
110
|
+
|
111
|
+
it "returns a stable order for types with equal priority" do
|
112
|
+
assert_equal %w[text/x-vcalendar text/x-vcard], MIME::Types[/text\/x-vca/]
|
113
|
+
end
|
108
114
|
end
|
109
115
|
|
110
116
|
describe ".count" do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mime-types
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.7.0.pre2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Austin Ziegler
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-04-07 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: mime-types-data
|
@@ -15,14 +15,20 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '3.
|
18
|
+
version: '3.2025'
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2025.0506.pre2
|
19
22
|
type: :runtime
|
20
23
|
prerelease: false
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
22
25
|
requirements:
|
23
26
|
- - "~>"
|
24
27
|
- !ruby/object:Gem::Version
|
25
|
-
version: '3.
|
28
|
+
version: '3.2025'
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 3.2025.0506.pre2
|
26
32
|
- !ruby/object:Gem::Dependency
|
27
33
|
name: logger
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
@@ -269,7 +275,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
269
275
|
- !ruby/object:Gem::Version
|
270
276
|
version: '0'
|
271
277
|
requirements: []
|
272
|
-
rubygems_version: 3.6.
|
278
|
+
rubygems_version: 3.6.6
|
273
279
|
specification_version: 4
|
274
280
|
summary: The mime-types library provides a library and registry for information about
|
275
281
|
MIME content type definitions
|