Feature #15240 ยป setducktyping15240.patch
lib/set.rb  

return self if instance_of?(Set) && klass == Set && block.nil? && args.empty?


klass.new(self, *args, &block)


end


alias to_st to_set


private def _to_st?(e)


if e.respond_to?(:to_st) && (s = e.to_st) && s.is_a?(Set)


s


end


end


def flatten_merge(set, seen = Set.new) # :nodoc:


set.each { e


if e.is_a?(Set)


if s = _to_st?(e)


e = s


if seen.include?(e_id = e.object_id)


raise ArgumentError, "tried to flatten recursive Set"


end


...  ...  
# Equivalent to Set#flatten, but replaces the receiver with the


# result in place. Returns nil if no modifications were made.


def flatten!


replace(flatten()) if any? { e e.is_a?(Set) }


replace(flatten()) if any? { e _to_st?(e) }


end


# Returns true if the set contains the given object.


...  ...  
case


when set.instance_of?(self.class) && @hash.respond_to?(:>=)


@hash >= set.instance_variable_get(:@hash)


when set.is_a?(Set)


when set = _to_st?(set)


size >= set.size && set.all? { o include?(o) }


else


raise ArgumentError, "value must be a set"


...  ...  
case


when set.instance_of?(self.class) && @hash.respond_to?(:>)


@hash > set.instance_variable_get(:@hash)


when set.is_a?(Set)


when set = _to_st?(set)


size > set.size && set.all? { o include?(o) }


else


raise ArgumentError, "value must be a set"


...  ...  
case


when set.instance_of?(self.class) && @hash.respond_to?(:<=)


@hash <= set.instance_variable_get(:@hash)


when set.is_a?(Set)


when set = _to_st?(set)


size <= set.size && all? { o set.include?(o) }


else


raise ArgumentError, "value must be a set"


...  ...  
case


when set.instance_of?(self.class) && @hash.respond_to?(:<)


@hash < set.instance_variable_get(:@hash)


when set.is_a?(Set)


when set = _to_st?(set)


size < set.size && all? { o set.include?(o) }


else


raise ArgumentError, "value must be a set"


...  ...  
# Set[1, 2, 3].intersect? Set[4, 5] #=> false


# Set[1, 2, 3].intersect? Set[3, 4] #=> true


def intersect?(set)


set.is_a?(Set) or raise ArgumentError, "value must be a set"


set = _to_st?(set) or raise ArgumentError, "value must be a set"


if size < set.size


any? { o set.include?(o) }


else


...  ...  
true


elsif other.instance_of?(self.class)


@hash == other.instance_variable_get(:@hash)


elsif other.is_a?(Set) && self.size == other.size


elsif (other = _to_st?(other)) && self.size == other.size


other.all? { o @hash.include?(o) }


else


false


...  ...  
end


def eql?(o) # :nodoc:


return false unless o.is_a?(Set)


return false unless o = _to_st?(o)


@hash.eql?(o.instance_variable_get(:@hash))


end


test/test_set.rb  

class TC_Set < Test::Unit::TestCase


class Set2 < Set


end


class ArraySet < Array


def self.[](*v)


new.concat(v)


end


alias to_st to_set


end


def test_aref


assert_nothing_raised {


...  ...  
set.superset?([2])


}


assert_equal(true, set.superset?(ArraySet[2]))


[Set, Set2].each { klass


assert_equal(true, set.superset?(klass[]), klass.name)


assert_equal(true, set.superset?(klass[1,2]), klass.name)


...  ...  
set.proper_superset?([2])


}


assert_equal(true, set.proper_superset?(ArraySet[2]))


[Set, Set2].each { klass


assert_equal(true, set.proper_superset?(klass[]), klass.name)


assert_equal(true, set.proper_superset?(klass[1,2]), klass.name)


...  ...  
set.subset?([2])


}


assert_equal(false, set.subset?(ArraySet[2]))


[Set, Set2].each { klass


assert_equal(true, set.subset?(klass[1,2,3,4]), klass.name)


assert_equal(true, set.subset?(klass[1,2,3]), klass.name)


...  ...  
set.proper_subset?([2])


}


assert_equal(false, set.proper_subset?(ArraySet[2]))


[Set, Set2].each { klass


assert_equal(true, set.proper_subset?(klass[1,2,3,4]), klass.name)


assert_equal(false, set.proper_subset?(klass[1,2,3]), klass.name)


...  ...  
case expected


when true


assert_send([set, :intersect?, other])


assert_send([other, :intersect?, set])


assert_send([other, :intersect?, set]) if other.is_a?(Set)


assert_not_send([set, :disjoint?, other])


assert_not_send([other, :disjoint?, set])


assert_not_send([other, :disjoint?, set]) if other.is_a?(Set)


when false


assert_not_send([set, :intersect?, other])


assert_not_send([other, :intersect?, set])


assert_not_send([other, :intersect?, set]) if other.is_a?(Set)


assert_send([set, :disjoint?, other])


assert_send([other, :disjoint?, set])


assert_send([other, :disjoint?, set]) if other.is_a?(Set)


when Class


assert_raise(expected) {


set.intersect?(other)


...  ...  
assert_intersect(ArgumentError, set, 3)


assert_intersect(ArgumentError, set, [2,4,6])


assert_intersect(true, set, ArraySet[2,4,6])


assert_intersect(true, set, set)


assert_intersect(true, set, Set[2,4])


...  ...  
assert_equal(set1, set1)


assert_equal(set1, set2)


assert_not_equal(Set[1], [1])


assert_equal(Set[1], ArraySet[1])


assert_equal(false, Set[1].eql?([1]))


assert_equal(true, Set[1].eql?(ArraySet[1]))


assert_equal(false, Set[1] == [1])


assert_equal(true, Set[1] == ArraySet[1])


set1 = Class.new(Set)["a", "b"]


set2 = Set["a", "b", set1]
