serdes.cr 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. class Dir
  2. def self.mkdir_p(name)
  3. sub = ""
  4. parts = name.split('/').reject { |e| e.empty? }
  5. parts.each do | part |
  6. sub << "/#{part}"
  7. mkdir sub rescue nil
  8. end
  9. end
  10. end
  11. # Module to help with serialization and deserialization of any type of data
  12. module Serdes
  13. module ClassMethods
  14. def serdes_add_to_fields(name, type = nil)
  15. @serdes_fields ||= []
  16. info = { :name => name, :type => type }
  17. @serdes_fields << info
  18. end
  19. def serdes_reader(name, type = nil)
  20. serdes_add_to_fields(name, type)
  21. attr_reader(name)
  22. end
  23. def serdes_writer(name)
  24. serdes_add_to_fields(name, type = nil)
  25. attr_writer(name)
  26. end
  27. def serdes_accessor(name, type = nil)
  28. serdes_add_to_fields(name, type)
  29. attr_accessor(name)
  30. end
  31. def serdes_fields()
  32. @serdes_fields ||= []
  33. return @serdes_fields
  34. end
  35. def serdes_register(obj)
  36. @serdes_loaded ||= {}
  37. @serdes_loaded[obj.id] = obj
  38. end
  39. def serdes_forget(id)
  40. @serdes_loaded ||= {}
  41. @serdes_loaded.delete(id)
  42. end
  43. def serdes_loaded()
  44. @serdes_loaded ||= {}
  45. return @serdes_loaded
  46. end
  47. def serdes_get(id)
  48. @serdes_loaded ||= {}
  49. return @serdes_loaded[id.to_sym]
  50. end
  51. def serdes_load_one(id)
  52. return nil unless id && !id.empty?
  53. full_name = Serdes.serdes_full_for(self, id)
  54. data, errors = Sitef.load_filename(full_name)
  55. unless data
  56. # log_error(errors.join(", "))
  57. return nil
  58. end
  59. eldat = data.select do |el|
  60. el['id'].to_s == id.to_s
  61. end
  62. return nil unless eldat
  63. eldat = eldat.first
  64. return nil unless eldat
  65. typedat = {}
  66. self.serdes_fields.each do |info|
  67. name = info[:name]
  68. type = info[:type]
  69. value = eldat[name.to_s]
  70. typevalue = nil
  71. if type
  72. if type.respond_to?(:serdes_load)
  73. typevalue = type.serdes_load(value)
  74. elsif Kernel.respond_to?(type.to_sym)
  75. typevalue = Kernel.send(type.to_sym, value) rescue nil
  76. elsif type.respond_to(:new)
  77. typevalue = type.new(value)
  78. else
  79. typevalue = value
  80. end
  81. else
  82. typevalue = value
  83. end
  84. typedat[name] = typevalue
  85. end
  86. obj = self.new(typedat)
  87. return obj
  88. end
  89. def serdes_fetch(id)
  90. res = serdes_get(id)
  91. return res if res
  92. return serdes_load_one(id)
  93. end
  94. alias :fetch :serdes_fetch
  95. alias :load_one :serdes_load_one
  96. alias :get :serdes_get
  97. def from_serdes(id)
  98. return serdes_fetch(id)
  99. end
  100. def to_serdes(value)
  101. return value.id.to_s
  102. end
  103. end
  104. # include callback, be sure to extend the class with the ClassMethods
  105. def self.included(klass)
  106. klass.extend(ClassMethods)
  107. end
  108. def self.serdes_dir=(dir)
  109. @serdes_dir = dir
  110. end
  111. def self.serdes_dir
  112. @serdes_dir ||= File.join(Dir.pwd, 'data', 'var')
  113. @serdes_dir
  114. end
  115. def self.serdes_dir_for(klass)
  116. top = File.join(Serdes.serdes_dir,
  117. klass.to_s.gsub('::', '/').downcase)
  118. return top
  119. end
  120. def self.serdes_file_for(id)
  121. top = id.to_s.dup
  122. top << '.sitef'
  123. return top
  124. end
  125. def self.serdes_full_for(klass, id)
  126. tdir = serdes_dir_for(klass)
  127. tfil = serdes_file_for(id)
  128. return File.join(tdir, tfil)
  129. end
  130. def serdes_data
  131. data = {}
  132. self.class.serdes_fields.each do |info|
  133. name = info[:name]
  134. type = info[:type]
  135. type||= String
  136. key = "#{name}"
  137. value = "#{self.send(name.to_sym)}"
  138. if type.respond_to?(:to_serdes)
  139. wrapvalue = type.to_serdes(value)
  140. else
  141. wrapvalue = value.to_s
  142. end
  143. data[key] = wrapvalue
  144. end
  145. return data
  146. end
  147. def save_one
  148. Dir.mkdir_p Serdes.serdes_dir_for(self.class)
  149. data = serdes_data
  150. full_name = Serdes.serdes_full_for(self.class, self.id)
  151. Sitef.save_filename(full_name, [ data ] )
  152. end
  153. def initialize(fields = {})
  154. fields.each do |key, value|
  155. p "Setting #{key} #{value}"
  156. instance_variable_set("@#{key}", value)
  157. end
  158. self.class.serdes_register(self)
  159. end
  160. end