module RGen module Serializer class JsonSerializer def initialize(writer, opts={}) @writer = writer @elementIdentifiers = {} @identAttrName = opts[:identAttrName] || "name" @separator = opts[:separator] || "/" @leadingSeparator = opts.has_key?(:leadingSeparator) ? opts[:leadingSeparator] : true @featureFilter = opts[:featureFilter] @identifierProvider = opts[:identifierProvider] end def elementIdentifier(element) ident = @identifierProvider && @identifierProvider.call(element) ident || (element.is_a?(RGen::MetamodelBuilder::MMProxy) && element.targetIdentifier) || qualifiedElementName(element) end # simple identifier calculation based on qualified names # prerequisits: # * containment relations must be bidirectionsl # * local name stored in single attribute +@identAttrName+ for all classes # def qualifiedElementName(element) return @elementIdentifiers[element] if @elementIdentifiers[element] localIdent = ((element.respond_to?(@identAttrName) && element.getGeneric(@identAttrName)) || "").strip parentRef = element.class.ecore.eAllReferences.select{|r| r.eOpposite && r.eOpposite.containment}.first parent = parentRef && element.getGeneric(parentRef.name) if parent if localIdent.size > 0 parentIdent = qualifiedElementName(parent) result = parentIdent + @separator + localIdent else result = qualifiedElementName(parent) end else result = (@leadingSeparator ? @separator : "") + localIdent end @elementIdentifiers[element] = result end def serialize(elements) if elements.is_a?(Array) write("[ ") elements.each_with_index do |e, i| serializeElement(e) write(",\n") unless i == elements.size-1 end write("]") else serializeElement(elements) end end def serializeElement(element, indent="") write(indent + "{ \"_class\": \""+element.class.ecore.name+"\"") element.class.ecore.eAllStructuralFeatures.each do |f| next if f.derived value = element.getGeneric(f.name) unless value == [] || value.nil? || (f.is_a?(RGen::ECore::EReference) && f.eOpposite && f.eOpposite.containment) || (@featureFilter && !@featureFilter.call(f)) write(", ") writeFeature(f, value, indent) end end write(" }") end def writeFeature(feat, value, indent) write("\""+feat.name+"\": ") if feat.is_a?(RGen::ECore::EAttribute) if value.is_a?(Array) write("[ "+value.collect{|v| attributeValue(v, feat)}.join(", ")+" ]") else write(attributeValue(value, feat)) end elsif !feat.containment if value.is_a?(Array) write("[ "+value.collect{|v| "\""+elementIdentifier(v)+"\""}.join(", ")+" ]") else write("\""+elementIdentifier(value)+"\"") end else if value.is_a?(Array) write("[ \n") value.each_with_index do |v, i| serializeElement(v, indent+" ") write(",\n") unless i == value.size-1 end write("]") else write("\n") serializeElement(value, indent+" ") end end end def attributeValue(value, a) if a.eType == RGen::ECore::EString || a.eType.is_a?(RGen::ECore::EEnum) "\""+value.to_s.gsub('\\','\\\\\\\\').gsub('"','\\"').gsub("\n","\\n").gsub("\r","\\r"). gsub("\t","\\t").gsub("\f","\\f").gsub("\b","\\b")+"\"" else value.to_s end end private def write(s) @writer.write(s) end end end end