diff --git a/lib/mime/types.rb b/lib/mime/types.rb index 026be34..05d7974 100644 --- a/lib/mime/types.rb +++ b/lib/mime/types.rb @@ -133,9 +133,7 @@ def [](type_id, complete: false, registered: false) @type_variants[MIME::Type.simplified(type_id)] end - prune_matches(matches, complete, registered).sort { |a, b| - a.priority_compare(b) - } + stable_sort(prune_matches(matches, complete, registered)) end # Return the list of MIME::Types which belongs to the file based on its @@ -151,11 +149,12 @@ def [](type_id, complete: false, registered: false) # puts MIME::Types.type_for(%w(citydesk.xml citydesk.gif)) # => [application/xml, image/gif, text/xml] def type_for(filename) - Array(filename).flat_map { |fn| - @extension_index[fn.chomp.downcase[/\.?([^.]*?)\z/m, 1]] - }.compact.inject(Set.new, :+).sort { |a, b| - a.priority_compare(b) - } + results = + Array(filename).flat_map { |fn| + @extension_index[fn.chomp.downcase[/\.?([^.]*?)\z/m, 1]] + }.compact.inject(Set.new, :+) + + stable_sort(results) end alias_method :of, :type_for @@ -223,6 +222,12 @@ def match(pattern) k =~ pattern }.values.inject(Set.new, :+) end + + def stable_sort(list) + list.lazy.each_with_index.sort { |(a, ai), (b, bi)| + a.priority_compare(b).nonzero? || ai <=> bi + }.map(&:first) + end end require "mime/types/cache" diff --git a/test/test_mime_types.rb b/test/test_mime_types.rb index a0812a8..e0e19c5 100644 --- a/test/test_mime_types.rb +++ b/test/test_mime_types.rb @@ -18,7 +18,8 @@ def mime_types "content-type" => "application/gzip", "extensions" => "gz", "registered" => true - ) + ), + *MIME::Types.type_for("foo.webm") } end @@ -38,8 +39,8 @@ def mime_types end it "is countable with an enumerator" do - assert_equal 6, mime_types.each.count - assert_equal 6, mime_types.lazy.count + assert_equal 8, mime_types.each.count + assert_equal 8, mime_types.lazy.count end end @@ -163,11 +164,15 @@ def mime_types it "handles newline characters correctly" do assert_includes mime_types.type_for("test.pdf\n.txt"), "text/plain" end + + it "returns a stable order for types with equal priority" do + assert_equal %w[audio/webm video/webm], mime_types.type_for("foo.webm") + end end describe "#count" do it "can count the number of types inside" do - assert_equal 6, mime_types.count + assert_equal 8, mime_types.count end end end diff --git a/test/test_mime_types_class.rb b/test/test_mime_types_class.rb index 08e9556..f219cb5 100644 --- a/test/test_mime_types_class.rb +++ b/test/test_mime_types_class.rb @@ -105,6 +105,10 @@ def setup assert_includes MIME::Types.type_for("test.pdf\n.txt"), "text/plain" assert_includes MIME::Types.type_for("test.txt\n.pdf"), "application/pdf" end + + it "returns a stable order for types with equal priority" do + assert_equal %w[audio/webm video/webm], MIME::Types.type_for("foo.webm") + end end describe ".count" do