Skip to content

Instantly share code, notes, and snippets.

@fallengiants
Last active December 11, 2015 14:29
Show Gist options
  • Select an option

  • Save fallengiants/4614254 to your computer and use it in GitHub Desktop.

Select an option

Save fallengiants/4614254 to your computer and use it in GitHub Desktop.
I need to modify this thing badly, it's old and not good.
=begin
dex.rb: Dex Recursive Data Structure
Functionality:
1. dx = Dex.new( hash of values OR a list of arguments to schematize- see #3)
2. dx.a.b.c = 5
[creates Dex children b and b.c and sets b.c to 5]
3. dx.agelimits.schema(21, :drinking_age, :adulthood)
[creates Dex child agelimits, sets default value to 21, and creates
agelimits.drinking_age and agelimits.adulthood]
4. dx.agelimits.alert(:change, :adulthood, '@data[:adulthood] = 21; parent.changed += 1')
[adds a proc object equal to the eval'd code in arg[2] to either :change or :fetch
as specified. Note that just setting 'adulthood=21' would trigger infinite recursion.
This example resets the adulthood value to 21, then sets dx.changed to 1 plus its original
value. Note also that dx.changed must already have a numeric value in this case, or you'll
trigger an error.]
5. dx.save('filename')
Saves as a Base64 encoded, marshalled file. Dex.load(filename) will
reload the object.
Dex instances duplicate the each_key, each, collect, select, and keys
functionality of their @data hashes (more or less).
=end
require 'base64'
class String
def symbolize
tr(' ','_').gsub(/\W/,'').intern
end
end
class Symbol
def symbolize; self; end
def gsub(*args); id2name.gsub(*args).symbolize; end
end
class Object
def meta; class << self; self; end; end
end
#Clean Version of Dex
class Dex
attr_accessor :data
attr_accessor :filename
attr_reader :parent
def initialize(*hs)
@parent = nil
@data = Hash.new(nil)
@alert = {:fetch => Hash.new(lambda{nil}), :change => Hash.new(lambda{nil})}
if hs
if hs[0].is_a?(Hash)
hs[0].each_pair {|k,v| add(k,v)}
else
schema(hs)
end
end
@filename = %Q{./._#{object_id}.dex}
end
def ==(obj); if obj.kind_of?(Dex) then @data == obj.data; end; end
def add(k, v=@data.default)
k = sym( k.to_s.gsub('=',''))
unless self.respond_to?(k)
meta.send(:define_method, k) {trigger(:fetch,k); @data[k]}
meta.send(:define_method, (k.id2name+'=').intern) {|*x| @data[k]=x.shift; trigger(:change,k); @data[k]}
end
@data[k] = (v.kind_of?(Hash) ? Dex.new(v) : v)
end
def adopt(par)
@parent = par
end
def alert(s,md, fn)
alertintegrity
@alert[sym(s)][sym(md)] = Proc.new { instance_eval fn }
end
def collect(&blk)
rv = initialize_copy(@data)
@data.each_pair do |k,v|
k0,v0 = blk.call(k,v) rescue [k,v]
unless k.is_a?(Symbol) && v0
v0,k0 = k0, k
end
rv[k1]=v1
end
return rv
end
def collect!(&blk); @data = collect(&blk); end
def default; @data.default; end
def each(&blk); md(&blk); end
def each_key(&blk); md(:each_key, &blk); end
def keys; @data.keys; end
def select(&blk); md(:select, &blk); end
def initialize_copy(orig); super; @data=data.dup; end
def Dex.load(fn); Marshal.load(Base64.decode64(IO.read(fn))); end
def marshal_load(x); @data = x; md(:each_pair) {|k,v| add(k,v)}; end
def method_missing(md, *args)
if @data.has_key?(md) then @data[md].send(*args)
elsif @data.respond_to?(md) then @data.send(md, *args)
else
@data[md] = create
st = md.id2name =~ /=$/
md = md.gsub(/=/,'') if st
add(md, args[0] || @data[md])
if st || args.empty?
return @data[md]
else
return @data[md].send(*args)
end
end
end
def save(fn=nil)
@filename = fn unless fn.nil?
tmp = File.open(@filename, 'w')
tmp.write(Base64.encode64(Marshal.dump(self)))
tmp.close
end
def schema(*args)
@data.default=args.shift
args.each {|x| add(x)}
end
def set_default(x); @data.default=x; end
def pass(*args)
md = sym(args.shift)
if data.has_key?(md)
if args.empty?
return @data[md]
else
args.unshift(:pass?) if @data[md].kind_of?(Dex)
@data[md].send(*args)
end
else
false
end
end
alias_method :each_pair, :each
alias_method :marshal_dump, :data
private
def create(*args)
rv = Dex.new(*args)
rv.adopt(self)
return rv
end
def md(md=:each_pair, &blk)
@data.method(md).call {|*x| blk.call(*x)}
end
def sym(x)
x=x.symbolize
raise "Symbol is empty" if x.nil? || x.to_s.length < 1
x
end
def trigger(sm, key)
return nil unless key.respond_to?(:symbolize)
alertintegrity
key = sym(key)
if @alert[sm].has_key?(key)
@alert[sm][key].call
end
end
def alertintegrity
@alert ||= {}
@alert[:fetch] ||= Hash.new(lambda {nil})
@alert[:change] ||= Hash.new(lambda {nil})
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment