Search code examples
rubycomparable

Ruby - Using Comparable mixin to compare objects on two different attributes


Is there an easy way (i.e. using the spaceship operator) to define comparison in Ruby based on two different attributes? I.e. If I have a class that contains two attributes, attr1 and attr2, is there a Rubyesque way of comparing two instances of this class on attr1, and if they're equal then compare them on attr2?


Solution

  • The whole point of the comparable mixin is to provide a definition for the spaceship (comparison) operator. So if you want to do a comparison across two attributes, then do it. Here's an overly verbose example:

    def <=>(obj)
      comparison = self.attr1 <=> obj.attr1
    
      if comparison == 0
        return self.attr2 <=> obj.attr2
      else
        return comparison
      end
    end
    

    Obviously the above assumes attr1, and attr2 both have definitions for the spaceship operator. As well you'll need to determine what constitutes greater than, and less than, which is likely a bit difficult across two attributes. Which suggests that comparable may not be the proper code for your scenario.


    A more succinct and idiomatic way of writing this would be:

    def <=>(obj)
      self.attr1 <=> obj.attr1 == 0 ? self.attr2 <=> obj.attr2 : self.attr1 <=> obj.attr1
    end