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
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 ftomassetti
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
codemodels
|
2
|
+
===========
|
3
|
+
|
4
|
+
codemodels is a library to create and manipulate models. A serialization format (based on JSON) is defined.
|
5
|
+
|
6
|
+
It is based on [RGen](http://github.com/mthiede/rgen) and it supportes the conversion of EMF models through [emf_jruby](http://github.com/ftomassetti/emf_jruby).
|
7
|
+
|
8
|
+
There are different gems which transform source code in models of the code. Currently they are:
|
9
|
+
* [html-lightmodels](http://github.com/ftomassetti/html-lightmodels)
|
10
|
+
* [java-lightmodels](http://github.com/ftomassetti/java-lightmodels)
|
11
|
+
* [js-lightmodels](http://github.com/ftomassetti/js-lightmodels)
|
12
|
+
* [properties-lightmodels](http://github.com/ftomassetti/properties-lightmodels)
|
13
|
+
* [ruby-lightmodels](http://github.com/ftomassetti/ruby-lightmodels)
|
14
|
+
* [xml-lightmodels](http://github.com/ftomassetti/xml-lightmodels)
|
15
|
+
|
16
|
+
Therefore it can be used to perform analysis on different languages.
|
17
|
+
|
18
|
+
Features
|
19
|
+
========
|
20
|
+
|
21
|
+
It handles also the case in which different languages are hosted in the same file (for example a Javascript script inside an HTML page).
|
22
|
+
|
23
|
+
Most of the parsers permit also to associate each node with a precise point in the source code, so thath they could be used to implement layout-preserving refactoring.
|
data/Rakefile
ADDED
data/codemodels.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'codemodels/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.platform = 'java'
|
8
|
+
s.name = 'codemodels'
|
9
|
+
s.version = CodeModels::VERSION
|
10
|
+
s.date = '2013-08-27'
|
11
|
+
s.summary = "Library to build models of code"
|
12
|
+
s.description = "Library to build models of code of different languages in a uniform way."
|
13
|
+
s.authors = ["Federico Tomassetti"]
|
14
|
+
s.email = 'f.tomassetti@gmail.com'
|
15
|
+
s.homepage = 'https://github.com/ftomassetti/codemodels'
|
16
|
+
s.license = "APACHE 2"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split($/)
|
19
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_dependency('json')
|
24
|
+
s.add_dependency('rgen')
|
25
|
+
|
26
|
+
s.add_development_dependency "bundler", "1.3.5"
|
27
|
+
s.add_development_dependency "rake"
|
28
|
+
s.add_development_dependency "simplecov"
|
29
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'rgen/metamodel_builder'
|
2
|
+
|
3
|
+
module CodeModels
|
4
|
+
module InfoExtraction
|
5
|
+
|
6
|
+
class TermsBreaker
|
7
|
+
|
8
|
+
attr_accessor :sequences, :inv_sequences
|
9
|
+
|
10
|
+
def initialize(language_specific_logic)
|
11
|
+
@language_specific_logic = language_specific_logic
|
12
|
+
@sequences = Hash.new {|h,k|
|
13
|
+
h[k] = Hash.new {|h,k|
|
14
|
+
h[k]=0
|
15
|
+
}
|
16
|
+
}
|
17
|
+
@inv_sequences = Hash.new {|h,k|
|
18
|
+
h[k] = Hash.new {|h2,k2|
|
19
|
+
h2[k2]=0
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.from_context(language_specific_logic,context)
|
25
|
+
values_map = context.values_map
|
26
|
+
instance = new(language_specific_logic)
|
27
|
+
values_map.each do |value,c|
|
28
|
+
value = value.to_s.strip
|
29
|
+
if language_specific_logic.terms_containing_value?(value)
|
30
|
+
words = language_specific_logic.to_words(value)
|
31
|
+
first_words = words[0...-1]
|
32
|
+
instance.inv_sequences[words[0].downcase][:start] += c
|
33
|
+
first_words.each_with_index do |w,i|
|
34
|
+
instance.sequences[w.downcase][words[i+1].downcase] += c
|
35
|
+
instance.inv_sequences[words[i+1].downcase][w.downcase] += c
|
36
|
+
end
|
37
|
+
last_word = words.last
|
38
|
+
instance.sequences[last_word.downcase][:end] += c
|
39
|
+
else
|
40
|
+
# who cares, it will be never considered for composed names...
|
41
|
+
end
|
42
|
+
end
|
43
|
+
instance
|
44
|
+
end
|
45
|
+
|
46
|
+
def terms_in_value(value)
|
47
|
+
value = value.to_s.strip
|
48
|
+
if @language_specific_logic.terms_containing_value?(value)
|
49
|
+
words = @language_specific_logic.to_words(value)
|
50
|
+
group_words_in_terms(words).map{|w| w.downcase}
|
51
|
+
else
|
52
|
+
[value]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def frequent_straight_sequence?(w1,w2)
|
59
|
+
w1 = w1.downcase
|
60
|
+
w2 = w2.downcase
|
61
|
+
all_sequences_of_w1 = 0
|
62
|
+
@sequences[w1].each do |k,v|
|
63
|
+
all_sequences_of_w1 += v
|
64
|
+
end
|
65
|
+
sequences_w1_w2 = @sequences[w1][w2]
|
66
|
+
(sequences_w1_w2.to_f/all_sequences_of_w1.to_f)>0.5
|
67
|
+
end
|
68
|
+
|
69
|
+
def frequent_inverse_sequence?(w1,w2)
|
70
|
+
w1 = w1.downcase
|
71
|
+
w2 = w2.downcase
|
72
|
+
all_inv_sequences_of_w1 = 0
|
73
|
+
@inv_sequences[w1].each do |k,v|
|
74
|
+
all_inv_sequences_of_w1 += v
|
75
|
+
end
|
76
|
+
inv_sequences_w1_w2 = @inv_sequences[w1][w2]
|
77
|
+
(inv_sequences_w1_w2.to_f/all_inv_sequences_of_w1.to_f)>0.5
|
78
|
+
end
|
79
|
+
|
80
|
+
def frequent_sequence?(w1,w2)
|
81
|
+
return false unless w2
|
82
|
+
frequent_straight_sequence?(w1,w2) && frequent_inverse_sequence?(w2,w1)
|
83
|
+
end
|
84
|
+
|
85
|
+
def group_words_in_terms(words)
|
86
|
+
# getNotSoGoodFieldName is not a term because
|
87
|
+
# notSoGoodFieldName is more frequently alone that preceded by get
|
88
|
+
|
89
|
+
return words if words.count==1
|
90
|
+
start_term = 0
|
91
|
+
end_term = 0
|
92
|
+
term = words[0]
|
93
|
+
while end_term < words.count && frequent_sequence?(words[end_term],words[end_term+1])
|
94
|
+
end_term += 1
|
95
|
+
term = @language_specific_logic.concat(term,words[end_term])
|
96
|
+
end
|
97
|
+
return [term] if end_term==(words.count-1)
|
98
|
+
[term] + group_words_in_terms(words[(end_term+1)..-1])
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
module InfoExtractionFunctionalities
|
104
|
+
|
105
|
+
def values_map
|
106
|
+
collect_values_with_count_subtree
|
107
|
+
end
|
108
|
+
|
109
|
+
def terms_map(language_specific_logic,context=nil)
|
110
|
+
# context default to root
|
111
|
+
unless context
|
112
|
+
context = self
|
113
|
+
while context.eContainer
|
114
|
+
context = context.eContainer
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# look into context to see how frequent are certain series of words,
|
119
|
+
# frequent series are recognized as composed terms
|
120
|
+
terms_breaker = TermsBreaker.from_context(language_specific_logic,context)
|
121
|
+
|
122
|
+
v_map = self.values_map
|
123
|
+
terms_map = Hash.new {|h,k| h[k]=0}
|
124
|
+
v_map.each do |v,n|
|
125
|
+
terms_breaker.terms_in_value(v).each do |t|
|
126
|
+
terms_map[t] += n
|
127
|
+
end
|
128
|
+
end
|
129
|
+
terms_map
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
class ::RGen::MetamodelBuilder::MMBase
|
135
|
+
include InfoExtractionFunctionalities
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module CodeModels
|
2
|
+
|
3
|
+
@@languages = []
|
4
|
+
|
5
|
+
class Parser
|
6
|
+
|
7
|
+
def parse_file(path)
|
8
|
+
code = IO.read(path)
|
9
|
+
parse_code(code)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
module CodeModelsReflectionInfo
|
15
|
+
attr_accessor :source
|
16
|
+
attr_accessor :language
|
17
|
+
end
|
18
|
+
|
19
|
+
class Position
|
20
|
+
attr_accessor :line, :column
|
21
|
+
end
|
22
|
+
|
23
|
+
class SourceInfo
|
24
|
+
attr_accessor :filename
|
25
|
+
attr_accessor :begin_pos, :end_pos
|
26
|
+
|
27
|
+
def to_code
|
28
|
+
raise "Unimplemented"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class Language
|
34
|
+
attr_reader :name
|
35
|
+
attr_reader :extensions
|
36
|
+
attr_reader :parser
|
37
|
+
|
38
|
+
def initialize(name)
|
39
|
+
@name = name
|
40
|
+
@extensions = []
|
41
|
+
end
|
42
|
+
|
43
|
+
def can_parse?(path)
|
44
|
+
extension = File.extname(path)
|
45
|
+
extension=extension[1..-1] if extension.length>0
|
46
|
+
@extensions.include?(extension)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.register_language(language)
|
52
|
+
@@languages << language
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.registered_languages
|
56
|
+
@@languages
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.parse_file(path)
|
60
|
+
l = @@languages.find {|l| l.can_parse?(path) }
|
61
|
+
raise "I don't know how to parse #{path}. Languages known: #{@@languages.map(&:name)}" unless l
|
62
|
+
l.parser.parse_file(path)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'codemodels/serialization'
|
2
|
+
|
3
|
+
module CodeModels
|
4
|
+
|
5
|
+
module ModelBuilding
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :verbose
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.verbose_warn(msg)
|
12
|
+
warn(msg) if verbose
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.handle_serialized_models_in_dir(src,src_extension,error_handler=nil,model_handler,&model_creator)
|
16
|
+
Dir["#{src}/**/*.#{src_extension}"].each do |fd|
|
17
|
+
verbose_warn "== #{fd} =="
|
18
|
+
handle_serialized_model_per_file(fd,error_handler,model_handler,&model_creator)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.handle_models_in_dir(src,src_extension,error_handler=nil,model_handler,&model_creator)
|
23
|
+
Dir["#{src}/**/*.#{src_extension}"].each do |fd|
|
24
|
+
verbose_warn "== #{fd} =="
|
25
|
+
handle_model_per_file(fd,error_handler,model_handler,&model_creator)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.generate_models_in_dir(src,dest,src_extension,dest_extension,max_nesting=500,error_handler=nil,&model_creator)
|
30
|
+
verbose_warn "== #{src} -> #{dest} =="
|
31
|
+
Dir["#{src}/**/*.#{src_extension}"].each do |fd|
|
32
|
+
if File.directory? fd
|
33
|
+
basename = File.basename(fd)
|
34
|
+
generate_models_in_dir("#{src}/#{basename}","#{dest}/#{basename}",src_extension,dest_extension,max_nesting,error_handler,&model_creator)
|
35
|
+
else
|
36
|
+
if File.extname(fd)==".#{src_extension}"
|
37
|
+
translated_simple_name = "#{File.basename(fd, ".#{src_extension}")}.#{dest_extension}"
|
38
|
+
translated_name = "#{dest}/#{translated_simple_name}"
|
39
|
+
verbose_warn "* #{fd} --> #{translated_name}"
|
40
|
+
generate_model_per_file(fd,translated_name,max_nesting,error_handler,&model_creator)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.handle_model_per_file(src,error_handler=nil,model_handler,&models_generator)
|
47
|
+
verbose_warn "<Model from #{src}>"
|
48
|
+
begin
|
49
|
+
m = models_generator.call(src)
|
50
|
+
model_handler.call(src,m)
|
51
|
+
rescue => e
|
52
|
+
if error_handler
|
53
|
+
error_handler.call(src,e)
|
54
|
+
else
|
55
|
+
raise e
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.generate_model_per_file(src,dest,max_nesting=500,error_handler=nil,&models_generator)
|
61
|
+
if not File.exist? dest
|
62
|
+
verbose_warn "<Model from #{src}>"
|
63
|
+
|
64
|
+
begin
|
65
|
+
m = models_generator.call(src)
|
66
|
+
LightModels::Serialization.save_model(m,dest,max_nesting)
|
67
|
+
rescue Exception => e
|
68
|
+
if error_handler
|
69
|
+
error_handler.call(src,e)
|
70
|
+
else
|
71
|
+
raise e
|
72
|
+
end
|
73
|
+
end
|
74
|
+
else
|
75
|
+
verbose_warn "skipping #{src} because #{dest} found"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
def simple_name
|
4
|
+
if (i = (r = name).rindex(':')) then r[0..i] = '' end
|
5
|
+
r
|
6
|
+
end
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
class String
|
11
|
+
|
12
|
+
def remove_postfix(postfix)
|
13
|
+
raise "'#{self}'' have not the right postfix '#{postfix}'" unless end_with?(postfix)
|
14
|
+
self[0..-(1+postfix.length)]
|
15
|
+
end
|
16
|
+
|
17
|
+
def remove_prefix(prefix)
|
18
|
+
raise "'#{self}'' have not the right prefix '#{prefix}'" unless start_with?(prefix)
|
19
|
+
self[prefix.length..-1]
|
20
|
+
end
|
21
|
+
|
22
|
+
def proper_capitalize
|
23
|
+
self[0, 1].upcase + self[1..-1]
|
24
|
+
end
|
25
|
+
|
26
|
+
def proper_uncapitalize
|
27
|
+
self[0, 1].downcase + self[1..-1]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'codemodels/monkey_patching'
|
2
|
+
|
3
|
+
module CodeModels
|
4
|
+
|
5
|
+
class ParsingError < Exception
|
6
|
+
attr_reader :node
|
7
|
+
attr_reader :line
|
8
|
+
|
9
|
+
def initialize(node,msg,line=nil)
|
10
|
+
@node = node
|
11
|
+
@msg = msg
|
12
|
+
@line = lin
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{@msg}, start line: #{@line}"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class UnknownNodeType < ParsingError
|
22
|
+
|
23
|
+
def initialize(node,line=nil,node_type=nil,where=nil)
|
24
|
+
super(node,"UnknownNodeType: type=#{node_type} , where: #{where}")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
module ParserWrapper
|
30
|
+
|
31
|
+
@@verbose = false
|
32
|
+
|
33
|
+
JavaCollection = ::Java::JavaClass.for_name("java.util.Collection")
|
34
|
+
|
35
|
+
def adapter(model_class,ref)
|
36
|
+
if adapter_specific_class(model_class,ref)
|
37
|
+
adapter_specific_class(model_class,ref)
|
38
|
+
else
|
39
|
+
if model_class.superclass!=Object
|
40
|
+
adapter(model_class.superclass,ref)
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def reference_to_method(model_class,ref)
|
48
|
+
s = ref.name
|
49
|
+
#s = 'value' if s=='body'
|
50
|
+
adapted = adapter(model_class,ref)
|
51
|
+
s = adapted if adapted
|
52
|
+
s.to_sym
|
53
|
+
end
|
54
|
+
|
55
|
+
def attribute_to_method(model_class,att)
|
56
|
+
s = att.name
|
57
|
+
adapted = adapter(model_class,att)
|
58
|
+
s = adapted if adapted
|
59
|
+
s.to_sym
|
60
|
+
end
|
61
|
+
|
62
|
+
def assign_ref_to_model(model,ref,value)
|
63
|
+
return unless value==nil # we do not need to assign a nil...
|
64
|
+
if ref.many
|
65
|
+
adder_method = :"add#{ref.name.capitalize}"
|
66
|
+
value.each {|el| model.send(adder_method,node_to_model(el))}
|
67
|
+
else
|
68
|
+
setter_method = :"#{ref.name}="
|
69
|
+
raise "Trying to assign an array to a single property. Class #{model.class}, property #{ref.name}" if value.is_a?(::Array)
|
70
|
+
model.send(setter_method,node_to_model(value))
|
71
|
+
end
|
72
|
+
rescue Object => e
|
73
|
+
puts "Problem while assigning ref #{ref.name} (many? #{ref.many}) to #{model.class}. Value: #{value.class}"
|
74
|
+
puts "\t<<#{e}>>"
|
75
|
+
raise e
|
76
|
+
end
|
77
|
+
|
78
|
+
def assign_att_to_model(model,att,value)
|
79
|
+
if att.many
|
80
|
+
adder_method = :"add#{att.name.capitalize}"
|
81
|
+
value.each {|el| model.send(adder_method,el)}
|
82
|
+
else
|
83
|
+
setter_method = :"#{att.name}="
|
84
|
+
raise "Trying to assign an array to a single property. Class #{model.class}, property #{att.name}" if value.is_a?(::Array)
|
85
|
+
model.send(setter_method,value)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def populate_attr(node,att,model)
|
90
|
+
value = get_feature_value(node,att)
|
91
|
+
model.send(:"#{att.name}=",value) if value!=nil
|
92
|
+
rescue Object => e
|
93
|
+
puts "Problem while populating attribute #{att.name} of #{model} from #{node}. Value: #{value}"
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
|
97
|
+
def populate_ref(node,ref,model)
|
98
|
+
log("populate ref #{ref.name}, node: #{node.class}, model: #{model.class}")
|
99
|
+
value = get_feature_value(node,ref)
|
100
|
+
log("\tvalue=#{value.class}")
|
101
|
+
if value!=nil
|
102
|
+
if value==node
|
103
|
+
puts "avoiding loop... #{ref.name}, class #{node.class}"
|
104
|
+
return
|
105
|
+
end
|
106
|
+
if JavaCollection.assignable_from?(value.java_class)
|
107
|
+
log("\tvalue is a collection")
|
108
|
+
capitalized_name = ref.name.proper_capitalize
|
109
|
+
value.each do |el|
|
110
|
+
unless el.respond_to?(:parent)
|
111
|
+
class << el
|
112
|
+
attr_accessor :parent
|
113
|
+
end
|
114
|
+
end
|
115
|
+
el.parent = node
|
116
|
+
model.send(:"add#{capitalized_name}",node_to_model(el))
|
117
|
+
end
|
118
|
+
else
|
119
|
+
log("\tvalue is not a collection")
|
120
|
+
unless value.respond_to?(:parent)
|
121
|
+
value.class.__persistent__ = true
|
122
|
+
class << value
|
123
|
+
attr_accessor :parent
|
124
|
+
end
|
125
|
+
end
|
126
|
+
value.parent = node
|
127
|
+
model.send(:"#{ref.name}=",node_to_model(value))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def log(msg)
|
133
|
+
puts msg if @@verbose
|
134
|
+
end
|
135
|
+
|
136
|
+
def node_to_model(node)
|
137
|
+
log("node_to_model #{node.class}")
|
138
|
+
metaclass = get_corresponding_metaclass(node)
|
139
|
+
instance = metaclass.new
|
140
|
+
metaclass.ecore.eAllAttributes.each do |attr|
|
141
|
+
populate_attr(node,attr,instance)
|
142
|
+
end
|
143
|
+
metaclass.ecore.eAllReferences.each do |ref|
|
144
|
+
populate_ref(node,ref,instance)
|
145
|
+
end
|
146
|
+
instance
|
147
|
+
end
|
148
|
+
|
149
|
+
def transform_enum_values(value)
|
150
|
+
if value.respond_to?(:java_class) && value.java_class.enum?
|
151
|
+
value.name
|
152
|
+
else
|
153
|
+
value
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def get_feature_value_through_getter(node,feat_name)
|
158
|
+
capitalized_name = feat_name.proper_capitalize
|
159
|
+
methods = [:"get#{capitalized_name}",:"is#{capitalized_name}"]
|
160
|
+
|
161
|
+
methods.each do |m|
|
162
|
+
if node.respond_to?(m)
|
163
|
+
begin
|
164
|
+
return transform_enum_values(node.send(m))
|
165
|
+
rescue Object => e
|
166
|
+
raise "Problem invoking #{m} on #{node.class}: #{e}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
raise "how should I get this... #{feat_name} on #{node.class}. It does not respond to #{methods}"
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_feature_value(node,feat)
|
174
|
+
adapter = adapter(node.class,feat)
|
175
|
+
if adapter
|
176
|
+
adapter[:adapter].call(node)
|
177
|
+
else
|
178
|
+
get_feature_value_through_getter(node,feat.name)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|