xmi 0.6.2 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 594be55008babe25af18895181e47ff22127d597bc56cc19c2c0b2717682e821
4
- data.tar.gz: aea140572fcae2dd36e4d8b5fce6e3d8fefffe1a30fc4ce74a6ff18fd5f8f409
3
+ metadata.gz: 3a7a71b5331da8d8c45859ce5c634bd65bd2564ce76505bdeea512df0ffb5001
4
+ data.tar.gz: bceea821dc3bfc67feff1e43b4124288c02e1b0bf99351e32679e87f67594da3
5
5
  SHA512:
6
- metadata.gz: 12c4a3dc4575038dfde21225351477d37177cda25004cc517690b0bdbfa86aa4014ad5d2204ce10e5d0718d5d9ab4fed82cea3cefa9610c56a6bc3accd0c4142
7
- data.tar.gz: b12d8eafaf2e5dcbf306769b809df0f5b80b8ca161aa4fda49e17cdeea13af5008d39b92e5f3066a73c276fe7d9a0fa3a87546fe53179cd1eeeee4f51ecbdb26
6
+ metadata.gz: 0a67bce4eef99e51ab0213309b2d24ddaf0170c01a1c5c3094f2ba3ae2436cf9c3052a828545516650bd321f2445081fd310233c8ddaa082ca0e8d653b299029
7
+ data.tar.gz: 7d7b2f66f23144d1c27809e2d471f430e98794681da8944305ee701b889ee612c486cc9a8a118c34ef3c6fef1091f89a08007e9139215fd8fb9b88378411996c
data/.rubocop_todo.yml CHANGED
@@ -247,6 +247,5 @@ Style/BlockDelimiters:
247
247
  # Configuration parameters: AllowedClasses.
248
248
  Style/OneClassPerFile:
249
249
  Exclude:
250
- - 'lib/xmi/performance/runner.rb'
251
250
  - 'lib/xmi.rb'
252
251
  - 'lib/xmi/namespace/dynamic.rb'
data/CHANGELOG.md CHANGED
@@ -9,6 +9,67 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Added
11
11
 
12
+ - `PackagedElement#nested_classifier` with `<nestedClassifier>` mapping
13
+ (Sparx EA nesting for classifiers owned by classes), covered by
14
+ `Xmi::Sparx::Index` lookups
15
+
16
+ ### Changed
17
+
18
+ - `OwnedAttribute`/`OwnedEnd`/`OwnedParameter` serialize `lowerValue`
19
+ before `upperValue`, matching Sparx EA's element order. Serialization
20
+ only — parsing accepts either order and is unaffected
21
+
22
+ ### Documented
23
+
24
+ - `OwnedParameter#type` keeps its xmi-namespaced mapping, and the
25
+ limitation is now stated in the code and pinned by specs.
26
+ `xmi:type` is the XMI metaclass discriminator and `type` is Sparx's
27
+ classifier reference — two different attributes. lutaml-model matches
28
+ by local name, so it collapses them into one slot and only the last
29
+ one read survives re-serialization. Keeping the slot namespaced
30
+ preserves the discriminator; restoring Sparx's classifier reference is
31
+ the Sparx exporter's job. Modelling both needs namespace-disjoint
32
+ attribute deserialization upstream (lutaml-model#744).
33
+
34
+ ## [0.6.2] - 2026-07-18
35
+
36
+ ### Added
37
+
38
+ - `Xmi::Performance` namespace for benchmark tooling (`Helpers`, `Comparator`, `Runner`) with autoload
39
+ - Polymorphic dispatch contract specs asserting frozen + default-value behavior at the data level
40
+ - Fallback coverage for `OwnedAttribute#upper_value`, `OwnedEnd#upper_value`, `OwnedParameter#upper_value` (previously only `Slot#value` was tested)
41
+ - Round-trip coverage for `uml:Component` and unknown `xmi:type` discriminators
42
+ - `spec/xmi/performance_spec.rb` covering autoload, class cloning, and namespace independence
43
+
44
+ ### Fixed
45
+
46
+ - Deep-freeze the inner `class_map` hash on both `PACKAGED_ELEMENT` and `VALUE_SPECIFICATION` polymorphic maps. The outer `.freeze` was shallow — the inner hash was mutable at runtime
47
+ - `cached_fixture` ivar caching bug: the cache lived on per-example `self` and was recreated empty on every call, defeating its purpose. Replaced with a top-level `FIXTURE_CONTENT_CACHE` constant
48
+
49
+ ### Changed
50
+
51
+ - Performance task constants moved into `Xmi::Performance` namespace: `PerformanceComparator` → `Xmi::Performance::Comparator`, `PerformanceHelpers` → `Xmi::Performance::Helpers`, `BenchmarkRunner` → `Xmi::Performance::Runner`. Dual-load mechanism replaced with class cloning via `const_set`
52
+ - Data-drive dispatch and subclass-schema specs from the class_map so adding a subclass + map entry auto-gains coverage (OCP for the test layer)
53
+ - Replace `.send(...)` with `.public_send(...)` in sparx extension specs for safer dynamic dispatch
54
+ - Normalize `require_relative` to `require "xmi"` in 8 spec files for consistency with the rest of the suite
55
+ - Correct polymorphic map comment terminology (`default_proc` → `default value`) and document the two-path fallback
56
+
57
+ ### Removed
58
+
59
+ - `lib/tasks/performance_helpers.rb`, `lib/tasks/performance_comparator.rb`, `lib/tasks/benchmark_runner.rb` (moved to `lib/xmi/performance/`)
60
+ - Top-level constants `PerformanceComparator`, `PerformanceHelpers`, `BenchmarkRunner`, `Term` (moved into `Xmi::Performance`)
61
+ - Stale `TODO.next/01` and `TODO 02` references from comments (scratchpads were deleted; Phase A explanations kept)
62
+
63
+ ## [0.6.1] - 2026-07-09
64
+
65
+ ### Added
66
+
67
+ - `Xmi::Uml::Component` subclass for `<packagedElement xmi:type="uml:Component">` (UML 2.5 §12.3)
68
+ - `uml:Component` entry in `PACKAGED_ELEMENT_POLYMORPHIC_MAP`
69
+ - Polymorphic dispatch fallback: unknown or missing `xmi:type` resolves to the abstract base class via `Hash` default value, avoiding the lutaml-model `Object.const_get(nil)` `TypeError` on real Sparx XMI containing types not yet modelled
70
+
71
+ ### Added
72
+
12
73
  - Namespace-bound registers for version-aware type resolution
13
74
  - `Register#bind_namespace` for binding registers to namespaces
14
75
  - `Register#resolve_in_namespace` for namespace-aware type lookup
data/CLAUDE.md CHANGED
@@ -150,7 +150,7 @@ Two attributes use lutaml-model's polymorphic dispatch on `xmi:type`:
150
150
  - `PackagedElement.packaged_element` (and `UmlModel.packaged_element`) — dispatches to typed subclasses (`UmlClass`, `Association`, `Interface`, `InstanceSpecification`, etc.). Map: `Xmi::Uml::PACKAGED_ELEMENT_POLYMORPHIC_MAP` in `lib/xmi/uml/packaged_element.rb`.
151
151
  - `Slot.value`, `OwnedAttribute.upper_value`/`lower_value`/`default_value`, `OwnedEnd.upper_value`/`lower_value`/`default_value`, `OwnedParameter.upper_value`/`lower_value`/`default_value` — dispatch to ValueSpecification subclasses (`OpaqueExpression`, `LiteralString`, `LiteralInteger`, etc.). Map: `Xmi::Uml::VALUE_SPECIFICATION_POLYMORPHIC_MAP` in `lib/xmi/uml/value_specification.rb`.
152
152
 
153
- **Known limitation:** polymorphic dispatch crashes with `TypeError` if the discriminator is missing or unrecognized. This is a lutaml-model upstream issue (it calls `Object.const_get(nil)`); the failure mode is locked in by `spec/xmi/uml/polymorphic_robustness_spec.rb`. Fix lives upstream, not here.
153
+ **Fallback contract:** unknown or missing `xmi:type` resolves to the abstract base (`PackagedElement` / `ValueSpecification`) via the class_map's Hash default value no crash. Locked in by `spec/xmi/uml/polymorphic_map_contract_spec.rb` and `spec/xmi/uml/polymorphic_robustness_spec.rb`. Two paths land at the base: a missing discriminator short-circuits upstream (the declared attribute type is used); an unknown discriminator hits the Hash default. Residual upstream gap — modelling `xmi:type` and unprefixed `type` as separate slots on one element — is tracked in lutaml-model#744.
154
154
 
155
155
  ### Key Files
156
156
 
@@ -188,7 +188,7 @@ A shared constant is available at `Xmi::Sparx::VALUE_MAP`.
188
188
 
189
189
  ## Known Issues
190
190
 
191
- One serialization test fails due to a lutaml-model bug where `to_xml` does not respect namespace declarations on custom types. See `LUTAML_MODEL_BUG_REPORT.md` for details. Parsing works correctly; only serialization is affected.
191
+ Attribute deserialization in lutaml-model is not namespace-disjoint: same-local-name attributes in different namespaces collapse into one model slot, document-order dependent. This affects modelling `xmi:type` (the XMI discriminator) and unprefixed `type` (Sparx's classifier reference) as separate attributes on one element. Tracked in lutaml-model#744 with a repro. Serialization is not affected it is already namespace-disjoint.
192
192
 
193
193
  ## Limitations
194
194
 
@@ -30,12 +30,12 @@ module Xmi
30
30
  all_current = {}
31
31
  all_base = {}
32
32
 
33
- puts Helpers::Term.header("Performance Comparison", color: Helpers::CYAN)
33
+ puts Term.header("Performance Comparison", color: CYAN)
34
34
  puts
35
- puts " #{Helpers::DIM}Comparing#{Helpers::CLEAR}:"
36
- puts " #{Helpers::CYAN} Current#{Helpers::CLEAR}: #{Helpers.current_branch}"
37
- puts " #{Helpers::CYAN} Base#{Helpers::CLEAR}: #{DEFAULT_BASE}"
38
- puts " #{Helpers::CYAN} Threshold#{Helpers::CLEAR}: #{(DEFAULT_THRESHOLD * 100).round(0)}% regression allowed"
35
+ puts " #{DIM}Comparing#{CLEAR}:"
36
+ puts " #{CYAN} Current#{CLEAR}: #{Helpers.current_branch}"
37
+ puts " #{CYAN} Base#{CLEAR}: #{DEFAULT_BASE}"
38
+ puts " #{CYAN} Threshold#{CLEAR}: #{(DEFAULT_THRESHOLD * 100).round(0)}% regression allowed"
39
39
  puts
40
40
 
41
41
  base_runner = Helpers::Base::Runner.new(
@@ -67,12 +67,12 @@ module Xmi
67
67
  def handle_results(summary)
68
68
  puts
69
69
  if summary[:regressions].any?
70
- puts " #{Helpers::RED}#{Helpers::BOLD}❌ PERFORMANCE REGRESSIONS DETECTED#{Helpers::CLEAR}"
71
- puts " #{Helpers::RED}#{summary[:regressions].length} benchmark(s) regressed beyond threshold#{Helpers::CLEAR}"
70
+ puts " #{RED}#{BOLD}❌ PERFORMANCE REGRESSIONS DETECTED#{CLEAR}"
71
+ puts " #{RED}#{summary[:regressions].length} benchmark(s) regressed beyond threshold#{CLEAR}"
72
72
  puts
73
73
  exit(1)
74
74
  else
75
- puts " #{Helpers::GREEN}#{Helpers::BOLD}✅ ALL BENCHMARKS PASSED#{Helpers::CLEAR}"
75
+ puts " #{GREEN}#{BOLD}✅ ALL BENCHMARKS PASSED#{CLEAR}"
76
76
  puts
77
77
  end
78
78
  end
@@ -8,45 +8,10 @@ require "fileutils"
8
8
  module Xmi
9
9
  module Performance
10
10
  # Shared helpers for the performance benchmark rake tasks.
11
- # Provides terminal formatting, git/process helpers, and the
12
- # dual-namespace Runner loader used by the comparison flow.
11
+ # Provides git/process helpers and the dual-namespace Runner loader
12
+ # used by the comparison flow. Terminal formatting lives in
13
+ # Xmi::Performance::Term; color codes on Xmi::Performance.
13
14
  module Helpers
14
- # ANSI color codes for terminal output
15
- CLEAR = "\e[0m"
16
- BOLD = "\e[1m"
17
- DIM = "\e[2m"
18
- CYAN = "\e[36m"
19
- GREEN = "\e[32m"
20
- YELLOW = "\e[33m"
21
- RED = "\e[31m"
22
- GRAY = "\e[90m"
23
- MAGENTA = "\e[35m"
24
-
25
- # Terminal formatting helpers
26
- module Term
27
- extend self
28
-
29
- HL = "─"
30
- VL = "│"
31
- TL = "┌"
32
- TR = "┐"
33
- BL = "└"
34
- BR = "┘"
35
-
36
- def header(title, color: Helpers::CYAN)
37
- width = 78
38
- line = HL * width
39
- puts
40
- puts "#{color}#{TL}#{line}#{TR}#{CLEAR}"
41
- puts "#{color}#{VL}#{CLEAR} #{BOLD}#{color}#{title}#{CLEAR}#{' ' * (width - title.length - 4)}#{color}#{VL}#{CLEAR}"
42
- puts "#{color}#{BL}#{line}#{BR}#{CLEAR}"
43
- end
44
-
45
- def sep(char: HL, width: 78)
46
- puts "#{DIM}#{char * width}#{CLEAR}"
47
- end
48
- end
49
-
50
15
  # Dual-namespace containers. The Runner class is cloned into
51
16
  # each so that Base and Current hold independent class objects
52
17
  # (preserving the shape of the comparison API even though both
@@ -123,7 +88,6 @@ module Xmi
123
88
  when "NEW" then YELLOW
124
89
  else GREEN
125
90
  end
126
- row[:status] == "REGRESSED" ? RED : DIM
127
91
 
128
92
  puts " #{row[:benchmark].ljust(40)} #{format('%-12.1f',
129
93
  row[:base_ips] || 0)} #{format('%-12.1f',
@@ -5,65 +5,6 @@ require "stringio"
5
5
 
6
6
  module Xmi
7
7
  module Performance
8
- # Pretty terminal formatting for benchmark output.
9
- module Term
10
- CLEAR = "\e[0m"
11
- BOLD = "\e[1m"
12
- DIM = "\e[2m"
13
- RED = "\e[31m"
14
- GREEN = "\e[32m"
15
- YELLOW = "\e[33m"
16
- CYAN = "\e[36m"
17
- MAGENTA = "\e[35m"
18
-
19
- HL = "─"
20
- VL = "│"
21
- TL = "┌"
22
- TR = "┐"
23
- BL = "└"
24
- BR = "┘"
25
-
26
- def self.header(title, color: CYAN)
27
- width = 78
28
- line = HL * width
29
- puts
30
- puts "#{color}#{TL}#{line}#{TR}#{CLEAR}"
31
- puts "#{color}#{VL}#{CLEAR} #{BOLD}#{color}#{title}#{CLEAR}#{' ' * (width - title.length - 4)}#{color}#{VL}#{CLEAR}"
32
- puts "#{color}#{BL}#{line}#{BR}#{CLEAR}"
33
- end
34
-
35
- def self.sep(char: HL, width: 78)
36
- puts "#{DIM}#{char * width}#{CLEAR}"
37
- end
38
-
39
- def self.env_info(ruby_version, platform)
40
- puts
41
- puts " #{DIM}Environment:#{CLEAR}"
42
- puts " #{VL} Ruby #{ruby_version} on #{platform}#{' ' * (60 - ruby_version.length - platform.length)}#{VL}"
43
- puts " #{DIM}#{BL}#{HL * 76}#{BR}#{CLEAR}"
44
- puts
45
- end
46
-
47
- def self.category(title, icon:, description:, failure_means:,
48
- compare_against: nil)
49
- puts
50
- puts "#{CYAN}#{VL}#{CLEAR} #{BOLD}#{MAGENTA}#{icon} #{title}#{CLEAR}"
51
- puts
52
- puts " #{DIM}#{description}#{CLEAR}"
53
- puts
54
-
55
- if compare_against
56
- puts " #{CYAN}Comparing against:#{CLEAR} #{compare_against}"
57
- puts
58
- end
59
-
60
- puts " #{YELLOW}⚠️ Failure means:#{CLEAR} #{failure_means}"
61
- puts
62
- sep(width: 76)
63
- puts
64
- end
65
- end
66
-
67
8
  # Runs XMI parsing benchmarks against fixture files and reports
68
9
  # iterations-per-second with error margins.
69
10
  class Runner
@@ -112,7 +53,7 @@ compare_against: nil)
112
53
  end
113
54
 
114
55
  def run_benchmarks
115
- Term.header("XMI Performance Benchmarks", color: Term::CYAN)
56
+ Term.header("XMI Performance Benchmarks", color: CYAN)
116
57
 
117
58
  unless @env_shown
118
59
  Term.env_info(RUBY_VERSION, RUBY_PLATFORM)
@@ -154,7 +95,7 @@ compare_against: nil)
154
95
  end
155
96
 
156
97
  puts " #{'Benchmark'.ljust(40)} #{'IPS'.rjust(12)} #{'Deviation'.rjust(12)}"
157
- puts " #{Term::DIM}#{Term::HL * 66}#{Term::CLEAR}"
98
+ puts " #{DIM}#{Term::HL * 66}#{CLEAR}"
158
99
 
159
100
  category_results.each do |r|
160
101
  ips = (r[:result][:lower] + r[:result][:upper]) / 2.0
@@ -246,7 +187,7 @@ compare_against: nil)
246
187
  puts
247
188
  Term.sep(width: 78)
248
189
  puts
249
- puts " #{Term::BOLD}#{Term::MAGENTA}SUMMARY#{Term::CLEAR}"
190
+ puts " #{BOLD}#{MAGENTA}SUMMARY#{CLEAR}"
250
191
  puts
251
192
 
252
193
  @all_results.each do |r|
@@ -254,7 +195,7 @@ compare_against: nil)
254
195
  end
255
196
 
256
197
  puts
257
- puts " #{Term::DIM}#{@all_results.length} benchmarks completed#{Term::CLEAR}"
198
+ puts " #{DIM}#{@all_results.length} benchmarks completed#{CLEAR}"
258
199
  puts
259
200
  end
260
201
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xmi
4
+ module Performance
5
+ # Terminal formatting for benchmark output. Colors live on the
6
+ # parent Xmi::Performance module; box-drawing characters here.
7
+ module Term
8
+ extend self
9
+
10
+ HL = "─"
11
+ VL = "│"
12
+ TL = "┌"
13
+ TR = "┐"
14
+ BL = "└"
15
+ BR = "┘"
16
+
17
+ def header(title, color: CYAN)
18
+ width = 78
19
+ line = HL * width
20
+ puts
21
+ puts "#{color}#{TL}#{line}#{TR}#{CLEAR}"
22
+ puts "#{color}#{VL}#{CLEAR} #{BOLD}#{color}#{title}#{CLEAR}#{' ' * (width - title.length - 4)}#{color}#{VL}#{CLEAR}"
23
+ puts "#{color}#{BL}#{line}#{BR}#{CLEAR}"
24
+ end
25
+
26
+ def sep(char: HL, width: 78)
27
+ puts "#{DIM}#{char * width}#{CLEAR}"
28
+ end
29
+
30
+ def env_info(ruby_version, platform)
31
+ puts
32
+ puts " #{DIM}Environment:#{CLEAR}"
33
+ puts " #{VL} Ruby #{ruby_version} on #{platform}#{' ' * (60 - ruby_version.length - platform.length)}#{VL}"
34
+ puts " #{DIM}#{BL}#{HL * 76}#{BR}#{CLEAR}"
35
+ puts
36
+ end
37
+
38
+ def category(title, icon:, description:, failure_means:,
39
+ compare_against: nil)
40
+ puts
41
+ puts "#{CYAN}#{VL}#{CLEAR} #{BOLD}#{MAGENTA}#{icon} #{title}#{CLEAR}"
42
+ puts
43
+ puts " #{DIM}#{description}#{CLEAR}"
44
+ puts
45
+
46
+ if compare_against
47
+ puts " #{CYAN}Comparing against:#{CLEAR} #{compare_against}"
48
+ puts
49
+ end
50
+
51
+ puts " #{YELLOW}⚠️ Failure means:#{CLEAR} #{failure_means}"
52
+ puts
53
+ sep(width: 76)
54
+ puts
55
+ end
56
+ end
57
+ end
58
+ end
@@ -11,5 +11,17 @@ module Xmi
11
11
  autoload :Helpers, "xmi/performance/helpers"
12
12
  autoload :Comparator, "xmi/performance/comparator"
13
13
  autoload :Runner, "xmi/performance/runner"
14
+ autoload :Term, "xmi/performance/term"
15
+
16
+ # ANSI color codes shared by Term, Helpers, Comparator, and Runner.
17
+ CLEAR = "\e[0m"
18
+ BOLD = "\e[1m"
19
+ DIM = "\e[2m"
20
+ CYAN = "\e[36m"
21
+ GREEN = "\e[32m"
22
+ YELLOW = "\e[33m"
23
+ RED = "\e[31m"
24
+ GRAY = "\e[90m"
25
+ MAGENTA = "\e[35m"
14
26
  end
15
27
  end
@@ -190,6 +190,7 @@ module Xmi
190
190
 
191
191
  # Recurse into children
192
192
  walk_packaged_elements(pe.packaged_element, pe)
193
+ walk_packaged_elements(pe.nested_classifier, pe)
193
194
  end
194
195
  end
195
196
 
@@ -35,10 +35,11 @@ module Xmi
35
35
  map_attribute "aggregation", to: :aggregation
36
36
 
37
37
  map_element "type", to: :uml_type
38
- map_element "upperValue", to: :upper_value,
39
- polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
38
+ # Sparx EA emits lowerValue before upperValue.
40
39
  map_element "lowerValue", to: :lower_value,
41
40
  polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
41
+ map_element "upperValue", to: :upper_value,
42
+ polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
42
43
  map_element "defaultValue", to: :default_value,
43
44
  polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
44
45
  end
@@ -24,10 +24,11 @@ module Xmi
24
24
  map_attribute "isComposite", to: :is_composite
25
25
 
26
26
  map_element "type", to: :uml_type
27
- map_element "upperValue", to: :upper_value,
28
- polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
27
+ # Sparx EA emits lowerValue before upperValue.
29
28
  map_element "lowerValue", to: :lower_value,
30
29
  polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
30
+ map_element "upperValue", to: :upper_value,
31
+ polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
31
32
  map_element "defaultValue", to: :default_value,
32
33
  polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
33
34
  end
@@ -4,6 +4,23 @@ module Xmi
4
4
  module Uml
5
5
  class OwnedParameter < Base
6
6
  attribute :name, :string
7
+ # These are two DIFFERENT attributes that collide here:
8
+ # xmi:type="uml:Parameter" — the XMI metaclass discriminator
9
+ # type="EAnone_void" — Sparx's classifier reference
10
+ #
11
+ # Known limit: lutaml-model matches attributes by local name only,
12
+ # so both land in this one slot and whichever appears LAST in the
13
+ # input wins. They are not two spellings of one concept, and only
14
+ # one of them can survive a round trip.
15
+ #
16
+ # The slot stays xmi-namespaced, which keeps the discriminator —
17
+ # the general UML XMI shape this gem round-trips. Sparx's
18
+ # classifier reference still parses into it, but re-serializes as
19
+ # `xmi:type`. Restoring the Sparx spelling belongs to the Sparx
20
+ # exporter, not to this shared model: flipping it here would break
21
+ # the general case for every other consumer. Modelling both at
22
+ # once needs namespace-disjoint attribute deserialization
23
+ # upstream (lutaml-model#744).
7
24
  attribute :type, ::Xmi::Type::XmiType
8
25
  attribute :direction, :string
9
26
  attribute :visibility, :string
@@ -24,10 +41,11 @@ module Xmi
24
41
  map_attribute "isUnique", to: :is_unique
25
42
  map_attribute "effect", to: :effect
26
43
 
27
- map_element "upperValue", to: :upper_value,
28
- polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
44
+ # Sparx EA emits lowerValue before upperValue.
29
45
  map_element "lowerValue", to: :lower_value,
30
46
  polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
47
+ map_element "upperValue", to: :upper_value,
48
+ polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
31
49
  map_element "defaultValue", to: :default_value,
32
50
  polymorphic: VALUE_SPECIFICATION_POLYMORPHIC_MAP
33
51
  end
@@ -64,6 +64,10 @@ module Xmi
64
64
 
65
65
  attribute :packaged_element, PackagedElement, collection: true,
66
66
  polymorphic: true
67
+ # Sparx EA nests child classifiers (a Class owned by a Class)
68
+ # as <nestedClassifier> rather than <packagedElement>.
69
+ attribute :nested_classifier, PackagedElement, collection: true,
70
+ polymorphic: true
67
71
  attribute :owned_end, OwnedEnd, collection: true
68
72
  attribute :owned_attribute, OwnedAttribute, collection: true
69
73
  attribute :owned_comment, OwnedComment, collection: true
@@ -96,6 +100,8 @@ module Xmi
96
100
  map_element "ownedOperation", to: :owned_operation, value_map: VALUE_MAP
97
101
  map_element "packagedElement", to: :packaged_element,
98
102
  polymorphic: PACKAGED_ELEMENT_POLYMORPHIC_MAP
103
+ map_element "nestedClassifier", to: :nested_classifier,
104
+ polymorphic: PACKAGED_ELEMENT_POLYMORPHIC_MAP
99
105
  map_element "memberEnd", to: :member_ends, value_map: VALUE_MAP
100
106
  map_element "slot", to: :slot, value_map: VALUE_MAP
101
107
  map_element "specification", to: :specification
data/lib/xmi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Xmi
4
- VERSION = "0.6.2"
4
+ VERSION = "0.7.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xmi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
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-07-18 00:00:00.000000000 Z
11
+ date: 2026-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -98,6 +98,7 @@ files:
98
98
  - lib/xmi/performance/comparator.rb
99
99
  - lib/xmi/performance/helpers.rb
100
100
  - lib/xmi/performance/runner.rb
101
+ - lib/xmi/performance/term.rb
101
102
  - lib/xmi/replace.rb
102
103
  - lib/xmi/root.rb
103
104
  - lib/xmi/sparx.rb