File: environment.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 (129 lines) | stat: -rw-r--r-- 2,970 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
module RGen

# An Environment is used to hold model elements.
#
class Environment

	def initialize
		@elements = {}
		@subClasses = {}
		@subClassesUpdated = {}
    @deleted = {}
    @deletedClasses = {}
	end
	
	# Add a model element. Returns the environment so <code><<</code> can be chained.
	# 
	def <<(el)
		clazz = el.class
		@elements[clazz] ||= []
		@elements[clazz] << el
		updateSubClasses(clazz)
		self
	end

	# Removes model element from environment.
	def delete(el)
    @deleted[el] = true
    @deletedClasses[el.class] = true
	end
		
	# Iterates each element
	#
	def each(&b)
    removeDeleted
		@elements.values.flatten.each(&b)
	end
	
	# Return the elements of the environment as an array
	#
	def elements
    removeDeleted
		@elements.values.flatten
	end
	
	# This method can be used to instantiate a class and automatically put it into
	# the environment. The new instance is returned.
	#
	def new(clazz, *args)
		obj = clazz.new(*args)
		self << obj
		obj
	end
	
	# Finds and returns model elements in the environment.
	# 
	# The search description argument must be a hash specifying attribute/value pairs.
	# Only model elements are returned which respond to the specified attribute methods
	# and return the specified values as result of these attribute methods.
	# 
	# As a special hash key :class can be used to look for model elements of a specific
	# class. In this case an array of possible classes can optionally be given.
	# 
	def find(desc)
    removeDeleted
		result = []
		classes = desc[:class] if desc[:class] and desc[:class].is_a?(Array)
		classes = [ desc[:class] ] if !classes and desc[:class]
		if classes
			hashKeys = classesWithSubClasses(classes)
		else
			hashKeys = @elements.keys
		end
		hashKeys.each do |clazz|
			next unless @elements[clazz]
			@elements[clazz].each do |e|
				failed = false
				desc.each_pair { |k,v|
					failed = true if k != :class and ( !e.respond_to?(k) or e.send(k) != v )
				}
				result << e unless failed
			end
		end
		result
	end
	
	private

  def removeDeleted
    @deletedClasses.keys.each do |c|
      @elements[c].reject!{|e| @deleted[e]}
    end
    @deletedClasses.clear
    @deleted.clear
  end
	
	def updateSubClasses(clazz)
		return if @subClassesUpdated[clazz]
		if clazz.respond_to?( :ecore )
			superClasses = clazz.ecore.eAllSuperTypes.collect{|c| c.instanceClass}
		else
			superClasses = superclasses(clazz)
		end
		superClasses.each do |c|
			next if c == Object
			@subClasses[c] ||= []
			@subClasses[c] << clazz
		end
		@subClassesUpdated[clazz] = true
	end	
	
	def classesWithSubClasses(classes)
		result = classes
		classes.each do |c|
			result += @subClasses[c] if @subClasses[c]
		end
		result.uniq
	end
	
	def superclasses(clazz)
		if clazz == Object
			[]
		else
			superclasses(clazz.superclass) << clazz.superclass
		end
	end
	
end

end