mime-types 3.6.2 → 3.7.0.pre1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d48539865c96a17991bbceab6d3ff2b2d6db5e281448d9bd76dd5fc12a48cd2
4
- data.tar.gz: 79bcc6970d5f1774fc6a45162ba28222e72eeb37110e4d61eef96a50faeea4ff
3
+ metadata.gz: fbc8ea5f8e0271da1f1b5ad79011d66be1ab6eaf2e51ccefb7a6b1744ab7a60c
4
+ data.tar.gz: c8bef17d139d55505852440b1f8103d0ed218093e7e6f0b999c58cfaa6a7f302
5
5
  SHA512:
6
- metadata.gz: 72aaaf23f926bd1ec8b4d978b8878d0c4b2a8b9083600ebbd051328c3f6cc3b15bbdb73be20cd87b9b3e49c83f29a63b8c54fad6026e4dc9dbaac052554f84f3
7
- data.tar.gz: 503bef89f86cf2cfbbbc5d76f642289ad011ca0c98ebef86e855be599efc3b90e59e3d4b984d4a17f59298ccf2b30c267ced17ee0b11ba905c9e732af51dd6f2
6
+ metadata.gz: 8a30479ab4fd1589bcdf9dd21b145786038799fb4f3e0b8bc0ba4ad14fd23c38e88265323752faca4750de2d5e23f30ecbbb4e9bc33fca2dd93ddf45032a5f40
7
+ data.tar.gz: 3b5dd2e2a4628096ab7b44a3a5cb43d1c2c0c5404fa8e16909f8e20481ad0521bbe957fc5e0410b807c6e834d5e086dd5bbe40ffbb13a289c41efc9e3f5585be
data/CHANGELOG.md CHANGED
@@ -1,10 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.7.0.pre1 / 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
+
3
22
  ## 3.6.2 / 2025-03-25
4
23
 
5
24
  - Updated the reference to the changelog in the README, fixing RubyGems metadata
6
25
  on the next release. Fixed in [#189][pull-189] by nna774.
7
26
 
27
+ - Daniel Watkins fixed an error in the repo tag for this release because the
28
+ modified gemspec was not included in the release. Fixed in [#196][pull-196].
29
+
8
30
  ## 3.6.1 / 2025-03-15
9
31
 
10
32
  - Restructure project structure to be more consistent with mime-types-data.
@@ -148,7 +170,7 @@ there are some validation changes and updated code with formatting.
148
170
 
149
171
  ## 3.3 / 2019-09-04
150
172
 
151
- - 1 minor enhancement
173
+ - 1 minor enhancement:
152
174
 
153
175
  - Jean Boussier reduced memory usage for Ruby versions 2.3 or higher by
154
176
  interning various string values in each type. This is done with a
@@ -373,6 +395,7 @@ there are some validation changes and updated code with formatting.
373
395
  [pull-179]: https://github.com/mime-types/ruby-mime-types/pull/179
374
396
  [pull-180]: https://github.com/mime-types/ruby-mime-types/pull/180
375
397
  [pull-189]: https://github.com/mime-types/ruby-mime-types/pull/189
398
+ [pull-196]: https://github.com/mime-types/ruby-mime-types/pull/196
376
399
  [pull-79]: https://github.com/mime-types/ruby-mime-types/pull/79
377
400
  [pull-84]: https://github.com/mime-types/ruby-mime-types/pull/84
378
401
  [pull-85]: https://github.com/mime-types/ruby-mime-types/pull/85
data/CONTRIBUTORS.md CHANGED
@@ -14,6 +14,7 @@ Thanks to everyone else who has contributed to mime-types over the years:
14
14
  - Brandon Galbraith
15
15
  - Burke Libbey
16
16
  - Chris Gat
17
+ - Daniel Watkins
17
18
  - David Genord
18
19
  - Dillon Welch
19
20
  - Edward Betts
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.2015"]
29
+ extra_deps << ["mime-types-data", "~> 3.2025", ">= 3.2025.0506.pre1"]
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"
@@ -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
- self.extensions = extensions
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,9 @@ 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
+ __extension_priorities
138
+
137
139
  self.extensions = []
138
140
 
139
141
  case content_type
@@ -164,6 +166,8 @@ class MIME::Type
164
166
  self.xrefs ||= {}
165
167
 
166
168
  yield self if block_given?
169
+
170
+ update_sort_priority
167
171
  end
168
172
 
169
173
  # Indicates that a MIME type is like another type. This differs from
@@ -182,60 +186,28 @@ class MIME::Type
182
186
  # simplified type (the simplified type will be used if comparing against
183
187
  # something that can be treated as a String with #to_s). In comparisons, this
184
188
  # is done against the lowercase version of the MIME::Type.
189
+ #
190
+ # Note that this implementation of #<=> is deprecated and will be changed
191
+ # in the next major version to be the same as #priority_compare.
192
+ #
193
+ # Note that MIME::Types no longer compare against nil.
185
194
  def <=>(other)
186
- if other.nil?
187
- -1
188
- elsif other.respond_to?(:simplified)
189
- simplified <=> other.simplified
190
- else
191
- filtered = "silent" if other == :silent
192
- filtered ||= "true" if other == true
193
- filtered ||= other.to_s
194
-
195
- simplified <=> MIME::Type.simplified(filtered)
196
- end
195
+ return priority_compare(other) if other.is_a?(MIME::Type)
196
+ simplified <=> other
197
197
  end
198
198
 
199
- # Compares the +other+ MIME::Type based on how reliable it is before doing a
200
- # normal <=> comparison. Used by MIME::Types#[] to sort types. The
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.
199
+ # Compares the +other+ MIME::Type using the simplified representation, then
200
+ # a pre-computed sort priority value. Used by MIME::Types#[] to sort types.
210
201
  #
211
- # While this method is public, its use is strongly discouraged by consumers
212
- # of mime-types. In mime-types 3, this method is likely to see substantial
213
- # revision and simplification to ensure current registered content types sort
214
- # before unregistered or obsolete content types.
202
+ # While this method is public, its direct use is strongly discouraged by
203
+ # consumers of mime-types. For the next major version of MIME::Types, this
204
+ # method will become #<=> and #priority_compare will be removed.
215
205
  def priority_compare(other)
216
- pc = simplified <=> other.simplified
217
- if pc.zero? || !(extensions & other.extensions).empty?
218
- pc =
219
- if (reg = registered?) != other.registered?
220
- reg ? -1 : 1 # registered < unregistered
221
- elsif (comp = complete?) != other.complete?
222
- comp ? -1 : 1 # complete < incomplete
223
- elsif (obs = obsolete?) != other.obsolete?
224
- obs ? 1 : -1 # current < obsolete
225
- elsif obs && ((ui = use_instead) != (oui = other.use_instead))
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
206
+ if (cmp = __sort_priority <=> other.__sort_priority) == 0
207
+ simplified <=> other.simplified
208
+ else
209
+ cmp
236
210
  end
237
-
238
- pc
239
211
  end
240
212
 
241
213
  # Returns +true+ if the +other+ object is a MIME::Type and the content types
@@ -270,6 +242,13 @@ class MIME::Type
270
242
  simplified.hash
271
243
  end
272
244
 
245
+ # The computed sort priority value. This is _not_ intended to be used by most
246
+ # callers.
247
+ def __sort_priority # :nodoc:
248
+ update_sort_priority if !instance_variable_defined?(:@__sort_priority) || @__sort_priority.nil?
249
+ @__sort_priority
250
+ end
251
+
273
252
  # Returns the whole MIME content-type string.
274
253
  #
275
254
  # The content type is a presentation value from the MIME type registry and
@@ -324,6 +303,7 @@ class MIME::Type
324
303
 
325
304
  ##
326
305
  def extensions=(value) # :nodoc:
306
+ clear_sort_priority
327
307
  @extensions = Set[*Array(value).flatten.compact].freeze
328
308
  MIME::Types.send(:reindex_extensions, self)
329
309
  end
@@ -352,10 +332,36 @@ class MIME::Type
352
332
  def preferred_extension=(value) # :nodoc:
353
333
  if value
354
334
  add_extensions(value)
335
+ set_preferred_extension_priority(value)
336
+ elsif instance_variable_defined?(:@preferred_extension)
337
+ clear_extension_priority(@preferred_extension)
355
338
  end
356
339
  @preferred_extension = value
357
340
  end
358
341
 
342
+ ##
343
+ # Optional extension priorities for this MIME type. This is a map of
344
+ # extensions to relative priority values (+-20..20+) similar to +nice(1)+.
345
+ # Unless otherwise specified in the data, an explicitly set
346
+ # +preferred_extension+ is automatically given a relative priority of +-10+.
347
+ #
348
+ # :attr_reader: extension_priorities
349
+ attr_accessor :extension_priorities
350
+
351
+ ##
352
+ # Returns the priority for the provided extension or extensions. If a priority
353
+ # is not set, the default priority is +0+. The range for priorities is
354
+ # +-20..20+, inclusive.
355
+ #
356
+ # Obsolete MIME types have a <code>+3</code> penalty applied to their
357
+ # extension priority and unregistered MIME types have a <code>+2</code>
358
+ # penalty to their extension priority, meaning that the highest priority an
359
+ # obsolete, unregistered MIME type can have is +-15+. The lowest priority is
360
+ # always <code>+20</code>.
361
+ def extension_priority(*exts)
362
+ exts.map { |ext| get_extension_priority(ext) }.min
363
+ end
364
+
359
365
  ##
360
366
  # The encoding (+7bit+, +8bit+, <tt>quoted-printable</tt>, or +base64+)
361
367
  # required to transport the data of this content type safely across a
@@ -405,9 +411,17 @@ class MIME::Type
405
411
  attr_writer :use_instead
406
412
 
407
413
  # Returns +true+ if the media type is obsolete.
408
- attr_accessor :obsolete
414
+ #
415
+ # :attr_accessor: obsolete
416
+ attr_reader :obsolete
409
417
  alias_method :obsolete?, :obsolete
410
418
 
419
+ ##
420
+ def obsolete=(value)
421
+ clear_sort_priority
422
+ @obsolete = !!value
423
+ end
424
+
411
425
  # The documentation for this MIME::Type.
412
426
  attr_accessor :docs
413
427
 
@@ -465,11 +479,27 @@ class MIME::Type
465
479
  end
466
480
 
467
481
  # Indicates whether the MIME type has been registered with IANA.
468
- attr_accessor :registered
482
+ #
483
+ # :attr_accessor: registered
484
+ attr_reader :registered
469
485
  alias_method :registered?, :registered
470
486
 
487
+ ##
488
+ def registered=(value)
489
+ clear_sort_priority
490
+ @registered = !!value
491
+ end
492
+
471
493
  # Indicates whether the MIME type's registration with IANA is provisional.
472
- attr_accessor :provisional
494
+ #
495
+ # :attr_accessor: provisional
496
+ attr_reader :provisional
497
+
498
+ ##
499
+ def provisional=(value)
500
+ clear_sort_priority
501
+ @provisional = !!value
502
+ end
473
503
 
474
504
  # Indicates whether the MIME type's registration with IANA is provisional.
475
505
  def provisional?
@@ -552,6 +582,8 @@ class MIME::Type
552
582
  coder["registered"] = registered?
553
583
  coder["provisional"] = provisional? if provisional?
554
584
  coder["signature"] = signature? if signature?
585
+ coder["sort-priority"] = __sort_priority || 0b11111111
586
+ coder["extension-priorities"] = __extension_priorities unless __extension_priorities.empty?
555
587
  coder
556
588
  end
557
589
 
@@ -560,6 +592,7 @@ class MIME::Type
560
592
  #
561
593
  # This method should be considered a private implementation detail.
562
594
  def init_with(coder)
595
+ @__sort_priority = 0
563
596
  self.content_type = coder["content-type"]
564
597
  self.docs = coder["docs"] || ""
565
598
  self.encoding = coder["encoding"]
@@ -571,8 +604,11 @@ class MIME::Type
571
604
  self.signature = coder["signature"]
572
605
  self.xrefs = coder["xrefs"] || {}
573
606
  self.use_instead = coder["use-instead"]
607
+ self.extension_priorities = coder["extension-priorities"]
574
608
 
575
609
  friendly(coder["friendly"] || {})
610
+
611
+ update_sort_priority
576
612
  end
577
613
 
578
614
  def inspect # :nodoc:
@@ -626,8 +662,62 @@ class MIME::Type
626
662
  end
627
663
  end
628
664
 
665
+ def __extension_priorities # :nodoc:
666
+ @extension_priorities ||= {}
667
+ end
668
+
629
669
  private
630
670
 
671
+ def clear_extension_priority(ext)
672
+ __extension_priorities.delete(ext) if ext
673
+ end
674
+
675
+ def get_extension_priority(ext)
676
+ [[-20, (__extension_priorities[ext] || 0) + __priority_penalty].max, 20].min
677
+ end
678
+
679
+ def set_preferred_extension_priority(ext)
680
+ __extension_priorities[ext] = -10 unless __extension_priorities.has_key?(ext)
681
+ end
682
+
683
+ def clear_sort_priority
684
+ @__sort_priority = nil
685
+ end
686
+
687
+ # Update the __sort_priority value. Lower numbers sort better, so the
688
+ # bitmapping may seem a little odd. The _best_ sort priority is 0.
689
+ #
690
+ # | bit | meaning | details |
691
+ # | --- | --------------- | --------- |
692
+ # | 7 | obsolete | 1 if true |
693
+ # | 6 | provisional | 1 if true |
694
+ # | 5 | registered | 0 if true |
695
+ # | 4 | complete | 0 if true |
696
+ # | 3 | # of extensions | see below |
697
+ # | 2 | # of extensions | see below |
698
+ # | 1 | # of extensions | see below |
699
+ # | 0 | # of extensions | see below |
700
+ #
701
+ # The # of extensions is marked as the number of extensions subtracted from
702
+ # 16, to a minimum of 0.
703
+ def update_sort_priority
704
+ extension_count = @extensions.length
705
+ obsolete = (instance_variable_defined?(:@obsolete) && @obsolete) ? 1 << 7 : 0
706
+ provisional = (instance_variable_defined?(:@provisional) && @provisional) ? 1 << 6 : 0
707
+ registered = (instance_variable_defined?(:@registered) && @registered) ? 0 : 1 << 5
708
+ complete = extension_count.nonzero? ? 0 : 1 << 4
709
+ extension_count = [0, 16 - extension_count].max
710
+
711
+ @__sort_priority = obsolete | registered | provisional | complete | extension_count
712
+ @__priority_penalty = ((instance_variable_defined?(:@obsolete) && @obsolete) ? 3 : 0) +
713
+ ((instance_variable_defined?(:@registered) && @registered) ? 0 : 2)
714
+ end
715
+
716
+ def __priority_penalty
717
+ update_sort_priority if @__priority_penalty.nil?
718
+ @__priority_penalty
719
+ end
720
+
631
721
  def content_type=(type_string)
632
722
  match = MEDIA_TYPE_RE.match(type_string)
633
723
  fail InvalidContentType, type_string if match.nil?
@@ -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, array: true))
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 dict(line, array: false)
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
- h[k] = array ? Array(v) : v
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
  []
@@ -4,7 +4,7 @@
4
4
  module MIME
5
5
  class Types
6
6
  # The released version of the mime-types library.
7
- VERSION = "3.6.2"
7
+ VERSION = "3.7.0.pre1"
8
8
  end
9
9
 
10
10
  class Type
data/lib/mime/types.rb CHANGED
@@ -151,7 +151,13 @@ class MIME::Types
151
151
  Array(filename).flat_map { |fn|
152
152
  @extension_index[fn.chomp.downcase[/\.?([^.]*?)\z/m, 1]]
153
153
  }.compact.inject(Set.new, :+).sort { |a, b|
154
- a.priority_compare(b)
154
+ by_ext = a.extension_priority(*a.extensions) <=> b.extension_priority(*b.extensions)
155
+
156
+ if by_ext.zero?
157
+ a.priority_compare(b)
158
+ else
159
+ by_ext
160
+ end
155
161
  }
156
162
  end
157
163
  alias_method :of, :type_for
@@ -193,6 +199,10 @@ class MIME::Types
193
199
  index_extensions!(type)
194
200
  end
195
201
 
202
+ def __fully_loaded? # :nodoc:
203
+ true
204
+ end
205
+
196
206
  private
197
207
 
198
208
  def add_type_variant!(mime_type)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ $debug = false
4
+
3
5
  gem "minitest"
4
6
  require "minitest/focus"
5
7
  require "minitest/hooks"
@@ -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, left
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 (1) based on the simplified type" do
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 (2) based on extensions" do
356
- text_1.extensions = ["foo", "bar"]
357
- text_2.extensions = ["foo"]
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
- assert_priority_same text_1, text_2
366
+ assert_priority text_1, text_1p, text_1b
367
+ end
360
368
 
361
- text_2.registered = true
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
- assert_priority_more text_1, text_2
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 (5) based on obsolete status" do
381
- text_1.obsolete = text_1p.obsolete = false
382
- text_1b = mime_type(text_1) { |t| t.obsolete = true }
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
- assert_priority text_1, text_1p, text_1b
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
@@ -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 application/x-gzip multipart/x-gzip], types
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,8 @@ 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
- assert_equal %w[image/jpeg text/plain],
91
- MIME::Types.type_for(%w[foo.txt foo.jpeg])
89
+ it "finds multiple extensions ordered by the filename list" do
90
+ assert_equal %w[text/plain image/jpeg], MIME::Types.type_for(%w[foo.txt foo.jpeg])
92
91
  end
93
92
 
94
93
  it "does not find unknown extensions" 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.6.2
4
+ version: 3.7.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Austin Ziegler
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-25 00:00:00.000000000 Z
10
+ date: 2025-04-04 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.2015'
18
+ version: '3.2025'
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2025.0506.pre1
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.2015'
28
+ version: '3.2025'
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 3.2025.0506.pre1
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.2
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