codemodels 0.2.2-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +23 -0
- data/Rakefile +9 -0
- data/codemodels.gemspec +29 -0
- data/lib/codemodels/foreign_ast.rb +11 -0
- data/lib/codemodels/info_extraction.rb +139 -0
- data/lib/codemodels/language.rb +65 -0
- data/lib/codemodels/metamodel.rb +11 -0
- data/lib/codemodels/model_building.rb +81 -0
- data/lib/codemodels/monkey_patching.rb +30 -0
- data/lib/codemodels/parsing.rb +184 -0
- data/lib/codemodels/query_serialized.rb +81 -0
- data/lib/codemodels/rgen_ext.rb +186 -0
- data/lib/codemodels/serialization.rb +142 -0
- data/lib/codemodels/version.rb +3 -0
- data/lib/codemodels.rb +5 -0
- data/test/data/node_setCompleted.json +443 -0
- data/test/test_foreign_ast.rb +28 -0
- data/test/test_helper.rb +10 -0
- data/test/test_info_extraction.rb +90 -0
- data/test/test_language.rb +28 -0
- data/test/test_monkey_patching.rb +38 -0
- data/test/test_query_serialized.rb +40 -0
- data/test/test_rgen_ext.rb +187 -0
- data/test/test_serialization.rb +83 -0
- metadata +167 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
# This module permits to manipulate Objects serialized
|
2
|
+
# as Hash
|
3
|
+
|
4
|
+
module CodeModels
|
5
|
+
|
6
|
+
module QuerySerialized
|
7
|
+
|
8
|
+
def self.rel_conts(root)
|
9
|
+
root.keys.select {|k| k.start_with? 'relcont_'}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.rel_non_conts(root)
|
13
|
+
root.keys.select {|k| k.start_with? 'relnoncont_'}
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.attrs(root)
|
17
|
+
root.keys.select {|k| k.start_with? 'attr_'}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.print_tree(root,depth=0)
|
21
|
+
traverse(root) do |n,d|
|
22
|
+
s = ""
|
23
|
+
d.times { s = s + " " }
|
24
|
+
s = s + n['type'] if n
|
25
|
+
s = s + '<NIL>' unless n
|
26
|
+
puts s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.values(root,feat)
|
31
|
+
raw = root[feat]
|
32
|
+
return [] if raw==nil
|
33
|
+
return raw if raw.is_a? Array
|
34
|
+
return [raw]
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.traverse(root,depth=0,&op)
|
38
|
+
return traverse(root['root'],depth,&op) if root and (root.key? 'root')
|
39
|
+
op.call(root,depth)
|
40
|
+
return unless root
|
41
|
+
rel_conts(root).each do |r|
|
42
|
+
if root[r].is_a? Array
|
43
|
+
root[r].each do |c|
|
44
|
+
raise "expected an object but it is a #{c.class} (relation: #{r})" unless c.is_a? Hash
|
45
|
+
traverse(c,depth+1,&op)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
traverse(root[r],depth+1,&op)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# the set of values appearing in the object and its children
|
54
|
+
def self.collect_values(el)
|
55
|
+
values = Set.new
|
56
|
+
rel_conts(el).each do |r|
|
57
|
+
values(el,r).each {|c| values.merge(collect_values(c))}
|
58
|
+
end
|
59
|
+
attrs(el).each do |a|
|
60
|
+
values(el,a).each {|v| values.add(v)}
|
61
|
+
end
|
62
|
+
values
|
63
|
+
end
|
64
|
+
|
65
|
+
# a counting map values appearing in the object and its children
|
66
|
+
def self.collect_values_with_count(el)
|
67
|
+
values = Hash.new {|h,k| h[k]=0}
|
68
|
+
rel_conts(el).each do |r|
|
69
|
+
values(el,r).each do |ch|
|
70
|
+
collect_values_with_count(ch).each {|v,count| values[v]+=count}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
attrs(el).each do |a|
|
74
|
+
values(el,a).each {|v| values[v]+=1 }
|
75
|
+
end
|
76
|
+
values
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# Extensions to RGen objects
|
2
|
+
|
3
|
+
require 'rgen/metamodel_builder'
|
4
|
+
|
5
|
+
class RGen::MetamodelBuilder::MMBase
|
6
|
+
|
7
|
+
module ClassAddOn
|
8
|
+
|
9
|
+
def build(values={})
|
10
|
+
instance = self.new
|
11
|
+
if values.is_a? Hash
|
12
|
+
values.each do |k,v|
|
13
|
+
attribute = self.ecore.eAllAttributes.find {|x| x.name==k.to_s}
|
14
|
+
reference = self.ecore.eAllReferences.find {|x| x.name==k.to_s}
|
15
|
+
raise EMF::UnexistingFeature.new(k.to_s) unless (attribute or reference)
|
16
|
+
setter = (k.to_s+'=').to_sym
|
17
|
+
instance.send setter, v
|
18
|
+
end
|
19
|
+
else
|
20
|
+
has_dynamic = false
|
21
|
+
self.ecore.eAllAttributes.each {|a| has_dynamic|=a.name=='dynamic'}
|
22
|
+
d = 0
|
23
|
+
d = 1 if has_dynamic
|
24
|
+
|
25
|
+
raise EMF::SingleAttributeRequired.new(self.ecore.name,self.ecore.eAllAttributes) if self.ecore.eAllAttributes.count!=1+d
|
26
|
+
attribute = self.ecore.eAllAttributes[0]
|
27
|
+
set_attr(instance,attribute,values)
|
28
|
+
end
|
29
|
+
instance
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def set_attr(instance,attribute,value)
|
35
|
+
setter = (attribute.name+'=').to_sym
|
36
|
+
instance.send setter, value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module SingletonAddOn
|
41
|
+
|
42
|
+
# It does not check references, it is needed to avoid infinite recursion
|
43
|
+
def shallow_eql?(other)
|
44
|
+
return false if other==nil
|
45
|
+
return false unless self.class==other.class
|
46
|
+
self.class.ecore.eAllAttributes.each do |attrib|
|
47
|
+
raise "Attrib <nil> for class #{self.class.ecore.name}" unless attrib
|
48
|
+
if attrib.name != 'dynamic' # I have to understand this...
|
49
|
+
self_value = self.get(attrib)
|
50
|
+
other_value = other.get(attrib)
|
51
|
+
#puts "returning false on #{attrib.name}" unless self_value.eql?(other_value)
|
52
|
+
return false unless self_value == other_value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def eql?(other)
|
59
|
+
# it should ignore relations which has as opposite a containement
|
60
|
+
return false unless self.shallow_eql?(other)
|
61
|
+
self.class.ecore.eAllReferences.each do |ref|
|
62
|
+
self_value = self.get(ref)
|
63
|
+
other_value = other.get(ref)
|
64
|
+
to_ignore = ref.getEOpposite and ref.getEOpposite.containment
|
65
|
+
unless to_ignore
|
66
|
+
if ref.containment
|
67
|
+
return false unless self_value == other_value
|
68
|
+
else
|
69
|
+
if (self_value.is_a? Array) or (other_value.is_a? Array)
|
70
|
+
return false unless self_value.count==other_value.count
|
71
|
+
for i in 0..(self_value.count-1)
|
72
|
+
unless self_value[i].shallow_eql?(other_value[i])
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
else
|
77
|
+
if self_value==nil
|
78
|
+
return false unless other_value==nil
|
79
|
+
else
|
80
|
+
return false unless self_value.shallow_eql?(other_value)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
def ==(other)
|
90
|
+
eql? other
|
91
|
+
end
|
92
|
+
|
93
|
+
def get(attr_or_ref)
|
94
|
+
getter = (attr_or_ref.name).to_sym
|
95
|
+
send getter
|
96
|
+
end
|
97
|
+
|
98
|
+
def all_children
|
99
|
+
arr = []
|
100
|
+
ecore = self.class.ecore
|
101
|
+
ecore.eAllReferences.select {|r| r.containment}.each do |ref|
|
102
|
+
res = self.send(ref.name.to_sym)
|
103
|
+
if ref.many
|
104
|
+
d = arr.count
|
105
|
+
res.each do |el|
|
106
|
+
arr << el unless res==nil
|
107
|
+
end
|
108
|
+
elsif res!=nil
|
109
|
+
d = arr.count
|
110
|
+
arr << res
|
111
|
+
end
|
112
|
+
end
|
113
|
+
arr
|
114
|
+
end
|
115
|
+
|
116
|
+
def all_children_deep
|
117
|
+
arr = []
|
118
|
+
all_children.each do |c|
|
119
|
+
arr << c
|
120
|
+
c.all_children_deep.each do |cc|
|
121
|
+
arr << cc
|
122
|
+
end
|
123
|
+
end
|
124
|
+
arr
|
125
|
+
end
|
126
|
+
|
127
|
+
def traverse(&op)
|
128
|
+
op.call(self)
|
129
|
+
all_children_deep.each do |c|
|
130
|
+
op.call(c)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def collect_values_with_count
|
135
|
+
values = Hash.new {|h,k| h[k]=0}
|
136
|
+
self.class.ecore.eAllAttributes.each do |a|
|
137
|
+
v = self.send(:"#{a.name}")
|
138
|
+
if v!=nil
|
139
|
+
if a.many
|
140
|
+
v.each {|el| values[el]+=1}
|
141
|
+
else
|
142
|
+
values[v]+=1
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
values
|
147
|
+
end
|
148
|
+
|
149
|
+
def collect_values_with_count_subtree
|
150
|
+
values = collect_values_with_count
|
151
|
+
all_children_deep.each do |c|
|
152
|
+
c.collect_values_with_count.each do |k,v|
|
153
|
+
values[k]+=v
|
154
|
+
end
|
155
|
+
end
|
156
|
+
values
|
157
|
+
end
|
158
|
+
|
159
|
+
def all_children_of_type(type)
|
160
|
+
all_children.select {|c| c and c.is_a?(type)}
|
161
|
+
end
|
162
|
+
|
163
|
+
def all_children_deep_of_type(type)
|
164
|
+
all_children_deep.select {|c| c and c.is_a?(type)}
|
165
|
+
end
|
166
|
+
|
167
|
+
def only_child_of_type(type)
|
168
|
+
selected = all_children_of_type(type)
|
169
|
+
raise "Exactly one child of type #{type} expected, #{selected.count} found on #{self}" unless selected.count==1
|
170
|
+
selected[0]
|
171
|
+
end
|
172
|
+
|
173
|
+
def only_child_deep_of_type(type)
|
174
|
+
selected = all_children_deep_of_type(type)
|
175
|
+
raise "Exactly one child of type #{type} expected, #{selected.count} found on #{self}" unless selected.count==1
|
176
|
+
selected[0]
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
class << self
|
182
|
+
include ClassAddOn
|
183
|
+
end
|
184
|
+
|
185
|
+
include SingletonAddOn
|
186
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# This code permit to transform RGen-Objects in Hash objects
|
2
|
+
# containing lists and single values
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'rgen/metamodel_builder'
|
7
|
+
|
8
|
+
module CodeModels
|
9
|
+
module Serialization
|
10
|
+
|
11
|
+
module SerializationFunctionalities
|
12
|
+
|
13
|
+
# It could be a simple hash with a block passed to the
|
14
|
+
# constructor...
|
15
|
+
class SerializationMemory
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@next_id = 1
|
19
|
+
@id_map = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def id(rgen_object)
|
23
|
+
unless @id_map[rgen_object]
|
24
|
+
@id_map[rgen_object] = @next_id
|
25
|
+
@next_id += 1
|
26
|
+
end
|
27
|
+
@id_map[rgen_object]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_json(serialization_memory=SerializationMemory.new,adapters={},with_source_info=true)
|
33
|
+
e_object = self
|
34
|
+
map = { 'type' => qname, 'id' => serialization_memory.id(e_object) }
|
35
|
+
if with_source_info
|
36
|
+
if self.respond_to?(:source) && self.source
|
37
|
+
source_map = {}
|
38
|
+
if self.source.begin_pos
|
39
|
+
source_map['begin_pos'] = {'line'=> self.source.begin_pos.line, 'column'=>self.source.begin_pos.column}
|
40
|
+
end
|
41
|
+
if self.source.end_pos
|
42
|
+
source_map['end_pos'] = {'line'=> self.source.end_pos.line, 'column'=>self.source.end_pos.column}
|
43
|
+
end
|
44
|
+
map['source'] = source_map
|
45
|
+
end
|
46
|
+
end
|
47
|
+
e_class = e_object.class.ecore
|
48
|
+
e_class.eAllAttributes.each do |a|
|
49
|
+
jsonize_attr_value(map,a)
|
50
|
+
end
|
51
|
+
e_class.eAllReferences.each do |r|
|
52
|
+
id = jsonize_ref_value(map,r,adapters,serialization_memory)
|
53
|
+
end
|
54
|
+
if adapters.has_key? qname
|
55
|
+
adapters[qname].adapt(self,map)
|
56
|
+
end
|
57
|
+
map
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def qname
|
63
|
+
self.class.to_s
|
64
|
+
end
|
65
|
+
|
66
|
+
def jsonize_attr_value(map,e_attr)
|
67
|
+
value = self.send(e_attr.name.to_sym)
|
68
|
+
if e_attr.upperBound==1
|
69
|
+
map["attr_#{e_attr.name}"] = value
|
70
|
+
else
|
71
|
+
l = []
|
72
|
+
value.each do |e|
|
73
|
+
l << e
|
74
|
+
end
|
75
|
+
map["attr_#{e_attr.name}"] = l
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def jsonize_ref_value(map,e_ref,adapters,serialization_memory)
|
80
|
+
value = self.send e_ref.name.to_sym
|
81
|
+
|
82
|
+
propname = "relcont_#{e_ref.name}" if e_ref.containment
|
83
|
+
propname = "relnoncont_#{e_ref.name}" if not e_ref.containment
|
84
|
+
|
85
|
+
if e_ref.upperBound==1
|
86
|
+
map[propname] = jsonize_ref_single_el(value,e_ref.containment,adapters,serialization_memory)
|
87
|
+
else
|
88
|
+
l = []
|
89
|
+
(0...(value.size)).each do |i|
|
90
|
+
l << jsonize_ref_single_el(value.at(i),e_ref.containment,adapters,serialization_memory)
|
91
|
+
end
|
92
|
+
map[propname] = l
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def jsonize_ref_single_el(single_value,containment,adapters,serialization_memory)
|
97
|
+
if containment
|
98
|
+
single_value.to_json(serialization_memory,adapters)
|
99
|
+
else
|
100
|
+
serialization_memory.id(single_value)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
class ::RGen::MetamodelBuilder::MMBase
|
107
|
+
include SerializationFunctionalities
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.load_file(path,max_nesting=500)
|
111
|
+
JSON.parse(File.read(path),{max_nesting: max_nesting})
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.save_model(model,model_path, max_nesting=500)
|
115
|
+
dir = File.dirname(model_path)
|
116
|
+
FileUtils.mkdir_p(dir)
|
117
|
+
|
118
|
+
File.open(model_path, 'w') do |file|
|
119
|
+
file.write(JSON.pretty_generate(model, :max_nesting => max_nesting))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.rgenobject_to_model(root,adapters={})
|
124
|
+
model = {}
|
125
|
+
external_elements = []
|
126
|
+
|
127
|
+
sm = SerializationFunctionalities::SerializationMemory.new
|
128
|
+
model['root'] = root.to_json(sm,adapters)
|
129
|
+
model['external_elements'] = []
|
130
|
+
external_elements.each do |ee|
|
131
|
+
model['external_elements'] << ee.to_json(sm,adapters)
|
132
|
+
end
|
133
|
+
model
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.save_as_model(root,model_path)
|
137
|
+
model = to_model(root)
|
138
|
+
save_model(model,model_path)
|
139
|
+
end
|
140
|
+
|
141
|
+
end # module
|
142
|
+
end # module
|