From 86d7cf4eaba1410fb791e8a9d3c2b34abe36615c Mon Sep 17 00:00:00 2001 From: Austin Ziegler Date: Sat, 21 Nov 2020 16:22:24 -0500 Subject: [PATCH] Add a stable sort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - This probably has a negative performance impact, so I’m not sure I’m going to merge this. --- lib/mime/types.rb | 19 ++++++++++++------- test/test_mime_types.rb | 19 ++++++++++++------- test/test_mime_types_class.rb | 4 ++++ 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/mime/types.rb b/lib/mime/types.rb index 1424666..8aadacf 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| + results = + Array(filename).flat_map { |fn| @extension_index[fn.chomp.downcase[/\.?([^.]*?)$/, 1]] - }.compact.inject(Set.new, :+).sort { |a, b| - a.priority_compare(b) - } + }.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 b01b702..597f0e9 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 @@ -37,9 +38,9 @@ def mime_types assert_kind_of Enumerator::Lazy, mime_types.map.lazy end - it "is countable with an enumerator" do - assert_equal 6, mime_types.each.count - assert_equal 6, mime_types.lazy.count + it 'is countable with an enumerator' do + assert_equal 8, mime_types.each.count + assert_equal 8, mime_types.lazy.count end end @@ -159,11 +160,15 @@ def mime_types plain_text.add_extensions("xtxt") assert_includes mime_types.type_for("xtxt"), "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 + describe '#count' do + it 'can count the number of types inside' do + 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 b47bca2..84fff6f 100644 --- a/test/test_mime_types_class.rb +++ b/test/test_mime_types_class.rb @@ -100,6 +100,10 @@ def setup plain_text.add_extensions("xtxt") assert_includes MIME::Types.type_for("xtxt"), "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