xmi 0.3.21 → 0.5.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.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +13 -6
- data/.gitignore +2 -1
- data/.rubocop.yml +12 -13
- data/.rubocop_todo.yml +150 -13
- data/CHANGELOG.md +55 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +10 -0
- data/README.adoc +319 -6
- data/benchmark_parse.rb +60 -0
- data/docs/migration.md +141 -0
- data/docs/versioning.md +255 -0
- data/lib/xmi/add.rb +14 -38
- data/lib/xmi/{the_custom_profile.rb → custom_profile.rb} +25 -25
- data/lib/xmi/delete.rb +14 -38
- data/lib/xmi/difference.rb +14 -38
- data/lib/xmi/documentation.rb +16 -101
- data/lib/xmi/ea_root.rb +114 -33
- data/lib/xmi/extension.rb +6 -6
- data/lib/xmi/namespace/dynamic.rb +28 -0
- data/lib/xmi/namespace/omg.rb +81 -0
- data/lib/xmi/namespace/sparx.rb +39 -0
- data/lib/xmi/namespace.rb +9 -0
- data/lib/xmi/namespace_detector.rb +138 -0
- data/lib/xmi/namespace_registry.rb +119 -0
- data/lib/xmi/parsing.rb +113 -0
- data/lib/xmi/replace.rb +14 -38
- data/lib/xmi/root.rb +49 -213
- data/lib/xmi/sparx/connector.rb +241 -0
- data/lib/xmi/sparx/custom_profile.rb +19 -0
- data/lib/xmi/sparx/diagram.rb +97 -0
- data/lib/xmi/sparx/ea_stub.rb +20 -0
- data/lib/xmi/{extensions/eauml.rb → sparx/ea_uml.rb} +3 -2
- data/lib/xmi/sparx/element.rb +453 -0
- data/lib/xmi/sparx/extension.rb +43 -0
- data/lib/xmi/{extensions → sparx}/gml.rb +9 -3
- data/lib/xmi/sparx/mappings/base_mapping.rb +182 -0
- data/lib/xmi/sparx/mappings.rb +10 -0
- data/lib/xmi/sparx/primitive_type.rb +18 -0
- data/lib/xmi/sparx/root.rb +60 -0
- data/lib/xmi/sparx/sys_ph_s.rb +18 -0
- data/lib/xmi/sparx.rb +17 -1376
- data/lib/xmi/type.rb +37 -0
- data/lib/xmi/uml.rb +191 -469
- data/lib/xmi/v20110701.rb +81 -0
- data/lib/xmi/v20131001.rb +68 -0
- data/lib/xmi/v20161101.rb +61 -0
- data/lib/xmi/version.rb +1 -1
- data/lib/xmi/version_registry.rb +164 -0
- data/lib/xmi/versioned.rb +142 -0
- data/lib/xmi.rb +83 -11
- data/scripts-xmi-profile/profile_xmi_simple.rb +213 -0
- data/xmi.gemspec +3 -9
- metadata +38 -77
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Xmi
|
|
4
|
+
# XMI 2.1 (July 2011) version-specific models
|
|
5
|
+
#
|
|
6
|
+
# This is the base version that others fall back to for common models.
|
|
7
|
+
#
|
|
8
|
+
module V20110701
|
|
9
|
+
extend Versioned
|
|
10
|
+
|
|
11
|
+
# Register ID
|
|
12
|
+
def self.register_id
|
|
13
|
+
:xmi_20110701
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Namespace classes this version binds to
|
|
17
|
+
def self.namespace_classes
|
|
18
|
+
[
|
|
19
|
+
Xmi::Namespace::Omg::Xmi20110701,
|
|
20
|
+
Xmi::Namespace::Omg::Uml20110701,
|
|
21
|
+
]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Fallback chain: common → default
|
|
25
|
+
def self.fallback_registers
|
|
26
|
+
%i[xmi_common default]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Register all models for this version
|
|
30
|
+
def self.register_models!
|
|
31
|
+
# Register version-specific models
|
|
32
|
+
register.register_model(Extension, id: :extension)
|
|
33
|
+
register.register_model(Documentation, id: :documentation)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# XMI 2.1 Extension element
|
|
37
|
+
#
|
|
38
|
+
# Structure is identical in 2.1 and 2.5.1, so V20131001 reuses this.
|
|
39
|
+
#
|
|
40
|
+
class Extension < Lutaml::Model::Serializable
|
|
41
|
+
attribute :extender, :string
|
|
42
|
+
attribute :extender_id, :string
|
|
43
|
+
|
|
44
|
+
xml do
|
|
45
|
+
root "Extension"
|
|
46
|
+
namespace Xmi::Namespace::Omg::Xmi20110701
|
|
47
|
+
|
|
48
|
+
map_attribute "extender", to: :extender
|
|
49
|
+
map_attribute "extenderID", to: :extender_id
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# XMI 2.1 Documentation element
|
|
54
|
+
#
|
|
55
|
+
# Structure differs from 2.5.1, so V20131001 defines its own.
|
|
56
|
+
#
|
|
57
|
+
class Documentation < Lutaml::Model::Serializable
|
|
58
|
+
attribute :contact, :string
|
|
59
|
+
attribute :exporter, :string
|
|
60
|
+
attribute :exporter_version, :string
|
|
61
|
+
attribute :exporter_id, :string
|
|
62
|
+
attribute :timestamp, :string
|
|
63
|
+
attribute :remarks, :string
|
|
64
|
+
|
|
65
|
+
xml do
|
|
66
|
+
root "Documentation"
|
|
67
|
+
namespace Xmi::Namespace::Omg::Xmi20110701
|
|
68
|
+
|
|
69
|
+
map_element "contact", to: :contact
|
|
70
|
+
map_element "exporter", to: :exporter
|
|
71
|
+
map_element "exporterVersion", to: :exporter_version
|
|
72
|
+
map_element "exporterID", to: :exporter_id
|
|
73
|
+
map_element "timestamp", to: :timestamp
|
|
74
|
+
map_element "remarks", to: :remarks
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Auto-register with VersionRegistry
|
|
79
|
+
VersionRegistry.register_version("20110701", self)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Xmi
|
|
4
|
+
# XMI 2.5.1 (October 2013) version-specific models
|
|
5
|
+
#
|
|
6
|
+
# Falls back to V20110701 for shared models (like Extension).
|
|
7
|
+
#
|
|
8
|
+
module V20131001
|
|
9
|
+
extend Versioned
|
|
10
|
+
|
|
11
|
+
# Register ID
|
|
12
|
+
def self.register_id
|
|
13
|
+
:xmi_20131001
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Namespace classes this version binds to
|
|
17
|
+
def self.namespace_classes
|
|
18
|
+
[
|
|
19
|
+
Xmi::Namespace::Omg::Xmi20131001,
|
|
20
|
+
Xmi::Namespace::Omg::Uml20131001,
|
|
21
|
+
Xmi::Namespace::Omg::UmlDi20131001,
|
|
22
|
+
Xmi::Namespace::Omg::UmlDc20131001,
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Fallback chain: V20110701 → common → default
|
|
27
|
+
# This allows V20131001 to use V20110701's Extension (same structure)
|
|
28
|
+
def self.fallback_registers
|
|
29
|
+
%i[xmi_20110701 xmi_common default]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Register all models for this version
|
|
33
|
+
def self.register_models!
|
|
34
|
+
# Extension is same as V20110701 - will be found via fallback
|
|
35
|
+
|
|
36
|
+
# Documentation is different - register our version
|
|
37
|
+
register.register_model(Documentation, id: :documentation)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# XMI 2.5.1 Documentation element
|
|
41
|
+
#
|
|
42
|
+
# Different structure from 2.1 - includes additional fields.
|
|
43
|
+
#
|
|
44
|
+
class Documentation < Lutaml::Model::Serializable
|
|
45
|
+
attribute :contact, :string
|
|
46
|
+
attribute :exporter, :string
|
|
47
|
+
attribute :exporter_version, :string
|
|
48
|
+
attribute :exporter_id, :string # NEW in 2.5.1
|
|
49
|
+
attribute :timestamp, :string # NEW in 2.5.1
|
|
50
|
+
attribute :remarks, :string
|
|
51
|
+
|
|
52
|
+
xml do
|
|
53
|
+
root "Documentation"
|
|
54
|
+
namespace Xmi::Namespace::Omg::Xmi20131001
|
|
55
|
+
|
|
56
|
+
map_element "contact", to: :contact
|
|
57
|
+
map_element "exporter", to: :exporter
|
|
58
|
+
map_element "exporterVersion", to: :exporter_version
|
|
59
|
+
map_element "exporterID", to: :exporter_id
|
|
60
|
+
map_element "timestamp", to: :timestamp
|
|
61
|
+
map_element "remarks", to: :remarks
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Auto-register with VersionRegistry
|
|
66
|
+
VersionRegistry.register_version("20131001", self)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Xmi
|
|
4
|
+
# XMI 2.5.2 (November 2016) version-specific models
|
|
5
|
+
#
|
|
6
|
+
# Falls back to V20131001 and V20110701 for shared models.
|
|
7
|
+
#
|
|
8
|
+
module V20161101
|
|
9
|
+
extend Versioned
|
|
10
|
+
|
|
11
|
+
# Register ID
|
|
12
|
+
def self.register_id
|
|
13
|
+
:xmi_20161101
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Namespace classes this version binds to
|
|
17
|
+
def self.namespace_classes
|
|
18
|
+
[
|
|
19
|
+
Xmi::Namespace::Omg::Xmi20161101,
|
|
20
|
+
Xmi::Namespace::Omg::Uml20161101,
|
|
21
|
+
Xmi::Namespace::Omg::UmlDi20161101,
|
|
22
|
+
Xmi::Namespace::Omg::UmlDc20161101,
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Fallback chain: V20131001 → V20110701 → common → default
|
|
27
|
+
def self.fallback_registers
|
|
28
|
+
%i[xmi_20131001 xmi_20110701 xmi_common default]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Register all models for this version
|
|
32
|
+
def self.register_models!
|
|
33
|
+
# Extension is different in 2.5.2 - register our version
|
|
34
|
+
register.register_model(Extension, id: :extension)
|
|
35
|
+
|
|
36
|
+
# Documentation is same as V20131001 - will be found via fallback
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# XMI 2.5.2 Extension element
|
|
40
|
+
#
|
|
41
|
+
# Different structure from 2.1/2.5.1 - includes additional fields.
|
|
42
|
+
#
|
|
43
|
+
class Extension < Lutaml::Model::Serializable
|
|
44
|
+
attribute :extender, :string
|
|
45
|
+
attribute :extender_id, :string
|
|
46
|
+
attribute :extender_version, :string # NEW in 2.5.2
|
|
47
|
+
|
|
48
|
+
xml do
|
|
49
|
+
root "Extension"
|
|
50
|
+
namespace Xmi::Namespace::Omg::Xmi20161101
|
|
51
|
+
|
|
52
|
+
map_attribute "extender", to: :extender
|
|
53
|
+
map_attribute "extenderID", to: :extender_id
|
|
54
|
+
map_attribute "extenderVersion", to: :extender_version
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Auto-register with VersionRegistry
|
|
59
|
+
VersionRegistry.register_version("20161101", self)
|
|
60
|
+
end
|
|
61
|
+
end
|
data/lib/xmi/version.rb
CHANGED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Xmi
|
|
4
|
+
# Registry for XMI version-specific model trees.
|
|
5
|
+
#
|
|
6
|
+
# Manages the mapping between XMI versions and their registers.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# # Get register for a specific version
|
|
10
|
+
# register = Xmi::VersionRegistry.register_for_version("20131001")
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# # Detect version from XML
|
|
14
|
+
# register = Xmi::VersionRegistry.detect_register(xml_content)
|
|
15
|
+
#
|
|
16
|
+
module VersionRegistry
|
|
17
|
+
# Map of version string => version module
|
|
18
|
+
@versions = {
|
|
19
|
+
"20110701" => nil, # Set during V20110701 init
|
|
20
|
+
"20131001" => nil, # Set during V20131001 init
|
|
21
|
+
"20161101" => nil, # Set during V20161101 init
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
class << self
|
|
25
|
+
# @api public
|
|
26
|
+
# Get register for a specific XMI version
|
|
27
|
+
#
|
|
28
|
+
# @param version [String] Version string (e.g., "20131001")
|
|
29
|
+
# @return [Lutaml::Model::Register, nil]
|
|
30
|
+
def register_for_version(version)
|
|
31
|
+
version_module = @versions[version]
|
|
32
|
+
return nil unless version_module
|
|
33
|
+
|
|
34
|
+
version_module.register
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @api public
|
|
38
|
+
# Get register for a namespace URI
|
|
39
|
+
#
|
|
40
|
+
# @param namespace_uri [String] The namespace URI
|
|
41
|
+
# @return [Lutaml::Model::Register, nil]
|
|
42
|
+
def register_for_namespace(namespace_uri)
|
|
43
|
+
Lutaml::Model::GlobalContext.register_for_namespace(namespace_uri)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @api public
|
|
47
|
+
# Register a version module
|
|
48
|
+
#
|
|
49
|
+
# @param version [String] Version string
|
|
50
|
+
# @param mod [Module] The version module
|
|
51
|
+
# @return [void]
|
|
52
|
+
def register_version(version, mod)
|
|
53
|
+
@versions = @versions.merge(version => mod)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @api public
|
|
57
|
+
# Get all registered versions
|
|
58
|
+
#
|
|
59
|
+
# @return [Array<String>]
|
|
60
|
+
def available_versions
|
|
61
|
+
@versions.keys
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @api public
|
|
65
|
+
# Get the version module for a version string
|
|
66
|
+
#
|
|
67
|
+
# @param version [String] Version string
|
|
68
|
+
# @return [Module, nil]
|
|
69
|
+
def version_module(version)
|
|
70
|
+
@versions[version]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @api public
|
|
74
|
+
# Detect version from XML content and return appropriate register
|
|
75
|
+
#
|
|
76
|
+
# For mixed namespace documents (e.g., XMI=20131001, UML=20161101), this
|
|
77
|
+
# extends the primary register's fallback chain to include registers for
|
|
78
|
+
# additional namespace versions, enabling correct type resolution.
|
|
79
|
+
#
|
|
80
|
+
# @param xml_content [String] XML content
|
|
81
|
+
# @return [Lutaml::Model::Register, nil]
|
|
82
|
+
def detect_register(xml_content)
|
|
83
|
+
versions = NamespaceDetector.detect_versions(xml_content)
|
|
84
|
+
xmi_version = versions[:xmi]
|
|
85
|
+
|
|
86
|
+
return nil unless xmi_version
|
|
87
|
+
|
|
88
|
+
primary_register = register_for_version(xmi_version)
|
|
89
|
+
return nil unless primary_register
|
|
90
|
+
|
|
91
|
+
# Handle mixed namespace documents (e.g., XMI=20131001 but UML=20161101).
|
|
92
|
+
# We need to ensure the primary register's fallback chain includes
|
|
93
|
+
# registers for any additional namespace versions, and bind those
|
|
94
|
+
# namespace URIs to the primary register so type resolution works.
|
|
95
|
+
all_versions = [versions[:xmi], versions[:uml], versions[:umldi],
|
|
96
|
+
versions[:umldc]].compact.uniq
|
|
97
|
+
|
|
98
|
+
extend_fallback_for_mixed_namespaces(primary_register, all_versions) if all_versions.length > 1
|
|
99
|
+
|
|
100
|
+
primary_register
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @api public
|
|
104
|
+
# Parse XML with automatic version detection
|
|
105
|
+
#
|
|
106
|
+
# @param xml_content [String] XML content
|
|
107
|
+
# @param model_class [Class] The model class to parse into
|
|
108
|
+
# @return [Object] Parsed model instance
|
|
109
|
+
def parse_with_detected_version(xml_content, model_class)
|
|
110
|
+
register = detect_register(xml_content)
|
|
111
|
+
|
|
112
|
+
if register
|
|
113
|
+
model_class.from_xml(xml_content, register: register)
|
|
114
|
+
else
|
|
115
|
+
# Fallback to default parsing (existing behavior)
|
|
116
|
+
model_class.from_xml(xml_content)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Handle mixed namespace documents by binding additional namespace URIs
|
|
121
|
+
# to the primary register and extending its fallback chain.
|
|
122
|
+
#
|
|
123
|
+
# The namespace binding allows the primary register to handle elements
|
|
124
|
+
# from additional namespace versions. The fallback chain extension allows
|
|
125
|
+
# type resolution for types that exist only in those additional registers.
|
|
126
|
+
#
|
|
127
|
+
# Cycles are prevented by checking that the additional register's fallback
|
|
128
|
+
# chain doesn't include the primary register (which would create a cycle).
|
|
129
|
+
#
|
|
130
|
+
# @param primary_register [Lutaml::Model::Register] The primary register
|
|
131
|
+
# @param all_versions [Array<String>] All detected namespace versions
|
|
132
|
+
# @return [void]
|
|
133
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
134
|
+
def extend_fallback_for_mixed_namespaces(primary_register, all_versions)
|
|
135
|
+
xmi_version = all_versions.first
|
|
136
|
+
other_versions = all_versions.drop(1)
|
|
137
|
+
|
|
138
|
+
other_versions.each do |ver|
|
|
139
|
+
next if ver == xmi_version
|
|
140
|
+
|
|
141
|
+
reg = register_for_version(ver)
|
|
142
|
+
next unless reg
|
|
143
|
+
|
|
144
|
+
# Bind additional namespace URIs to the primary register using
|
|
145
|
+
# proper namespace classes from NamespaceRegistry.
|
|
146
|
+
reg.bound_namespace_uris.each do |uri|
|
|
147
|
+
next if primary_register.handles_namespace?(uri)
|
|
148
|
+
|
|
149
|
+
ns_class = NamespaceRegistry.resolve(uri)
|
|
150
|
+
next unless ns_class
|
|
151
|
+
|
|
152
|
+
primary_register.bind_namespace(ns_class)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Extend fallback chain only if it won't create a cycle.
|
|
156
|
+
# A cycle would occur if reg's fallback chain includes primary_register.
|
|
157
|
+
# We check this by seeing if primary_register.id appears in reg's fallback.
|
|
158
|
+
primary_register.fallback << reg.id unless reg.fallback.include?(primary_register.id)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Xmi
|
|
4
|
+
# Base module for version-specific XMI model trees.
|
|
5
|
+
#
|
|
6
|
+
# Each version module (V20110701, V20131001, V20161101) extends this
|
|
7
|
+
# and provides its own register and namespace bindings.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# module Xmi::V20131001
|
|
11
|
+
# extend Xmi::Versioned
|
|
12
|
+
#
|
|
13
|
+
# def self.register_id
|
|
14
|
+
# :xmi_20131001
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# def self.namespace_classes
|
|
18
|
+
# [Xmi::Namespace::Omg::Xmi20131001, Xmi::Namespace::Omg::Uml20131001]
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# def self.register_models!
|
|
22
|
+
# # Register version-specific models
|
|
23
|
+
# end
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
module Versioned
|
|
27
|
+
# @api public
|
|
28
|
+
# Called when a module extends Versioned
|
|
29
|
+
def self.extended(base)
|
|
30
|
+
base.class_eval do
|
|
31
|
+
@version_register = nil
|
|
32
|
+
@initialized = false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @api public
|
|
37
|
+
# Get the register for this version
|
|
38
|
+
#
|
|
39
|
+
# @return [Lutaml::Model::Register] The version-specific register
|
|
40
|
+
def register
|
|
41
|
+
@register ||= create_register
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @api public
|
|
45
|
+
# Create and configure the register
|
|
46
|
+
#
|
|
47
|
+
# @return [Lutaml::Model::Register]
|
|
48
|
+
def create_register
|
|
49
|
+
reg = Lutaml::Model::Register.new(register_id, fallback: fallback_registers)
|
|
50
|
+
|
|
51
|
+
# Register in GlobalRegister first
|
|
52
|
+
Lutaml::Model::GlobalRegister.register(reg)
|
|
53
|
+
|
|
54
|
+
# Bind to all namespaces this version handles
|
|
55
|
+
namespace_classes.each do |ns_class|
|
|
56
|
+
reg.bind_namespace(ns_class)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@version_register = reg
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @api public
|
|
63
|
+
# Initialize this version's model tree
|
|
64
|
+
#
|
|
65
|
+
# This should be called after all version-specific models are defined.
|
|
66
|
+
# It registers all models in this version's register.
|
|
67
|
+
#
|
|
68
|
+
# @return [void]
|
|
69
|
+
def init_models!
|
|
70
|
+
return if @initialized
|
|
71
|
+
|
|
72
|
+
register
|
|
73
|
+
register_models!
|
|
74
|
+
|
|
75
|
+
@initialized = true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @api public
|
|
79
|
+
# Register all models for this version
|
|
80
|
+
#
|
|
81
|
+
# Override in each version module to register specific models.
|
|
82
|
+
#
|
|
83
|
+
# @return [void]
|
|
84
|
+
def register_models!
|
|
85
|
+
raise NotImplementedError,
|
|
86
|
+
"Each version must implement #register_models!"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @api public
|
|
90
|
+
# Get the register ID for this version
|
|
91
|
+
#
|
|
92
|
+
# @return [Symbol]
|
|
93
|
+
def register_id
|
|
94
|
+
raise NotImplementedError,
|
|
95
|
+
"Each version must implement #register_id"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @api public
|
|
99
|
+
# Get namespace classes this version binds to
|
|
100
|
+
#
|
|
101
|
+
# @return [Array<Class>] Array of Lutaml::Xml::Namespace subclasses
|
|
102
|
+
def namespace_classes
|
|
103
|
+
raise NotImplementedError,
|
|
104
|
+
"Each version must implement #namespace_classes"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @api public
|
|
108
|
+
# Get fallback register IDs for this version
|
|
109
|
+
#
|
|
110
|
+
# Default: fall back to common, then default.
|
|
111
|
+
# Override for version chains (e.g., V20161101 falls back to V20131001).
|
|
112
|
+
#
|
|
113
|
+
# @return [Array<Symbol>]
|
|
114
|
+
def fallback_registers
|
|
115
|
+
%i[xmi_common default]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @api public
|
|
119
|
+
# Get the XMI namespace class for this version
|
|
120
|
+
#
|
|
121
|
+
# @return [Class, nil]
|
|
122
|
+
def xmi_namespace
|
|
123
|
+
namespace_classes.find { |ns| ns.uri.include?("/XMI/") }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# @api public
|
|
127
|
+
# Get the UML namespace class for this version
|
|
128
|
+
#
|
|
129
|
+
# @return [Class, nil]
|
|
130
|
+
def uml_namespace
|
|
131
|
+
namespace_classes.find { |ns| ns.uri.include?("/UML/") && !ns.uri.include?("UMLD") }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# @api public
|
|
135
|
+
# Check if this version has been initialized
|
|
136
|
+
#
|
|
137
|
+
# @return [Boolean]
|
|
138
|
+
def initialized?
|
|
139
|
+
@initialized
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
data/lib/xmi.rb
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "lutaml/model"
|
|
4
|
-
require "lutaml/
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
Lutaml::Model::Config.configure do |config|
|
|
9
|
-
config.xml_adapter = Lutaml::Model::XmlAdapter::NokogiriAdapter
|
|
10
|
-
# config.yaml_adapter = Lutaml::Model::YamlAdapter::StandardYamlAdapter
|
|
11
|
-
# config.json_adapter = Lutaml::Model::JsonAdapter::StandardJsonAdapter
|
|
12
|
-
end
|
|
4
|
+
require "lutaml/xml"
|
|
5
|
+
|
|
6
|
+
# Configure XML adapter
|
|
7
|
+
Lutaml::Model::Config.xml_adapter_type = :nokogiri
|
|
13
8
|
|
|
14
9
|
module Lutaml
|
|
15
10
|
module Model
|
|
@@ -22,12 +17,33 @@ module Lutaml
|
|
|
22
17
|
end
|
|
23
18
|
|
|
24
19
|
require_relative "xmi/version"
|
|
20
|
+
require_relative "xmi/namespace"
|
|
21
|
+
require_relative "xmi/namespace/dynamic"
|
|
22
|
+
require_relative "xmi/type"
|
|
23
|
+
require_relative "xmi/namespace_detector"
|
|
24
|
+
require_relative "xmi/namespace_registry"
|
|
25
25
|
|
|
26
26
|
module Xmi
|
|
27
27
|
class Error < StandardError; end
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
# Shared value_map for XMI elements
|
|
30
|
+
# Used to handle nil, empty, and omitted values consistently
|
|
31
|
+
VALUE_MAP = {
|
|
32
|
+
from: { nil: :empty, empty: :empty, omitted: :empty },
|
|
33
|
+
to: { nil: :empty, empty: :empty, omitted: :empty },
|
|
34
|
+
}.freeze
|
|
29
35
|
end
|
|
30
36
|
|
|
37
|
+
# Bootstrap the namespace registry
|
|
38
|
+
Xmi::NamespaceRegistry.bootstrap!
|
|
39
|
+
|
|
40
|
+
# Version infrastructure
|
|
41
|
+
require_relative "xmi/versioned"
|
|
42
|
+
require_relative "xmi/version_registry"
|
|
43
|
+
require_relative "xmi/v20110701"
|
|
44
|
+
require_relative "xmi/v20131001"
|
|
45
|
+
require_relative "xmi/v20161101"
|
|
46
|
+
|
|
31
47
|
require_relative "xmi/add"
|
|
32
48
|
require_relative "xmi/delete"
|
|
33
49
|
require_relative "xmi/difference"
|
|
@@ -36,6 +52,62 @@ require_relative "xmi/extension"
|
|
|
36
52
|
require_relative "xmi/replace"
|
|
37
53
|
require_relative "xmi/ea_root"
|
|
38
54
|
require_relative "xmi/uml"
|
|
39
|
-
require_relative "xmi/
|
|
55
|
+
require_relative "xmi/custom_profile"
|
|
40
56
|
require_relative "xmi/root"
|
|
41
57
|
require_relative "xmi/sparx"
|
|
58
|
+
|
|
59
|
+
# Unified parsing API
|
|
60
|
+
require_relative "xmi/parsing"
|
|
61
|
+
|
|
62
|
+
module Xmi
|
|
63
|
+
class << self
|
|
64
|
+
# @api public
|
|
65
|
+
# Initialize all version registers
|
|
66
|
+
#
|
|
67
|
+
# Call this during gem initialization or before first use.
|
|
68
|
+
#
|
|
69
|
+
# @return [void]
|
|
70
|
+
def init_versioning!
|
|
71
|
+
return if @versioning_initialized
|
|
72
|
+
|
|
73
|
+
# Initialize versions in order (newest depends on older)
|
|
74
|
+
V20110701.init_models!
|
|
75
|
+
V20131001.init_models!
|
|
76
|
+
V20161101.init_models!
|
|
77
|
+
|
|
78
|
+
@versioning_initialized = true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @api public
|
|
82
|
+
# Parse XMI with automatic version detection
|
|
83
|
+
#
|
|
84
|
+
# @param xml_content [String] XML content
|
|
85
|
+
# @return [Root] Parsed XMI document
|
|
86
|
+
def parse(xml_content)
|
|
87
|
+
init_versioning!
|
|
88
|
+
VersionRegistry.parse_with_detected_version(xml_content, Root)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @api public
|
|
92
|
+
# Parse XMI with a specific version register
|
|
93
|
+
#
|
|
94
|
+
# @param xml_content [String] XML content
|
|
95
|
+
# @param version [String] Version string (e.g., "20131001")
|
|
96
|
+
# @return [Root] Parsed XMI document
|
|
97
|
+
def parse_with_version(xml_content, version)
|
|
98
|
+
init_versioning!
|
|
99
|
+
register = VersionRegistry.register_for_version(version)
|
|
100
|
+
raise ArgumentError, "Unknown version: #{version}" unless register
|
|
101
|
+
|
|
102
|
+
Root.from_xml(xml_content, register: register)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @api public
|
|
106
|
+
# Check if versioning has been initialized
|
|
107
|
+
#
|
|
108
|
+
# @return [Boolean]
|
|
109
|
+
def versioning_initialized?
|
|
110
|
+
@versioning_initialized || false
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|