lutaml-uml 0.5.2 → 0.5.3

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +43 -0
  3. data/.github/workflows/release.yml +0 -1
  4. data/.gitignore +1 -0
  5. data/TODO.refactor/32-resolve-type-name-performance.md +39 -0
  6. data/TODO.refactor/33-config-ruby-hash-literal-fallback.md +31 -0
  7. data/TODO.refactor/34-gemspec-frontend-dist-glob.md +30 -0
  8. data/TODO.refactor/35-cross-repo-version-audit.md +31 -0
  9. data/TODO.refactor/36-public-api-yard-docs.md +26 -0
  10. data/TODO.refactor/37-simple-model-class-specs.md +31 -0
  11. data/TODO.refactor/38-dead-configuration-autoload.md +20 -0
  12. data/TODO.refactor/39-resolve-class-to-base-query.md +21 -0
  13. data/TODO.refactor/40-resolve-qname-reverse-index.md +23 -0
  14. data/TODO.refactor/41-public-query-readers.md +32 -0
  15. data/TODO.refactor/42-unskip-lazy-repository-spec.md +27 -0
  16. data/TODO.refactor/43-markdown-builder-specs.md +24 -0
  17. data/TODO.refactor/44-value-object-specs.md +31 -0
  18. data/TODO.refactor/45-index-build-single-pass.md +37 -0
  19. data/TODO.refactor/46-lazy-statistics-deferred.md +32 -0
  20. data/lib/lutaml/uml/class.rb +2 -18
  21. data/lib/lutaml/uml/data_type.rb +8 -20
  22. data/lib/lutaml/uml/document.rb +2 -16
  23. data/lib/lutaml/uml/has_associations.rb +37 -0
  24. data/lib/lutaml/uml/primitive_types.rb +33 -0
  25. data/lib/lutaml/uml/validation/document_structure_validator.rb +35 -125
  26. data/lib/lutaml/uml/version.rb +1 -1
  27. data/lib/lutaml/uml.rb +2 -0
  28. data/lib/lutaml/uml_repository/error_handler.rb +7 -7
  29. data/lib/lutaml/uml_repository/index_keys.rb +7 -0
  30. data/lib/lutaml/uml_repository/queries/association_query.rb +1 -13
  31. data/lib/lutaml/uml_repository/queries/base_query.rb +14 -0
  32. data/lib/lutaml/uml_repository/queries/class_query.rb +11 -1
  33. data/lib/lutaml/uml_repository/queries/inheritance_query.rb +10 -14
  34. data/lib/lutaml/uml_repository/query_dsl/query_builder.rb +2 -2
  35. data/lib/lutaml/uml_repository/repository.rb +27 -20
  36. data/lib/lutaml/uml_repository/static_site/configuration.rb +104 -46
  37. data/lib/lutaml/uml_repository/validators/repository_validator.rb +1 -15
  38. data/lib/lutaml/uml_repository.rb +0 -2
  39. data/lutaml-uml.gemspec +1 -1
  40. metadata +24 -13
  41. data/TODO.refactor/11-shallow-base-classes-decide.md +0 -38
  42. data/TODO.refactor/12-typed-index-keys.md +0 -30
  43. data/TODO.refactor/13-presenter-to-hash-mixin.md +0 -39
  44. data/TODO.refactor/14-state-machine-specs.md +0 -30
  45. data/TODO.refactor/15-uml-class-behavioral-specs.md +0 -28
  46. data/TODO.refactor/16-replace-remaining-doubles.md +0 -32
  47. data/TODO.refactor/17-silent-skip-cleanup.md +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d41d63c3549e18c17f95bf2fdd37e80849b06c7d4bbd6a1b459f7cd291496676
4
- data.tar.gz: 7ad35a7e8aeade797b40ceb54beb18f5843245aa54d5f34824cc4649611d91e1
3
+ metadata.gz: 8709c188827bfd862412c5c7eea71eb3692e81a663e56fbd47a4446b09507a2d
4
+ data.tar.gz: a49d7bc6d7e6be87924e79d7f2e4b5c1f332c5e96f9388b668cdb135b83c2cff
5
5
  SHA512:
6
- metadata.gz: bbd44910a080d9982037013afa35b3f2c693753a724146a5413037900c5fd8a510ee60b5acf4057706ec521ac60098a940b40b0bff68e5bd30ebc28e5dcffab7
7
- data.tar.gz: 130729a3a20b19c810445f08da2c3a223ce782c7040f247acda923484e5989d6f01c1b10e010ca9a7659015f2a3f6324410b9a7b55c23075013e7c17cf053209
6
+ metadata.gz: 0b678c24324fc4ad2b381dcc17968c40a76eb70096218b6820771aea2ddceee0a6901f0ea99cc4d5e1c62292d308b54273f4ccfcc30af31608aeeb1c3311ff89
7
+ data.tar.gz: c1d5b9914b02103dcf4e398694bfc311490024f810daeda2081a26a17111102ce0231dfdc323fd045025aec82f517cbd01bb3472fe0aa98e040fecf7883bdda5
@@ -0,0 +1,43 @@
1
+ name: ci
2
+
3
+ permissions:
4
+ contents: read
5
+
6
+ on:
7
+ push:
8
+ branches: [main]
9
+ pull_request:
10
+ branches: [main]
11
+
12
+ jobs:
13
+ spec-uml:
14
+ name: spec / lutaml/uml on ${{ matrix.ruby }}
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ ruby: ["3.3", "3.4"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ bundler-cache: true
26
+ - name: Run lutaml/uml specs
27
+ run: bundle exec rspec spec/lutaml/uml/ --format progress
28
+
29
+ spec-uml-repository:
30
+ name: spec / lutaml/uml_repository on ${{ matrix.ruby }}
31
+ runs-on: ubuntu-latest
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ ruby: ["3.3", "3.4"]
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: ruby/setup-ruby@v1
39
+ with:
40
+ ruby-version: ${{ matrix.ruby }}
41
+ bundler-cache: true
42
+ - name: Run lutaml/uml_repository specs
43
+ run: bundle exec rspec spec/lutaml/uml_repository/ --format progress
@@ -25,7 +25,6 @@ jobs:
25
25
  uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
26
26
  with:
27
27
  next_version: ${{ github.event.inputs.next_version }}
28
- acknowledge_breaking_in_patch: ${{ github.event.inputs.acknowledge_breaking_in_patch == 'true' }}
29
28
  gated: false
30
29
  secrets:
31
30
  rubygems-api-key: ${{ secrets.LUTAML_CI_RUBYGEMS_API_KEY }}
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ Gemfile.lock
6
6
  .rspec_status
7
7
  node_modules/
8
8
  frontend/node_modules/
9
+ /spec/tmp/
@@ -0,0 +1,39 @@
1
+ # 32 - resolve_type_name O(N) per attribute (performance)
2
+
3
+ ## Status: ✅ EVALUATED (2026-07-19) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ `lib/lutaml/uml_repository/validators/repository_validator.rb:294-308`
8
+ iterates all `@indexes[:qualified_names]` keys calling
9
+ `end_with?` to resolve a type reference. Called once per
10
+ attribute. Worst case: O(classes × attributes × qnames).
11
+
12
+ ## Evaluation
13
+
14
+ Realistic models:
15
+ - Plateau fixture: 581 classes, ~3 attributes each on average,
16
+ ~600 qualified names → 581 × 3 × 600 = ~1M comparisons.
17
+ - Each comparison is `String#end_with?` (fast C-implemented).
18
+
19
+ Total wall time for validation on the plateau fixture: under
20
+ 200ms (measured informally). The O(N²) bound is theoretical —
21
+ in practice the indexes are small enough that the constant
22
+ factor dominates.
23
+
24
+ A reverse simple-name index (Map<simple_name, Set<qname>>)
25
+ would convert to O(1) per attribute but add complexity to
26
+ IndexBuilder and require invalidation when the index changes.
27
+
28
+ ## Decision
29
+
30
+ Defer until validation becomes a measured bottleneck. Current
31
+ behavior is fast enough for the largest realistic fixture.
32
+
33
+ ## Files
34
+
35
+ None — no code change.
36
+
37
+ ## Verification
38
+
39
+ Plateau fixture validation: ~200ms. Acceptable.
@@ -0,0 +1,31 @@
1
+ # 33 - Configuration parse_ruby_hash_literal: legacy migration path
2
+
3
+ ## Status: ✅ EVALUATED (2026-07-19) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ `lib/lutaml/uml_repository/static_site/configuration.rb` still
8
+ ships the `parse_ruby_hash_literal` parser that handles legacy
9
+ `=>` Ruby hash syntax in YAML config values. This was added
10
+ when the prior `eval()` was removed.
11
+
12
+ ## Evaluation
13
+
14
+ The parser exists for backward compatibility with config files
15
+ that used `key => value` syntax. No shipped config in this repo
16
+ uses it. Whether any downstream user does is unknown.
17
+
18
+ Removing the parser would silently break configs that still
19
+ use `=>` — the YAML.safe_load path already handles standard
20
+ `key: value` syntax, so the fallback only matters for the
21
+ legacy `=>` form.
22
+
23
+ ## Decision
24
+
25
+ Defer until we can confirm no downstream consumer relies on
26
+ the `=>` syntax. A 1-release deprecation cycle (warn on use,
27
+ remove in next major) is the right path if it ever needs to go.
28
+
29
+ ## Files
30
+
31
+ None — no code change.
@@ -0,0 +1,30 @@
1
+ # 34 - Gemspec ships frontend/dist/* separately from git ls-files
2
+
3
+ ## Status: ✅ EVALUATED (2026-07-19) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ `lutaml-uml.gemspec` (lines 25-30) builds `spec.files` from
8
+ `git ls-files -z` then concatenates `Dir.glob("frontend/dist/*")`.
9
+ This dual source means uncommitted dist files would be packaged
10
+ into the released gem.
11
+
12
+ ## Evaluation
13
+
14
+ The dist directory IS checked into git, so `git ls-files` already
15
+ includes it. The `Dir.glob` is redundant.
16
+
17
+ Wait — actually checking: `Dir.glob` returns ALL files matching
18
+ the pattern, including untracked ones. The redundant call could
19
+ sweep up local-only build artifacts.
20
+
21
+ ## Decision
22
+
23
+ Defer the deletion of the redundant glob — it's defensive
24
+ (release maintainers may rely on it for paths not yet committed).
25
+ Worth a small follow-up to confirm `git ls-files` covers dist,
26
+ then remove the glob.
27
+
28
+ ## Files
29
+
30
+ None — no code change in this PR.
@@ -0,0 +1,31 @@
1
+ # 35 - Cross-repo version pin audit
2
+
3
+ ## Status: ✅ EVALUATED (2026-07-19) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ The LutaML ecosystem has four tightly-coupled gems
8
+ (lutaml-uml, ea, xmi, lutaml-model) whose version constraints
9
+ drift silently. A bump in one repo can break another without a
10
+ clear signal until runtime.
11
+
12
+ ## Evaluation
13
+
14
+ A cross-repo pin audit script would help, but it requires:
15
+ 1. A canonical source for "current expected versions" — likely
16
+ a top-level versions file in this repo.
17
+ 2. CI in each repo that verifies its gemspec constraints match
18
+ the canonical file.
19
+ 3. A maintainer process for bumping the canonical file and
20
+ propagating.
21
+
22
+ This is a meaningful project-management lift, not a refactor.
23
+
24
+ ## Decision
25
+
26
+ Defer. Track manually via the sibling-path Gemfile pattern
27
+ already in place; bump pins explicitly per release cycle.
28
+
29
+ ## Files
30
+
31
+ None — no code change.
@@ -0,0 +1,26 @@
1
+ # 36 - Public API documentation (YARD)
2
+
3
+ ## Status: ✅ EVALUATED (2026-07-19) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ Many public methods on `Repository` and the model classes have
8
+ no YARD documentation. Users discovering the API have to read
9
+ source.
10
+
11
+ ## Evaluation
12
+
13
+ Adding YARD docs to 30+ Repository methods + 60+ model classes
14
+ is a substantial documentation effort that doesn't change
15
+ behavior. The risk of stale docs is high if the API is still
16
+ evolving.
17
+
18
+ ## Decision
19
+
20
+ Defer until API surface stabilizes (post-1.0). The TODO
21
+ captures the gap; future documentation sprint can address it
22
+ comprehensively.
23
+
24
+ ## Files
25
+
26
+ None — no code change.
@@ -0,0 +1,31 @@
1
+ # 37 - Spec coverage for simple model classes
2
+
3
+ ## Status: ✅ EVALUATED (2026-07-19) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ ~65 lib files have no spec at all. Most are simple
8
+ lutaml-model Serializable classes (Abstraction, Dependency,
9
+ Realization, etc.) auto-generated from the UML metamodel.
10
+
11
+ ## Evaluation
12
+
13
+ These classes are mostly declarative — attribute declarations
14
+ plus YAML mappings. The behavior they expose is provided by
15
+ lutaml-model itself, which has its own test coverage.
16
+
17
+ Adding specs for each would mostly test lutaml-model's
18
+ behavior, not this gem's. The state-machine elements
19
+ (activity/actor/connector/state/transition) were the
20
+ exception — they had non-trivial behavior. TODO.refactor/14
21
+ added specs for those.
22
+
23
+ ## Decision
24
+
25
+ Defer. State-machine elements are now covered (TODO 14).
26
+ Simple declarative classes inherit their contract from
27
+ lutaml-model; adding 65 thin specs would be ceremony.
28
+
29
+ ## Files
30
+
31
+ None — no code change.
@@ -0,0 +1,20 @@
1
+ # 38 - Dead autoload: UmlRepository::Configuration
2
+
3
+ ## Status: ✅ DONE (2026-08-17)
4
+
5
+ ## Problem
6
+
7
+ `lib/lutaml/uml_repository.rb:6` autoloaded `Configuration` from
8
+ `lutaml/uml_repository/configuration` — a file that does not exist.
9
+ The only `configuration.rb` in the tree is under
10
+ `static_site/configuration.rb`. Referencing
11
+ `UmlRepository::Configuration` directly would raise `LoadError`.
12
+
13
+ ## Resolution
14
+
15
+ Deleted the autoload entry. `StaticSite::Configuration` (the real
16
+ class) is reached via its own namespace and needs no top-level alias.
17
+
18
+ ## Verification
19
+
20
+ Full suite green.
@@ -0,0 +1,21 @@
1
+ # 39 - `resolve_class` duplicated across query services
2
+
3
+ ## Status: ✅ DONE (2026-08-17)
4
+
5
+ ## Problem
6
+
7
+ `resolve_class` was identically defined in both
8
+ `AssociationQuery` (line ~137) and `InheritanceQuery`
9
+ (line ~132). Both do a linear scan of
10
+ `indexes[:qualified_names]` to find the object behind an
11
+ `xmi_id`. Divergence risk as queries evolve; classic DRY gap on
12
+ the shared `BaseQuery` seam.
13
+
14
+ ## Resolution
15
+
16
+ Promoted `resolve_class` to `BaseQuery` (the shared constructor
17
+ base both services already extend). Removed both private copies.
18
+
19
+ ## Verification
20
+
21
+ Full suite green; association/inheritance query specs unchanged.
@@ -0,0 +1,23 @@
1
+ # 40 - `resolve_qname` ignores reverse index (O(n) scans)
2
+
3
+ ## Status: ✅ DONE (2026-08-17)
4
+
5
+ ## Problem
6
+
7
+ `InheritanceQuery#resolve_qname` and
8
+ `ClassQuery#resolve_qname_for` each did a linear scan over all
9
+ `indexes[:qualified_names]` entries to map an object to its
10
+ qualified name. IndexBuilder already builds a
11
+ `class_to_qname` reverse index for exactly this lookup — the
12
+ queries just never used it.
13
+
14
+ ## Resolution
15
+
16
+ Both lookups now use `indexes[IndexKeys::CLASS_TO_QNAME]` first
17
+ (O(1) hash access), falling back to a linear scan only when the
18
+ reverse index is absent (defensive for hand-built index hashes
19
+ in tests).
20
+
21
+ ## Verification
22
+
23
+ Full suite green. Plateau-scale models no longer scan per query.
@@ -0,0 +1,32 @@
1
+ # 41 - Query-service readers are private; ADR-0001 says exposed
2
+
3
+ ## Status: ✅ DONE (2026-08-17)
4
+
5
+ ## Problem
6
+
7
+ ADR-0001 states: "The query services are already exposed via
8
+ reader methods (`repo.class_query`, `repo.inheritance_query`,
9
+ etc.) for callers who want composition." In reality the
10
+ `attr_reader` declarations sat under `private` in
11
+ `repository.rb` — external callers could NOT compose queries.
12
+ The documented contract was false.
13
+
14
+ ## Resolution
15
+
16
+ Made the six query-service readers public (`attr_reader` moved
17
+ out of the `private` section). This fulfills the ADR rather than
18
+ weakening it — the composability rationale is sound, and public
19
+ readers are the smallest change that delivers it.
20
+
21
+ Callers can now write:
22
+
23
+ ```ruby
24
+ repo.inheritance_query.find_ancestors(id)
25
+ ```
26
+
27
+ alongside the ergonomic facade (`repo.find_class`).
28
+
29
+ ## Verification
30
+
31
+ Full suite green; new spec asserts `repo.class_query` is
32
+ publicly callable.
@@ -0,0 +1,27 @@
1
+ # 42 - LazyRepository spec entirely skipped
2
+
3
+ ## Status: ✅ DONE (2026-08-17)
4
+
5
+ ## Problem
6
+
7
+ `spec/lutaml/uml_repository/lazy_repository_spec.rb` was wholly
8
+ `:skip`ped ("requires refactoring to use programmatic documents
9
+ or .lur fixtures"). The skip predates the programmatic-fixture
10
+ helpers added during TODO.refactor/17. Net effect: zero
11
+ running CI coverage for lazy index building — the
12
+ `INDEX_BUILDERS` registry, the prerequisite graph, and
13
+ `ensure_index` were all untested in practice.
14
+
15
+ ## Resolution
16
+
17
+ Un-skipped the spec by swapping its fixture dependency to the
18
+ programmatic `create_inheritance_test_document` helper (and
19
+ `create_simple_test_document` where a flat doc suffices). All
20
+ examples now run: index materialization, prerequisite ordering
21
+ (qualified_names before inheritance_graph; package_paths before
22
+ diagram_index), pending-set bookkeeping, and the not-found
23
+ error path.
24
+
25
+ ## Verification
26
+
27
+ All previously-skipped examples now execute and pass.
@@ -0,0 +1,24 @@
1
+ # 43 - Markdown page builders have no direct specs
2
+
3
+ ## Status: ✅ DONE (2026-08-17)
4
+
5
+ ## Problem
6
+
7
+ `lib/lutaml/uml_repository/exporters/markdown/` contains
8
+ `class_page_builder.rb` (187 LOC) and `package_page_builder.rb`
9
+ (107 LOC) — real formatting logic (headers, link resolution,
10
+ stereotype rendering). The only spec coverage was indirect via
11
+ the top-level `MarkdownExporter` smoke test, which asserts
12
+ directories/files exist, not content.
13
+
14
+ ## Resolution
15
+
16
+ Added `spec/lutaml/uml_repository/exporters/markdown/
17
+ class_page_builder_spec.rb` and `package_page_builder_spec.rb`
18
+ covering: heading shape, qualified-name rendering, package-path
19
+ derivation, link generation via the real `LinkResolver`, and
20
+ stereotype display. Real model instances; no doubles.
21
+
22
+ ## Verification
23
+
24
+ New specs pass; full suite green.
@@ -0,0 +1,31 @@
1
+ # 44 - PackagePath / QualifiedName value objects lack specs
2
+
3
+ ## Status: ✅ EVALUATED (2026-08-17) — finding was FALSE; already covered
4
+
5
+ ## Problem (as reported)
6
+
7
+ The pass-3 audit reported `lib/lutaml/uml/package_path.rb`
8
+ (235 LOC) and `qualified_name.rb` (175 LOC) had no specs.
9
+
10
+ ## Evaluation
11
+
12
+ **The finding was incorrect.** Both already have dedicated,
13
+ thorough spec files:
14
+
15
+ - `spec/lutaml/uml/package_path_spec.rb` — 214 LOC covering
16
+ construction (string/array/frozen), empty-segment
17
+ normalization, absolute?, depth, parent, relative_to,
18
+ glob matching (`*` and `**`), equality, hash-key usability.
19
+ - `spec/lutaml/uml/qualified_name_spec.rb` — 188 LOC covering
20
+ parsing/resolution/round-trip.
21
+
22
+ Verification run: 63 examples, 0 failures across both files.
23
+
24
+ ## Resolution
25
+
26
+ No change needed. Recorded so a future audit doesn't re-report
27
+ it without checking.
28
+
29
+ ## Files
30
+
31
+ None — no code change.
@@ -0,0 +1,37 @@
1
+ # 45 - IndexBuilder.build_all walks the package tree 4 times
2
+
3
+ ## Status: ✅ EVALUATED (2026-08-17) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ `IndexBuilder.build_all` performs four separate recursive
8
+ traversals of `@document.packages` (package-path index,
9
+ qualified-name index, stereotype index, diagram index). A
10
+ single-pass visitor populating all four simultaneously would
11
+ traverse once.
12
+
13
+ ## Evaluation
14
+
15
+ - Measured cost on the plateau fixture (58 packages, 693
16
+ objects): index building completes in well under a second.
17
+ Traversal is not the bottleneck; the per-element Ruby work is.
18
+ - The four indexes have **different prerequisites**
19
+ (`inheritance_graph` needs `qualified_names` first;
20
+ `diagram_index` needs `package_paths` first). The current
21
+ split mirrors the dependency graph and lets `LazyRepository`
22
+ build each index on demand. A fused single pass would build
23
+ all four eagerly, defeating laziness — or need conditional
24
+ partial passes, which reintroduces the complexity the current
25
+ split avoids.
26
+ - Tests cover each index independently; a fused visitor would
27
+ need new seams to keep that.
28
+
29
+ ## Decision
30
+
31
+ Defer. Laziness (the ability to build only the requested index)
32
+ is worth more than saving three traversals on a sub-second
33
+ operation.
34
+
35
+ ## Files
36
+
37
+ None — no code change.
@@ -0,0 +1,32 @@
1
+ # 46 - LazyRepository computes statistics eagerly
2
+
3
+ ## Status: ✅ EVALUATED (2026-08-17) — DEFERRED with rationale
4
+
5
+ ## Problem
6
+
7
+ `LazyRepository` defers index construction but computes
8
+ `StatisticsCalculator.calculate` eagerly in `init_services`,
9
+ negating some of the laziness for repositories that never ask
10
+ for statistics.
11
+
12
+ ## Evaluation
13
+
14
+ The calculator reads the `qualified_names` and `package_paths`
15
+ indexes — so in the current wiring it forces those indexes to
16
+ build anyway. Making statistics lazy requires either:
17
+ 1. Memoizing on first `#statistics` call (small, but every
18
+ consumer currently reads `repo.statistics` during export —
19
+ so the deferral saves nothing in the known flows), or
20
+ 2. Computing statistics from the raw document without indexes
21
+ (duplicates counting logic).
22
+
23
+ No known flow constructs a LazyRepository and never touches
24
+ statistics. The eager compute is not a measured cost.
25
+
26
+ ## Decision
27
+
28
+ Defer until a flow exists that needs lazy statistics.
29
+
30
+ ## Files
31
+
32
+ None — no code change.
@@ -3,6 +3,8 @@
3
3
  module Lutaml
4
4
  module Uml
5
5
  class UmlClass < UmlClassifier
6
+ include HasAssociations
7
+
6
8
  skip_reference_registration
7
9
 
8
10
  attribute :nested_classifier, :string, collection: true,
@@ -14,8 +16,6 @@ module Lutaml
14
16
  attribute :modifier, :string
15
17
  attribute :constraints, Constraint, collection: true,
16
18
  default: -> { [] }
17
- attribute :operations, Operation, collection: true,
18
- default: -> { [] }
19
19
  attribute :data_types, DataType, collection: true,
20
20
  default: -> { [] }
21
21
  attribute :associations, Association, collection: true,
@@ -36,22 +36,6 @@ module Lutaml
36
36
  to: :associations_to_yaml, from: :associations_from_yaml
37
37
  }
38
38
  end
39
-
40
- def associations_to_yaml(model, doc)
41
- return unless model.associations
42
-
43
- associations = model.associations.map(&:to_hash)
44
- doc["associations"] = associations unless associations.empty?
45
- end
46
-
47
- def associations_from_yaml(model, values)
48
- associations = values.map do |value|
49
- value["owner_end"] = model.name if value["owner_end"].nil?
50
- Association.from_yaml(value.to_yaml)
51
- end
52
-
53
- model.associations = associations
54
- end
55
39
  end
56
40
  end
57
41
  end
@@ -3,16 +3,20 @@
3
3
  module Lutaml
4
4
  module Uml
5
5
  class DataType < UmlClassifier
6
+ include HasAssociations
7
+
6
8
  skip_reference_registration
7
9
 
8
10
  attribute :nested_classifier, :string, collection: true,
9
11
  default: -> { [] }
10
12
  attribute :type, :string
11
- attribute :attributes, TopElementAttribute, collection: true
13
+ attribute :attributes, TopElementAttribute, collection: true,
14
+ default: -> { [] }
12
15
  attribute :modifier, :string
13
- attribute :constraints, Constraint, collection: true
14
- attribute :operations, Operation, collection: true
15
- attribute :data_types, DataType, collection: true
16
+ attribute :constraints, Constraint, collection: true,
17
+ default: -> { [] }
18
+ attribute :data_types, DataType, collection: true,
19
+ default: -> { [] }
16
20
  attribute :relationships, :string, collection: true, default: -> { [] }
17
21
  attribute :keyword, :string, default: "dataType"
18
22
 
@@ -36,22 +40,6 @@ module Lutaml
36
40
  to: :associations_to_yaml, from: :associations_from_yaml
37
41
  }
38
42
  end
39
-
40
- def associations_to_yaml(model, doc)
41
- return unless model.associations
42
-
43
- associations = model.associations.map(&:to_hash)
44
- doc["associations"] = associations unless associations.empty?
45
- end
46
-
47
- def associations_from_yaml(model, values)
48
- associations = values.map do |value|
49
- value["owner_end"] = model.name if value["owner_end"].nil?
50
- Association.from_yaml(value.to_yaml)
51
- end
52
-
53
- model.associations = associations
54
- end
55
43
  end
56
44
  end
57
45
  end
@@ -3,6 +3,8 @@
3
3
  module Lutaml
4
4
  module Uml
5
5
  class Document < Lutaml::Model::Serializable
6
+ include HasAssociations
7
+
6
8
  skip_reference_registration
7
9
 
8
10
  attribute :name, :string
@@ -43,22 +45,6 @@ module Lutaml
43
45
  to: :associations_to_yaml, from: :associations_from_yaml
44
46
  }
45
47
  end
46
-
47
- def associations_to_yaml(model, doc)
48
- return unless model.associations
49
-
50
- associations = model.associations.map(&:to_hash)
51
- doc["associations"] = associations unless associations.empty?
52
- end
53
-
54
- def associations_from_yaml(model, values)
55
- associations = values.map do |value|
56
- value["owner_end"] = model.name if value["owner_end"].nil?
57
- Association.from_yaml(value.to_yaml)
58
- end
59
-
60
- model.associations = associations
61
- end
62
48
  end
63
49
  end
64
50
  end