Skip to content

Commit 2b8ae86

Browse files
committed
Ensure priority sort over alpha sort
- Added extension priority map. This is an imperfect solution, and is not used by default with default configuration (column-based data). - We may want to consider a revised columnar format for a future version that has a bit more information than is present in the base file. - Adding the sort priority and extension priority helped, but because the alphanumeric sort was first in `MIME::Type#priority_compare`, the results weren't as good as they should have been. We now sort by the sort priority values _first_ and the alphanumeric values _second_. - Stored sort priority was not respected because it depends on flags not kept in the base file. Added support for a binary file with this to ensure it is loaded.
1 parent 8748d86 commit 2b8ae86

File tree

4 files changed

+64
-9
lines changed

4 files changed

+64
-9
lines changed

lib/mime/type.rb

+22-9
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ def <=>(other)
188188
# consumers of mime-types. For the next major version of MIME::Types, this
189189
# method will become #<=> and #priority_compare will be removed.
190190
def priority_compare(other)
191-
if (cmp = simplified <=> other.simplified).zero?
192-
__sort_priority <=> other.__sort_priority
191+
if (cmp = __sort_priority <=> other.__sort_priority).zero?
192+
simplified <=> other.simplified
193193
else
194194
cmp
195195
end
@@ -229,7 +229,7 @@ def hash
229229

230230
# The computed sort priority value. This is _not_ intended to be used by most
231231
# callers.
232-
def __sort_priority
232+
def __sort_priority # :nodoc:
233233
@__sort_priority || update_sort_priority
234234
end
235235

@@ -324,17 +324,24 @@ def preferred_extension=(value) # :nodoc:
324324
end
325325

326326
##
327-
# Optional extension priorities for this MIME type. This is a relative value
328-
# similar to nice(1). An explicitly set `preferred_extension` is automatically
329-
# given a relative priority of `-10`.
327+
# Optional extension priorities for this MIME type. This is a map of
328+
# extensions to relative priority values (+-20..20+) similar to +nice(1)+.
329+
# Unless otherwise specified in the data, an explicitly set
330+
# +preferred_extension+ is automatically given a relative priority of +-10+.
330331
#
331332
# :attr_reader: extension_priorities
332333
attr_accessor :extension_priorities
333334

334335
##
335336
# Returns the priority for the provided extension or extensions. If a priority
336-
# is not set, the default priority is 0. The range for priorities is -20..20,
337-
# inclusive.
337+
# is not set, the default priority is +0+. The range for priorities is
338+
# +-20..20+, inclusive.
339+
#
340+
# Obsolete MIME types have a <code>+3</code> penalty applied to their
341+
# extension priority and unregistered MIME types have a <code>+2</code>
342+
# penalty to their extension priority, meaning that the highest priority an
343+
# obsolete, unregistered MIME type can have is +-15+. The lowest priority is
344+
# always <code>+20</code>.
338345
def extension_priority(*exts)
339346
exts.map { |ext| get_extension_priority(ext) }.min
340347
end
@@ -650,7 +657,7 @@ def clear_extension_priority(ext)
650657
end
651658

652659
def get_extension_priority(ext)
653-
[[-20, __extension_priorities[ext] || 0].max, 20].min
660+
[[-20, (__extension_priorities[ext] || 0) + __priority_penalty].max, 20].min
654661
end
655662

656663
def set_preferred_extension_priority(ext)
@@ -686,6 +693,12 @@ def update_sort_priority
686693
extension_count = [0, 16 - extension_count].max
687694

688695
@__sort_priority = obsolete | registered | provisional | complete | extension_count
696+
@__priority_penalty = (@obsolete ? 3 : 0) + (@registered ? 0 : 2)
697+
end
698+
699+
def __priority_penalty
700+
update_sort_priority if @__priority_penalty.nil?
701+
@__priority_penalty
689702
end
690703

691704
def content_type=(type_string)

lib/mime/type/columnar.rb

+11
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ def encode_with(coder) # :nodoc:
5353
super
5454
end
5555

56+
def update_sort_priority
57+
if @container.__fully_loaded?
58+
super
59+
else
60+
obsolete = (@__sort_priority & (1 << 7)) != 0
61+
registered = (@__sort_priority & (1 << 5)) == 0
62+
63+
@__priority_penalty = (@obsolete ? 3 : 0) + (@registered ? 0 : 2)
64+
end
65+
end
66+
5667
class << self
5768
undef column
5869
end

lib/mime/types.rb

+4
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ def add_type(type, quiet = false)
204204
index_extensions!(type)
205205
end
206206

207+
def __fully_loaded? # :nodoc:
208+
true
209+
end
210+
207211
private
208212

209213
def add_type_variant!(mime_type)

lib/mime/types/_columnar.rb

+27
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ def self.extended(obj) # :nodoc:
1818
obj.instance_variable_set(:@__files__, Set.new)
1919
end
2020

21+
def __fully_loaded? # :nodoc:
22+
@__files__.size == 10
23+
end
24+
2125
# Load the first column data file (type and extensions).
2226
def load_base_data(path) # :nodoc:
2327
@__root__ = path
@@ -33,6 +37,10 @@ def load_base_data(path) # :nodoc:
3337
add(type)
3438
end
3539

40+
each_file_byte("spri") do |type, byte|
41+
type.instance_variable_set(:@__sort_priority, byte)
42+
end
43+
3644
self
3745
end
3846

@@ -60,6 +68,25 @@ def each_file_line(name, lookup = true)
6068
end
6169
end
6270

71+
def each_file_byte(name)
72+
LOAD_MUTEX.synchronize do
73+
next if @__files__.include?(name)
74+
75+
i = -1
76+
77+
filename = File.join(@__root__, "mime.#{name}.column")
78+
79+
next unless File.exist?(filename)
80+
81+
IO.binread(filename).unpack("C*").each do |byte|
82+
(type = @__mime_data__[i += 1]) || next
83+
yield type, byte
84+
end
85+
86+
@__files__ << name
87+
end
88+
end
89+
6390
def load_encoding
6491
each_file_line("encoding") do |type, line|
6592
pool ||= {}

0 commit comments

Comments
 (0)