Provides Comparator and declarative definition of comparison operator.
Add this line to your application's Gemfile:
gem 'comparability'
And then execute:
$ bundle
Or install it yourself as:
$ gem install comparability
You can declaratively define your class's comparison with comparable_by
method.
To use, you need to extend your class with ComparableBy
module.
require 'comparability'
class MyClass
extend ComparableBy
attr_reader :a, :b, :c, :d, :e
comparable_by :a, # order of a
[:b, reverse: true], # reverse order of b
[:c, nil: :first], # order of c, ordered first if c is nil
[:d, reverse: true, nil: :last] # reverse order of d, ordered last if d is nil
->(_){ _.e.upcase }, # order of e, case-insensitive
end
Call of comparable_by
defines <=>
instance method, and includes Comparable
module.
Each parameter to comparable_by
should be either an instance of Comparator
or arguments to Comparator.create
in order of precedence.
Some pre-defined comparisons are accessible with special methods.
Other variations are created with Comparator.create
.
The most simple Comparator
which just evokes the comparison (spaceship) operator.
Comparator.natural_order # essentially compare(a,b) is defined as a <=> b
Comparator.natural_order(reverse: true) # b <=> a instead
This special Comparator
orders only by whether object is nil or not.
Comparator.prioritize_nil(:first) # nil is smaller
Comparator.prioritize_nil(:last) # nil is bigger
If you specify a symbol to Comparator.create
,
the comparator will compare objects by the results of the specified method.
Comparator.create(:size) # compares by size (prioritise smaller)
Comparator.create(:size, reverse: true) # compares by size (prioritise bigger)
You can use :nil
option to specify the priority of nil value.
Comparator.create(:priority, nil: :last) # compares by priority (prioritise smaller, last if nil)
Comparator.create(:priority, reverse: true, nil: :last) # compares by priority (prioritise bigger, last if nil)
The attribute method can be public or protected, but not private.
If you specify a proc with arity 1 to Comparator.create
,
the comparator will compare objects by the results of the specified proc yielding each object.
You can also pass the comparison as block.
Comparator.create { |str| str.length } # compares by length (prioritise shorter)
Comparator.create { |str| -str.length } # compares by length (prioritise longer)
If you specify a proc with arity 2 to Comparator.create
,
it creates a comparator defined by the specified proc.
You can also pass the comparison as block.
Comparator.create do |obj1, obj2|
# ... your comparison here ...
end
You can chain comparators with Comparator.chain
or its alias Comparator.[]
.
Comparator[comparator1, comparator2] # compares with comparator1, then tie-breaks with comparator2
You can reverse existing comparators with Comparator.reverse
.
Comparator.reverse(comparator) # reverses the order
Comparator#to_proc
returns a Proc
compatible with Enumerable#sort
.
You can use the ampersand shorthand to convert a comparator and pass as block.
comparator = Comparator[Comparator.prioritize_nil(:last),
Comparator.natural_order(reverse: true)]
[nil,1,2,3,4].sort(&comparator) # => [4, 3, 2, 1, nil]
- Fork it ( http://github.com/ippeiukai/comparability/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request