I too, find Ruby (or at least my knowledge of it) short of the mark in this area. For instance the following does what I want but is clumsy,
class Frob
attr_reader :val1, :val2
Tolerance = 2 * Float::EPSILON
def initialize(val1, val2)
@val2 = val1
@val2 = val2
...
end
# Stuff that's likely to change and I don't want part
# of a public API. Furthermore, the method is operating
# solely upon 'reference' and 'under_test' and will be flagged as having
# low cohesion by quality metrics unless made a class method.
def self.compare(reference, under_test)
# special floating point comparison
(reference - under_test).abs <= Tolerance
end
private_class_method :compare
def ==(arg)
self.class.send(:compare, val1, arg.val1) &&
self.class.send(:compare, val2, arg.val2) &&
...
end
end
My problems with the code above is that the Ruby syntax requirements and my code quality metrics conspire to made for cumbersome code. To have the code both work as I want and to quiet the metrics, I must make compare() a class method. Since I don't want it to be part of the class' public API, I need it to be private, yet 'private' by itself does not work. Instead I am force to use 'private_class_method' or some such work-around. This, in turn, forces the use of 'self.class.send(:compare...' for each variable I test in '==()'. Now that's a bit unwieldy.