require 'uuid'
ObjectSpace; alias :each :each_object; include Enumerable; end
class AwesomeSet
include Enumerable
def initialize ary = []
@uuid = UUID.create.to_s
@m = "is_in_awesomeset_#{@uuid}?".to_sym
ary.each {|o| add(o)}
end
def & set
AwesomeSet.new select {|o| set.member? o}
end
alias :intersection :&
def | set
AwesomeSet.new(to_a + set.to_a)
end
alias :+ :|
def - set
AwesomeSet.new select {|o| !set.member?(o)}
end
alias :difference :-
def == set
to_a == obj.to_a
end
def ^ set
(self | set) - (self & set)
end
def add obj
return if member? obj
obj.define_method @m { true }
end
alias :<< :add
def add? obj
r = member?(obj) ? self : nil
add obj
r
end
def classify
h = {}
to_a.each do |o|
r = yield(o)
h[r] ||= []
h[r] << o
end
h
end
def clear
each {|o| delete(o)}
self
end
def collect!
items = map {|o| yield o}
clear
items.each {|o| add o}
self
end
alias :map! :collect!
def delete obj
obj.undef(@m)
end
def delete? obj
r = member?(obj) ? self : nil
delete obj
r
end
def delete_if? &b
reject! &b
self
end
def divide &blk
Set.new( self).divide(&blk)
end
def each &blk
to_a.each &blk
end
def empty?
to_a.empty?
end
def flatten
flat = AwesomeSet.new
each {|o| o.responds_to?(:flatten) ? flat.merge(o.flatten) : flat.add(o)}
flat
end
def flatten!
c = nil
select {|o| o.responds_to?(:flatten) }.each do |o|
c = self
merge(o.flatten)
delete(o)
end
c
end
def member? obj
obj.send @m
end
alias :include? :member
def initialize_copy(orig)
clear
merge orig.to_a
end
alias :merge :initialize_copy
def inspect
"#<AwesomeSet: " + map(&:inspect).join(", ") + ">"
end
def keep_if &b
reject! &b
self
end
def reject!
r = nil
delete_if do |o|
r = self
! yield(o)
end
r
end
def size
to_a.size
end
alias :size :length
def merge set
set.each {|o| add o}
self
end
def proper_subset? set
each {|o| return false unless set.member? o}
end
alias :subset? :proper_subset?
def proper_superset? set
set.each {|o| return false unless member? o}
end
alias :superset? :proper_superset?
def reject!
r = nil
each do |o|
r = self
delete(o) if yield(o)
end
r
end
def to_a
ObjectSpace.select(&@m)
end
end