sts 0.6.2 → 0.6.4
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/.rubocop_todo.yml +1 -0
- data/TODO.finalize/00-overview.md +56 -0
- data/TODO.finalize/01-investigation-findings.md +39 -0
- data/TODO.finalize/02-delete-tbxisotml-fn-fngroup.md +20 -0
- data/TODO.finalize/03-repoint-isosts-call-sites.md +27 -0
- data/TODO.finalize/04-repoint-tbxisotml-call-sites.md +24 -0
- data/TODO.finalize/05-sts-regression-specs.md +27 -0
- data/TODO.finalize/06-lutaml-model-element-builder-fix.md +45 -0
- data/TODO.finalize/07-lutaml-model-specs.md +12 -0
- data/TODO.finalize/08-sts-ruby-pr.md +20 -0
- data/TODO.finalize/09-lutaml-model-pr.md +5 -0
- data/TODO.finalize/10-audit-other-duplicates.md +29 -0
- data/TODO.finalize/11-strengthen-anti-patterns-spec.md +24 -0
- data/TODO.sts-refactor/00-overview.md +30 -18
- data/TODO.sts-refactor/03-namespace-coupling.md +50 -32
- data/lib/sts/iso_sts/abbrev.rb +41 -0
- data/lib/sts/iso_sts/annotation.rb +31 -0
- data/lib/sts/iso_sts/body.rb +2 -3
- data/lib/sts/iso_sts/bold.rb +1 -1
- data/lib/sts/iso_sts/copyright_holder.rb +6 -0
- data/lib/sts/iso_sts/copyright_statement.rb +6 -0
- data/lib/sts/iso_sts/copyright_year.rb +4 -0
- data/lib/sts/iso_sts/country.rb +26 -0
- data/lib/sts/iso_sts/day.rb +24 -0
- data/lib/sts/iso_sts/doc_number.rb +4 -1
- data/lib/sts/iso_sts/doc_type.rb +4 -1
- data/lib/sts/iso_sts/edition.rb +6 -0
- data/lib/sts/iso_sts/email.rb +37 -0
- data/lib/sts/iso_sts/etal.rb +22 -0
- data/lib/sts/iso_sts/ext_link.rb +10 -0
- data/lib/sts/iso_sts/fax.rb +22 -0
- data/lib/sts/iso_sts/fpage.rb +2 -0
- data/lib/sts/iso_sts/front.rb +0 -2
- data/lib/sts/iso_sts/graphic.rb +10 -0
- data/lib/sts/iso_sts/ics.rb +4 -1
- data/lib/sts/iso_sts/inline_graphic.rb +42 -0
- data/lib/sts/iso_sts/institution.rb +41 -0
- data/lib/sts/iso_sts/is_proof.rb +7 -2
- data/lib/sts/iso_sts/issue.rb +2 -0
- data/lib/sts/iso_sts/italic.rb +1 -1
- data/lib/sts/iso_sts/label.rb +4 -0
- data/lib/sts/iso_sts/lpage.rb +2 -0
- data/lib/sts/iso_sts/milestone_end.rb +25 -0
- data/lib/sts/iso_sts/milestone_start.rb +25 -0
- data/lib/sts/iso_sts/mixed_citation.rb +15 -3
- data/lib/sts/iso_sts/month.rb +24 -0
- data/lib/sts/iso_sts/named_content.rb +2 -0
- data/lib/sts/iso_sts/num.rb +24 -0
- data/lib/sts/iso_sts/object_id.rb +24 -0
- data/lib/sts/iso_sts/originator.rb +4 -1
- data/lib/sts/iso_sts/page_range.rb +2 -0
- data/lib/sts/iso_sts/paragraph.rb +1 -1
- data/lib/sts/iso_sts/part_number.rb +4 -1
- data/lib/sts/iso_sts/phone.rb +22 -0
- data/lib/sts/iso_sts/proj_id.rb +4 -1
- data/lib/sts/iso_sts/pub_date.rb +2 -0
- data/lib/sts/iso_sts/pub_id.rb +2 -0
- data/lib/sts/iso_sts/publisher.rb +23 -0
- data/lib/sts/iso_sts/publisher_loc.rb +29 -0
- data/lib/sts/iso_sts/publisher_name.rb +23 -0
- data/lib/sts/iso_sts/release_version.rb +4 -1
- data/lib/sts/iso_sts/sdo.rb +4 -1
- data/lib/sts/iso_sts/season.rb +24 -0
- data/lib/sts/iso_sts/sec.rb +2 -5
- data/lib/sts/iso_sts/secretariat.rb +4 -1
- data/lib/sts/iso_sts/standard.rb +2 -2
- data/lib/sts/iso_sts/std.rb +1 -1
- data/lib/sts/iso_sts/sub.rb +4 -0
- data/lib/sts/iso_sts/sup.rb +4 -0
- data/lib/sts/iso_sts/suppl_number.rb +4 -1
- data/lib/sts/iso_sts/suppl_type.rb +4 -1
- data/lib/sts/iso_sts/suppl_version.rb +4 -1
- data/lib/sts/iso_sts/td.rb +1 -1
- data/lib/sts/iso_sts/term_sec.rb +1 -1
- data/lib/sts/iso_sts/th.rb +1 -1
- data/lib/sts/iso_sts/title.rb +4 -0
- data/lib/sts/iso_sts/underline.rb +2 -0
- data/lib/sts/iso_sts/uri.rb +2 -0
- data/lib/sts/iso_sts/urn.rb +4 -1
- data/lib/sts/iso_sts/version.rb +4 -1
- data/lib/sts/iso_sts/volume.rb +2 -0
- data/lib/sts/iso_sts/year.rb +2 -0
- data/lib/sts/iso_sts.rb +23 -2
- data/lib/sts/tbx_iso_tml/table_wrap_foot.rb +2 -2
- data/lib/sts/tbx_iso_tml/td.rb +1 -1
- data/lib/sts/tbx_iso_tml/th.rb +1 -1
- data/lib/sts/tbx_iso_tml.rb +0 -2
- data/lib/sts/version.rb +1 -1
- metadata +32 -3
- data/lib/sts/tbx_iso_tml/fn.rb +0 -20
- data/lib/sts/tbx_iso_tml/fn_group.rb +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c758f04c86a04df1adb4bc66d09aac7f31477d8ce6879bb9cd8935d86a7ae616
|
|
4
|
+
data.tar.gz: 56893d54b3e2193926f95a8a988d0a12dc73b31a85d9223e90edfe46adf80b07
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e2444f3c73074bd001445a89a5712854e112b429180b7a96feff1e01e303dfd5791a7ab6e81eb27498ba859078a8a647793a8e40276ec6e2cab2d90c9b7a4517
|
|
7
|
+
data.tar.gz: d3b0d7c1ba7721b108ae509b5847e1a21917d4cc5507581d7581af2d71a0f742d16b316fc53a3d8c263b11816ee074a6b5a17547b9773dd3f99e472959db9069
|
data/.rubocop_todo.yml
CHANGED
|
@@ -70,6 +70,7 @@ RSpec/DescribeClass:
|
|
|
70
70
|
- 'spec/elements/new_elements_spec.rb'
|
|
71
71
|
- 'spec/elements/reference_models_spec.rb'
|
|
72
72
|
- 'spec/elements/structural_models_spec.rb'
|
|
73
|
+
- 'spec/fn_namespace_spec.rb'
|
|
73
74
|
- 'spec/mathml_version_spec.rb'
|
|
74
75
|
- 'spec/round_trip/reference_docs_spec.rb'
|
|
75
76
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# sts-ruby + lutaml-model Finalization Plan
|
|
2
|
+
|
|
3
|
+
**Date**: 2026-07-25
|
|
4
|
+
**Trigger**: User-reported `NoMethodError: paragraph` on `Sts::TbxIsoTml::Fn` nested inside `Sts::NisoSts::Back` (rice.xml e2e).
|
|
5
|
+
**Status**: PR #1 (sts-ruby dedup) in flight; PR #2 (lutaml-model) deferred per downstream maintainer feedback.
|
|
6
|
+
|
|
7
|
+
## Root Cause Summary
|
|
8
|
+
|
|
9
|
+
Two layered bugs:
|
|
10
|
+
|
|
11
|
+
1. **sts-ruby**: `Sts::TbxIsoTml::Fn` (Ruby attr `:p`) and `Sts::NisoSts::Fn` (Ruby attr `:paragraph`) are duplicate `<fn>` classes with conflicting Ruby attribute names. `TbxIsoTml::FnGroup` similarly duplicates `NisoSts::FnGroup`. Six `Fn`/`FnGroup` classes exist across three namespaces; only four are schema-correct.
|
|
12
|
+
2. **lutaml-model**: `Lutaml::Xml::TransformationSupport::ElementBuilder#create_nested_model_element` uses the rule's cached `child_transformation` (keyed on declared `attribute_type`) regardless of the value's actual class. When a caller assigns an unrelated `Serializable` to a typed slot, the wrong transformation is applied silently, producing confusing `NoMethodError`s.
|
|
13
|
+
|
|
14
|
+
The cache itself is correct (`transformation_key` includes `object_id`). The bug is in the dispatch logic.
|
|
15
|
+
|
|
16
|
+
## Architecture Decision (PR #1)
|
|
17
|
+
|
|
18
|
+
`<fn>` and `<fn-group>` are JATS / NISO STS elements (per ISOSTS.xsd and NISO-STS-extended-1.xsd). They are **not** TBX-ISO-TML elements (TBX-ISO-TML is ISO 30042, a terminology model). The presence of `TbxIsoTml::Fn` and `TbxIsoTml::FnGroup` is a misclassification — same pattern as the prior `TbxIsoTml::Math` removal in commit `9e977a5`. Remove them.
|
|
19
|
+
|
|
20
|
+
Per [[architecture-namespace-independence]]:
|
|
21
|
+
- `IsoSts::*` references use `IsoSts::Fn` / `IsoSts::FnGroup` (independence from NisoSts).
|
|
22
|
+
- `NisoSts::*` references continue to use `NisoSts::Fn` / `NisoSts::FnGroup`.
|
|
23
|
+
- `TbxIsoTml::*` references follow the existing `TbxIsoTml::Bold` / `TbxIsoTml::Italic` precedent (both already use `NisoSts::Fn`): use `NisoSts::Fn` / `NisoSts::FnGroup`. TBX is a shared namespace.
|
|
24
|
+
|
|
25
|
+
## Decision: Defer PR #2 (lutaml-model)
|
|
26
|
+
|
|
27
|
+
Downstream metanorma-iso maintainer reviewed the plan and recommended defer:
|
|
28
|
+
> #2 is a real robustness win but introduces a new contract that may break
|
|
29
|
+
> other downstream consumers who've been quietly relying on the current
|
|
30
|
+
> lenient behavior. Worth doing eventually, but urgency drops once #1 lands.
|
|
31
|
+
|
|
32
|
+
Once #1 lands, the trap cannot be triggered via the original repo's classes. The lenient dispatch remains a robustness gap for future duplicates — see TODO 10 (audit other potential duplicates).
|
|
33
|
+
|
|
34
|
+
## Execution Order
|
|
35
|
+
|
|
36
|
+
| # | File | Status |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| 01 | investigation findings | complete |
|
|
39
|
+
| 02 | delete `TbxIsoTml::Fn` / `TbxIsoTml::FnGroup` | complete |
|
|
40
|
+
| 03 | repoint IsoSts call sites to `IsoSts::Fn` | complete |
|
|
41
|
+
| 04 | repoint TbxIsoTml call sites to `NisoSts::Fn` | complete |
|
|
42
|
+
| 05 | sts-ruby regression specs | complete |
|
|
43
|
+
| 06 | lutaml-model `ElementBuilder` dispatch fix | **deferred** |
|
|
44
|
+
| 07 | lutaml-model specs | **deferred** |
|
|
45
|
+
| 08 | sts-ruby PR | in flight |
|
|
46
|
+
| 09 | lutaml-model PR | **deferred** |
|
|
47
|
+
| 10 | audit other potential duplicates | deferred (future) |
|
|
48
|
+
| 11 | strengthen `anti_patterns_spec.rb` | deferred (future) |
|
|
49
|
+
|
|
50
|
+
## Principles enforced (PR #1)
|
|
51
|
+
|
|
52
|
+
- **MECE**: each Fn class lives in exactly one namespace; no parallel hierarchies.
|
|
53
|
+
- **Model-driven**: every `<fn>` reference is a typed `attribute :fn, ::Sts::<Namespace>::Fn`.
|
|
54
|
+
- **OCP**: adding a new host namespace = adding new Fn classes there, not editing existing ones.
|
|
55
|
+
- **DRY**: one class per (namespace, XML element) pair.
|
|
56
|
+
- **No anti-patterns**: no `send`, no `instance_variable_set/get`, no `respond_to?`, no `require_relative` in lib.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# 01: Investigation Findings — Fn/FnGroup Duplication
|
|
2
|
+
|
|
3
|
+
**Status**: complete (findings documented for reference)
|
|
4
|
+
|
|
5
|
+
## Six classes discovered
|
|
6
|
+
|
|
7
|
+
| Class | File | Ruby attr for `<p>` | Other notable attrs |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `Sts::IsoSts::Fn` | `lib/sts/iso_sts/fn.rb` | `:paragraph` | fn_type, specific_use, symbol, xml_lang, non_normative_note, non_normative_example |
|
|
10
|
+
| `Sts::IsoSts::FnGroup` | `lib/sts/iso_sts/fn_group.rb` | — | content_type, specific_use, xml_lang, originator, label, title |
|
|
11
|
+
| `Sts::NisoSts::Fn` | `lib/sts/niso_sts/fn.rb` | `:paragraph` | (minimal) |
|
|
12
|
+
| `Sts::NisoSts::FnGroup` | `lib/sts/niso_sts/fn_group.rb` | — | (minimal) |
|
|
13
|
+
| `Sts::TbxIsoTml::Fn` | `lib/sts/tbx_iso_tml/fn.rb` | `:p` ← **outlier** | (minimal) |
|
|
14
|
+
| `Sts::TbxIsoTml::FnGroup` | `lib/sts/tbx_iso_tml/fn_group.rb` | — | (minimal) |
|
|
15
|
+
|
|
16
|
+
## Call sites (24 total)
|
|
17
|
+
|
|
18
|
+
### IsoSts (8 sites — all wrong, should be IsoSts::Fn)
|
|
19
|
+
- `lib/sts/iso_sts/{td,bold,paragraph,mixed_citation,sec,th,std,italic}.rb`
|
|
20
|
+
|
|
21
|
+
### IsoSts (correct — already uses IsoSts::Fn/IsoSts::FnGroup)
|
|
22
|
+
- `lib/sts/iso_sts/{fig,table_wrap_foot,fn_group,app,back,term_sec}.rb`
|
|
23
|
+
|
|
24
|
+
### TbxIsoTml (4 sites — should be NisoSts::Fn following Bold/Italic pattern)
|
|
25
|
+
- `lib/sts/tbx_iso_tml/{td,th,table_wrap_foot,fn_group}.rb`
|
|
26
|
+
|
|
27
|
+
### TbxIsoTml (correct — already uses NisoSts::Fn)
|
|
28
|
+
- `lib/sts/tbx_iso_tml/{bold,italic}.rb`
|
|
29
|
+
|
|
30
|
+
### NisoSts (correct — uses NisoSts::Fn/NisoSts::FnGroup)
|
|
31
|
+
- `lib/sts/niso_sts/{author_notes,source,data_title,named_content,mixed_citation,paragraph,section,back,display_formula,role,reference_standard,contrib,styled_content,toc,boxed_text,fn_group}.rb`
|
|
32
|
+
|
|
33
|
+
## Verification of root cause
|
|
34
|
+
|
|
35
|
+
Patch on `Lutaml::Xml::Transformation#apply_standard_rules` showed: when `Sts::TbxIsoTml::Fn` is serialized inside a `Sts::NisoSts::Back` (whose `:fn_group` is typed `NisoSts::FnGroup`), the transformation applied has `model_class = Sts::NisoSts::Fn` (not `TbxIsoTml::Fn`). Its compiled rules include `attribute_name=:paragraph`, which is then `public_send`-ed on the TbxIsoTml::Fn value, raising `NoMethodError`.
|
|
36
|
+
|
|
37
|
+
The reverse also fails: `NisoSts::Fn` inside `TbxIsoTml::FnGroup` raises `private method 'p' called`.
|
|
38
|
+
|
|
39
|
+
The cache key in `TransformationRegistry#transformation_key` includes `object_id`, so cache collision is NOT the cause. The bug is in `ElementBuilder#create_nested_model_element` — it reuses `rule.child_transformation` (cached at compile time for the declared `attribute_type`) without consulting `value.class`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 02: Delete `Sts::TbxIsoTml::Fn` and `Sts::TbxIsoTml::FnGroup`
|
|
2
|
+
|
|
3
|
+
**Status**: pending
|
|
4
|
+
**Blocks**: 03, 04, 05
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
`<fn>` and `<fn-group>` are JATS / NISO STS elements. They are not defined by TBX-ISO-TML (ISO 30042). The `TbxIsoTml::Fn` and `TbxIsoTml::FnGroup` classes are misclassified duplicates of `NisoSts::Fn` / `NisoSts::FnGroup` with one schema-breaking difference: the Ruby attribute for `<p>` is `:p` in TbxIsoTml and `:paragraph` in every other namespace. This mismatch is the root cause of the user-reported `NoMethodError`.
|
|
9
|
+
|
|
10
|
+
## Actions
|
|
11
|
+
|
|
12
|
+
- [x] Delete `lib/sts/tbx_iso_tml/fn.rb`
|
|
13
|
+
- [x] Delete `lib/sts/tbx_iso_tml/fn_group.rb`
|
|
14
|
+
- [x] Remove `autoload :Fn` and `autoload :FnGroup` from `lib/sts/tbx_iso_tml.rb`
|
|
15
|
+
- [x] Run `bundle exec rspec` — confirm no spec references the deleted constants
|
|
16
|
+
|
|
17
|
+
## Verification
|
|
18
|
+
|
|
19
|
+
- `grep -rn "TbxIsoTml::Fn\b\|TbxIsoTml::FnGroup\b" lib/ spec/` returns nothing after steps 03 and 04 complete.
|
|
20
|
+
- `Sts::TbxIsoTml.const_defined?(:Fn)` is `false`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# 03: Repoint IsoSts call sites to `IsoSts::Fn`
|
|
2
|
+
|
|
3
|
+
**Status**: pending
|
|
4
|
+
**Blocked by**: 02
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
Per [[architecture-namespace-independence]], `IsoSts` must be independent of `NisoSts`. The 8 IsoSts files that currently reference `TbxIsoTml::Fn` violate this. They should reference `IsoSts::Fn`, which already exists with the correct ISOSTS schema (5 attributes + label + paragraph + non_normative_note + non_normative_example).
|
|
9
|
+
|
|
10
|
+
## Actions
|
|
11
|
+
|
|
12
|
+
For each file, swap `::Sts::TbxIsoTml::Fn` → `::Sts::IsoSts::Fn`:
|
|
13
|
+
|
|
14
|
+
- [x] `lib/sts/iso_sts/td.rb:28`
|
|
15
|
+
- [x] `lib/sts/iso_sts/bold.rb:25`
|
|
16
|
+
- [x] `lib/sts/iso_sts/paragraph.rb:27`
|
|
17
|
+
- [x] `lib/sts/iso_sts/mixed_citation.rb:22`
|
|
18
|
+
- [x] `lib/sts/iso_sts/sec.rb:37`
|
|
19
|
+
- [x] `lib/sts/iso_sts/th.rb:28`
|
|
20
|
+
- [x] `lib/sts/iso_sts/std.rb:14`
|
|
21
|
+
- [x] `lib/sts/iso_sts/italic.rb:25`
|
|
22
|
+
|
|
23
|
+
## Verification
|
|
24
|
+
|
|
25
|
+
- `grep -rn "TbxIsoTml::Fn\b" lib/sts/iso_sts/` returns nothing.
|
|
26
|
+
- `bundle exec rspec spec/iso_sts/` is green.
|
|
27
|
+
- Full suite green (no spec depends on the old typing).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# 04: Repoint TbxIsoTml call sites to `NisoSts::Fn`
|
|
2
|
+
|
|
3
|
+
**Status**: pending
|
|
4
|
+
**Blocked by**: 02
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
After step 02 deletes `TbxIsoTml::Fn` / `TbxIsoTml::FnGroup`, the 4 TbxIsoTml files that referenced them must point somewhere. Following the established `TbxIsoTml::Bold` / `TbxIsoTml::Italic` precedent (both already use `NisoSts::Fn`), use `NisoSts::Fn` / `NisoSts::FnGroup`.
|
|
9
|
+
|
|
10
|
+
TBX-ISO-TML is a shared namespace (per [[architecture-namespace-independence]]: "independence from NisoSts is not independence in general"). `<fn>` inside a TBX table cell is a NISO STS element borrowed into TBX context, so the NISO STS type is the correct reference.
|
|
11
|
+
|
|
12
|
+
## Actions
|
|
13
|
+
|
|
14
|
+
- [x] `lib/sts/tbx_iso_tml/td.rb:94` — `::Sts::TbxIsoTml::Fn` → `::Sts::NisoSts::Fn`
|
|
15
|
+
- [x] `lib/sts/tbx_iso_tml/th.rb:95` — same
|
|
16
|
+
- [x] `lib/sts/tbx_iso_tml/table_wrap_foot.rb:7` — `::Sts::TbxIsoTml::FnGroup` → `::Sts::NisoSts::FnGroup`
|
|
17
|
+
- [x] `lib/sts/tbx_iso_tml/table_wrap_foot.rb:13` — `::Sts::TbxIsoTml::Fn` → `::Sts::NisoSts::Fn`
|
|
18
|
+
|
|
19
|
+
`lib/sts/tbx_iso_tml/fn_group.rb` is deleted in step 02 — no repoint needed.
|
|
20
|
+
|
|
21
|
+
## Verification
|
|
22
|
+
|
|
23
|
+
- `grep -rn "TbxIsoTml::Fn\b\|TbxIsoTml::FnGroup\b" lib/sts/tbx_iso_tml/` returns nothing.
|
|
24
|
+
- `bundle exec rspec` green.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# 05: Add sts-ruby regression specs
|
|
2
|
+
|
|
3
|
+
**Status**: pending
|
|
4
|
+
**Blocked by**: 02, 03, 04
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
Round-tripping alone cannot catch this class of bug — the wrong-type assignment only fails when nested two levels deep, and a future contributor could re-introduce `TbxIsoTml::Fn` thinking it is a reasonable place for a TBX footnote. Specs must assert:
|
|
9
|
+
|
|
10
|
+
1. The deleted constants stay deleted.
|
|
11
|
+
2. Each call site uses the correct namespace's Fn.
|
|
12
|
+
3. The original bug repro (NisoSts::Back wrapping TbxIsoTml-style Fn usage) no longer raises — but this is now impossible to express directly because TbxIsoTml::Fn is gone. Instead, assert that a NisoSts::Back → NisoSts::FnGroup → NisoSts::Fn serialization round-trips, and the original error message ("undefined method 'paragraph'") cannot occur.
|
|
13
|
+
|
|
14
|
+
## Actions
|
|
15
|
+
|
|
16
|
+
- [x] Add `spec/fn_namespace_spec.rb` asserting:
|
|
17
|
+
- `Sts::TbxIsoTml.const_defined?(:Fn)` is `false`
|
|
18
|
+
- `Sts::TbxIsoTml.const_defined?(:FnGroup)` is `false`
|
|
19
|
+
- `lib/sts/iso_sts/**/*.rb` files reference `IsoSts::Fn` / `IsoSts::FnGroup`, never `TbxIsoTml::Fn`
|
|
20
|
+
- `lib/sts/tbx_iso_tml/**/*.rb` files reference `NisoSts::Fn` / `NisoSts::FnGroup`, never `TbxIsoTml::Fn`
|
|
21
|
+
- Cross-namespace `Fn`/`FnGroup` instantiation and round-trip works through `NisoSts::Back → NisoSts::FnGroup → NisoSts::Fn`
|
|
22
|
+
- [x] Run full suite, confirm green.
|
|
23
|
+
|
|
24
|
+
## Verification
|
|
25
|
+
|
|
26
|
+
- New spec file passes (14+ examples).
|
|
27
|
+
- Full suite: 2300+ examples, 0 failures.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# 06: lutaml-model `ElementBuilder#create_nested_model_element` dispatch fix
|
|
2
|
+
|
|
3
|
+
**Status**: DEFERRED (per downstream maintainer feedback 2026-07-25)
|
|
4
|
+
**Repo**: `lutaml/lutaml-model`
|
|
5
|
+
**File**: `lib/lutaml/xml/transformation/element_builder.rb`
|
|
6
|
+
|
|
7
|
+
## Why deferred
|
|
8
|
+
|
|
9
|
+
The downstream metanorma-iso maintainer (who originally reported the bug) reviewed the proposed two-PR plan and recommended:
|
|
10
|
+
|
|
11
|
+
> Defer #2. The fix is a real robustness win but introduces a new contract
|
|
12
|
+
> ("declared type must match value class") that may break other downstream
|
|
13
|
+
> consumers who've been quietly relying on the current lenient behavior. Worth
|
|
14
|
+
> doing eventually, but the urgency drops once #1 lands — without the
|
|
15
|
+
> duplicate classes there's no easy way to trigger the trap.
|
|
16
|
+
|
|
17
|
+
## Original analysis (kept for future reference)
|
|
18
|
+
|
|
19
|
+
Currently `create_nested_model_element` reuses `rule.child_transformation` (compiled for the declared `attribute_type`) for any value that is not a declared subtype. When a caller assigns an unrelated `Lutaml::Model::Serialize` to a typed slot, the wrong transformation is applied to the value, producing confusing `NoMethodError`s on whichever Ruby attribute name differs.
|
|
20
|
+
|
|
21
|
+
The cache itself is fine — `transformation_key` includes `object_id`. The dispatch logic is the bug.
|
|
22
|
+
|
|
23
|
+
## When to revisit
|
|
24
|
+
|
|
25
|
+
- Track upstream consumers: if a second case of cross-class assignment emerges (e.g., another gem duplicates a Serializable with different Ruby attribute names), the urgency rises.
|
|
26
|
+
- Pair with a proper audit of existing polymorphic specs to ensure the lenient dispatch wouldn't break tests.
|
|
27
|
+
- Consider an opt-in flag (`strict_type_check: true`) before flipping default behavior.
|
|
28
|
+
|
|
29
|
+
## Sketch of the fix (when revisited)
|
|
30
|
+
|
|
31
|
+
In `lib/lutaml/xml/transformation/element_builder.rb#create_nested_model_element`:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
dispatch_on_value_class = union || is_polymorphic ||
|
|
35
|
+
(value.is_a?(Lutaml::Model::Serialize) && value.class != rule.attribute_type)
|
|
36
|
+
|
|
37
|
+
child_transformation = if dispatch_on_value_class
|
|
38
|
+
value.class.transformation_for(:xml, register)
|
|
39
|
+
else
|
|
40
|
+
rule.child_transformation ||
|
|
41
|
+
rule.attribute_type.transformation_for(:xml, register)
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This subsumes the existing `is_polymorphic_subtype` check (subtypes already have `value.class != rule.attribute_type`).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# 07: lutaml-model specs for cross-class dispatch
|
|
2
|
+
|
|
3
|
+
**Status**: DEFERRED (follows step 06)
|
|
4
|
+
|
|
5
|
+
See step 06 for the deferral rationale. When 06 is revisited, the specs described below should accompany it.
|
|
6
|
+
|
|
7
|
+
## Originally planned specs
|
|
8
|
+
|
|
9
|
+
- Cross-class dispatch: parent declares `attribute :child, ParentClass`; caller assigns `OtherSerializable.new` (not a subtype). Serialization uses `OtherSerializable`'s mapping rules.
|
|
10
|
+
- Round-trip preserved: parsing the serialized XML yields an instance whose attributes match the original.
|
|
11
|
+
- Declared-type fast path unchanged: assigning a `ParentClass` instance uses the cached `child_transformation`.
|
|
12
|
+
- Subtype polymorphism (existing `is_polymorphic_subtype` behaviour) still works.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 08: Open sts-ruby PR
|
|
2
|
+
|
|
3
|
+
**Status**: pending
|
|
4
|
+
**Blocked by**: 02, 03, 04, 05
|
|
5
|
+
|
|
6
|
+
## Actions
|
|
7
|
+
|
|
8
|
+
- [x] Branch `fix/remove-tbxisotml-fn-duplicate` off latest `main`.
|
|
9
|
+
- [x] Commit steps 02–05 with a clear message.
|
|
10
|
+
- [x] Push, open PR against `metanorma/sts-ruby`.
|
|
11
|
+
- [x] PR body via `--body-file` (contains backticks — never inline).
|
|
12
|
+
|
|
13
|
+
## PR description points
|
|
14
|
+
|
|
15
|
+
- Root cause: duplicate `<fn>` classes across namespaces with conflicting Ruby attr names.
|
|
16
|
+
- Why TbxIsoTml loses its Fn/FnGroup: `<fn>` is not a TBX-ISO-TML element.
|
|
17
|
+
- Why IsoSts keeps its own: namespace independence (per ADR 2026-05-07).
|
|
18
|
+
- Why TbxIsoTml call sites use NisoSts::Fn: matches existing Bold/Italic pattern; TBX is shared.
|
|
19
|
+
- Behaviour change: callers that construct IsoSts documents using `TbxIsoTml::Fn` must now use `IsoSts::Fn` (drop-in: same `:paragraph` Ruby attr).
|
|
20
|
+
- References TODO.finalize/00-overview.md.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 10: Audit other potential duplicates (deferred)
|
|
2
|
+
|
|
3
|
+
**Status**: deferred — track for future investigation
|
|
4
|
+
**Priority**: medium
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
The Fn/FnGroup duplication suggests `TbxIsoTml` may contain other JATS / NISO STS elements misclassified as TBX. Each duplicate is a potential version-mismatch footgun. A one-time audit would surface them.
|
|
9
|
+
|
|
10
|
+
## Suspects to investigate
|
|
11
|
+
|
|
12
|
+
Cross-reference each `TbxIsoTml::*` class against the TBX-ISO-TML (ISO 30042) element list. Anything NOT in TBX-ISO-TML is a misfit. Likely candidates:
|
|
13
|
+
|
|
14
|
+
- `TbxIsoTml::Xref` — `<xref>` is a JATS element
|
|
15
|
+
- `TbxIsoTml::TableWrap` — `<table-wrap>` is JATS / NISO STS
|
|
16
|
+
- `TbxIsoTml::Table`, `TbxIsoTml::Thead`, `TbxIsoTml::Tbody`, `TbxIsoTml::Tfoot`, `TbxIsoTml::Tr`, `TbxIsoTml::Th`, `TbxIsoTml::Td`, `TbxIsoTml::Col`, `TbxIsoTml::Colgroup` — XHTML table model, not TBX
|
|
17
|
+
- `TbxIsoTml::Caption` — `<caption>` is JATS
|
|
18
|
+
- `TbxIsoTml::FnGroup` (deleted in step 02)
|
|
19
|
+
- `TbxIsoTml::List` (if present) — `<list>` is JATS
|
|
20
|
+
|
|
21
|
+
True TBX-ISO-TML elements (must stay): `TermEntry`, `Tig`, `Term`, `TermInformationGroup`, `EntailedTerm`, `Descrip`, `DescripGrp`, `Note` (TBX-spec note, not JATS note), `Definition`, `Source`, `LangSet`, `SubjectField`, `PartOfSpeech`, etc.
|
|
22
|
+
|
|
23
|
+
## Verification approach for each suspect
|
|
24
|
+
|
|
25
|
+
1. Check ISO 30042 / TBX-INFO documentation for the element name.
|
|
26
|
+
2. If NOT in TBX-ISO-TML: should not exist in `Sts::TbxIsoTml::*`.
|
|
27
|
+
3. Decide: delete (if no semantic difference from the JATS / NISO STS equivalent) or move to the correct namespace.
|
|
28
|
+
|
|
29
|
+
This is **not** in scope for the current PR series. Track as a follow-up.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# 11: Strengthen `anti_patterns_spec.rb` (deferred)
|
|
2
|
+
|
|
3
|
+
**Status**: deferred — track for future improvement
|
|
4
|
+
**Priority**: low
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
The current `spec/anti_patterns_spec.rb` checks for `method_missing`, `respond_to_missing?`, `Object.const_get`, `.send(` — but misses several global-rule patterns. The MathML hack file (`lib/sts/iso_sts/mathml2/math.rb`, since deleted in TODO 02 of the prior audit) had `instance_variable_set`, `respond_to?(:read)`, and hand-rolled `to_xml` — none would have been caught.
|
|
9
|
+
|
|
10
|
+
## Add checks for
|
|
11
|
+
|
|
12
|
+
- [ ] `instance_variable_set` / `instance_variable_get` (forbidden by global rule)
|
|
13
|
+
- [ ] `respond_to?` for type-checking (allowed only inside test infrastructure or explicit adapter negotiation — define an allowlist)
|
|
14
|
+
- [ ] Hand-rolled serialization methods on `Lutaml::Model::Serializable` subclasses: `def to_h`, `def to_hash`, `def from_h`, `def from_hash`, `def to_json`, `def from_json`, `def to_xml`, `def from_xml`, `def serialize`, `def deserialize`
|
|
15
|
+
- [ ] `require_relative` anywhere in `lib/` (autoloads only — global rule)
|
|
16
|
+
- [ ] `double(` in specs (global rule)
|
|
17
|
+
|
|
18
|
+
## Implementation notes
|
|
19
|
+
|
|
20
|
+
- The existing pattern (file-by-file source scan) extends naturally — add new `it` blocks per check.
|
|
21
|
+
- Some checks may need an allowlist (e.g., `respond_to?` for IO vs String detection at gem boundaries). Document the allowlist inline.
|
|
22
|
+
- Run after every lib change, not just at PR time.
|
|
23
|
+
|
|
24
|
+
This is **not** in scope for the current PR series. Track as a follow-up.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|---|------|----------|----------|--------------|
|
|
20
20
|
| 01 | `01-mathml-delegation.md` | Anti-Pattern Fix | DONE | — |
|
|
21
21
|
| 02 | `02-type-resolution.md` | Anti-Pattern Fix | DONE | — |
|
|
22
|
-
| 03 | `03-namespace-coupling.md` | Architecture | IN PROGRESS (63→
|
|
22
|
+
| 03 | `03-namespace-coupling.md` | Architecture | IN PROGRESS (63→16 refs) | 01, 02 |
|
|
23
23
|
| 04 | `04-register-versioning.md` | Architecture | HIGH | 01, 02 |
|
|
24
24
|
| 05 | `05-missing-elements.md` | Feature Gap | MOSTLY DONE | 04 |
|
|
25
25
|
| 06 | `06-missing-attributes.md` | Feature Gap | DONE | 04 |
|
|
@@ -166,27 +166,39 @@ grep -r "method_missing|respond_to_missing|Object.const_get|\.send" lib/
|
|
|
166
166
|
- ~~Expand StringName usage (in contrib, element-citation, related-article — NISO STS 1.2)~~ → DONE: added to name-alternatives; already in person-group and mixed-citation
|
|
167
167
|
|
|
168
168
|
### Architectural Items (High Effort)
|
|
169
|
-
- `03-namespace-coupling.md` — IN PROGRESS: 63→
|
|
170
|
-
remaining (issue #40).
|
|
171
|
-
|
|
169
|
+
- `03-namespace-coupling.md` — IN PROGRESS: 63→16 IsoSts→NisoSts references
|
|
170
|
+
remaining (issue #40). ISOSTS.xsd governs content models and all non-`@id`
|
|
171
|
+
attributes; the `@id` follows the 86948b9 convention.
|
|
172
172
|
- `04-register-versioning.md` — Version the models via lutaml-model Registers
|
|
173
173
|
- `11-duplicate-models.md` — 44 overlapping element resolution (depends on 03)
|
|
174
174
|
|
|
175
|
-
###
|
|
175
|
+
### Schema conformance — dropped ISOSTS attributes
|
|
176
176
|
The 2026-05-07 "@id added to all models (XSD-verified)" pass verified against
|
|
177
|
-
the **NISO** XSD and applied the result to IsoSts.
|
|
178
|
-
- **
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`
|
|
182
|
-
|
|
183
|
-
-
|
|
184
|
-
|
|
177
|
+
the **NISO** XSD and applied the result to IsoSts.
|
|
178
|
+
- **Fixed — dropped ISOSTS attributes restored.** 15 IsoSts models were
|
|
179
|
+
silently dropping ISOSTS attributes present in real documents (data loss):
|
|
180
|
+
`sub`/`sup` (`arrange`+`specific-use`), `ext-link`/`mixed-citation`/`uri`/
|
|
181
|
+
`named-content` (`xlink:*`), `graphic` (`xlink:*`+`originator`), `copyright-*`,
|
|
182
|
+
`edition`, `title`, `label`, `underline`, `body`. This change adds them and
|
|
183
|
+
fixes `sec`/`standard`/`term-sec`, which mapped `xml:lang` under the wrong XML
|
|
184
|
+
name. (`meta-date` was NOT lossy — it already maps `type`.)
|
|
185
|
+
- **Not a bug — the conventional `@id`.** IsoSts models carry an `@id` that
|
|
186
|
+
ISOSTS does not itself define; this is the deliberate 86948b9 convention
|
|
187
|
+
(NISO-XSD-verified), not dead surface.
|
|
188
|
+
- **Remaining follow-up (separate change).** 7 spurious attributes on 5 models
|
|
189
|
+
(model carries an attr ISOSTS does not define: `graphic` `type`, `body`/`back`
|
|
190
|
+
`content-type`, `content-language`/`language` extras), and the 6 classes left
|
|
191
|
+
without `@id` in 86948b9 (`monospace`, `sc`, `strike`, `underline`, `uri`,
|
|
192
|
+
`standard_ref`).
|
|
185
193
|
|
|
186
194
|
## Next Action
|
|
187
195
|
Two independent tracks:
|
|
188
|
-
1. Finish `03` — the
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
1. Finish `03` — the 16 remaining refs split evenly between seven recursive
|
|
197
|
+
roots and five child-bearing roots. The first 15 high-reuse dependency
|
|
198
|
+
leaves are now modelled, reducing the unresolved closures to 78–84
|
|
199
|
+
not-yet-modelled ISOSTS elements before existing IsoSts boundaries. The
|
|
200
|
+
remaining work still needs an architecture decision for the recursive
|
|
201
|
+
content core.
|
|
202
|
+
2. The remaining schema-conformance follow-up above — the 7 spurious attributes
|
|
203
|
+
on 5 models and the 6 classes without `@id`. (The dropped-attribute data loss
|
|
204
|
+
is now fixed.)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Priority**: HIGH
|
|
4
4
|
**Category**: Architecture
|
|
5
5
|
**Estimated Effort**: High
|
|
6
|
-
**Status**: Partially done — 63 →
|
|
6
|
+
**Status**: Partially done — 63 → 16 references (GitHub issue #40)
|
|
7
7
|
|
|
8
8
|
## Problem
|
|
9
9
|
|
|
@@ -12,49 +12,63 @@ independent of NisoSts (ADR 2026-05-07): ISOSTS is frozen legacy, NISO STS
|
|
|
12
12
|
evolves, so coupling them violates OCP.
|
|
13
13
|
|
|
14
14
|
PR #31 reduced this from 157 to 63 references. Issue #40 reduced it further,
|
|
15
|
-
from 63 to
|
|
15
|
+
from 63 to 16.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Content models from ISOSTS.xsd; `@id` from the 86948b9 convention
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
`
|
|
19
|
+
IsoSts models carry `@id` following the compatibility convention established in
|
|
20
|
+
86948b9 (NISO-XSD-verified). ISOSTS.xsd governs element content
|
|
21
|
+
models and all non-`@id` attributes; it is not an authority that forbids the
|
|
22
|
+
conventional `@id`. So the two schemas can legitimately differ per element:
|
|
22
23
|
|
|
23
|
-
| Element | ISOSTS
|
|
24
|
+
| Element | ISOSTS content/attrs | NisoSts model |
|
|
24
25
|
|---|---|---|
|
|
25
|
-
| `
|
|
26
|
-
| `doc-type` (:6378) | `type="xs:string"` — no attributes at all | `@id` + content |
|
|
26
|
+
| `doc-type` (:6378) | `type="xs:string"` | `@id` + content |
|
|
27
27
|
| `ics` (:6373) | `type="xs:string"` | `@id` + `ics-desc` child |
|
|
28
28
|
| `fpage` | `content-type`, `seq`, `specific-use`, `xml:lang`; no children | `@id` + bold/italic |
|
|
29
29
|
| `license` (:51) | `license-type`, `specific-use`, `xml:lang` | `@id`, `xlink:href` |
|
|
30
|
-
| `ruby` | **not an ISOSTS element** | exists (NISO only) |
|
|
31
30
|
|
|
32
31
|
`feature_doc.xml` declares `<!DOCTYPE standard SYSTEM ".../ISOSTS.dtd">`, and
|
|
33
32
|
the ISOSTS DTD agrees with ISOSTS.xsd (both derive `bold`, `sub` etc. from the
|
|
34
|
-
JATS 0.4 modules)
|
|
33
|
+
JATS 0.4 modules) on content models.
|
|
35
34
|
|
|
36
35
|
**Round-tripping does not prove correctness.** A model that invents or drops an
|
|
37
36
|
attribute still parses and serialises symmetrically, so the suite stays green
|
|
38
37
|
while the model is wrong. Assert the exact attribute set per element instead.
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
on `tex-math` and `specific-use` on `pub-id` sit after long
|
|
42
|
-
blocks and are invisible to a truncated read.
|
|
39
|
+
Non-`@id` attribute lists must be **generated** from the XSD, never hand-read:
|
|
40
|
+
`version` on `tex-math` and `specific-use` on `pub-id` sit after long
|
|
41
|
+
`xs:enumeration` blocks and are invisible to a truncated read.
|
|
43
42
|
|
|
44
|
-
## Done in issue #40 —
|
|
43
|
+
## Done in issue #40 — 47 refs removed, 46 classes added
|
|
45
44
|
|
|
46
45
|
- **14 `xs:string` elements** (`originator`, `doc-type`, `doc-number`,
|
|
47
46
|
`part-number`, `version`, `suppl-type`, `suppl-number`, `suppl-version`,
|
|
48
47
|
`urn`, `sdo`, `proj-id`, `release-version`, `ics`, `secretariat`) — modelled
|
|
49
|
-
as content
|
|
48
|
+
as content IsoSts classes that also carry the conventional `@id` (86948b9);
|
|
49
|
+
`secretariat` is content plus `@id`, not content-only. 23 refs.
|
|
50
50
|
- **3 `permissions` refs** repointed to the existing `IsoSts::Permissions`.
|
|
51
|
-
- **`ruby` deleted** from `StyledContent` — ISOSTS
|
|
51
|
+
- **`ruby` deleted** from `StyledContent` — ISOSTS's `styled-content` content
|
|
52
|
+
model omits `<ruby>` (NISO permits it transitively via the emphasis group).
|
|
52
53
|
Behaviour change: `<ruby>` in `<styled-content>` no longer round-trips.
|
|
53
54
|
- **13 element classes** modelled from ISOSTS.xsd: `Year`, `PubDate`,
|
|
54
55
|
`ReleaseVersionId`, `IsProof`, `AltText`, `LongDesc`, `TexMath`, `PubId`,
|
|
55
56
|
`Volume`, `Issue`, `Fpage`, `Lpage`, `PageRange`. 16 refs.
|
|
56
57
|
- **`WiNumber` added** — ISOSTS gives `wi-number` an `@id`; it was typed as a
|
|
57
58
|
plain string, silently discarding that `@id`.
|
|
59
|
+
- **`Publisher` closure added** — `Publisher`, `PublisherName`, `PublisherLoc`,
|
|
60
|
+
and `Email` are modelled from ISOSTS.xsd; `PublisherLoc` reuses the existing
|
|
61
|
+
IsoSts `ExtLink` and `Uri` boundary models. All four retain the
|
|
62
|
+
project-mandated `@id` model surface. 1 ref.
|
|
63
|
+
- **15 reusable dependency leaves added** — `Abbrev`, `Annotation`, `Country`,
|
|
64
|
+
`Day`, `Etal`, `Fax`, `InlineGraphic`, `Institution`, `MilestoneEnd`,
|
|
65
|
+
`MilestoneStart`, `Month`, `Num`, `ObjectId`, `Phone`, and `Season` are
|
|
66
|
+
modelled from ISOSTS.xsd and close entirely on existing IsoSts types. They
|
|
67
|
+
remove no direct reference yet, but establish the first shared dependency
|
|
68
|
+
layer for the remaining recursive roots.
|
|
69
|
+
- **3 Niso-only child refs deleted** — `std-meta` from `Front` and
|
|
70
|
+
`editing-instruction` from `Body` and `Sec`. Neither element exists in
|
|
71
|
+
ISOSTS.xsd, so adding IsoSts equivalents would incorrectly expand the schema.
|
|
58
72
|
|
|
59
73
|
### Why classes and not plain `:string`
|
|
60
74
|
|
|
@@ -65,20 +79,23 @@ round-trip. For a scalar, `render_empty: :empty` recovers it; for a collection
|
|
|
65
79
|
to `[]`, destroying the information at parse time before any render option
|
|
66
80
|
applies. Content-only classes round-trip every case.
|
|
67
81
|
|
|
68
|
-
## Remaining —
|
|
82
|
+
## Remaining — 16 refs
|
|
69
83
|
|
|
70
|
-
**
|
|
71
|
-
`
|
|
72
|
-
|
|
73
|
-
(`
|
|
74
|
-
children but pulls all 152. No incremental path — needs its own decision.
|
|
84
|
+
**8 refs to 7 recursive roots**: `ElementCitation`, `PersonGroup`, `Collab`,
|
|
85
|
+
`Source`, `DispQuote`, `TermDisplay`, and `BoxedText`. Each reaches the same
|
|
86
|
+
78–79-element mutually-recursive core before existing IsoSts boundaries
|
|
87
|
+
(`sec` → `p` → `disp-quote` → `p`). No direct one-file path remains.
|
|
75
88
|
|
|
76
|
-
**
|
|
77
|
-
`attrib` (:1082)
|
|
78
|
-
|
|
79
|
-
`
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
**8 refs to 5 child-bearing roots**, now measured after the first dependency
|
|
90
|
+
layer: `attrib` (:1082) reaches 78 not-yet-modelled ISOSTS elements before
|
|
91
|
+
existing IsoSts boundaries, `term-head` (:4308) reaches 79, `article-title`
|
|
92
|
+
reaches 78, `license` → `license-p` (:51) reaches 84, and
|
|
93
|
+
`custom-meta-group` → `custom-meta` reaches 82. They converge on the same
|
|
94
|
+
recursive content core as the deep roots, so none is another bounded model
|
|
95
|
+
batch. `publisher` was the only exception: its four-element closure
|
|
96
|
+
(`publisher`, `publisher-name`, `publisher-loc`, `email`) is complete.
|
|
97
|
+
The Niso `Attrib` class is only 17 lines because it omits all 37 ISOSTS child
|
|
98
|
+
types; copying it would silently drop valid ISO content rather than decouple it.
|
|
82
99
|
|
|
83
100
|
## Rejected: three-tier `Sts::Base` hierarchy
|
|
84
101
|
|
|
@@ -113,7 +130,8 @@ reaches `TbxIsoTml`/MathML. Those are shared namespaces, outside this ADR.
|
|
|
113
130
|
|
|
114
131
|
## Verification
|
|
115
132
|
|
|
116
|
-
1. `grep -rho "Sts::NisoSts::" lib/sts/iso_sts/ | wc -l` → `
|
|
117
|
-
2. Every attribute on an IsoSts model traces to a line in
|
|
118
|
-
|
|
133
|
+
1. `grep -rho "Sts::NisoSts::" lib/sts/iso_sts/ | wc -l` → `16`
|
|
134
|
+
2. Every *non-`@id`* attribute on an IsoSts model traces to a line in
|
|
135
|
+
`ISOSTS.xsd`; `@id` follows the 86948b9 convention
|
|
136
|
+
3. Autoload registry 1:1 with the directory (131/131)
|
|
119
137
|
4. `bundle exec rspec` green; `bundle exec rubocop` clean
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sts
|
|
4
|
+
module IsoSts
|
|
5
|
+
class Abbrev < Lutaml::Model::Serializable
|
|
6
|
+
attribute :id, :string
|
|
7
|
+
attribute :content_type, :string
|
|
8
|
+
attribute :specific_use, :string
|
|
9
|
+
attribute :alt, :string
|
|
10
|
+
attribute :xml_lang, :string
|
|
11
|
+
attribute :xlink_type, :string
|
|
12
|
+
attribute :xlink_href, :string
|
|
13
|
+
attribute :xlink_role, :string
|
|
14
|
+
attribute :xlink_title, :string
|
|
15
|
+
attribute :xlink_show, :string
|
|
16
|
+
attribute :xlink_actuate, :string
|
|
17
|
+
attribute :content, :string, collection: true
|
|
18
|
+
attribute :def, ::Sts::IsoSts::Def, collection: true
|
|
19
|
+
|
|
20
|
+
xml do
|
|
21
|
+
element "abbrev"
|
|
22
|
+
mixed_content
|
|
23
|
+
|
|
24
|
+
map_attribute "id", to: :id
|
|
25
|
+
map_attribute "content-type", to: :content_type
|
|
26
|
+
map_attribute "specific-use", to: :specific_use
|
|
27
|
+
map_attribute "alt", to: :alt
|
|
28
|
+
map_attribute "xml:lang", to: :xml_lang
|
|
29
|
+
map_attribute "xlink:type", to: :xlink_type
|
|
30
|
+
map_attribute "xlink:href", to: :xlink_href
|
|
31
|
+
map_attribute "xlink:role", to: :xlink_role
|
|
32
|
+
map_attribute "xlink:title", to: :xlink_title
|
|
33
|
+
map_attribute "xlink:show", to: :xlink_show
|
|
34
|
+
map_attribute "xlink:actuate", to: :xlink_actuate
|
|
35
|
+
|
|
36
|
+
map_content to: :content
|
|
37
|
+
map_element "def", to: :def
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|