lib/bake/mergeConfig.rb in bake-toolkit-2.20.4 vs lib/bake/mergeConfig.rb in bake-toolkit-2.21.0

- old
+ new

@@ -1,209 +1,209 @@ -require 'common/ext/rtext' - -module Bake - - class MergeConfig - - def initialize(child, parent) - @child = child - @parent = parent - end - - def self.clone(obj) - if obj.is_a?(Metamodel::ModelElement) - cloneModelElement(obj) - elsif Array === obj - obj.map { |o| clone(o) } - else - obj # no clone, should not happen - end - end - - def self.cloneModelElement(obj) - cpy = obj.class.new - cpy.file_name = obj.file_name - obj.class.ecore.eAllStructuralFeatures.each do |f| - value = obj.getGeneric(f.name) - if f.is_a?(RGen::ECore::EReference) && f.containment - if value.is_a?(Array) - cpy.setGeneric(f.name, value.collect{|v| clone(v)}) - elsif !value.nil? - cpy.setGeneric(f.name, clone(value)) - end - elsif f.is_a?(RGen::ECore::EAttribute) - cpy.setGeneric(f.name, value) if obj.eIsSet(f.name) - end - end - cpy - end - - - def replace() - @child.class.ecore.eAllReferences.each do |f| - next unless @parent.class.ecore.eAllReferences.include?f - next unless f.containment - childData = @child.getGeneric(f.name) - if Metamodel::ModelElement === childData - @parent.setGeneric(f.name,childData) if !childData.nil? - elsif Array === childData - if !childData.empty? - parentData = @parent.getGeneric(f.name) - cclasses = childData.map { |c| c.class }.uniq - parentData.delete_if { |p| cclasses.include?p.class } - parentData += childData - @parent.setGeneric(f.name,parentData) - end - end - end - end - - def hasSubNodes(elem) - elem.class.ecore.eAllReferences.each do |f| - next unless f.containment - elemData = elem.getGeneric(f.name) - return true if (Array === elemData && !elemData.empty?) - return true if (Metamodel::ModelElement === elemData) - end - false - end - - def sameAttr(childData, parentData) - childData.class.ecore.eAllAttributes.all? { |a| - a.eAnnotations.each do |x| x.details.each do |y| - return true if (y.key == :internal and y.value == true) - end; end - a.name == "line_number" || (not childData.eIsSet(a.name)) || (childData.getGeneric(a.name) == parentData.getGeneric(a.name)) - } - end - - def removeChilds(childElem, parentElem) - return if childElem.nil? or parentElem.nil? - - childElem.class.ecore.eAllReferences.each do |f| - next unless f.containment - begin - childData = childElem.getGeneric(f.name) - parentData = parentElem.getGeneric(f.name) - rescue Exception => ex - next # how to check fast if f.name is valid? - end - next if childData.nil? or parentData.nil? - if (Array === childData) - if !parentData.empty? && !childData.empty? - childData.each do |c| - cN = hasSubNodes(c) - toRemove = [] - parentData.each do |p| - next if p.class != c.class - if (not cN) - if sameAttr(c, p) - toRemove << p - end - else - removeChilds(c, p); - end - end - toRemove.each do |r| - parentElem.removeGeneric(f.name, r) - end - end - end - elsif Metamodel::ModelElement === childData - if parentData.class == childData.class && sameAttr(childData, parentData) - cN = hasSubNodes(childData) - if (not cN) - parentElem.setGeneric(f.name, nil) - else - removeChilds(childData, parentData) - end - end # otherwise not equal, will not be deleted - end - end - end - - def extendAttributes(childData, parentData) - parentData.class.ecore.eAllAttributes.each do |a| - childData.setGeneric(a.name, parentData.getGeneric(a.name)) if !childData.eIsSet(a.name) && parentData.eIsSet(a.name) - end - end - - def extend(child, parent) - (parent.class.ecore.eAllReferences & child.class.ecore.eAllReferences).each do |f| - next unless f.containment - parentData = parent.getGeneric(f.name) - next if parentData.nil? or (Array === parentData && parentData.empty?) - childData = child.getGeneric(f.name) - - if Array === parentData - if f.name == "compiler" - extendedParentData = [] - parentData.each do |p| - c = childData.find { |c| p.ctype == c.ctype } - if c - extendAttributes(c, p) - extend(c, p) - extendedParentData << c - else - extendedParentData << p - end - end - restOfChildData = childData.find_all { |c| parentData.find {|p| p.ctype != c.ctype } } - child.setGeneric(f.name, extendedParentData + restOfChildData) - else - child.setGeneric(f.name, parentData + childData) - end - elsif Metamodel::ModelElement === parentData - if childData.nil? || childData.class != parentData.class - child.setGeneric(f.name, parentData) - else - extendAttributes(childData, parentData) - extend(childData, parentData) - end - end - end - end - - def copyChildToParent(c, p) - (p.class.ecore.eAllReferences & c.class.ecore.eAllReferences).each do |f| - next unless f.containment - childData = c.getGeneric(f.name) - next if childData.nil? || (Array === childData && childData.empty?) - p.setGeneric(f.name, childData) - end - end - - def merge(type) - s = StringIO.new - ser = RText::Serializer.new(Language) - - if Bake.options.debug - s.puts "\n>>>> child <<<<" - ser.serialize(@child, s) - s.puts "\n>>>> parent <<<<" - ser.serialize(@parent, s) - end - - if (type == :remove) - removeChilds(@child, @parent) - elsif (type == :replace) - replace - elsif (type == :extend) - c = MergeConfig.clone(@child) - extend(c, @parent) - copyChildToParent(c, @parent) - elsif (type == :merge) - extend(@child, MergeConfig.clone(@parent)) - end - - if Bake.options.debug - s.puts "\n>>>> result of #{type.to_s} <<<<" - ser.serialize(type == :merge ? @child : @parent, s) - puts "#{s.string}" - end - - - end - - end - +require 'common/ext/rtext' + +module Bake + + class MergeConfig + + def initialize(child, parent) + @child = child + @parent = parent + end + + def self.clone(obj) + if obj.is_a?(Metamodel::ModelElement) + cloneModelElement(obj) + elsif Array === obj + obj.map { |o| clone(o) } + else + obj # no clone, should not happen + end + end + + def self.cloneModelElement(obj) + cpy = obj.class.new + cpy.file_name = obj.file_name + obj.class.ecore.eAllStructuralFeatures.each do |f| + value = obj.getGeneric(f.name) + if f.is_a?(RGen::ECore::EReference) && f.containment + if value.is_a?(Array) + cpy.setGeneric(f.name, value.collect{|v| clone(v)}) + elsif !value.nil? + cpy.setGeneric(f.name, clone(value)) + end + elsif f.is_a?(RGen::ECore::EAttribute) + cpy.setGeneric(f.name, value) if obj.eIsSet(f.name) + end + end + cpy + end + + + def replace() + @child.class.ecore.eAllReferences.each do |f| + next unless @parent.class.ecore.eAllReferences.include?f + next unless f.containment + childData = @child.getGeneric(f.name) + if Metamodel::ModelElement === childData + @parent.setGeneric(f.name,childData) if !childData.nil? + elsif Array === childData + if !childData.empty? + parentData = @parent.getGeneric(f.name) + cclasses = childData.map { |c| c.class }.uniq + parentData.delete_if { |p| cclasses.include?p.class } + parentData += childData + @parent.setGeneric(f.name,parentData) + end + end + end + end + + def hasSubNodes(elem) + elem.class.ecore.eAllReferences.each do |f| + next unless f.containment + elemData = elem.getGeneric(f.name) + return true if (Array === elemData && !elemData.empty?) + return true if (Metamodel::ModelElement === elemData) + end + false + end + + def sameAttr(childData, parentData) + childData.class.ecore.eAllAttributes.all? { |a| + a.eAnnotations.each do |x| x.details.each do |y| + return true if (y.key == :internal and y.value == true) + end; end + a.name == "line_number" || (not childData.eIsSet(a.name)) || (childData.getGeneric(a.name) == parentData.getGeneric(a.name)) + } + end + + def removeChilds(childElem, parentElem) + return if childElem.nil? or parentElem.nil? + + childElem.class.ecore.eAllReferences.each do |f| + next unless f.containment + begin + childData = childElem.getGeneric(f.name) + parentData = parentElem.getGeneric(f.name) + rescue Exception => ex + next # how to check fast if f.name is valid? + end + next if childData.nil? or parentData.nil? + if (Array === childData) + if !parentData.empty? && !childData.empty? + childData.each do |c| + cN = hasSubNodes(c) + toRemove = [] + parentData.each do |p| + next if p.class != c.class + if (not cN) + if sameAttr(c, p) + toRemove << p + end + else + removeChilds(c, p); + end + end + toRemove.each do |r| + parentElem.removeGeneric(f.name, r) + end + end + end + elsif Metamodel::ModelElement === childData + if parentData.class == childData.class && sameAttr(childData, parentData) + cN = hasSubNodes(childData) + if (not cN) + parentElem.setGeneric(f.name, nil) + else + removeChilds(childData, parentData) + end + end # otherwise not equal, will not be deleted + end + end + end + + def extendAttributes(childData, parentData) + parentData.class.ecore.eAllAttributes.each do |a| + childData.setGeneric(a.name, parentData.getGeneric(a.name)) if !childData.eIsSet(a.name) && parentData.eIsSet(a.name) + end + end + + def extend(child, parent) + (parent.class.ecore.eAllReferences & child.class.ecore.eAllReferences).each do |f| + next unless f.containment + parentData = parent.getGeneric(f.name) + next if parentData.nil? or (Array === parentData && parentData.empty?) + childData = child.getGeneric(f.name) + + if Array === parentData + if f.name == "compiler" + extendedParentData = [] + parentData.each do |p| + c = childData.find { |c| p.ctype == c.ctype } + if c + extendAttributes(c, p) + extend(c, p) + extendedParentData << c + else + extendedParentData << p + end + end + restOfChildData = childData.find_all { |c| parentData.find {|p| p.ctype != c.ctype } } + child.setGeneric(f.name, extendedParentData + restOfChildData) + else + child.setGeneric(f.name, parentData + childData) + end + elsif Metamodel::ModelElement === parentData + if childData.nil? || childData.class != parentData.class + child.setGeneric(f.name, parentData) + else + extendAttributes(childData, parentData) + extend(childData, parentData) + end + end + end + end + + def copyChildToParent(c, p) + (p.class.ecore.eAllReferences & c.class.ecore.eAllReferences).each do |f| + next unless f.containment + childData = c.getGeneric(f.name) + next if childData.nil? || (Array === childData && childData.empty?) + p.setGeneric(f.name, childData) + end + end + + def merge(type) + s = StringIO.new + ser = RText::Serializer.new(Language) + + if Bake.options.debug + s.puts "\n>>>> child <<<<" + ser.serialize(@child, s) + s.puts "\n>>>> parent <<<<" + ser.serialize(@parent, s) + end + + if (type == :remove) + removeChilds(@child, @parent) + elsif (type == :replace) + replace + elsif (type == :extend) + c = MergeConfig.clone(@child) + extend(c, @parent) + copyChildToParent(c, @parent) + elsif (type == :merge) + extend(@child, MergeConfig.clone(@parent)) + end + + if Bake.options.debug + s.puts "\n>>>> result of #{type.to_s} <<<<" + ser.serialize(type == :merge ? @child : @parent, s) + puts "#{s.string}" + end + + + end + + end + end \ No newline at end of file