Skip to content

Commit fc1372e

Browse files
committed
Add a stable sort
- This probably has a negative performance impact, so I’m not sure I’m going to merge this.
1 parent ca7142f commit fc1372e

File tree

3 files changed

+26
-12
lines changed

3 files changed

+26
-12
lines changed

lib/mime/types.rb

+13-8
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,7 @@ def [](type_id, complete: false, registered: false)
130130
@type_variants[MIME::Type.simplified(type_id)]
131131
end
132132

133-
prune_matches(matches, complete, registered).sort { |a, b|
134-
a.priority_compare(b)
135-
}
133+
stable_sort(prune_matches(matches, complete, registered))
136134
end
137135

138136
# Return the list of MIME::Types which belongs to the file based on its
@@ -148,11 +146,12 @@ def [](type_id, complete: false, registered: false)
148146
# puts MIME::Types.type_for(%w(citydesk.xml citydesk.gif))
149147
# => [application/xml, image/gif, text/xml]
150148
def type_for(filename)
151-
Array(filename).flat_map { |fn|
152-
@extension_index[fn.chomp.downcase[/\.?([^.]*?)\z/m, 1]]
153-
}.compact.inject(Set.new, :+).sort { |a, b|
154-
a.priority_compare(b)
155-
}
149+
results =
150+
Array(filename).flat_map { |fn|
151+
@extension_index[fn.chomp.downcase[/\.?([^.]*?)\z/m, 1]]
152+
}.compact.inject(Set.new, :+)
153+
154+
stable_sort(results)
156155
end
157156
alias_method :of, :type_for
158157

@@ -220,6 +219,12 @@ def match(pattern)
220219
k =~ pattern
221220
}.values.inject(Set.new, :+)
222221
end
222+
223+
def stable_sort(list)
224+
list.lazy.each_with_index.sort { |(a, ai), (b, bi)|
225+
a.priority_compare(b).nonzero? || ai <=> bi
226+
}.map(&:first)
227+
end
223228
end
224229

225230
require "mime/types/cache"

test/test_mime_types.rb

+9-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ def mime_types
1212
MIME::Type.new("content-type" => "application/x-wordperfect6.1"),
1313
MIME::Type.new("content-type" => "application/x-www-form-urlencoded", "registered" => true),
1414
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")
1617
)
1718
}
1819
end
@@ -33,8 +34,8 @@ def mime_types
3334
end
3435

3536
it "is countable with an enumerator" do
36-
assert_equal 6, mime_types.each.count
37-
assert_equal 6, mime_types.lazy.count
37+
assert_equal 8, mime_types.each.count
38+
assert_equal 8, mime_types.lazy.count
3839
end
3940
end
4041

@@ -158,11 +159,15 @@ def mime_types
158159
it "handles newline characters correctly" do
159160
assert_includes mime_types.type_for("test.pdf\n.txt"), "text/plain"
160161
end
162+
163+
it "returns a stable order for types with equal priority" do
164+
assert_equal %w[audio/webm video/webm], mime_types.type_for("foo.webm")
165+
end
161166
end
162167

163168
describe "#count" do
164169
it "can count the number of types inside" do
165-
assert_equal 6, mime_types.count
170+
assert_equal 8, mime_types.count
166171
end
167172
end
168173
end

test/test_mime_types_class.rb

+4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ def setup
105105
assert_includes MIME::Types.type_for("test.pdf\n.txt"), "text/plain"
106106
assert_includes MIME::Types.type_for("test.txt\n.pdf"), "application/pdf"
107107
end
108+
109+
it "returns a stable order for types with equal priority" do
110+
assert_equal %w[audio/webm video/webm], MIME::Types.type_for("foo.webm")
111+
end
108112
end
109113

110114
describe ".count" do

0 commit comments

Comments
 (0)