Related
I have used the bcrypt library in my Ruby program. I noticed that the order of the equality operator seems to be important. Depending on which variable is left or right of the '==' I get a different result.
Here is an example program:
require 'bcrypt'
my_pw = "pw1"
puts "This is my unhashed password: #{my_pw}"
hashed_pw = BCrypt::Password.create(my_pw)
puts "This is my hashed password: #{hashed_pw}"
20.times{print"-"}
puts
puts "my_pw == hashed_pw equals:"
if (my_pw == hashed_pw)
puts "TRUE"
else
puts "FALSE"
end
puts "hashed_pw == my_pw equals:"
if (hashed_pw == my_pw)
puts "TRUE"
else
puts "FALSE"
end
Regards
schande
Yes, there is a difference.
my_pw == hashed_pw calls the == method on the my_pw string and passes hashed_pw as an argument. That means you are using the String#== method. From the docs of String#==:
string == object → true or false
Returns true if object has the same length and content; as self; false otherwise
Whereas hashed_pw == my_pw calls the == method on an instance of BCrypt::Password and passes my_pw as an argument. From the docs of BCrypt::Password#==:
#==(secret) ⇒ Object
Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
This doesn't really have anything to do with equality. This is just fundamentals of Object-Oriented Programming.
In OOP, all computation is done by objects sending messages to other objects. And one of the fundamental properties of OOP is that the receiver object and only the receiver object decides how to respond to this message. This is how encapsulation, data hiding, and abstraction are achieved in OOP.
So, if you send the message m to object a passing b as the argument, then a gets to decide how to interpret this message. If you send the message m to object b passing a as the argument, then it is b which gets to decide how to interpret this message. There is no built-in mechanism that would guarantee that a and b interpret this message the same. Only if the two objects decide to coordinate with each other, will the response actually be the same.
If you think about, it would be very weird if 2 - 3 and 3 - 2 had the same result.
That is exactly what is happening here: In the first example, you are sending the message == to my_pw, passing hashed_pw as the argument. my_pw is an instance of the String class, thus the == message will be dispatched to the String#== method. This method knows how to compare the receiver object to another String. It does, however, not know how to compare the receiver to a BCrypt::Password, which is what the class of hashed_pw is.
And if you think about it, that makes sense: BCrypt::Password is a third-party class from outside of Ruby, how could a built-in Ruby class know about something that didn't even exist at the time the String class was implemented?
In your second example, on the other hand, you are sending the message == to hashed_pw, passing my_pw as the argument. This message gets dispatched to the BCrypt::Password#== method, which does know how to compare the receiver with a String:
Method: BCrypt::Password#==
Defined in: lib/bcrypt/password.rb
#==(secret) ⇒ Object
Also known as: is_password?
Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
Actually, the problem in this particular case is even more subtle than it may at first appear.
I wrote above that String#== doesn't know what to do with a BCrypt::Password as an argument, because it only knows how to compare Strings. Well, actually BCrypt::Password inherits from String, meaning that a BCrypt::Password IS-A String, so String#== should know how to handle it!
But think about what String#== does:
string == object → true or false
Returns true if object has the same length and content; as self; false otherwise […]
Think about this: "returns true if object has the same length and content". For a hash, this will practically never be true. self will be something like 'P#$$w0rd!' and object will be something like '$2y$12$bxWYpd83lWyIr.dF62eO7.gp4ldf2hMxDofXPwdDZsnc2bCE7hN9q', so clearly, they are neither the same length nor the same content. And object cannot possibly be the same content because the whole point of a cryptographically secure password hash is that you cannot reverse it. So, even if object somehow wanted to present itself as the original password, it couldn't do it.
The only way this would work, is if String and BCrypt::Password could somehow "work together" to figure out equality.
Now, if we look close at the documentation of String#==, there is actually a way to make this work:
If object is not an instance of String but responds to to_str, then the two strings are compared using object.==.
So, if the author of BCrypt::Password had made a different design decision, then it would work:
Do not let BCrypt::Password inherit from String.
Implement BCrypt::Password#to_str. This will actually allow BCrypt::Password to be used practically interchangeably with String because any method that accepts Strings should also accept objects that respond to to_str.
Now, as per the documentation of String#==, if you write my_pw == hashed_pw, the following happens:
String#== notices that hashed_pw is not a String.
String#== notices that hashed_pw does respond to to_str.
Therefore, it will send the message object == self (which in our case is equivalent to hashed_pw == my_pw), which means we are now in the second scenario from your question, which works just fine.
Here's an example of how that would work:
class Pwd
def initialize(s)
#s = s.downcase.freeze
end
def to_str
p __callee__
#s.dup.freeze
end
def ==(other)
p __callee__, other
#s == other.downcase
end
end
p = Pwd.new('HELLO')
s = 'hello'
p == s
# :==
# "hello"
#=> true
s == p
# :==
# "hello"
#=> true
As you can see, we are getting the results we are expecting, and Pwd#== gets called both times. Also, to_str never gets called, it only gets inspected by String#==.
So, it turns out that ironically, the problem is not so much that String#== doesn't know how to deal with BCrypt::Password objects, but actually the problem is that it does know how to deal with them as generic Strings. If they weren't Strings but merely responded to to_str, then String#== would actually know to ask them for help.
Numeric objects in Ruby have a whole coercion protocol to make sure arithmetic operations between different "number-like" operand types are supported even for third-party numerics libraries.
The expressions would be equivalent if both operands were, for instance, of type String. In your case, one operand is a String and the other one is a BCrypt::Password. Therefore my_pw == hashed_pw invokes the equality method defined in the String class, while hashed_pw == my_pw invokes the one defined in BCrypt::Password.
I have never worked with BCrypt::Password, but would expect that you get false for the former and true for the latter.
In Ruby you can override the equality method for a given class or instance:
class Test
define_method(:==) do |_other|
true
end
end
Test.new == 'foo' # => true
Test.new == nil # => true
Test.new == 42 # => true
'foo' == Test.new # => false
nil == Test.new # => false
42 == Test.new # => true
Generally speaking, it's considered bad practice to override equality without making it symetric, but you sometimes see it in the wild.
I want to define singleton method to every integer value (object) . but i am getting error while applying singleton method.
RubyDoc says There is effectively only one Fixnum object instance for any given integer value . what does this mean ?? how it is different from other normal classes?? i am not able to interpret this line.
I want to define singleton method to every integer value (object)
This is contradictory. The singleton class is for when you want something to apply to a single object. You want to define something for every integer object, so the singleton class is not an appropriate tool. Just use the normal class
class Integer
def foobar
"hey"
end
end
3.foobar
# "hey"
If you could modify the singleton class of 3, then there would be some behaviors that only apply to the number 3 and no other number. There is no technical reason to prevent that, but trust me that it's a good thing that you can't.
There is effectively only one Fixnum object instance for any given integer value
This is talking about something else. Notice the difference:
x = []
y = []
x == y # true
x.object_id == y.object_id # false!
x = 3
y = 3
x == y # true
x.object_id == y.object_id # true!
x.object_id == 5.object_id # false
Unlike most other objects, equal fixnums are identical objects. 3 and 5 are two different instances of Fixnum, but it is impossible to have two different instances of Fixnum that are both 3. Every 3 is the same. Again, this is not a technical necessity but more of a convenience for how most programmers think about numerical data.
It means that whenever you access some Fixnum, such as the number 1, you’re always treating with the same “instance”, this is mostly an implementation detail which ruby uses to optimize numbers.
The Integer class is frozen by default:
1.frozen?
=> true
There only ever exists one instance of any Integer object. You don't have to do anything special to enable this. In other words, the optimization you are trying to apply is built into Ruby.
I have the following code as an example.
a = [2]
b = a
puts a == b
a.each do |num|
a[0] = num-1
end
puts a == b
I want b to refer to a's value, and the value of b not to change when a is changed.(The second puts should return false).
Thank you in advance.
Edited-
The answer posted by user2864740 seems to work for the example I gave. However, I'm working on a sudoku solving program, and it doesn't seem to work there.
#gridbylines = [[1,0,0,9,2,0,0,0,0],
[5,2,4,0,1,0,0,0,0],
[0,0,0,0,0,0,0,7,0],
[0,5,0,0,0,8,1,0,2],
[0,0,0,0,0,0,0,0,0],
[4,0,2,7,0,0,0,9,0],
[0,6,0,0,0,0,0,0,0],
[0,0,0,0,3,0,9,4,5],
[0,0,0,0,7,1,0,0,6]]
save = Array.new(#gridbylines) #or #gridbylines.dup
puts save == #gridbylines #returns true
puts save.equal?(#gridbylines) #returns false
#gridbylines[0][0] = 'foo'
puts save.equal?(#gridbylines) #returns false
puts save == #gridbylines #returns true, but I want "save" not to change when I change "#gridbylines"
Does this have something to do with the fact that I'm using a global variable, or the version of Ruby I'm using, or even because it's a multidimentional array unlike the previous example?
Variables name or "refer to" objects1. In the code above the same object (which has two names, a and b) is being changed.
A simple solution in this case is to make a (shallow) copy of the original Array object, such as b = a.dup or b = Array.new(a). (With a shallow copy, elements in the array are also shared and will exhibit the similar phoneme as the original question unless they to are [recursively] duplicated, etc.2)
a = [2]
b = Array.new(a) # create NEW array object, a shallow-copy of `a`
puts a == b # true (same content)
puts a.equal?(b) # false (different objects)
a.each do |num|
a[0] = num-1 # now changing the object named by `a` does not
# affect the object named by `b` as they are different
end
puts a == b # false (different content)
And an isolated example of this "naming" phenomena (see the different equality forms):
a = []
b = a # assignment does NOT make a copy of the object
a.equals?(b) # true (same object)
c = a.dup # like Array.new, create a new shallow-copy object
a.equals?(c) # false (different object)
1 I find it most uniform to talk about variables being names, as such a concept can be applied across many languages - the key here is that any object can have one or more names, just as a person can have many nicknames. If an object has zero names then it is no longer strongly reachable and, just like a person, is forgotten.
However, another way to view variables (naming objects) is that they hold reference values, where the reference value identifies an object. This leads to phrasing such as
"variable a contains a reference [value] to object x" - or,
"variable a refers to / references object x" - or, as I prefer,
"variable a is a name for object x".
For the case or immutable "primitive" or "immediate" values the underlying mechanics are slightly different but, being immutable the object values cannot be changed and such a lack-of-shared object nature will not manifest itself.
See also:
String assignment by reference/copy? (examines object relationship after assignment)
Strange Feature? of Ruby Arrays (examines same-object mutation)
Is Ruby pass by reference or by value? (assignment works in the same way as argument passing)
2 As per the updated question with nested arrays, this is explained by the previous rules - the variables (well, really expressions) still name shared objects. In any case, one way to "clone an array of arrays" (to two levels, although not recursively) is to use:
b = a.map {|r| r.dup}
This is because Array#map returns a new array with the mapped values which are, in this case, duplicates (shallow clones) of the corresponding nested arrays.
See How to create a deep copy of an object in Ruby? for other "deep[er] copy" approaches - especially if the arrays (or affect mutable objects) were nested to N-levels.
I am trying to understand the difference between these four methods. I know by default that == calls the method equal? which returns true when both operands refer to exactly the same object.
=== by default also calls == which calls equal?... okay, so if all these three methods are not overridden, then I guess
===, == and equal? do exactly the same thing?
Now comes eql?. What does this do (by default)? Does it make a call to the operand's hash/id?
Why does Ruby have so many equality signs? Are they supposed to differ in semantics?
I'm going to heavily quote the Object documentation here, because I think it has some great explanations. I encourage you to read it, and also the documentation for these methods as they're overridden in other classes, like String.
Side note: if you want to try these out for yourself on different objects, use something like this:
class Object
def all_equals(o)
ops = [:==, :===, :eql?, :equal?]
Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
end
end
"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}
== — generic "equality"
At the Object level, == returns true only if obj and other are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.
This is the most common comparison, and thus the most fundamental place where you (as the author of a class) get to decide if two objects are "equal" or not.
=== — case equality
For class Object, effectively the same as calling #==, but typically overridden by descendants to provide meaningful semantics in case statements.
This is incredibly useful. Examples of things which have interesting === implementations:
Range
Regex
Proc (in Ruby 1.9)
So you can do things like:
case some_object
when /a regex/
# The regex matches
when 2..4
# some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
# the lambda returned true
end
See my answer here for a neat example of how case+Regex can make code a lot cleaner. And of course, by providing your own === implementation, you can get custom case semantics.
eql? — Hash equality
The eql? method returns true if obj and other refer to the same hash key. This is used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==. Subclasses normally continue this tradition by aliasing eql? to their overridden == method, but there are exceptions. Numeric types, for example, perform type conversion across ==, but not across eql?, so:
1 == 1.0 #=> true
1.eql? 1.0 #=> false
So you're free to override this for your own uses, or you can override == and use alias :eql? :== so the two methods behave the same way.
equal? — identity comparison
Unlike ==, the equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b).
This is effectively pointer comparison.
I love jtbandes answer, but since it is pretty long, I will add my own compact answer:
==, ===, eql?, equal?
are 4 comparators, ie. 4 ways to compare 2 objects, in Ruby.
As, in Ruby, all comparators (and most operators) are actually method-calls, you can change, overwrite, and define the semantics of these comparing methods yourself. However, it is important to understand, when Ruby's internal language constructs use which comparator:
== (value comparison)
Ruby uses :== everywhere to compare the values of 2 objects, eg. Hash-values:
{a: 'z'} == {a: 'Z'} # => false
{a: 1} == {a: 1.0} # => true
=== (case comparison)
Ruby uses :=== in case/when constructs. The following code snippets are logically identical:
case foo
when bar; p 'do something'
end
if bar === foo
p 'do something'
end
eql? (Hash-key comparison)
Ruby uses :eql? (in combination with the method hash) to compare Hash-keys. In most classes :eql? is identical with :==.
Knowledge about :eql? is only important, when you want to create your own special classes:
class Equ
attr_accessor :val
alias_method :initialize, :val=
def hash() self.val % 2 end
def eql?(other) self.hash == other.hash end
end
h = {Equ.new(3) => 3, Equ.new(8) => 8, Equ.new(15) => 15} #3 entries, but 2 are :eql?
h.size # => 2
h[Equ.new(27)] # => 15
Note: The commonly used Ruby-class Set also relies on Hash-key-comparison.
equal? (object identity comparison)
Ruby uses :equal? to check if two objects are identical. This method (of class BasicObject) is not supposed to be overwritten.
obj = obj2 = 'a'
obj.equal? obj2 # => true
obj.equal? obj.dup # => false
Equality operators: == and !=
The == operator, also known as equality or double equal, will return true if both objects are equal and false if they are not.
"koan" == "koan" # Output: => true
The != operator, also known as inequality, is the opposite of ==. It will return true if both objects are not equal and false if they are equal.
"koan" != "discursive thought" # Output: => true
Note that two arrays with the same elements in a different order are not equal, uppercase and lowercase versions of the same letter are not equal and so on.
When comparing numbers of different types (e.g., integer and float), if their numeric value is the same, == will return true.
2 == 2.0 # Output: => true
equal?
Unlike the == operator which tests if both operands are equal, the equal method checks if the two operands refer to the same object. This is the strictest form of equality in Ruby.
Example:
a = "zen"
b = "zen"
a.object_id # Output: => 20139460
b.object_id # Output :=> 19972120
a.equal? b # Output: => false
In the example above, we have two strings with the same value. However, they are two distinct objects, with different object IDs. Hence, the equal? method will return false.
Let's try again, only this time b will be a reference to a. Notice that the object ID is the same for both variables, as they point to the same object.
a = "zen"
b = a
a.object_id # Output: => 18637360
b.object_id # Output: => 18637360
a.equal? b # Output: => true
eql?
In the Hash class, the eql? method it is used to test keys for equality. Some background is required to explain this. In the general context of computing, a hash function takes a string (or a file) of any size and generates a string or integer of fixed size called hashcode, commonly referred to as only hash. Some commonly used hashcode types are MD5, SHA-1, and CRC. They are used in encryption algorithms, database indexing, file integrity checking, etc. Some programming languages, such as Ruby, provide a collection type called hash table. Hash tables are dictionary-like collections which store data in pairs, consisting of unique keys and their corresponding values. Under the hood, those keys are stored as hashcodes. Hash tables are commonly referred to as just hashes. Notice how the word hashcan refer to a hashcode or to a hash table. In the context of Ruby programming, the word hash almost always refers to the dictionary-like collection.
Ruby provides a built-in method called hash for generating hashcodes. In the example below, it takes a string and returns a hashcode. Notice how strings with the same value always have the same hashcode, even though they are distinct objects (with different object IDs).
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
The hash method is implemented in the Kernel module, included in the Object class, which is the default root of all Ruby objects. Some classes such as Symbol and Integer use the default implementation, others like String and Hash provide their own implementations.
Symbol.instance_method(:hash).owner # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel
String.instance_method(:hash).owner # Output: => String
Hash.instance_method(:hash).owner # Output: => Hash
In Ruby, when we store something in a hash (collection), the object provided as a key (e.g., string or symbol) is converted into and stored as a hashcode. Later, when retrieving an element from the hash (collection), we provide an object as a key, which is converted into a hashcode and compared to the existing keys. If there is a match, the value of the corresponding item is returned. The comparison is made using the eql? method under the hood.
"zen".eql? "zen" # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true
In most cases, the eql? method behaves similarly to the == method. However, there are a few exceptions. For instance, eql? does not perform implicit type conversion when comparing an integer to a float.
2 == 2.0 # Output: => true
2.eql? 2.0 # Output: => false
2.hash == 2.0.hash # Output: => false
Case equality operator: ===
Many of Ruby's built-in classes, such as String, Range, and Regexp, provide their own implementations of the === operator, also known as case-equality, triple equals or threequals. Because it's implemented differently in each class, it will behave differently depending on the type of object it was called on. Generally, it returns true if the object on the right "belongs to" or "is a member of" the object on the left. For instance, it can be used to test if an object is an instance of a class (or one of its subclasses).
String === "zen" # Output: => true
Range === (1..2) # Output: => true
Array === [1,2,3] # Output: => true
Integer === 2 # Output: => true
The same result can be achieved with other methods which are probably best suited for the job. It's usually better to write code that is easy to read by being as explicit as possible, without sacrificing efficiency and conciseness.
2.is_a? Integer # Output: => true
2.kind_of? Integer # Output: => true
2.instance_of? Integer # Output: => false
Notice the last example returned false because integers such as 2 are instances of the Fixnum class, which is a subclass of the Integer class. The ===, is_a? and instance_of? methods return true if the object is an instance of the given class or any subclasses. The instance_of method is stricter and only returns true if the object is an instance of that exact class, not a subclass.
The is_a? and kind_of? methods are implemented in the Kernel module, which is mixed in by the Object class. Both are aliases to the same method. Let's verify:
Kernel.instance_method(:kind_of?) == Kernel.instance_method(:is_a?) # Output: => true
Range Implementation of ===
When the === operator is called on a range object, it returns true if the value on the right falls within the range on the left.
(1..4) === 3 # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6 # Output: => false
("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false
Remember that the === operator invokes the === method of the left-hand object. So (1..4) === 3 is equivalent to (1..4).=== 3. In other words, the class of the left-hand operand will define which implementation of the === method will be called, so the operand positions are not interchangeable.
Regexp Implementation of ===
Returns true if the string on the right matches the regular expression on the left.
/zen/ === "practice zazen today" # Output: => true
# is the same as
"practice zazen today"=~ /zen/
Implicit usage of the === operator on case/when statements
This operator is also used under the hood on case/when statements. That is its most common use.
minutes = 15
case minutes
when 10..20
puts "match"
else
puts "no match"
end
# Output: match
In the example above, if Ruby had implicitly used the double equal operator (==), the range 10..20 would not be considered equal to an integer such as 15. They match because the triple equal operator (===) is implicitly used in all case/when statements. The code in the example above is equivalent to:
if (10..20) === minutes
puts "match"
else
puts "no match"
end
Pattern matching operators: =~ and !~
The =~ (equal-tilde) and !~ (bang-tilde) operators are used to match strings and symbols against regex patterns.
The implementation of the =~ method in the String and Symbol classes expects a regular expression (an instance of the Regexp class) as an argument.
"practice zazen" =~ /zen/ # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil
:zazen =~ /zen/ # Output: => 2
:zazen =~ /discursive thought/ # Output: => nil
The implementation in the Regexp class expects a string or a symbol as an argument.
/zen/ =~ "practice zazen" # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil
In all implementations, when the string or symbol matches the Regexp pattern, it returns an integer which is the position (index) of the match. If there is no match, it returns nil. Remember that, in Ruby, any integer value is "truthy" and nil is "falsy", so the =~ operator can be used in if statements and ternary operators.
puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes
Pattern-matching operators are also useful for writing shorter if statements. Example:
if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
true
end
The !~ operator is the opposite of =~, it returns true when there is no match and false if there is a match.
More info is available at this blog post.
I would like to expand on the === operator.
=== is not an equality operator!
Not.
Let's get that point really across.
You might be familiar with === as an equality operator in Javascript and PHP, but this just not an equality operator in Ruby and has fundamentally different semantics.
So what does === do?
=== is the pattern matching operator!
=== matches regular expressions
=== checks range membership
=== checks being instance of a class
=== calls lambda expressions
=== sometimes checks equality, but mostly it does not
So how does this madness make sense?
Enumerable#grep uses === internally
case when statements use === internally
Fun fact, rescue uses === internally
That is why you can use regular expressions and classes and ranges and even lambda expressions in a case when statement.
Some examples
case value
when /regexp/
# value matches this regexp
when 4..10
# value is in range
when MyClass
# value is an instance of class
when ->(value) { ... }
# lambda expression returns true
when a, b, c, d
# value matches one of a through d with `===`
when *array
# value matches an element in array with `===`
when x
# values is equal to x unless x is one of the above
end
All these example work with pattern === value too, as well as with grep method.
arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)
# => ["quick", "fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the", "quick", "brown", "fox"]
arr.grep(1)
# => [1, 1]
Ruby exposes several different methods for handling equality:
a.equal?(b) # object identity - a and b refer to the same object
a.eql?(b) # object equivalence - a and b have the same value
a == b # object equivalence - a and b have the same value with type conversion.
Continue reading by clicking the link below, it gave me a clear summarized understanding.
https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers
Hope it helps others.
=== #---case equality
== #--- generic equality
both works similar but "===" even do case statements
"test" == "test" #=> true
"test" === "test" #=> true
here the difference
String === "test" #=> true
String == "test" #=> false
.eql? - This operator returns true if the receiver and argument have both the same type and equal values.
for example - 10.eql?(10.0) is false.
=== - it will test equality in case statement.
for example - (1...10) === 1 is true
== - This operator checks whether the two given operands are equal or not. If equals, it returns TRUE, Otherwise it returns FALSE.
for example - (1...10) == 1 is false
for more example click here
I wrote a simple test for all the above.
def eq(a, b)
puts "#{[a, '==', b]} : #{a == b}"
puts "#{[a, '===', b]} : #{a === b}"
puts "#{[a, '.eql?', b]} : #{a.eql?(b)}"
puts "#{[a, '.equal?', b]} : #{a.equal?(b)}"
end
eq("all", "all")
eq(:all, :all)
eq(Object.new, Object.new)
eq(3, 3)
eq(1, 1.0)
From what I have understood, the equal method checks if the object is the same.
person = Person.create!(:name => "David")
Person.find_by_name("David").should equal(person)
This should be true.
But aren't there two different objects here?
How could two objects be the same? I don't understand that.
Rails and RSpec equality tests have a variety of choices.
Rails 3.2 ActiveRecord::Base uses the == equality matcher.
It returns true two different ways:
If self is the same exact object as the comparison object
If self is the same type as the comparison object and has the same ID
Note that ActiveRecord::Base has the == method which is aliased as eql?. This is different than typical Ruby objects, which define == and eql? differently.
RSpec 2.0 has these equality matchers in rspec-expectations:
a.should equal(b) # passes if a.equal?(b)
a.should eql(b) # passes if a.eql?(b)
a.should == b # passes if a == b
RSpec also has two equality matchers intended to have more of a DSL feel to them:
a.should be(b) # passes if a.equal?(b)
a.should eq(b) # passes if a == b
In your example you're creating a record then finding it.
So you have two choices for testing #find_by_name:
To test if it retrieves the exact same object OR an equivalent Person record with the same ID, then use should == or its equivalent a.should eql or its DSL version should eq
To test if it uses the exact same object NOT an equivalent Person record with the same ID, then use should equal or its DSL version should be
equal checks if the reference is the same. It corresponds to the Object#equal? method. You want to use == to compare these objects.