From 446d7d78b332b764d7af6ad1a38efea2a67c4416 Mon Sep 17 00:00:00 2001 From: Alex Vondrak Date: Fri, 1 Jul 2022 16:54:06 -0700 Subject: Define MIME::Type#hash Fixes #166. --- lib/mime/type.rb | 26 ++++++++++++++++++++++++++ test/test_mime_type.rb | 22 +++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/mime/type.rb b/lib/mime/type.rb index db1cb20..d40b9b1 100644 --- a/lib/mime/type.rb +++ b/lib/mime/type.rb @@ -224,6 +224,32 @@ class MIME::Type other.is_a?(MIME::Type) && (self == other) end + # Returns a hash based on the #simplified value. + # + # This maintains the invariant that two #eql? instances must have the same + # #hash (although having the same #hash does *not* imply that the objects are + # #eql?). + # + # To see why, suppose a MIME::Type instance +a+ is compared to another object + # +b+, and that a.eql?(b) is true. By the definition of #eql?, + # we know the following: + # + # 1. +b+ is a MIME::Type instance itself. + # 2. a == b is true. + # + # Due to the first point, we know that +b+ should respond to the #simplified + # method. Thus, per the definition of #<=>, we know that +a.simplified+ must + # be equal to +b.simplified+, as compared by the <=> method corresponding to + # +a.simplified+. + # + # Presumably, if a.simplified <=> b.simplified is +0+, then + # +a.simplified+ has the same hash as +b.simplified+. So we assume it's + # suitable for #hash to delegate to #simplified in service of the #eql? + # invariant. + def hash + simplified.hash + end + # Returns the whole MIME content-type string. # # The content type is a presentation value from the MIME type registry and diff --git a/test/test_mime_type.rb b/test/test_mime_type.rb index 5ef4aeb..25f0a07 100644 --- a/test/test_mime_type.rb +++ b/test/test_mime_type.rb @@ -266,7 +266,27 @@ describe MIME::Type do end it "is true for an equivalent MIME::Type" do - assert text_plain, mime_type("text/Plain") + assert text_plain.eql?(mime_type("text/Plain")) + end + + it "is true for an equivalent subclass of MIME::Type" do + subclass = Class.new(MIME::Type) + assert text_plain.eql?(subclass.new("text/plain")) + end + end + + describe "#hash" do + it "is the same between #eql? MIME::Type instances" do + assert_equal text_plain.hash, mime_type("text/plain").hash + end + + it "is the same between #eql? MIME::Type instances of different classes" do + subclass = Class.new(MIME::Type) + assert_equal text_plain.hash, subclass.new("text/plain").hash + end + + it "uses the #simplified value" do + assert_equal text_plain.hash, mime_type("text/Plain").hash end end -- cgit v1.2.1