class Dir def self.mkdir_p(name) sub = "" parts = name.split('/').reject { |e| e.empty? } parts.each do | part | sub << "/#{part}" mkdir sub rescue nil end end end # Module to help with serialization and deserialization of any type of data module Serdes module ClassMethods def serdes_add_to_fields(name, type = nil) @serdes_fields ||= [] info = { :name => name, :type => type } @serdes_fields << info end def serdes_reader(name, type = nil) serdes_add_to_fields(name, type) attr_reader(name) end def serdes_writer(name) serdes_add_to_fields(name, type = nil) attr_writer(name) end def serdes_accessor(name, type = nil) serdes_add_to_fields(name, type) attr_accessor(name) end def serdes_fields() @serdes_fields ||= [] return @serdes_fields end def serdes_register(obj) @serdes_loaded ||= {} @serdes_loaded[obj.id] = obj end def serdes_forget(id) @serdes_loaded ||= {} @serdes_loaded.delete(id) end def serdes_loaded() @serdes_loaded ||= {} return @serdes_loaded end def serdes_get(id) @serdes_loaded ||= {} return @serdes_loaded[id.to_sym] end def serdes_load_one(id) return nil unless id && !id.empty? full_name = Serdes.serdes_full_for(self, id) data, errors = Sitef.load_filename(full_name) unless data # log_error(errors.join(", ")) return nil end eldat = data.select do |el| el['id'].to_s == id.to_s end return nil unless eldat eldat = eldat.first return nil unless eldat typedat = {} self.serdes_fields.each do |info| name = info[:name] type = info[:type] value = eldat[name.to_s] typevalue = nil if type if type.respond_to?(:serdes_load) typevalue = type.serdes_load(value) elsif Kernel.respond_to?(type.to_sym) typevalue = Kernel.send(type.to_sym, value) rescue nil elsif type.respond_to(:new) typevalue = type.new(value) else typevalue = value end else typevalue = value end typedat[name] = typevalue end obj = self.new(typedat) return obj end def serdes_fetch(id) res = serdes_get(id) return res if res return serdes_load_one(id) end alias :fetch :serdes_fetch alias :load_one :serdes_load_one alias :get :serdes_get def from_serdes(id) return serdes_fetch(id) end def to_serdes(value) return value.id.to_s end end # include callback, be sure to extend the class with the ClassMethods def self.included(klass) klass.extend(ClassMethods) end def self.serdes_dir=(dir) @serdes_dir = dir end def self.serdes_dir @serdes_dir ||= File.join(Dir.pwd, 'data', 'var') @serdes_dir end def self.serdes_dir_for(klass) top = File.join(Serdes.serdes_dir, klass.to_s.gsub('::', '/').downcase) return top end def self.serdes_file_for(id) top = id.to_s.dup top << '.sitef' return top end def self.serdes_full_for(klass, id) tdir = serdes_dir_for(klass) tfil = serdes_file_for(id) return File.join(tdir, tfil) end def serdes_data data = {} self.class.serdes_fields.each do |info| name = info[:name] type = info[:type] type||= String key = "#{name}" value = "#{self.send(name.to_sym)}" if type.respond_to?(:to_serdes) wrapvalue = type.to_serdes(value) else wrapvalue = value.to_s end data[key] = wrapvalue end return data end def save_one Dir.mkdir_p Serdes.serdes_dir_for(self.class) data = serdes_data full_name = Serdes.serdes_full_for(self.class, self.id) Sitef.save_filename(full_name, [ data ] ) end def initialize(fields = {}) fields.each do |key, value| p "Setting #{key} #{value}" instance_variable_set("@#{key}", value) end self.class.serdes_register(self) end end