Skip to content

Repository files navigation

attr_comparable gem

Mix-in to make a class Comparable, declaratively

Use attr_compare <attribute list> to declare the attributes which should be compared, in their order of precedence. Attributes may be nil. nil attributes sort earlier than non-nil to match the SQL behavior for NULL.

Example without AttrComparable

Consider this value class that holds full names:

classFullNameincludeComparableattr_reader:first,:middle,:last,:suffixdefinitialize(first,middle,last,suffix=nil)@first=first@middle=middle@last=last@suffix=suffixenddef <=>(other)(last <=> other.last).nonzero? ||
(first <=> other.first).nonzero? ||
(middle <=> other.middle).nonzero? ||
suffix <=> other.suffixenddefto_sno_suffix=[first.presence,middle.presence,last.presence].compact.join(' ')[no_suffix,suffix.presence].compact.join(', ')endend

You can see that the <=> method isn't very DRY, and as shown it doesn't even work with nil. (That's just too ugly to show.)

Example with AttrComparable

Here it is using the gem. Only the 2 lines with the comments are needed.

require'attr_comparable'require'active_support'classFullNameincludeAttrComparable# AttrComparable automatically includes Comparableattr_compare:last,:first,:middle,:suffix# will be compared in this precedence orderattr_reader:first,:middle,:last,:suffixdefinitialize(first,middle,last,suffix=nil)@first=first@middle=middle@last=last@suffix=suffixenddefto_sno_suffix=[first.presence,middle.presence,last.presence].compact.join(' ')[no_suffix,suffix.presence].compact.join(', ')endend

Example Usage

>> mom=FullName.new("Kathy",nil,"Doe")
>> dad=FullName.new("John","Q.","Public")
>> junior=FullName.new("John","Q.","Public","Jr.")
>> junior > dad=>true
>> [junior,mom,dad].sort.map &:to_s=>["Kathy Doe","John Q. Public","John Q. Public, Jr."]

About

AttrComparable gem

Resources

Stars

7 stars

Watchers

41 watching

Forks

Releases

Packages

Used by

Contributors

Languages