From: Zakaria Date: 2004-06-18T15:37:23+09:00 Subject: Re: How to make generic #== method? On Fri, Jun 18, 2004 at 10:15:44AM +0900, Joel VanderWerf wrote: > Zakaria wrote: > >Hi, > > > >Currently I got many simple class which is just a simple record-like. > >An example > >----------------------------------- > >class LoopTag # :nodoc: > > attr_reader :param > > attr_reader :contents > > > > def initialize(param) > > @param, @contents = param, [] > > end > > > > def ==(other) > > return false unless other.class == self.class > > return other.param == @param && other.contents == @contents > > end > >end > >------------------------------------ > >and I got a couple more class like this. > >Is there a way to make a generic #== or some Module that I can include ? > One way I've done it is this: > module ContentEquality > def hash > content.hash > end > def eql?(other) > content.eql? other.content > end > def ==(other) > # self.class == other.class and # optional > content == other.content > end > end > Just include the module and define a content method that returns > something like and array of objects that are significant for comparison > purposes: > class LoopTag > include ContentEquality > def content > [@param, @contents] > end > end > Another way might be to iterate over a list of instance variables (or > all of 'em, if that's what you want). Thank you Joel for the answer. This is what I ended up with ---------------------------------------------------------------------------- module AttrsEquality def ==(other) self.class === other && attrs == other.attrs end def attrs res = {} instance_variables.each {|n| res[n.intern] = instance_variable_get(n) } res end end ---------------------------------------------------------------------------- with unit-test ---------------------------------------------------------------------------- class TC_AttrsEquality < Test::Unit::TestCase class T1 include AttrsEquality def initialize(a, b, c, d) @a, @b, @d, @c = a, b, d, c end end def test_attrs t = T1.new(1, 'ab', ['some', 4], {'x' => 1, 3 => 'y'}) x = {:@a => 1, :@b => 'ab', :@c => ['some', 4], :@d => {'x' => 1, 3 => 'y'}} assert_equal(x, t.attrs) end def test_equal t1 = T1.new(1, 'ab', ['some', 4], {'x' => 1, 3 => 'y'}) t2 = T1.new(1, 'ab', ['some', 4], {'x' => 1, 3 => 'y'}) assert(t1 == t2, 'equal') end end ---------------------------------------------------------------------------- I remove the eql? and hash method because 1) I don't need it 2) It doesn't work if the class has hash attribute because {'a' => 1}.hash != {'a' => 1}.hash 3) I'm not really understand the functionality to test it Could someone enlighten me why Hash#hash doesn't result the same and where .hash and .eql? used ? PS: Is there any place where I could post this snippet, so others could use it? Wassallam, -- Zakaria z4k4ri4@bigfoot.com Yahoo!: z4k4ri4 http://zakaria.is-a-geek.org http://pemula.linux.or.id