File: model_comparator_base.rb

package info (click to toggle)
ruby-rgen 0.10.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,428 kB
  • sloc: ruby: 11,344; xml: 1,368; yacc: 72; makefile: 10
file content (142 lines) | stat: -rw-r--r-- 3,482 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
require 'andand'

module RGen

module Util
	
class ModelComparatorBase
	
	CompareSpec = Struct.new(:identifier, :recurse, :filter, :ignore_features, :display_name, :sort)
	INDENT = "  "	

	class << self
		attr_reader :compareSpecs
		
		def compare_spec(clazz, hash)
			@compareSpecs ||= {}
			raise "Compare spec already defined for #{clazz}" if @compareSpecs[clazz]
			spec = CompareSpec.new
			hash.each_pair do |k,v|
				spec.send("#{k}=",v)
			end
			@compareSpecs[clazz] = spec
		end
	end
	
	# compares two sets of elements
	def compare(as, bs, recursive=true)
		result = []
		aById = as.select{|e| useElement?(e)}.inject({}){|r, e| r[elementIdentifier(e)] = e; r}
		bById = bs.select{|e| useElement?(e)}.inject({}){|r, e| r[elementIdentifier(e)] = e; r}
		onlyA = sortElements((aById.keys - bById.keys).collect{|id| aById[id]})
		onlyB = sortElements((bById.keys - aById.keys).collect{|id| bById[id]})
		aAndB = sortElementPairs((aById.keys & bById.keys).collect{|id| [aById[id], bById[id]]})
		onlyA.each do |e|
			result << "- #{elementDisplayName(e)}"
		end
		onlyB.each do |e|
			result << "+ #{elementDisplayName(e)}"
		end
		if recursive
			aAndB.each do |ab|
				a, b = *ab
				r = compareElements(a, b)
				if r.size > 0
					result << "#{elementDisplayName(a)}"
					result += r.collect{|l| INDENT+l}
				end
			end
		end
		result
	end
	
	def sortElementPairs(pairs)
		pairs.sort do |x,y|
			a, b = x[0], y[0]
			r = a.class.name <=> b.class.name
			r = compareSpec(a).sort.call(a,b) if r == 0 && compareSpec(a) && compareSpec(a).sort
			r
		end
	end
	
	def sortElements(elements)
		elements.sort do |a,b|
			r = a.class.name <=> b.class.name
			r = compareSpec(a).sort.call(a,b) if r == 0 && compareSpec(a) && compareSpec(a).sort
			r
		end
	end
	
	def elementDisplayName(e)
		if compareSpec(e) && compareSpec(e).display_name
			compareSpec(e).display_name.call(e)
		else
			elementIdentifier(e)
		end
	end
	
	def compareElements(a, b)
		result = []
		if a.class != b.class
			result << "Class: #{a.class} -> #{b.class}"
		else
			a.class.ecore.eAllStructuralFeatures.reject{|f| f.derived || compareSpec(a).andand.ignore_features.andand.include?(f.name.to_sym)}.each do |f|
				va, vb = a.getGeneric(f.name), b.getGeneric(f.name)
				if f.is_a?(RGen::ECore::EAttribute)
					r = compareValues(f.name, va, vb)
					result << r if r
				else
					va, vb = [va].compact, [vb].compact unless f.many
					r = compare(va, vb, f.containment || compareSpec(a).andand.recurse.andand.include?(f.name.to_sym))
					if r.size > 0
						result << "[#{f.name}]"
						result += r.collect{|l| INDENT+l}
					end
				end	
			end
		end
		result
	end
	
	def compareValues(name, val1, val2)
		result = nil
		result = "[#{name}] #{val1} -> #{val2}" if val1 != val2
		result
	end
	
	def elementIdentifier(element)
		cs = compareSpec(element)
		if cs && cs.identifier
			if cs.identifier.is_a?(Proc)
				cs.identifier.call(element)
			else
				cs.identifier
			end
		else
			if element.respond_to?(:name)
				element.name
			else
				element.object_id
			end
		end
	end
	
	def useElement?(element)
		cs = compareSpec(element)
		!(cs && cs.filter) || cs.filter.call(element)
	end
	
	def compareSpec(element)
		@compareSpec ||= {}
		return @compareSpec[element.class] if @compareSpec[element.class]
		return nil unless self.class.compareSpecs
		key = self.class.compareSpecs.keys.find{|k| element.is_a?(k)}
		@compareSpec[element.class] = self.class.compareSpecs[key]
	end
	
end

end

end