summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/set.rb19
-rw-r--r--test/test_set.rb18
2 files changed, 34 insertions, 3 deletions
diff --git a/lib/set.rb b/lib/set.rb
index cb07037e82..625046d37c 100644
--- a/lib/set.rb
+++ b/lib/set.rb
@@ -45,9 +45,9 @@
# == Comparison
#
# The comparison operators <, >, <=, and >= are implemented as
-# shorthand for the {proper_,}{subset?,superset?} methods. However,
-# the <=> operator is intentionally left out because not every pair of
-# sets is comparable ({x, y} vs. {x, z} for example).
+# shorthand for the {proper_,}{subset?,superset?} methods.
+# The <=> operator reflects this order, or return `nil` for
+# sets that both have distinct elements ({x, y} vs. {x, z} for example).
#
# == Example
#
@@ -302,6 +302,19 @@ class Set
end
alias < proper_subset?
+ # Returns 0 if the set are equal,
+ # -1 / +1 if the set is a proper subset / superset of the given set,
+ # or nil if they both have unique elements.
+ def <=>(set)
+ return unless set.is_a?(Set)
+
+ case size <=> set.size
+ when -1 then -1 if proper_subset?(set)
+ when +1 then +1 if proper_superset?(set)
+ else 0 if self.==(set)
+ end
+ end
+
# Returns true if the set and the given set have at least one
# element in common.
#
diff --git a/test/test_set.rb b/test/test_set.rb
index 54ef80b067..05431e4c63 100644
--- a/test/test_set.rb
+++ b/test/test_set.rb
@@ -332,6 +332,24 @@ class TC_Set < Test::Unit::TestCase
}
end
+ def test_spacecraft_operator
+ set = Set[1,2,3]
+
+ assert_nil(set <=> 2)
+
+ assert_nil(set <=> set.to_a)
+
+ [Set, Set2].each { |klass|
+ assert_equal(-1, set <=> klass[1,2,3,4], klass.name)
+ assert_equal( 0, set <=> klass[3,2,1] , klass.name)
+ assert_equal(nil, set <=> klass[1,2,4] , klass.name)
+ assert_equal(+1, set <=> klass[2,3] , klass.name)
+ assert_equal(+1, set <=> klass[] , klass.name)
+
+ assert_equal(0, Set[] <=> klass[], klass.name)
+ }
+ end
+
def assert_intersect(expected, set, other)
case expected
when true