xmimodel 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/xmimodel.rb +205 -0
- data/lib/xmimodel/action_state.rb +17 -0
- data/lib/xmimodel/activity_graph.rb +81 -0
- data/lib/xmimodel/association.rb +26 -0
- data/lib/xmimodel/attribute.rb +76 -0
- data/lib/xmimodel/clazz.rb +123 -0
- data/lib/xmimodel/data_type.rb +21 -0
- data/lib/xmimodel/final_state.rb +13 -0
- data/lib/xmimodel/generalization.rb +36 -0
- data/lib/xmimodel/namespace.rb +373 -0
- data/lib/xmimodel/operation.rb +51 -0
- data/lib/xmimodel/package.rb +84 -0
- data/lib/xmimodel/parameter.rb +55 -0
- data/lib/xmimodel/pseudo_state.rb +16 -0
- data/lib/xmimodel/signal_event.rb +41 -0
- data/lib/xmimodel/state.rb +66 -0
- data/lib/xmimodel/stereotype.rb +52 -0
- data/lib/xmimodel/tagged_value.rb +41 -0
- data/lib/xmimodel/transition.rb +64 -0
- data/lib/xmimodel/use_case.rb +85 -0
- data/lib/xmimodel/xmihelper.rb +683 -0
- metadata +66 -0
data/lib/xmimodel.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), 'xmimodel/package.rb')
|
4
|
+
require File.join(File.dirname(__FILE__), 'xmimodel/generalization.rb')
|
5
|
+
require File.join(File.dirname(__FILE__), 'xmimodel/xmihelper.rb')
|
6
|
+
|
7
|
+
##
|
8
|
+
# A helper class for working with XMI Models.
|
9
|
+
class XmiModel
|
10
|
+
|
11
|
+
# @return [Nokogiri::XML::Document]
|
12
|
+
attr_reader :document
|
13
|
+
|
14
|
+
# @return [String] The contents of the tag 'XMI.header/XMI.documentation/XMI.exporter'.
|
15
|
+
attr_reader :exporter
|
16
|
+
|
17
|
+
# @return [String] The contents of the tag 'XMI.header/XMI.documentation/XMI.exporterVersion'.
|
18
|
+
attr_reader :exporter_version
|
19
|
+
|
20
|
+
# @return [String] The value of property xmi.version of the tag 'XMI.header/XMI.metamodel'.
|
21
|
+
attr_reader :metamodel_version
|
22
|
+
|
23
|
+
# @return [Array<Generalization>] All model generalizations.
|
24
|
+
attr_reader :generalizations
|
25
|
+
|
26
|
+
# @return [Array<Association>] All model associations.
|
27
|
+
attr_reader :associations
|
28
|
+
|
29
|
+
##
|
30
|
+
# Constructor.
|
31
|
+
#
|
32
|
+
# @param [String, #read] Path of model.
|
33
|
+
def initialize(model_file_name)
|
34
|
+
|
35
|
+
# Obtem a tag 'XMI.content' que contém todos os objetos que serão tratados
|
36
|
+
f = File.open(model_file_name)
|
37
|
+
doc = Nokogiri::XML(f)
|
38
|
+
@document = doc
|
39
|
+
xmi_content = doc.at_xpath("./XMI/XMI.content")
|
40
|
+
f.close
|
41
|
+
|
42
|
+
# Header
|
43
|
+
@exporter = XmiHelper.exporter(doc)
|
44
|
+
@exporter_version = XmiHelper.exporter_version(doc)
|
45
|
+
@metamodel_version = XmiHelper.metamodel_version(doc)
|
46
|
+
|
47
|
+
# Constrói vetor de pacotes
|
48
|
+
@packages = Array.new
|
49
|
+
XmiHelper.packages(xmi_content).each do |uml_package|
|
50
|
+
if ! (uml_package.attribute('name').nil? ||
|
51
|
+
uml_package.attribute('name').to_s.empty? ||
|
52
|
+
uml_package.attribute('name').to_s.strip == "Component View" ||
|
53
|
+
uml_package.attribute('name').to_s.strip == "Data types")
|
54
|
+
p = Package.new(uml_package, nil)
|
55
|
+
@packages << p
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Constrói vetor de heranças
|
60
|
+
@generalizations = Array.new
|
61
|
+
XmiHelper.all_generalizations(xmi_content).each do |xml|
|
62
|
+
g = Generalization.new(xml, self)
|
63
|
+
|
64
|
+
g.child_obj.parent = g.parent_obj unless g.child_obj.nil?
|
65
|
+
g.parent_obj.children << g.child_obj unless g.parent_obj.nil?
|
66
|
+
|
67
|
+
#puts "#{g.child_obj.full_name} - #{g.parent_obj.full_name}"
|
68
|
+
@generalizations << g
|
69
|
+
end
|
70
|
+
|
71
|
+
@associations = Array.new
|
72
|
+
XmiHelper.all_associations(xmi_content).each do |xml|
|
73
|
+
@associations << Association.new(xml, self)
|
74
|
+
end
|
75
|
+
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Get the object of type 'Clazz' by full name of class.
|
81
|
+
#
|
82
|
+
# @param [String, #read] Name of the class including package name.
|
83
|
+
# @return [Clazz]
|
84
|
+
def class_by_full_name(full_class_name)
|
85
|
+
raise ArgumentError.new("Parameter 'full_class_name' cannot be empty.") if full_class_name.nil? or full_class_name.empty?
|
86
|
+
clazz = classes.select{|c| c.full_name == full_class_name}
|
87
|
+
|
88
|
+
if !clazz.nil? && clazz.size > 0
|
89
|
+
clazz[0]
|
90
|
+
else
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Get the object of type 'Clazz' by id.
|
97
|
+
#
|
98
|
+
# @param [String, #read] Id of the class in model file.
|
99
|
+
# @return [Clazz]
|
100
|
+
def class_by_id(class_id)
|
101
|
+
raise ArgumentError.new("#{__method__}: 'class_id' cannot be empty.") if class_id.nil? or class_id.empty?
|
102
|
+
clazz = classes.select{|c| c.id == class_id}
|
103
|
+
|
104
|
+
if !clazz.nil? && clazz.size > 0
|
105
|
+
clazz[0]
|
106
|
+
else
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# Get all model classes.
|
113
|
+
#
|
114
|
+
# @return [Array<Clazz>]
|
115
|
+
def classes
|
116
|
+
return @classes unless @classes.nil?
|
117
|
+
@classes = Array.new
|
118
|
+
packages.each do |p|
|
119
|
+
@classes.concat p.classes.sort
|
120
|
+
end
|
121
|
+
@classes
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Get the object of type 'Package' by full name of package.
|
126
|
+
#
|
127
|
+
# @param [String, #read] Name of the package including sub packages name.
|
128
|
+
# @return [Package]
|
129
|
+
def package_by_full_name(full_package_name)
|
130
|
+
raise ArgumentError.new("Parameter 'full_package_name' cannot be empty.") if full_package_name.nil? or full_package_name.empty?
|
131
|
+
package = packages.select{|p| p.full_name == full_package_name}
|
132
|
+
|
133
|
+
if !package.nil? && package.size > 0
|
134
|
+
package[0]
|
135
|
+
else
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# Get all model packages.
|
142
|
+
#
|
143
|
+
# @return [Array<Package>]
|
144
|
+
def packages
|
145
|
+
return @all_packages unless @all_packages.nil?
|
146
|
+
@all_packages = Array.new
|
147
|
+
|
148
|
+
add_package(@packages)
|
149
|
+
|
150
|
+
@all_packages.sort!
|
151
|
+
@all_packages
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Get the object of type 'State' by id.
|
156
|
+
#
|
157
|
+
# @param [String, #read] Id of the state in model file.
|
158
|
+
# @return [ActionState, FinalState, PseudoState]
|
159
|
+
def state_by_id(id)
|
160
|
+
raise ArgumentError.new("Parameter 'id' cannot be empty.") if id.nil? or id.empty?
|
161
|
+
objs = states.select{|obj| obj.id == id}
|
162
|
+
(!objs.nil? && objs.size > 0) ? objs[0] : nil
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
##
|
167
|
+
# Get all model states.
|
168
|
+
#
|
169
|
+
# @return [Array<ActionState, FinalState, PseudoState>]
|
170
|
+
def states
|
171
|
+
return @states unless @states.nil?
|
172
|
+
|
173
|
+
@states = Array.new
|
174
|
+
packages.each do |p|
|
175
|
+
p.use_cases.each do |u|
|
176
|
+
u.activity_graphs.each do |a|
|
177
|
+
@states.concat a.action_states
|
178
|
+
@states.concat a.final_states
|
179
|
+
@states.concat a.pseudo_states
|
180
|
+
end
|
181
|
+
end
|
182
|
+
p.activity_graphs.each do |a|
|
183
|
+
@states.concat a.action_states
|
184
|
+
@states.concat a.final_states
|
185
|
+
@states.concat a.pseudo_states
|
186
|
+
end
|
187
|
+
end
|
188
|
+
@states
|
189
|
+
end
|
190
|
+
|
191
|
+
def to_s
|
192
|
+
"'XmiModel #{exporter} #{exporter_version} [Packages: #{packages.size}, Classes: #{classes.size}]'"
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
|
197
|
+
def add_package(packages)
|
198
|
+
packages.each do |p|
|
199
|
+
#puts p.name
|
200
|
+
@all_packages << p
|
201
|
+
add_package(p.packages) unless p.packages.nil?
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'xmimodel/state'
|
2
|
+
|
3
|
+
class ActionState < State
|
4
|
+
|
5
|
+
attr_reader :deferrable_event
|
6
|
+
|
7
|
+
def initialize(xml, activity_graph)
|
8
|
+
super(xml, activity_graph)
|
9
|
+
@deferrable_event = xml.attribute("deferrableEvent").to_s
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"ActionState"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'xmimodel/action_state'
|
2
|
+
require 'xmimodel/final_state'
|
3
|
+
require 'xmimodel/pseudo_state'
|
4
|
+
require 'xmimodel/transition'
|
5
|
+
|
6
|
+
##
|
7
|
+
# In umbrelo ActivityGraph is not represented by tag 'UML:ActivityGraph'.
|
8
|
+
# It's represented by tag diagram inside of XMI.extension.
|
9
|
+
#
|
10
|
+
#
|
11
|
+
class ActivityGraph
|
12
|
+
|
13
|
+
attr_reader :xml
|
14
|
+
|
15
|
+
attr_reader :id
|
16
|
+
attr_reader :name
|
17
|
+
|
18
|
+
attr_reader :pseudo_states
|
19
|
+
attr_reader :action_states
|
20
|
+
attr_reader :final_states
|
21
|
+
attr_reader :transitions
|
22
|
+
|
23
|
+
def initialize(xml, parent)
|
24
|
+
@xml = xml
|
25
|
+
@use_case = parent.parent
|
26
|
+
|
27
|
+
@id = xml.attribute("xmi.id").to_s
|
28
|
+
@name = xml.attribute("name").to_s
|
29
|
+
|
30
|
+
@pseudo_states = Array.new
|
31
|
+
XmiHelper.pseudo_states(xml).each do |uml|
|
32
|
+
pseudo_state = PseudoState.new(uml, self)
|
33
|
+
@pseudo_states << pseudo_state
|
34
|
+
end
|
35
|
+
|
36
|
+
@action_states = Array.new
|
37
|
+
XmiHelper.action_states(xml).each do |uml|
|
38
|
+
action_state = ActionState.new(uml, self)
|
39
|
+
@action_states << action_state
|
40
|
+
end
|
41
|
+
|
42
|
+
@final_states = Array.new
|
43
|
+
XmiHelper.final_states(xml).each do |uml|
|
44
|
+
final_state = FinalState.new(uml, self)
|
45
|
+
@final_states << final_state
|
46
|
+
end
|
47
|
+
|
48
|
+
@transitions = Array.new
|
49
|
+
XmiHelper.transitions(xml).each do |uml|
|
50
|
+
transition = Transition.new(uml, self)
|
51
|
+
@transitions << transition
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def full_name
|
56
|
+
"#{@use_case.full_name}::#{@name}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"ActivityGraph[#{full_name}]"
|
61
|
+
end
|
62
|
+
|
63
|
+
def state_by_name(name_state, state_name)
|
64
|
+
case name_state
|
65
|
+
when "PseudoState"
|
66
|
+
state = @pseudo_states.select{|obj| obj.name == state_name}
|
67
|
+
when "ActionState"
|
68
|
+
state = @action_states.select{|obj| obj.name == state_name}
|
69
|
+
when "FinalState"
|
70
|
+
state = @final_states.select{|obj| obj.name == state_name}
|
71
|
+
end
|
72
|
+
return state[0] if !state.nil? && state.size > 0
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def transition_by_source_target_ids(source, target)
|
77
|
+
objs = @transitions.select{|obj| obj.source == source && obj.target == target}
|
78
|
+
(!objs.nil? && objs.size > 0) ? objs[0] : nil
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
class Association
|
3
|
+
|
4
|
+
attr_reader :xml
|
5
|
+
attr_reader :parent
|
6
|
+
|
7
|
+
attr_reader :id
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# TODO Build AssociationEnd class
|
11
|
+
def initialize(xml, parent)
|
12
|
+
@xml = xml
|
13
|
+
@parent = parent
|
14
|
+
|
15
|
+
@id = xml.attribute("xmi.id").to_s
|
16
|
+
@name = xml.attribute("name").to_s.strip
|
17
|
+
|
18
|
+
#association_end_a
|
19
|
+
#association_end_b
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"Association[#{@name}]"
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'xmimodel/stereotype'
|
2
|
+
require 'xmimodel/tagged_value'
|
3
|
+
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
attr_reader :xml
|
7
|
+
|
8
|
+
attr_reader :id
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :type
|
11
|
+
attr_reader :visibility
|
12
|
+
attr_reader :initial_value
|
13
|
+
attr_reader :multiplicity_range
|
14
|
+
|
15
|
+
attr_reader :clazz
|
16
|
+
|
17
|
+
attr_reader :stereotypes
|
18
|
+
attr_reader :tagged_values
|
19
|
+
|
20
|
+
def initialize(xml, clazz)
|
21
|
+
@xml = xml
|
22
|
+
@clazz = clazz
|
23
|
+
|
24
|
+
@id = xml.attribute("xmi:id").to_s
|
25
|
+
@name = xml.attribute("name").to_s.strip
|
26
|
+
@visibility = xml.attribute("visibility").to_s
|
27
|
+
@visibility = "private" if @visibility == ""
|
28
|
+
|
29
|
+
@type = XmiHelper.attribute_type_name(xml)
|
30
|
+
|
31
|
+
@initial_value = XmiHelper.attribute_initial_value(xml)
|
32
|
+
@multiplicity_range = XmiHelper.multiplicity_range(xml)
|
33
|
+
|
34
|
+
@stereotypes = Array.new
|
35
|
+
XmiHelper.stereotypes(xml).each do |uml_stereotype|
|
36
|
+
stereotype = Stereotype.new(uml_stereotype, self)
|
37
|
+
@stereotypes << stereotype
|
38
|
+
end
|
39
|
+
|
40
|
+
@tagged_values = Array.new
|
41
|
+
XmiHelper.tagged_values(xml).each do |uml_tagged_value|
|
42
|
+
tagged_value = TaggedValue.new(uml_tagged_value, self)
|
43
|
+
@tagged_values << tagged_value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def full_name
|
48
|
+
"#{@clazz.full_name}::#{@name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def stereotype_by_name(name)
|
52
|
+
stereotype = @stereotypes.select{|s| s.name == name}
|
53
|
+
return stereotype[0] if !stereotype.nil? && stereotype.size > 0
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def tagged_value_by_name(tagged_value_name)
|
58
|
+
tagged_value = @tagged_values.select{|t| t.name == tagged_value_name}
|
59
|
+
return tagged_value[0] if !tagged_value.nil? && tagged_value.size > 0
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def ==(obj)
|
64
|
+
return false if obj.nil?
|
65
|
+
if String == obj.class
|
66
|
+
full_name == obj
|
67
|
+
else
|
68
|
+
full_name == obj.full_name
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
"Attribute[#{full_name}]"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'xmimodel/attribute'
|
4
|
+
require 'xmimodel/stereotype'
|
5
|
+
require 'xmimodel/tagged_value'
|
6
|
+
require 'xmimodel/operation'
|
7
|
+
|
8
|
+
class Clazz
|
9
|
+
|
10
|
+
attr_reader :xml
|
11
|
+
|
12
|
+
attr_reader :id
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
# @return [String] Full Package name of class.
|
16
|
+
attr_reader :package
|
17
|
+
|
18
|
+
# @return [Array<Attribute>] Class attributes.
|
19
|
+
attr_reader :attributes
|
20
|
+
|
21
|
+
# @return [Array<String>] Class associations.
|
22
|
+
attr_reader :stereotypes
|
23
|
+
|
24
|
+
attr_reader :tagged_values
|
25
|
+
attr_reader :operations
|
26
|
+
|
27
|
+
attr_accessor :children
|
28
|
+
attr_accessor :parent
|
29
|
+
|
30
|
+
def initialize(xml, parent)
|
31
|
+
@xml = xml
|
32
|
+
@package = parent.parent
|
33
|
+
|
34
|
+
@id = xml.attribute("xmi.id").to_s
|
35
|
+
@name = xml.attribute("name").to_s.strip
|
36
|
+
|
37
|
+
@attributes = Array.new
|
38
|
+
XmiHelper.attributes(xml).each do |uml_attribute|
|
39
|
+
attribute = Attribute.new(uml_attribute, self)
|
40
|
+
@attributes << attribute
|
41
|
+
end
|
42
|
+
|
43
|
+
@stereotypes = Array.new
|
44
|
+
stereotype_id = xml.attribute("stereotype").to_s
|
45
|
+
if !stereotype_id.empty?
|
46
|
+
stereotype = XmiHelper.stereotype_by_id(xml, stereotype_id)
|
47
|
+
stereotype = Stereotype.new(stereotype, self)
|
48
|
+
@stereotypes << stereotype
|
49
|
+
end
|
50
|
+
XmiHelper.stereotypes(xml).each do |uml_stereotype|
|
51
|
+
stereotype = Stereotype.new(uml_stereotype, self)
|
52
|
+
@stereotypes << stereotype
|
53
|
+
end
|
54
|
+
|
55
|
+
@tagged_values = Array.new
|
56
|
+
XmiHelper.tagged_values(xml).each do |uml_tagged_value|
|
57
|
+
tagged_value = TaggedValue.new(uml_tagged_value, self)
|
58
|
+
@tagged_values << tagged_value
|
59
|
+
end
|
60
|
+
|
61
|
+
@operations = Array.new
|
62
|
+
XmiHelper.operations(xml).each do |uml_operation|
|
63
|
+
tagged_value = Operation.new(uml_operation, self)
|
64
|
+
@operations << tagged_value
|
65
|
+
end
|
66
|
+
|
67
|
+
# Será povoado quando tratar dos objetos do tipo Genezalization
|
68
|
+
@children = Array.new
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def attribute_by_id(attribute_id)
|
73
|
+
attribute = @attributes.select{|obj| obj.id == attribute_id}
|
74
|
+
return attribute[0] if !attribute.nil? && attribute.size > 0
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def attribute_by_name(attribute_name)
|
79
|
+
attribute = @attributes.select{|obj| obj.name == attribute_name}
|
80
|
+
return attribute[0] if !attribute.nil? && attribute.size > 0
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def operation_by_name(operation_name)
|
85
|
+
operation = @operations.select{|obj| obj.name == operation_name}
|
86
|
+
return operation[0] if !operation.nil? && operation.size > 0
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def stereotype_by_name(name)
|
91
|
+
stereotype = @stereotypes.select{|obj| obj == name}
|
92
|
+
return stereotype[0] if !stereotype.nil? && stereotype.size > 0
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def tagged_value_by_name(tagged_value_name)
|
97
|
+
tagged_value = @tagged_values.select{|obj| obj.name == tagged_value_name}
|
98
|
+
return tagged_value[0] if !tagged_value.nil? && tagged_value.size > 0
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
|
102
|
+
def <=>(obj)
|
103
|
+
full_name <=> obj.full_name
|
104
|
+
end
|
105
|
+
|
106
|
+
def ==(obj)
|
107
|
+
return false if obj.nil?
|
108
|
+
if String == obj.class
|
109
|
+
full_name == obj
|
110
|
+
else
|
111
|
+
full_name == obj.full_name
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def full_name
|
116
|
+
"#{package.full_name}.#{name}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_s
|
120
|
+
"Clazz[#{full_name}]"
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|