ea 0.6.129 → 0.6.131

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29ca7acdd9050d074b2b4db4206b75b9601a6a3241211dc371e4d4d0fb78e0f4
4
- data.tar.gz: 12f9fa35b19bfcafac72caceb32217ab2ec98d8fac0cc6cd7e659c3dae0bada6
3
+ metadata.gz: 1ecc752b8f42a0d41b86681bc355d5f76e87c656ec5f18c2beaeffbbabe6f990
4
+ data.tar.gz: a5d37a462b9f90e594243b2d0deb2b1692866a846a9e3a57423c6ebd41ea7a13
5
5
  SHA512:
6
- metadata.gz: 6482340f93e344e5cd7a034d3af0db2152b0738f6f85eb1fb5d0a5114ff119d0b8bd0fa150b5f8e4795e92b8b5743a03f8e668f38a4b5e9ba665bcbf19c1e050
7
- data.tar.gz: 2ded830ba84797da9a07c0d9c0e70351292b5e68869f4fce38692774d55977fe3808a4651e35313025644304d9458e03f5b13225a47830013bf8a673f113376a
6
+ metadata.gz: 011a8bf645f17a054db1fc45e8b078a5436bf8dc57fa27c27a3c91fd8a34178c9f22722ceed040893417335ec472e9f751656be2d471c9f9e252b7ca882a3c44
7
+ data.tar.gz: 051b2492e102e467b7ea3f6a59edb1a3981ef7579d80fd51a23aaf815434ba90635d155a8c024cfad4d082cf006ae41c33387a2fac2cf9f5188cdc9d6fcefa11
@@ -32,9 +32,11 @@ module Ea
32
32
  relationships: relationships,
33
33
  stereotypes: [],
34
34
  notes: notes,
35
+ instance_specifications: instance_specifications,
35
36
  diagrams: diagrams
36
37
  )
37
38
  apply_tagged_values(doc)
39
+ apply_receptions(doc)
38
40
  apply_stereotypes(doc)
39
41
  resolve_type_names(doc)
40
42
  doc
@@ -42,6 +44,13 @@ module Ea
42
44
 
43
45
  private
44
46
 
47
+ def apply_receptions(doc)
48
+ grouped = ReceptionBuilder.new(xmi_path).grouped_by_owner
49
+ doc.classifiers.each do |classifier|
50
+ classifier.operations.concat(grouped.fetch(classifier.id, []))
51
+ end
52
+ end
53
+
45
54
  # Attach stereotypes parsed from <xmi:Extension>/<elements>
46
55
  # to their owning classifiers and packages.
47
56
  def apply_stereotypes(doc)
@@ -90,27 +99,37 @@ module Ea
90
99
  end
91
100
  end
92
101
 
102
+ # Replaces each type reference with its in-model qualified
103
+ # name; references that are not classifiers (primitive hrefs,
104
+ # EA placeholder idrefs) take the type name EA stores in the
105
+ # extension block.
93
106
  def resolve_type_names(doc)
94
- # In the XMI, the <type xmi:idref=...> is the type
95
- # classifier's GUID. The property's type_name was
96
- # pre-populated by PropertyBuilder with the same idref;
97
- # we replace it with the in-model qualified name when
98
- # the referenced classifier is loaded.
99
107
  qualified_by_id = doc.classifiers.each_with_object({}) do |c, acc|
100
108
  acc[c.id] = c.qualified_name if c.id && c.qualified_name
101
109
  end
110
+ types = ExtensionTypes.from_path(xmi_path)
102
111
 
103
112
  doc.classifiers.each do |classifier|
104
113
  (classifier.properties || []).each do |prop|
105
- ref = prop.type_ref
106
- next if ref.nil? || ref.empty?
107
-
108
- resolved = qualified_by_id[ref]
109
- prop.type_name = resolved if resolved
114
+ prop.type_name = qualified_by_id[prop.type_ref] ||
115
+ types.attribute_type(prop.id) || prop.type_name
116
+ end
117
+ (classifier.operations || []).each do |op|
118
+ resolve_operation_types(op, qualified_by_id, types)
110
119
  end
111
120
  end
112
121
  end
113
122
 
123
+ def resolve_operation_types(operation, qualified_by_id, types)
124
+ operation.return_type_name = qualified_by_id[operation.return_type_name] ||
125
+ types.return_type(operation.id) ||
126
+ operation.return_type_name
127
+ operation.parameters.each do |param|
128
+ param.type_name = qualified_by_id[param.type_name] ||
129
+ types.parameter_type(param.id) || param.type_name
130
+ end
131
+ end
132
+
114
133
  def metadata
115
134
  @metadata ||= MetadataBuilder.new(root, xmi_path).build
116
135
  end
@@ -123,6 +142,10 @@ module Ea
123
142
  @classifiers ||= ClassifierBuilder.new(root).build_all
124
143
  end
125
144
 
145
+ def instance_specifications
146
+ @instance_specifications ||= InstanceBuilder.new(root, xmi_path, classifiers).build_all
147
+ end
148
+
126
149
  def relationships
127
150
  @relationships ||= RelationshipBuilder.new(root).build_all
128
151
  end
@@ -22,6 +22,14 @@ module Ea
22
22
  from_comments(comments, owner_id, kind: kind)
23
23
  end
24
24
 
25
+ # Documentation text from the element's Extension properties,
26
+ # the XMI counterpart of an EA element note.
27
+ def self.from_documentation(text, owner_id, kind: "documentation")
28
+ return [] if text.nil? || text.empty?
29
+
30
+ [new(owner_id).build(kind, text)]
31
+ end
32
+
25
33
  def self.from_comments(comments, owner_id, kind: "documentation")
26
34
  Array(comments).map { |c| new(owner_id).build(kind, c.body_element || c.body_attribute) }
27
35
  end
@@ -55,10 +55,20 @@ module Ea
55
55
  visibility: element.visibility,
56
56
  properties: PropertyBuilder.new.build_all_for(element),
57
57
  operations: OperationBuilder.new.build_all_for(element),
58
- annotations: AnnotationBuilder.from_element(element, id)
58
+ annotations: annotations_for(element, id)
59
59
  }
60
60
  end
61
61
 
62
+ def annotations_for(element, id)
63
+ AnnotationBuilder.from_element(element, id) +
64
+ AnnotationBuilder.from_documentation(documentation_by_id[id], id)
65
+ end
66
+
67
+ def documentation_by_id
68
+ @documentation_by_id ||=
69
+ (root.extension&.elements&.element || []).to_h { |e| [e.idref, e.properties&.documentation] }
70
+ end
71
+
62
72
  def enumeration_args(element)
63
73
  literals = element.owned_literal.map.with_index do |lit, idx|
64
74
  Ea::Model::EnumerationLiteral.new(
@@ -67,13 +67,14 @@ module Ea
67
67
  value == "1" || value == "true" || value == "-1"
68
68
  end
69
69
 
70
+ # fontsz is EA's tenths of a point, rendered through GDI's double
71
+ # rounding (pixels = floor(tenths * 96 / 720), points =
72
+ # floor(pixels * 72 / 96)). Absent or zero means inherit, as nil.
70
73
  def scale_font_size(value)
71
- return 13 if value.nil? || value.empty?
74
+ tenths = int(value)
75
+ return nil if tenths.nil? || tenths.zero?
72
76
 
73
- pct = int(value)
74
- return 13 if pct.nil? || pct.zero?
75
-
76
- (pct * 13 / 100).round
77
+ (tenths * 96 / 720 * 72 / 96.0).floor
77
78
  end
78
79
 
79
80
  Style = Struct.new(
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+
5
+ module Ea
6
+ module Sources
7
+ module Xmi
8
+ # Type names EA stores in the <xmi:Extension><elements> block,
9
+ # where the UML side only carries a primitive-type href or a
10
+ # placeholder idref. The xmi gem does not expose operations or
11
+ # parameters of the extension, so the raw XML is read once.
12
+ #
13
+ # <attribute xmi:idref="ID"><properties type="int"/>
14
+ # <operation xmi:idref="ID"><type type="void"/>
15
+ # <parameter xmi:idref="ID"><properties type="int"/>
16
+ class ExtensionTypes
17
+ def self.from_path(xmi_path)
18
+ return empty if xmi_path.nil?
19
+
20
+ new(Nokogiri::XML(File.read(xmi_path)))
21
+ end
22
+
23
+ def self.empty
24
+ new(nil)
25
+ end
26
+
27
+ def initialize(document)
28
+ @attributes = index(document, "attribute", "properties")
29
+ @returns = index(document, "operation", "type")
30
+ @parameters = index(document, "parameter", "properties")
31
+ end
32
+
33
+ def attribute_type(id)
34
+ @attributes[id]
35
+ end
36
+
37
+ def return_type(operation_id)
38
+ @returns[operation_id]
39
+ end
40
+
41
+ def parameter_type(parameter_id)
42
+ @parameters[parameter_id]
43
+ end
44
+
45
+ private
46
+
47
+ def index(document, owner, child)
48
+ return {} unless document
49
+
50
+ document.xpath(%(//*[local-name()="#{owner}"][@*[local-name()="idref"]])).each_with_object({}) do |node, acc|
51
+ type = node.at_xpath(%(*[local-name()="#{child}"]/@type))&.value
52
+ idref = node.at_xpath("@*[local-name()='idref']").value
53
+ acc[idref] = type unless type.nil? || type.empty?
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+
5
+ module Ea
6
+ module Sources
7
+ module Xmi
8
+ # Builds Ea::Model::InstanceSpecification objects from
9
+ # uml:InstanceSpecification packaged elements. Slots come from
10
+ # the `runstate` attribute of the element's Extension entry,
11
+ # which carries slot names and operators that the typed
12
+ # `<slot>` children omit.
13
+ class InstanceBuilder
14
+ XMI_TYPE = "uml:InstanceSpecification"
15
+ RUNSTATE_XPATH =
16
+ %(//*[local-name()="element"]/*[local-name()="extendedProperties"][@runstate])
17
+
18
+ attr_reader :root, :xmi_path, :classifiers
19
+
20
+ def initialize(root, xmi_path, classifiers)
21
+ @root = root
22
+ @xmi_path = xmi_path
23
+ @classifiers = classifiers
24
+ end
25
+
26
+ def build_all
27
+ instances = []
28
+ walk(root.model) do |element, package|
29
+ instances << build_one(element, package) if element.type == XMI_TYPE
30
+ end
31
+ instances
32
+ end
33
+
34
+ private
35
+
36
+ def walk(element, package = nil, &block)
37
+ yield element, package
38
+ element.packaged_element.each do |inner|
39
+ walk(inner, inner.type == "uml:Package" ? inner : package, &block)
40
+ end
41
+ end
42
+
43
+ def build_one(element, package)
44
+ id = IdNormalizer.from_xmi_id(element.id)
45
+ properties = extension_properties[id]
46
+ Ea::Model::InstanceSpecification.new(
47
+ id: id,
48
+ name: element.name.to_s,
49
+ role_name: properties&.alias,
50
+ classifier_id: IdNormalizer.from_xmi_id(element.classifier),
51
+ classifier_name: classifier_names[element.classifier],
52
+ stereotype: properties&.stereotype.to_s,
53
+ package_id: package && IdNormalizer.from_xmi_id(package.id),
54
+ package_name: package&.name,
55
+ qualified_name: qualified_name(element, package),
56
+ slots: slots_for(id),
57
+ annotations: AnnotationBuilder.from_element(element, id) +
58
+ AnnotationBuilder.from_documentation(properties&.documentation, id)
59
+ )
60
+ end
61
+
62
+ def qualified_name(element, package)
63
+ name = element.name.to_s
64
+ return name if name.empty? || package.nil?
65
+
66
+ "#{package.name}::#{name}"
67
+ end
68
+
69
+ def classifier_names
70
+ @classifier_names ||= classifiers.to_h { |c| [c.id, c.name.to_s] }
71
+ end
72
+
73
+ def extension_properties
74
+ @extension_properties ||=
75
+ (root.extension&.elements&.element || []).to_h { |e| [e.idref, e.properties] }
76
+ end
77
+
78
+ def slots_for(id)
79
+ runstates[id].to_s.scan(Ea::Sources::Qea::InstanceBuilder::RUN_STATE_PATTERN).map do |(name, value, op)|
80
+ Ea::Model::Slot.new(name: name.to_s, value: value.to_s, op: op.to_s.empty? ? "=" : op)
81
+ end
82
+ end
83
+
84
+ def runstates
85
+ @runstates ||= extension_runstates
86
+ end
87
+
88
+ def extension_runstates
89
+ return {} if xmi_path.nil?
90
+
91
+ Nokogiri::XML(File.read(xmi_path))
92
+ .xpath(RUNSTATE_XPATH)
93
+ .to_h { |node| [node.parent["xmi:idref"], node["runstate"]] }
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -19,7 +19,7 @@ module Ea
19
19
  owner_id: owner.id,
20
20
  qualified_name: "#{owner.name}::#{op.name}",
21
21
  return_type_name: return_type_name_for(op),
22
- visibility: op.visibility,
22
+ visibility: op.visibility || "public",
23
23
  is_static: boolean(op.is_static),
24
24
  is_abstract: boolean(op.is_abstract),
25
25
  parameters: build_parameters(op, id),
@@ -30,21 +30,21 @@ module Ea
30
30
  private
31
31
 
32
32
  def build_parameters(op, owner_op_id)
33
- op.owned_parameter.map.with_index do |param, idx|
34
- direction = param.direction || (idx.zero? ? "return" : "in")
33
+ op.owned_parameter.reject { |p| p.direction == "return" }.map.with_index do |param, idx|
34
+ direction = param.direction || "in"
35
35
  Ea::Model::Parameter.new(
36
36
  id: IdNormalizer.from_xmi_id(param.id) ||
37
37
  IdNormalizer.synthetic_id(owner_op_id, "param", idx.to_s),
38
38
  name: param.name || direction,
39
39
  ordinal: idx,
40
40
  direction: direction,
41
- type_name: param.type
41
+ type_name: param.classifier_type
42
42
  )
43
43
  end
44
44
  end
45
45
 
46
46
  def return_type_name_for(op)
47
- op.owned_parameter.find { |p| p.direction == "return" }&.type
47
+ op.owned_parameter.find { |p| p.direction == "return" }&.classifier_type
48
48
  end
49
49
 
50
50
  def boolean(value)
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+
5
+ module Ea
6
+ module Sources
7
+ module Xmi
8
+ # The xmi gem omits ownedReception, so read those source members
9
+ # directly rather than inferring operations from extension rows.
10
+ class ReceptionBuilder
11
+ def initialize(xmi_path)
12
+ @xmi_path = xmi_path
13
+ end
14
+
15
+ def grouped_by_owner
16
+ return {} unless @xmi_path
17
+
18
+ @grouped_by_owner ||= read_receptions(Nokogiri::XML(File.read(@xmi_path)))
19
+ end
20
+
21
+ private
22
+
23
+ def read_receptions(document)
24
+ scopes = extension_scopes(document)
25
+ xpath = '//*[local-name()="Model"]//*[local-name()="packagedElement"]/*[local-name()="ownedReception"]'
26
+ document.xpath(xpath).each_with_object({}) do |node, grouped|
27
+ owner_id = xmi_attribute(node.parent, "id")
28
+ next unless owner_id
29
+
30
+ (grouped[owner_id] ||= []) << build_one(node, owner_id, scopes)
31
+ end
32
+ end
33
+
34
+ def build_one(node, owner_id, scopes)
35
+ id = xmi_attribute(node, "id") ||
36
+ IdNormalizer.synthetic_id(owner_id, "reception", node["name"])
37
+ Ea::Model::Operation.new(
38
+ id: id, name: node["name"], owner_id: owner_id,
39
+ qualified_name: "#{node.parent["name"]}::#{node["name"]}",
40
+ is_reception: true,
41
+ visibility: node["visibility"] || scopes[id] || "public"
42
+ )
43
+ end
44
+
45
+ def extension_scopes(document)
46
+ xpath = '//*[local-name()="Extension"]//*[local-name()="receptions"]/*[local-name()="reception"]'
47
+ document.xpath(xpath).each_with_object({}) do |node, scopes|
48
+ id = xmi_attribute(node, "idref")
49
+ scopes[id] = node["scope"].downcase if id && node["scope"]
50
+ end
51
+ end
52
+
53
+ def xmi_attribute(node, name)
54
+ node.at_xpath("@*[local-name()='#{name}']")&.value
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -7,6 +7,13 @@ module Ea
7
7
  # uml:Generalization, uml:Realization, uml:Dependency) into
8
8
  # the appropriate Ea::Model::Relationship subclass.
9
9
  class RelationshipBuilder
10
+ # Connector types that imply an aggregation on the source end
11
+ # when the end itself records none.
12
+ AGGREGATION_FOR_CONNECTOR_TYPE = {
13
+ "Aggregation" => "shared",
14
+ "Composition" => "composite"
15
+ }.freeze
16
+
10
17
  attr_reader :root
11
18
 
12
19
  def initialize(root)
@@ -59,6 +66,41 @@ module Ea
59
66
  end
60
67
 
61
68
  def association_args(element)
69
+ connector = connector_index[element.id]
70
+ return owned_end_args(element) unless connector&.source && connector.target
71
+
72
+ connector_end_args(element, connector)
73
+ end
74
+
75
+ def connector_end_args(element, connector)
76
+ source = connector.source
77
+ target = connector.target
78
+ {
79
+ source_id: source.idref,
80
+ target_id: target.idref,
81
+ source_role_name: source.role&.name,
82
+ target_role_name: target.role&.name,
83
+ source_multiplicity_lower: card_lower(source.type&.multiplicity),
84
+ source_multiplicity_upper: card_upper(source.type&.multiplicity),
85
+ target_multiplicity_lower: card_lower(target.type&.multiplicity),
86
+ target_multiplicity_upper: card_upper(target.type&.multiplicity),
87
+ source_multiplicity_raw: raw_card(source.type&.multiplicity),
88
+ target_multiplicity_raw: raw_card(target.type&.multiplicity),
89
+ source_aggregation: source_aggregation(connector),
90
+ target_aggregation: target.type&.aggregation || "none",
91
+ source_navigable: navigable?(element, :source),
92
+ target_navigable: navigable?(element, :target)
93
+ }
94
+ end
95
+
96
+ def source_aggregation(connector)
97
+ flagged = connector.source.type&.aggregation || "none"
98
+ return flagged unless flagged == "none"
99
+
100
+ AGGREGATION_FOR_CONNECTOR_TYPE.fetch(connector.properties&.ea_type, "none")
101
+ end
102
+
103
+ def owned_end_args(element)
62
104
  ends = element.member_ends.to_a
63
105
  source_id = ends.first&.idref
64
106
  target_id = ends.last&.idref
@@ -81,6 +123,24 @@ module Ea
81
123
  }
82
124
  end
83
125
 
126
+ def raw_card(cardinality)
127
+ text = cardinality.to_s.strip
128
+ text.empty? ? nil : text
129
+ end
130
+
131
+ def card_lower(cardinality)
132
+ text = raw_card(cardinality)
133
+ Integer(text.split("..").first, exception: false) if text
134
+ end
135
+
136
+ def card_upper(cardinality)
137
+ text = raw_card(cardinality)
138
+ return nil unless text
139
+
140
+ upper = text.split("..").last
141
+ upper == "*" ? -1 : Integer(upper, exception: false)
142
+ end
143
+
84
144
  def generalization_args(element)
85
145
  # PackagedElement#generalization is a collection of
86
146
  # AssociationGeneralization rows. The "specific" (child)
@@ -15,6 +15,7 @@ module Ea
15
15
  "uml:PrimitiveType" => "Ea::Model::PrimitiveType",
16
16
  "uml:Enumeration" => "Ea::Model::Enumeration",
17
17
  "uml:Interface" => "Ea::Model::Interface",
18
+ "uml:Signal" => "Ea::Model::Signal",
18
19
  }.freeze
19
20
 
20
21
  def class_for(xmi_type)
@@ -40,6 +40,14 @@ module Ea
40
40
 
41
41
  private
42
42
 
43
+ # Text of the shape's UMLKeywordLabel child; name labels and
44
+ # other labelled children never contribute a keyword.
45
+ def keyword_text(shape)
46
+ label = shape.xpath("./ownedElement[@*[local-name()=\"type\"]=\"umldi:UMLKeywordLabel\"]").first
47
+ text = label && label["text"]
48
+ text unless text.nil? || text.empty?
49
+ end
50
+
43
51
  def doc
44
52
  @doc ||= Nokogiri::XML(File.read(xmi_path))
45
53
  end
@@ -47,34 +55,14 @@ module Ea
47
55
  def keywords_by_diagram
48
56
  @keywords_by_diagram ||= begin
49
57
  result = {}
50
- # The Sparx XMI export declares the umldi: namespace
51
- # but the elements inside Diagram have lost their
52
- # prefix binding once parsed by Nokogiri — the
53
- # element name resolves to local-name "ownedElement"
54
- # and the umldi:UMLClassifierShape type information
55
- # lives in the literal `type` attribute. We therefore
56
- # match shape children by the presence of `modelElement`
57
- # and the keyword label by its `text` attribute.
58
58
  doc.xpath("//*[local-name()=\"Diagram\"]").each do |diagram|
59
59
  diagram_id = diagram["id"] || diagram["xmi:id"]
60
60
  next unless diagram_id
61
61
 
62
62
  keywords = {}
63
63
  diagram.xpath("./ownedElement[@modelElement]").each do |shape|
64
- model_id = shape["modelElement"]
65
- next unless model_id
66
-
67
- # Keyword label is the first ownedElement child
68
- # with a non-empty `text` attribute. The name
69
- # label follows it.
70
- shape.xpath("./ownedElement[@text]").each do |child|
71
- text = child["text"]
72
- next if text.nil? || text.empty?
73
- next if text.start_with?("«") # safety
74
-
75
- keywords[model_id] = text
76
- break
77
- end
64
+ text = keyword_text(shape)
65
+ keywords[shape["modelElement"]] = text if text
78
66
  end
79
67
  result[diagram_id] = keywords unless keywords.empty?
80
68
  end
@@ -18,14 +18,17 @@ module Ea
18
18
  autoload :MetadataBuilder, "ea/sources/xmi/metadata_builder"
19
19
  autoload :PackageBuilder, "ea/sources/xmi/package_builder"
20
20
  autoload :ClassifierBuilder, "ea/sources/xmi/classifier_builder"
21
+ autoload :InstanceBuilder, "ea/sources/xmi/instance_builder"
21
22
  autoload :PropertyBuilder, "ea/sources/xmi/property_builder"
22
23
  autoload :OperationBuilder, "ea/sources/xmi/operation_builder"
24
+ autoload :ReceptionBuilder, "ea/sources/xmi/reception_builder"
23
25
  autoload :RelationshipBuilder, "ea/sources/xmi/relationship_builder"
24
26
  autoload :AnnotationBuilder, "ea/sources/xmi/annotation_builder"
25
27
  autoload :TagBuilder, "ea/sources/xmi/tag_builder"
26
28
  autoload :NoteBuilder, "ea/sources/xmi/note_builder"
27
29
  autoload :StereotypeBuilder, "ea/sources/xmi/stereotype_builder"
28
30
  autoload :DiagramBuilder, "ea/sources/xmi/diagram_builder"
31
+ autoload :ExtensionTypes, "ea/sources/xmi/extension_types"
29
32
  autoload :ExtensionElements, "ea/sources/xmi/extension_elements"
30
33
  autoload :ExtensionGeometryParser, "ea/sources/xmi/extension_geometry_parser"
31
34
  autoload :ExtensionStyleParser, "ea/sources/xmi/extension_style_parser"
data/lib/ea/version.rb CHANGED
@@ -4,5 +4,5 @@ module Ea
4
4
  # Gem release version. Extracted to its own file so the
5
5
  # `gem-release` tool's `gem bump` can find and update it via the
6
6
  # standard `lib/<gem>/version.rb` convention.
7
- VERSION = "0.6.129"
7
+ VERSION = "0.6.131"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.129
4
+ version: 0.6.131
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-19 00:00:00.000000000 Z
11
+ date: 2026-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -853,12 +853,15 @@ files:
853
853
  - lib/ea/sources/xmi/extension_elements.rb
854
854
  - lib/ea/sources/xmi/extension_geometry_parser.rb
855
855
  - lib/ea/sources/xmi/extension_style_parser.rb
856
+ - lib/ea/sources/xmi/extension_types.rb
856
857
  - lib/ea/sources/xmi/id_normalizer.rb
858
+ - lib/ea/sources/xmi/instance_builder.rb
857
859
  - lib/ea/sources/xmi/metadata_builder.rb
858
860
  - lib/ea/sources/xmi/note_builder.rb
859
861
  - lib/ea/sources/xmi/operation_builder.rb
860
862
  - lib/ea/sources/xmi/package_builder.rb
861
863
  - lib/ea/sources/xmi/property_builder.rb
864
+ - lib/ea/sources/xmi/reception_builder.rb
862
865
  - lib/ea/sources/xmi/relationship_builder.rb
863
866
  - lib/ea/sources/xmi/relationship_type_map.rb
864
867
  - lib/ea/sources/xmi/stereotype_builder.rb