def SuperStruct.new(*args)
@table = []
@setsyms = []
klass = Class.new
if (args.size == 1) && (args[0].is_a? Array)
args = args[0]
end
strs = args.map {|x| x.to_s }
args.each_with_index do |k,i|
case
when (! [String,Symbol].include? k.class)
raise ArgumentError, "Need a String or Symbol"
when (strs[i] !~ /[_a-zA-Z][_a-zA-Z0-9]*/)
raise ArgumentError, "Illegal character"
end
k = k.intern if k.is_a? String
@table << k
@setsyms << (k.to_s + "=").intern
klass.instance_eval { attr_accessor k }
end
setsyms = @setsyms
table = @table
vals = @vals
klass.class_eval do
attr_reader :singleton
define_method(:initialize) do |*vals|
n = vals.size
m = table.size
case
when n < m
when n > m
raise ArgumentError, "Too many arguments (#{n} for #{m})"
end
setsyms.each_with_index do |var,i|
self.send(var,vals[i])
end
end
define_method(:pretty_print) do |q|
q.object_group(self) do
q.seplist(self.members, proc { q.text "," }) do |member|
q.breakable
q.text member.to_s
q.text '='
q.group(1) do
q.breakable ''
q.pp self[member]
end
end
end
end
define_method(:inspect) do
str = "#<#{self.class}:"
table.each {|item| str << " #{item}=#{self.send(item)}" }
str + ">"
end
define_method(:[]) do |*index|
case index.map {|x| x.class }
when [Fixnum]
self.send(table[*index])
when [Fixnum,Fixnum], [Range]
table[*index].map {|x| self.send(x)}
when [String]
self.send(index[0].intern)
when [Symbol]
self.send(index[0])
else
raise ArgumentError,"Illegal index"
end
end
define_method(:[]=) do |*index|
value = index[-1]
index = index[0..-2]
case index.map {|x| x.class }
when [Fixnum]
self.send(table[*index])
when [Fixnum,Fixnum], [Range]
setsyms[*index].map {|x| self.send(x,value) }
when [String]
self.send(index[0].intern,value)
when [Symbol]
self.send(index[0],value)
else
raise ArgumentError,"Illegal index"
end
end
define_method(:to_a) { table.map {|x| eval("@"+x.to_s) } }
define_method(:to_ary) { to_a }
define_method(:members) { table.map {|x| x.to_s } }
define_method(:to_struct) do
mems = table
Struct.new("TEMP",*mems)
data = mems.map {|x| self.send(x) }
Struct::TEMP.new(*data)
end
define_method(:to_hash) do
hash = {}
table.each do |mem|
mem = mem.to_s
hash.update(mem => self.send(mem))
end
hash
end
define_method(:set) {|h| h.each_pair {|k,v| send(k.to_s+"=",v) } }
@singleton = class << self
self
end
@singleton.instance_eval do
define_method(:members) do
table.map {|x| x.to_s }
end
me = self
define_method(:attr_tester) do |*syms|
syms.each {|sym| alias_method(sym.to_s+"?",sym) }
end
end
end
klass
end