Skip to content

Commit

Permalink
Override StripeObject#eql? and #hash to produce more optimistic e…
Browse files Browse the repository at this point in the history
…quivalency

Overrides `#eql?` (hash equality) and `#hash` so that Stripe objects can
be used more easily as Hash keys and that certain other frameworks that
rely on these methods will have an easier time (e.g. RSpec's `change`,
see #687).

I think this might be a little controversial if we weren't already
overriding the `#==` implementation, but because we are, I think it
makes sense to extent it to these two methods as well.
  • Loading branch information
brandur committed Sep 13, 2018
1 parent 27f39ae commit 7c01836
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
11 changes: 11 additions & 0 deletions lib/stripe/stripe_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ def ==(other)
other.is_a?(StripeObject) && @values == other.instance_variable_get(:@values)
end

# Hash equality. As with ==, we consider two equivalent Stripe objects equal.
def eql?(other)
self == other
end

# As for equality, we hash to Stripe objects to the same value if they're
# equivalent objects.
def hash
@values.hash
end

# Indicates whether or not the resource has been deleted on the server.
# Note that some, but not all, resources can indicate whether they have
# been deleted.
Expand Down
40 changes: 40 additions & 0 deletions test/stripe/stripe_object_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,46 @@ class TestObject < Stripe::StripeObject; end
end
end

context "#eql?" do
should "produce the true for two equivalent Stripe objects" do
obj1 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
obj2 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
assert obj1.eql?(obj2)
end

should "produce false for non-equivalent Stripe objects" do
obj1 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
obj2 = Stripe::StripeObject.construct_from(id: 2, name: "Stripe")
refute obj1.eql?(obj2)
end

should "produce false for different types" do
obj1 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
obj2 = 7
refute obj1.eql?(obj2)
end
end

context "#hash" do
should "produce the same hash for two equivalent Stripe objects" do
obj1 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
obj2 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
assert_equal obj1.hash, obj2.hash
end

should "produce different hashes for non-equivalent Stripe objects" do
obj1 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
obj2 = Stripe::StripeObject.construct_from(id: 2, name: "Stripe")
refute_equal obj1.hash, obj2.hash
end

should "produce different hashes for different types" do
obj1 = Stripe::StripeObject.construct_from(id: 1, name: "Stripe")
obj2 = 7
refute_equal obj1.hash, obj2.hash
end
end

context "#to_hash" do
should "skip calling to_hash on nil" do
module NilWithToHash
Expand Down

0 comments on commit 7c01836

Please sign in to comment.