xmimodel 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|