<<Метапрограммирование на Ruby
Лекция 8. Реализация класса Set
Класс Set
Класс Set присутствует в стандартной библиотеке Ruby.
Попробуем реализовать его сами.
def extract_options(ary)
if ary.last.is_a?(Hash)
ary.pop
else
{}
end
end
class Module
def delegate(*args)
options = extract_options(args)
to = options[:to]
args.each do |method|
define_method(method) do |*args|
send(to).send(method, *args)
end
end
end
end
class Set
def initialize(*elements)
@data = {}
elements.each do |e|
@data[e] = true
end
end
attr_accessor :data
private :data
delegate :size, :delete, :include?, :to => :data
def insert(x)
@data[x] = true
end
alias :<< :insert
def each(&block)
@data.each_key do |key|
block[key]
end
end
alias :=== :include?
def to_a
@data.keys
end
def join!(s)
if s.respond_to?(:each)
s.each do |e|
self << e
end
self
else
raise ArgumentError
end
end
def +(s)
self.dup.join!(s)
end
def minus!(s)
if s.respond_to?(:each)
s.each do |e|
delete(e)
end
self
else
raise ArgumentError
end
end
def -(s)
self.dup.minus!(s)
end
def intersect!(s)
if s.respond_to?(:each)
s = s.to_set
to_a.each do |e|
self.delete(e) unless s.include?(e)
end
else
raise ArgumentError
end
end
include Enumerable
end
Метод to_set
Добавим метод
to_set
всем контейнерам сразу:
Enumerable.module_eval do
def to_set
inject(Set.new) do |s,e|
s << e
end
end
end
Тестирование
# здесь опущено определение класса Set,
# данное выше
if $0 == __FILE__
require 'test/unit'
class SetTest < Test::Unit::TestCase
def ttttinitialize(test_method)
@s = Set.new
@s << 1
@s << 2
@s << 1
test_method.to_sym
end
def test_include
@s = Set.new
@s << 1
@s << 2
@s << 1
assert(@s.include?(1))
assert(@s.include?(2))
assert(!@s.include?(3))
assert_equal([1,2], @s.to_a.sort)
end
def test_delete
@s = Set.new
@s << 1
@s << 2
@s << 1
@s.delete(1)
assert(!@s.include?(1))
assert(@s.include?(2))
end
def test_plus_and_minus
a = [1,2,3,4,5,6]
b = [4,3,1,6,7,8,9]
sa = Set.new(*a)
sb = Set.new(*b)
sc = Set.new(1,2,3)
assert((a - b).uniq.sort, (sa - sb).to_a.sort)
assert((a + b).uniq.sort, (sa + sb).to_a.sort)
end
end
end
--
ArtemVoroztsov - 22 Apr 2010