I have a hash, let's say:
ahash = {test1: "test1", test2: "test2"}
Why is it that Hash === ahash
returns true, but ahash === Hash
doesn't? Is this some default ruby behavior with === and class name?
It's just how the ===
method works. It's directional and that applies to any class:
"foo" === String
# => false
String === "foo"
# => true
This is because that evaluates to:
"foo".send(:===, String)
String.send(:===, "foo")
Those are two different methods, one for the class, one for the instance.
If you're only concerned with class information:
"foo".is_a?(String)
# => true
{ }.is_a?(Hash)
# => true
This method makes it a lot more clear what your intention is.
Module#=== (also called the "case equality operator") returns true if the object on the right-hand side of the expression is an instance of the left-hand side, or one of its descendants. When you ask:
Hash === {test1: "test1", test2: "test2"}
what you're really asking is this: "Is this hash literal an instance or descendant of the Hash class?" On the other hand, the reverse is not true, since the Hash class is not an instance or descendant of your hash literal.
On the other hand, the following works either way:
Hash.new === {}
{} === Hash.new
because both expressions are case-equivalent. Here's the same result using your data:
Hash[:test1, "test1", :test2, "test2"] === {:test1=>"test1", :test2=>"test2"}
#=> true
{:test1=>"test1", :test2=>"test2"} === Hash[:test1, "test1", :test2, "test2"]
#=> true
However, threequals isn't just a stand-in for Object#is_a?. It's really meant to be consumed by case/when statements, and Giles Bowkett says:
The === method exists for controlling how a case/when block will evaluate an object. It should never be used by humans. It is code written to be consumed by other code, specifically, by case and when.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With