Re-enable spec/library for full CI runs.
[rbx.git] / kernel / core / comparable.rb
blob37873f88600daf2310a30e9f6299c6e3324afe31
1 # depends on: module.rb
3 ##
4 # The Comparable mixin is used by classes whose objects may be ordered. The
5 # class must define the <tt><=></tt> (spaceship) operator, which compares the
6 # receiver against another object, returning -1, 0, or +1 depending on whether
7 # the receiver is less than, equal to, or greater than the other object.
9 # Comparable uses <tt><=></tt> to implement the conventional comparison
10 # operators (<tt><</tt>, <tt><=</tt>, <tt>==</tt>, <tt>>=</tt>, and
11 # <tt>></tt>) and the method <tt>between?</tt>.
13 #   class SizeMatters
14 #     include Comparable
15 #     attr :str
16 #     def <=>(other)
17 #       str.size <=> other.str.size
18 #     end
19 #     def initialize(str)
20 #       @str = str
21 #     end
22 #     def inspect
23 #       @str
24 #     end
25 #   end
26 #   
27 #   s1 = SizeMatters.new "Z"
28 #   s2 = SizeMatters.new "YY"
29 #   s3 = SizeMatters.new "XXX"
30 #   s4 = SizeMatters.new "WWWW"
31 #   s5 = SizeMatters.new "VVVVV"
32 #   
33 #   s1 < s2                       #=> true
34 #   s4.between? s1, s3            #=> false
35 #   s4.between? s3, s5            #=> true
36 #   [ s3, s2, s5, s4, s1 ].sort   #=> [Z, YY, XXX, WWWW, VVVVV]
38 module Comparable
40   # Compares two objects based on the receiver's <code><=></code>
41   # method, returning true if it returns 0. Also returns true if
42   # _obj_ and _other_ are the same object.
43   def ==(other)
44     return true if self.equal?(other)
45     
46     return unless c = (self <=> other)
47     return c == 0 if c.is_a?(Numeric)
49     raise ArgumentError, "comparison of #{self.class} with #{other.class} failed"
50   rescue StandardError
51     return nil
52   end
54   #  Compares two objects based on the receiver's <code><=></code>
55   #  method, returning true if it returns 1.
56   def >(other)
57     __internal_compare__(other) > 0
58   end
60   #  Compares two objects based on the receiver's <code><=></code>
61   #  method, returning true if it returns 0 or 1.
62   def >=(other)
63     __internal_compare__(other) >= 0
64   end
66   #  Compares two objects based on the receiver's <code><=></code>
67   #  method, returning true if it returns -1.
68   def <(other)
69     __internal_compare__(other) < 0
70   end
72   #  Compares two objects based on the receiver's <code><=></code>
73   #  method, returning true if it returns -1 or 0.
74   def <=(other)
75     __internal_compare__(other) <= 0
76   end
77   
78   #  Returns <code>false</code> if <i>obj</i> <code><=></code>
79   #  <i>min</i> is less than zero or if <i>anObject</i> <code><=></code>
80   #  <i>max</i> is greater than zero, <code>true</code> otherwise.
81   #     
82   #     3.between?(1, 5)               #=> true
83   #     6.between?(1, 5)               #=> false
84   #     'cat'.between?('ant', 'dog')   #=> true
85   #     'gnu'.between?('ant', 'dog')   #=> false
86   #     
87   def between?(min, max)
88     (min <= self) && (self <= max)
89   end
90   
91   # TODO: mark as internal only
92   #private
93   def __internal_compare__(other)
94     unless result = (self <=> other)
95       raise ArgumentError, "comparison of #{self.class} with #{other.class} failed"
96     end
97     
98     return result
99   end