Submitted by Robert (Fri Feb 18 07:02:01 UTC 2005)
def key_attributes(*fields) code = "" code << "def ==(o) " << fields.map {|f| "self.#{f} == o.#{f}" }.join(" && ") << " end\n" code << "def eql?(o) " << fields.map {|f| "self.#{f}.eql?(o.#{f})" }.join(" && ") << " end\n" code << "def hash() " << fields.map {|f| "self.#{f}.hash" }.join(" ^ ") << " end\n" # puts code class_eval code fields end def sort_attributes(*fields) code = fields.inject("def <=>(o)\n") {|s,f| s << "cmp = self.#{f} <=> o.#{f}; return cmp unless cmp == 0\n" } << "0\nend" # puts code class_eval code fields endend
Foo = Struct.new(:name, :age, :info)
class Foo
key_attributes :name, :age sort_attributes :name, :info, :ageend
f = [
Foo.new( "x", 1, "aaa" ), Foo.new( "x", 1, "bbb" ), Foo.new( "x", 2 , "aaa" ), Foo.new( "y", 1 , "aaa"),]
p f.sort
f.each do |f1|
f.each do |f2| puts "#{f1.inspect} == #{f2.inspect} : #{f1==f2}" puts "#{f1.inspect} eql? #{f2.inspect} : #{f1.eql? f2}" puts "#{f1.inspect} equal? #{f2.inspect} : #{f1.equal? f2}" end putsend
Comments | Current voting | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
RCRchive copyright © David Alan Black, 2003-2005.
Powered by .
FYI, I've added these methods to Ruby Facets.
Thanks.
~Trans
It's funny, I thought about this exact thing and googled to see if anyone had implemented this or if it was already in the language and I just wasn't aware...and I stumble into the RCR.
Yes. I have to strongly advocate this. Particularly on the sorting issue. It's a lot cleaner than using the Comparable mixin and definining <=> for specifying sort criteria for a class.
Particularly with how often one works with an array of objects. (Which, yes...in Ruby is technically any time that you have an array period.)
I was looking at this again and thinking the implementation might be a perfect candidate for parameterized modules.
T.
Change the hashing to linear congruential random number generator (LCR), for example:
"def hash()\n h=1\n" << fields.map {|f| " h=((h * 31) ^ self.#{f}.hash) & 0xFFFF_FFFF" }.join("\n") << "\n h\nend\n"
(suggested by Hugh Sasse)
In the linear congruential version above, I now think that we DO need % instead of & , and that the number should be 0x7FFF_FFFF to fit in Fixnum on most present-day systems (1 bit less than word size).