Overriding eql? and hash


#1

Hi,

I am working in an application and I need to store my own objects in
some collections. I was using instances of Array to store that objects,
but now, I need not to store duplicated instances. Searching the Web I
found de class ‘Set’, which seems to do that. I also read that with this
collection you have to override the eql? and hash methods in your
classes objects to set a criteria to compare you objects.

I will try to explain better myself with an example:

I have the following class Track

class Track < ActiveRecord::Base
belongs_to :album

def hash
StringUtils.nice_slug(self.name, “false”).hash

end

def eql?(other)
equal = false
if StringUtils.nice_slug(self.name, “false”).downcase.eql?
StringUtils.nice_slug(other.name, “false”).downcase
equal = true
end
equal
end
end

Now, I create two instances of Track and two of Set, and I insert one
track into each Set.

a = Set::new

t1 = Track.new

=> #<Track id: nil, name: nil, lyric: nil, created_at: nil, updated_at:
nil>

t1.name = “Gracias por elegirme”

t2 = Track.new

=> #<Track id: nil, name: nil, lyric: nil, created_at: nil, updated_at:
nil>

t2.name = “Gracias Por Elegirme”

a << t1

=> #<Set: {#<Track id: nil, name: “Gracias por elegirme”, lyric: nil,
created_at: nil, updated_at: nil>}>

b = Set::new

b << t2

#<Set: {#<Track id: nil, name: “Gracias Por Elegirme”, lyric: nil,
created_at: nil, updated_at: nil>}>

And finally, I try to insert the content of b into a:

a.merge(b)

The result that I am expecting is that nothing is inserted into a
because the name of the two tracks is very similar, and when we convert
into downcase the are equal (“gracias por elegirme”).

But instead I get the following:

#<Set: {#<Track id: nil, name: “Gracias Por Elegirme”, lyric: nil,
created_at: nil, updated_at: nil>, #<Track id: nil, name: “Gracias por
elegirme”, lyric: nil, created_at: nil, updated_at: nil>}>

Now a stores the two Track instances.

I would appreciate so much your help.


#2

César Díaz wrote:

  end
  equal
 end

If two strings are equal except for case your eql? method will return
true. Or
at least it would if it ever got called. But since you don’t call
downcase in
the hash method, those two objects will have different hash values and
Set
will never bother to call eql? on them.
In other words: call downcase in the hash method as well and you’ll be
fine.

HTH,
Sebastian


#3

It works perfectly.

Thank you very much!!!