relaton 3.0.0.pre.alpha.17 → 3.0.0.pre.alpha.19
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/data/equivalence/adoption-chains.yaml +59 -0
- data/lib/relaton/3gpp/CLAUDE.md +187 -0
- data/lib/relaton/3gpp/README.adoc +149 -0
- data/lib/relaton/adobe/CLAUDE.md +104 -0
- data/lib/relaton/bib/CLAUDE.md +130 -0
- data/lib/relaton/bib/README.adoc +330 -0
- data/lib/relaton/bib/model/item_shared.rb +5 -1
- data/lib/relaton/bib/model/series.rb +1 -1
- data/lib/relaton/bipm/CLAUDE.md +173 -0
- data/lib/relaton/bipm/README.adoc +352 -0
- data/lib/relaton/bipm/data_fetcher.rb +3 -2
- data/lib/relaton/bsi/CLAUDE.md +35 -0
- data/lib/relaton/bsi/README.adoc +112 -0
- data/lib/relaton/calconnect/CLAUDE.md +177 -0
- data/lib/relaton/calconnect/README.adoc +140 -0
- data/lib/relaton/ccsds/CLAUDE.md +74 -0
- data/lib/relaton/ccsds/README.adoc +154 -0
- data/lib/relaton/cen/CLAUDE.md +219 -0
- data/lib/relaton/cen/README.adoc +155 -0
- data/lib/relaton/cie/CLAUDE.md +90 -0
- data/lib/relaton/cie/README.adoc +121 -0
- data/lib/relaton/core/CLAUDE.md +140 -0
- data/lib/relaton/core/README.adoc +64 -0
- data/lib/relaton/core/data_fetcher.rb +142 -3
- data/lib/relaton/db/CLAUDE.md +373 -0
- data/lib/relaton/db.rb +21 -1
- data/lib/relaton/doi/CLAUDE.md +105 -0
- data/lib/relaton/doi/README.adoc +89 -0
- data/lib/relaton/easc/CLAUDE.md +85 -0
- data/lib/relaton/ecma/CLAUDE.md +217 -0
- data/lib/relaton/ecma/README.adoc +178 -0
- data/lib/relaton/equivalence.rb +117 -0
- data/lib/relaton/etsi/CLAUDE.md +219 -0
- data/lib/relaton/etsi/README.adoc +137 -0
- data/lib/relaton/evs/CLAUDE.md +120 -0
- data/lib/relaton/evs/README.adoc +27 -0
- data/lib/relaton/gb/CLAUDE.md +47 -0
- data/lib/relaton/gb/README.adoc +169 -0
- data/lib/relaton/gost/CLAUDE.md +100 -0
- data/lib/relaton/iala/CLAUDE.md +97 -0
- data/lib/relaton/iana/CLAUDE.md +105 -0
- data/lib/relaton/iana/README.adoc +107 -0
- data/lib/relaton/iec/CLAUDE.md +13 -0
- data/lib/relaton/iec/README.adoc +280 -0
- data/lib/relaton/iec/data_fetcher.rb +24 -8
- data/lib/relaton/iec/project_fetcher.rb +48 -0
- data/lib/relaton/iec/project_parser.rb +111 -0
- data/lib/relaton/iec.rb +5 -0
- data/lib/relaton/ieee/CLAUDE.md +176 -0
- data/lib/relaton/ieee/README.adoc +131 -0
- data/lib/relaton/ietf/CLAUDE.md +357 -0
- data/lib/relaton/ietf/README.adoc +167 -0
- data/lib/relaton/iho/CLAUDE.md +70 -0
- data/lib/relaton/iho/README.adoc +119 -0
- data/lib/relaton/index/CLAUDE.md +207 -0
- data/lib/relaton/index/README.adoc +221 -0
- data/lib/relaton/index/dataset_lock.rb +122 -0
- data/lib/relaton/index/family.rb +63 -0
- data/lib/relaton/index/type.rb +32 -0
- data/lib/relaton/index.rb +3 -0
- data/lib/relaton/isbn/CLAUDE.md +47 -0
- data/lib/relaton/isbn/README.adoc +91 -0
- data/lib/relaton/iso/CLAUDE.md +38 -0
- data/lib/relaton/iso/README.adoc +370 -0
- data/lib/relaton/iso/data_fetcher.rb +16 -1
- data/lib/relaton/itu/CLAUDE.md +685 -0
- data/lib/relaton/itu/README.adoc +188 -0
- data/lib/relaton/jcgm/CLAUDE.md +107 -0
- data/lib/relaton/jis/CLAUDE.md +64 -0
- data/lib/relaton/jis/README.adoc +167 -0
- data/lib/relaton/logger/CLAUDE.md +37 -0
- data/lib/relaton/logger/README.adoc +120 -0
- data/lib/relaton/nist/CLAUDE.md +180 -0
- data/lib/relaton/nist/README.adoc +389 -0
- data/lib/relaton/nist/bibliography.rb +17 -1
- data/lib/relaton/nist/data_fetcher.rb +60 -4
- data/lib/relaton/nist/hit_collection.rb +121 -59
- data/lib/relaton/nist/scraper.rb +21 -7
- data/lib/relaton/oasis/CLAUDE.md +251 -0
- data/lib/relaton/oasis/README.adoc +132 -0
- data/lib/relaton/ogc/CLAUDE.md +242 -0
- data/lib/relaton/ogc/README.adoc +134 -0
- data/lib/relaton/ogc/data_fetcher.rb +9 -3
- data/lib/relaton/oiml/CLAUDE.md +47 -0
- data/lib/relaton/oiml/README.adoc +70 -0
- data/lib/relaton/omg/CLAUDE.md +137 -0
- data/lib/relaton/omg/README.adoc +101 -0
- data/lib/relaton/plateau/CLAUDE.md +126 -0
- data/lib/relaton/plateau/README.adoc +139 -0
- data/lib/relaton/sdo/CLAUDE.md +81 -0
- data/lib/relaton/un/CLAUDE.md +91 -0
- data/lib/relaton/un/README.adoc +125 -0
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton/w3c/CLAUDE.md +369 -0
- data/lib/relaton/w3c/README.adoc +140 -0
- data/lib/relaton/w3c/data_fetcher.rb +1 -1
- data/lib/relaton/xsf/CLAUDE.md +189 -0
- data/lib/relaton/xsf/README.adoc +127 -0
- data/lib/relaton.rb +1 -0
- metadata +85 -4
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
relaton-omg is a Ruby gem that searches and fetches standards from The Object Management Group (OMG) at https://www.omg.org. It is part of the larger Relaton family of bibliographic data gems (v2.0.0-alpha.1).
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
- **Run all tests:** `bundle exec rspec`
|
|
12
|
+
- **Run a single test:** `bundle exec rspec spec/relaton/omg/item_spec.rb`
|
|
13
|
+
- **Lint:** `bundle exec rubocop` (follows Ribose OSS style guide)
|
|
14
|
+
- **Lint with autofix:** `bundle exec rubocop -a`
|
|
15
|
+
- **Install deps:** `bundle install`
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
### Module structure
|
|
20
|
+
|
|
21
|
+
All source lives under `lib/relaton/omg/`. The main entry point is `lib/relaton/omg.rb` which loads everything under the `Relaton::Omg` module namespace.
|
|
22
|
+
|
|
23
|
+
### Class hierarchy
|
|
24
|
+
|
|
25
|
+
The gem extends `relaton-bib` (~> 2.0.0-alpha.1), the core Relaton bibliographic data library:
|
|
26
|
+
|
|
27
|
+
- `Relaton::Omg::Item` < `Bib::Item` — base item class, uses `Omg::ItemData` model (subclass of `Bib::ItemData`)
|
|
28
|
+
- `Relaton::Omg::Ext` < `Bib::Ext` — overrides `get_schema_version` to return the OMG model version
|
|
29
|
+
- `Relaton::Omg::Bibitem` < `Item` — includes `Bib::BibitemShared`, for `<bibitem>` XML
|
|
30
|
+
- `Relaton::Omg::Bibdata` < `Item` — includes `Bib::BibdataShared`, for `<bibdata>` XML
|
|
31
|
+
- `Relaton::Omg::Docidentifier` < `Bib::Docidentifier` — the document id, backed by `Pubid::Omg`; `Item` declares it, so XML and YAML deserialization produce it too
|
|
32
|
+
- `Relaton::Omg::Processor` < `Core::Processor` — relaton-core integration, delegates to `Bibliography`, `Bibitem`, `Item`
|
|
33
|
+
- `Relaton::Omg::Bibliography` — fetches standards via `Scraper`
|
|
34
|
+
- `Relaton::Omg::Scraper` — scrapes https://www.omg.org/spec for bibliographic data
|
|
35
|
+
|
|
36
|
+
### References are parsed with pubid
|
|
37
|
+
|
|
38
|
+
OMG uses `Pubid::Omg` and no hand regex. The flavor historically had no index
|
|
39
|
+
and no data repository (the BSI and CEN shape: parse the reference, and back
|
|
40
|
+
the document id with pubid). That changed: **relaton-data-omg** now crawls
|
|
41
|
+
www.omg.org/spec and serves the machine index on Pages (the relaton#206
|
|
42
|
+
contract), and `Relaton::Omg::INDEXFILE = "index-v2"` names it — the gem-side
|
|
43
|
+
consumer flip (reading the machine index in `Bibliography` the way the other
|
|
44
|
+
flavors do) is the follow-up; retrieval still scrapes live.
|
|
45
|
+
|
|
46
|
+
The grammar is `OMG <ACRONYM>[ <VERSION>][<sep><PART>]`, where `<sep>` is a
|
|
47
|
+
space, or a slash after a version. The version can carry a beta label (`2.5 beta`,
|
|
48
|
+
`2.0 beta 1`). The part is a volume or a format name (`Superstructure`, `PDF`).
|
|
49
|
+
|
|
50
|
+
- **`get` takes a String or a `Pubid::Omg::Identifier`** (the parse that
|
|
51
|
+
`Relaton::Db` routed with, relaton#205). `Scraper.scrape_page` parses only a
|
|
52
|
+
String, and the log keys print `ref.to_s`.
|
|
53
|
+
- **An unrecognized reference raises.** `Scraper.scrape_page` lets
|
|
54
|
+
`Pubid::Errors::ParseError` propagate, so
|
|
55
|
+
`OMG Model Driven Architecture Guide rev. 2.0` raises and does not show as
|
|
56
|
+
"Not found". Only the transport errors are rescued, by name.
|
|
57
|
+
- **The request URL is the acronym and the version, and nothing else.**
|
|
58
|
+
`get_doc` builds `https://www.omg.org/spec/<ACRONYM>/<VERSION>`, with each
|
|
59
|
+
space of the version turned into `/` (`1.0 beta 2` becomes `1.0/beta/2`). The
|
|
60
|
+
part stays out of the URL: `fetch_link` uses it to find the part's PDF link
|
|
61
|
+
on the version page, and `fetch_title` appends it. The cassettes replay only
|
|
62
|
+
while the URL does not change.
|
|
63
|
+
- **The docid version comes from the page, not from the query.** That is why
|
|
64
|
+
`get "OMG AMI4CCM"` answers `OMG AMI4CCM 1.1`. `fetch_docid` and the History
|
|
65
|
+
ids of `fetch_relation` are rendered by
|
|
66
|
+
`Pubid::Omg::Identifiers::Specification`, not by parsing a joined string.
|
|
67
|
+
- **pubid renders one separator.** `OMG DDS 1.4/PDF` renders back as
|
|
68
|
+
`OMG DDS 1.4 PDF`. Both spellings name the same document, and one rendering
|
|
69
|
+
keeps `==` and `matches?` true between them. If you echo a caller's
|
|
70
|
+
reference, echo the string, not `pubid.to_s`.
|
|
71
|
+
- **Known limit.** OMG's URL spelling `Beta2` (label and number joined) parses
|
|
72
|
+
as a part, not a version. It round-trips, so nothing is lost.
|
|
73
|
+
- **The acronym is the URL segment, verbatim.** 30 of the 270 acronyms in the
|
|
74
|
+
OMG catalog carry a hyphen, a slash, a plus, or start in lower case
|
|
75
|
+
(`DDS-XTypes`, `EDMC-FIBO/BE`, `VSIPL++`, `smartant`). pubid PR #376 accepts
|
|
76
|
+
all 270. A slash **before** the version belongs to the acronym
|
|
77
|
+
(`OMG EDMC-FIBO/BE 1.1` fetches `spec/EDMC-FIBO/BE/1.1`); a slash **after**
|
|
78
|
+
the version separates the part. So `OMG UML/Superstructure` is the acronym
|
|
79
|
+
`UML/Superstructure`; write the part behind a space. With pubid `ce2f75ef`
|
|
80
|
+
(PR #372) those 30 raised, and the migration waited for #376. Fix a grammar
|
|
81
|
+
gap in pubid; do not split the acronym in the flavor.
|
|
82
|
+
|
|
83
|
+
`Docidentifier` parses its `content` on the data side and rescues the parse, so
|
|
84
|
+
a value that is not an OMG identifier stays verbatim with a nil `pubid`. Its
|
|
85
|
+
mutators:
|
|
86
|
+
|
|
87
|
+
- `remove_date!` drops the **version**. OMG identifiers carry no date, and the
|
|
88
|
+
version is the discriminator, as IALA maps `remove_date!` onto its edition.
|
|
89
|
+
So `to_most_recent_reference` turns `OMG AMI4CCM 1.0` into `OMG AMI4CCM`.
|
|
90
|
+
- `remove_part!` drops the part: `OMG UML 2.1.1 Superstructure` becomes
|
|
91
|
+
`OMG UML 2.1.1`.
|
|
92
|
+
- `to_all_parts!` is the inherited no-op. An OMG part is a name, not a numbered
|
|
93
|
+
part, so there is no "all parts" form.
|
|
94
|
+
|
|
95
|
+
The processor sets `@pubid_flavor = :Omg`. That changes nothing today:
|
|
96
|
+
`Pubid::Omg.prefixes` is `["OMG"]`, the same as `@prefix`.
|
|
97
|
+
|
|
98
|
+
### Publication date comes from JSON-LD, not the visible text
|
|
99
|
+
|
|
100
|
+
`Scraper#pub_date` reads the `publicationDate` value out of the page's
|
|
101
|
+
`application/ld+json` block, not the `<dt>Publication Date:</dt>` text. Two
|
|
102
|
+
reasons, both verified against cassettes:
|
|
103
|
+
|
|
104
|
+
- **Locale.** The OMG server renders the month name in its own locale, and
|
|
105
|
+
Cloudflare caches that variant. A response can carry `Content-Language: zh-CN`
|
|
106
|
+
with an otherwise English page (`<html lang="en">`) and a `<dd>七月 2007</dd>`,
|
|
107
|
+
which made `Date.parse` raise `Date::Error`. The request already sends
|
|
108
|
+
`Accept-Language: en-us,en;q=0.5`; the CDN answers `Vary: accept-encoding`
|
|
109
|
+
only, so it does not vary on language and no request header can prevent this.
|
|
110
|
+
- **Precision.** The visible text is a lossy render of the same value:
|
|
111
|
+
`2013-03-31` prints as "March 2013". Parsing the text rounded every OMG date
|
|
112
|
+
down to day 01.
|
|
113
|
+
|
|
114
|
+
The `<dd>` text stays as a fallback for a page with no JSON-LD, and a month name
|
|
115
|
+
it cannot parse logs a warning instead of raising.
|
|
116
|
+
`spec/omg/relaton/omg/scraper_spec.rb` guards all three paths with
|
|
117
|
+
`spec/omg/fixtures/localized_date.html`. Do not "simplify" the parser back to
|
|
118
|
+
the `<dd>` text.
|
|
119
|
+
|
|
120
|
+
### Serialization formats
|
|
121
|
+
|
|
122
|
+
Items can be serialized to/from YAML and XML. Tests verify round-trip fidelity for all three classes. XML output is validated against RELAX NG schemas in `grammars/`.
|
|
123
|
+
|
|
124
|
+
### Test patterns
|
|
125
|
+
|
|
126
|
+
- RSpec with `expect` syntax (monkey patching disabled)
|
|
127
|
+
- `equivalent-xml` for XML comparison
|
|
128
|
+
- `ruby-jing` for RELAX NG schema validation against `grammars/relaton-omg-compile.rng`
|
|
129
|
+
- VCR cassettes in `spec/vcr_cassettes/` for HTTP interaction recording
|
|
130
|
+
- Fixtures in `spec/fixtures/` (YAML and XML reference files)
|
|
131
|
+
- Tests follow a round-trip pattern: load fixture → parse → serialize → compare to fixture
|
|
132
|
+
|
|
133
|
+
## Style
|
|
134
|
+
|
|
135
|
+
- Ruby >= 3.1.0
|
|
136
|
+
- Rubocop inherits from Ribose OSS guide with `rubocop-rails` required but Rails cops disabled
|
|
137
|
+
- OMG document reference format: `OMG {ACRONYM}[ {VERSION}][ {PART}]` (e.g., `OMG AMI4CCM 1.0`, `OMG UML 2.1.1 Superstructure`)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
= Relaton::Omg
|
|
2
|
+
|
|
3
|
+
RelatonOmg is a Ruby gem that searches and fetches standards from https://www.omg.org[The Object Management Group (OMG)].
|
|
4
|
+
|
|
5
|
+
The standards are scraped from https://www.omg.org/spec
|
|
6
|
+
|
|
7
|
+
== Usage
|
|
8
|
+
|
|
9
|
+
=== Search document
|
|
10
|
+
|
|
11
|
+
Reference format is `OMG + {ACRONYM} + {VERSION}`
|
|
12
|
+
|
|
13
|
+
- `ACRONYM` is an acronym from the list of specs https://www.omg.org/spec/#all
|
|
14
|
+
- `VERSION` (optional) if omitted then the latest version is fetched
|
|
15
|
+
|
|
16
|
+
[source,ruby]
|
|
17
|
+
----
|
|
18
|
+
require 'relaton/omg'
|
|
19
|
+
=> true
|
|
20
|
+
|
|
21
|
+
item = Relaton::Omg::Bibliography.get 'OMG AMI4CCM 1.0'
|
|
22
|
+
[relaton-omg] INFO: (OMG AMI4CCM 1.0) Fetching from www.omg.org ...
|
|
23
|
+
[relaton-omg] INFO: (OMG AMI4CCM 1.0) Found: `OMG AMI4CCM 1.0`
|
|
24
|
+
=> #<Relaton::Bib::ItemData:0x0000000128bf7650
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
# Return nil if the document doesn't exist.
|
|
28
|
+
Relaton::Omg::Bibliography.get 'OMG 1111'
|
|
29
|
+
[relaton-omg] INFO: (OMG 1111) Fetching from www.omg.org ...
|
|
30
|
+
[relaton-omg] INFO: (OMG 1111) Not found.
|
|
31
|
+
=> nil
|
|
32
|
+
----
|
|
33
|
+
|
|
34
|
+
=== Serialization
|
|
35
|
+
|
|
36
|
+
[source,ruby]
|
|
37
|
+
----
|
|
38
|
+
item.to_xml
|
|
39
|
+
=> "<bibitem id="OMGAMI4CCM10" schema-version="v1.4.1">
|
|
40
|
+
<fetched>2026-02-27</fetched>
|
|
41
|
+
<title language="en" script="Latn" type="main">Asynchronous Method Invocation for CCM</title>
|
|
42
|
+
<uri type="src">https://www.omg.org/spec/AMI4CCM/1.0/About-AMI4CCM</uri>
|
|
43
|
+
<uri type="pdf">https://www.omg.org/spec/AMI4CCM/1.0/PDF</uri>
|
|
44
|
+
<docidentifier type="OMG" primary="true">OMG AMI4CCM 1.0</docidentifier>
|
|
45
|
+
...
|
|
46
|
+
</bibitem>"
|
|
47
|
+
|
|
48
|
+
item.to_xml bibdata: true
|
|
49
|
+
=> "<bibdata schema-version="v1.4.1">
|
|
50
|
+
<fetched>2026-02-27</fetched>
|
|
51
|
+
<title language="en" script="Latn" type="main">Asynchronous Method Invocation for CCM</title>
|
|
52
|
+
<uri type="src">https://www.omg.org/spec/AMI4CCM/1.0/About-AMI4CCM</uri>
|
|
53
|
+
<uri type="pdf">https://www.omg.org/spec/AMI4CCM/1.0/PDF</uri>
|
|
54
|
+
<docidentifier type="OMG" primary="true">OMG AMI4CCM 1.0</docidentifier>
|
|
55
|
+
...
|
|
56
|
+
</bibdata>"
|
|
57
|
+
----
|
|
58
|
+
|
|
59
|
+
=== Typed links
|
|
60
|
+
|
|
61
|
+
OMG documents may have `src` and `pdf` link source types.
|
|
62
|
+
|
|
63
|
+
[source,ruby]
|
|
64
|
+
----
|
|
65
|
+
item.source[0].type
|
|
66
|
+
=> "src"
|
|
67
|
+
|
|
68
|
+
item.source[0].content
|
|
69
|
+
=> "https://www.omg.org/spec/AMI4CCM/1.0/About-AMI4CCM"
|
|
70
|
+
----
|
|
71
|
+
|
|
72
|
+
=== Create bibliographic item from XML
|
|
73
|
+
|
|
74
|
+
[source,ruby]
|
|
75
|
+
----
|
|
76
|
+
xml = File.read 'spec/fixtures/omg_ami4ccm_1_0.xml', encoding: 'UTF-8'
|
|
77
|
+
item = Relaton::Omg::Bibitem.from_xml xml
|
|
78
|
+
=> #<Relaton::Bib::ItemData:0x00000001248f8c00
|
|
79
|
+
...
|
|
80
|
+
----
|
|
81
|
+
|
|
82
|
+
=== Create bibliographic item from YAML
|
|
83
|
+
[source,ruby]
|
|
84
|
+
----
|
|
85
|
+
yaml = File.read 'spec/fixtures/omg_ami4ccm_1_0.yaml', encoding: 'UTF-8'
|
|
86
|
+
item = Relaton::Omg::Item.from_yaml yaml
|
|
87
|
+
=> #<Relaton::Bib::ItemData:0x000000012813b180
|
|
88
|
+
...
|
|
89
|
+
----
|
|
90
|
+
|
|
91
|
+
=== Logging
|
|
92
|
+
|
|
93
|
+
RelatonOmg uses the relaton-logger gem for logging. By default, it logs to STDOUT. To change the log levels and add other loggers, read the https://github.com/relaton/relaton-logger#usage[relaton-logger] documentation.
|
|
94
|
+
|
|
95
|
+
== Contributing
|
|
96
|
+
|
|
97
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/relaton/relaton-omg.
|
|
98
|
+
|
|
99
|
+
== License
|
|
100
|
+
|
|
101
|
+
The gem is available as open source under the terms of the https://opensource.org/licenses/MIT[MIT License].
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
relaton-plateau is a Ruby gem for retrieving and managing bibliographic metadata for Project PLATEAU (Japanese 3D city model standards published by MLIT). It is part of the Relaton ecosystem of bibliographic gems.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
bundle install
|
|
14
|
+
|
|
15
|
+
# Run all tests
|
|
16
|
+
bundle exec rake spec
|
|
17
|
+
|
|
18
|
+
# Run a single test file
|
|
19
|
+
bundle exec rspec spec/relaton/plateau/bibitem_spec.rb
|
|
20
|
+
|
|
21
|
+
# Run a specific test by line number
|
|
22
|
+
bundle exec rspec spec/relaton/plateau/bibitem_spec.rb:15
|
|
23
|
+
|
|
24
|
+
# Lint
|
|
25
|
+
bundle exec rake rubocop
|
|
26
|
+
|
|
27
|
+
# Default rake task (runs specs)
|
|
28
|
+
bundle exec rake
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
|
|
33
|
+
All code lives in `lib/relaton/plateau/`. The gem uses LutaML::Model::Serializable for data modeling with automatic XML/YAML serialization.
|
|
34
|
+
|
|
35
|
+
### Models
|
|
36
|
+
- **Item** (`item.rb`) — base Plateau item extending `Bib::Item`, declares `model ItemData` and adds `ext` attribute
|
|
37
|
+
- **ItemData** (`item_data.rb`) — data class extending `Bib::ItemData`, returned by `Item.from_xml`, `Item.from_yaml`, and `Bibliography.get`
|
|
38
|
+
- **Bibitem** (`bibitem.rb`) — bibliographic item variant (includes `Bib::BibitemShared`)
|
|
39
|
+
- **Bibdata** (`bibdata.rb`) — bibliographic data variant (includes `Bib::BibdataShared`)
|
|
40
|
+
- **Ext** (`ext.rb`) — extension element: doctype, subdoctype, flavor, editorialgroup, stagename, filesize, etc.
|
|
41
|
+
- **Doctype** (`doctype.rb`) — extends `Bib::Doctype`, valid values: `handbook`, `technical-report`, `annex`
|
|
42
|
+
|
|
43
|
+
### Retrieval & Data Fetching
|
|
44
|
+
- **Bibliography** (`bibliography.rb`) — module with `get(code)` for index-based document retrieval, returns `ItemData`
|
|
45
|
+
- **HitCollection** / **Hit** — search the relaton-data-plateau index and fetch YAML documents
|
|
46
|
+
- **DataFetcher** (`data_fetcher.rb`) — extends `Core::DataFetcher`, scrapes MLIT JSON APIs for handbooks and technical reports
|
|
47
|
+
- **Parser** / **HandbookParser** / **TechnicalReportParser** — parse JSON into `ItemData` objects
|
|
48
|
+
- **Processor** (`processor.rb`) — standard Relaton processor plugin (`get`, `from_xml`, `from_yaml`, `fetch_data`, `grammar_hash`)
|
|
49
|
+
|
|
50
|
+
### Serialization Methods
|
|
51
|
+
- `bib.to_xml` — XML (bibitem format)
|
|
52
|
+
- `Item.to_yaml(bib)` — YAML (class method)
|
|
53
|
+
- `bib.to_rfcxml` — BibXML/RFC XML
|
|
54
|
+
- `Item.from_xml(xml)` — parse XML into `ItemData`
|
|
55
|
+
- `Item.from_yaml(yaml)` — parse YAML into `ItemData`
|
|
56
|
+
|
|
57
|
+
### Data Sources
|
|
58
|
+
- Handbooks: `https://www.mlit.go.jp/plateau/_next/data/1.3.0/libraries/handbooks.json`
|
|
59
|
+
- Technical Reports: `https://www.mlit.go.jp/plateau/_next/data/1.3.0/libraries/technical-reports.json`
|
|
60
|
+
- Pre-fetched index: `https://raw.githubusercontent.com/relaton/relaton-data-plateau/v2/` (`HitCollection::ENDPOINT`)
|
|
61
|
+
|
|
62
|
+
### Pubid-backed index (index-v2)
|
|
63
|
+
|
|
64
|
+
The index is **pubid-structured** (`_type: pubid:plateau:*` rows), mirroring
|
|
65
|
+
NIST/CIE. The producer and the consumer `Relaton::Index.find_or_create` call
|
|
66
|
+
sites (`data_fetcher.rb`, `hit_collection.rb`) pass
|
|
67
|
+
`pubid_class: ::Pubid::Plateau::Identifier`, and `INDEXFILE = "index-v2"`.
|
|
68
|
+
`processor.rb#remove_index_file` passes `url: true` and `file:` only: the delete
|
|
69
|
+
never reads the index (see `lib/relaton/index/CLAUDE.md`).
|
|
70
|
+
|
|
71
|
+
**Ids are pubid-canonical.** The parsers emit the form `Pubid::Plateau.parse`
|
|
72
|
+
accepts, which also matches the MLIT source:
|
|
73
|
+
- Handbook: `PLATEAU Handbook #NN 第X.Y版` (Japanese edition label — the parser
|
|
74
|
+
keeps the source `第X.Y版`; the Latinized `#edition` is retained only for the
|
|
75
|
+
structured `Bib::Edition`/`ext` fields).
|
|
76
|
+
- Technical Report: `PLATEAU Technical Report #NN` (**no edition** — pubid TRs
|
|
77
|
+
carry none; the document still has a `1.0` `Bib::Edition`).
|
|
78
|
+
- Sub-numbers use a hyphen (`#46-1`), not the source underscore (`#46_1`).
|
|
79
|
+
|
|
80
|
+
`DataFetcher#save_document` parses the canonical id via `#pubid` (a round-trip
|
|
81
|
+
guard: `from_hash(to_hash) == to_hash`) and stores the `Pubid::Plateau::Identifier`
|
|
82
|
+
object; unparseable ids are warned and skipped (defensive — the parser already
|
|
83
|
+
emits canonical, so nothing is expected to skip).
|
|
84
|
+
|
|
85
|
+
**Search accepts both forms.** `HitCollection#find` parses the query via `#ref`
|
|
86
|
+
(`Pubid::Plateau.parse`, memoized; an unparseable query **raises**
|
|
87
|
+
`Pubid::Errors::ParseError`; `Bibliography.get` rescues transport errors only,
|
|
88
|
+
as `Relaton::RequestError`, and `Hit#item` raises that same error on a
|
|
89
|
+
non-200) and matches on **pubid objects**, mirroring the
|
|
90
|
+
other pubid flavors: an exact edition uses `index.search(ref, exact: true)`
|
|
91
|
+
(pubid `==` compares type + number + annex + edition); a family query
|
|
92
|
+
(`ref.edition.nil?` — an edition-less handbook, or any Technical Report) uses
|
|
93
|
+
the default subset match `ref === row`, where the omitted edition matches any
|
|
94
|
+
value. pubid declares `annex` strict for PLATEAU (pubid#408), so
|
|
95
|
+
`PLATEAU Handbook #03` does not reach the annex `#03-1`;
|
|
96
|
+
`hit_collection_spec.rb` pins that against the index fixture. This keeps the
|
|
97
|
+
family-vs-exact decision and the match on the *same* parsed identifier (no raw
|
|
98
|
+
`@ref` regex). Canonical (`第1.0版`), edition-less (`#00`), and **legacy Latin**
|
|
99
|
+
(`#00 1.0`) references all resolve — `Pubid::Plateau` normalizes Latin input to
|
|
100
|
+
the canonical id (metanorma/pubid #269; needs the pubid `main` pin). No
|
|
101
|
+
relaton-side Latin shim exists by design.
|
|
102
|
+
|
|
103
|
+
`EDITION_SUFFIX` is **not** used for matching; it lives only in `#to_all_editions`,
|
|
104
|
+
which strips the edition off the fetched document's `Bib::Docidentifier`/docnumber
|
|
105
|
+
**strings** (relaton-bib content, not pubid) to build the family record — it
|
|
106
|
+
matches both Japanese and Latin suffixes so it works against the current (Latin)
|
|
107
|
+
VCR-cassette documents and future canonical ones.
|
|
108
|
+
|
|
109
|
+
### Schema Validation
|
|
110
|
+
RNG grammar files in `grammars/` define the XML schema. Tests validate fixtures against `relaton-plateau-compile.rng` using the `ruby-jing` gem.
|
|
111
|
+
|
|
112
|
+
## Testing
|
|
113
|
+
|
|
114
|
+
- **Index fixture:** `spec/fixtures/index-v2.zip` (pubid-backed, `_type: pubid:plateau:*` rows) is pre-loaded into the `Relaton::Index` pool in `before(:suite)` via a `Relaton::Index::Type` built with `::Pubid::Plateau::Identifier` (configured in `spec/support/webmock.rb`, mirroring NIST/CIE). Run `rake spec:update_index` to refresh from relaton-data-plateau.
|
|
115
|
+
- RSpec with `expect` syntax (no monkey-patching)
|
|
116
|
+
- VCR cassettes record HTTP interactions (in `spec/fixtures/vcr_cassettes/`)
|
|
117
|
+
- `equivalent-xml` for XML comparison assertions
|
|
118
|
+
- `jing` matcher for RNG schema validation
|
|
119
|
+
- SimpleCov for code coverage
|
|
120
|
+
|
|
121
|
+
## Key Conventions
|
|
122
|
+
|
|
123
|
+
- Document identifiers are pubid-canonical: `PLATEAU Handbook #XX 第Y.Z版` (Japanese edition) or `PLATEAU Technical Report #XX` (no edition); sub-numbers use a hyphen (`#XX-N`). See "Pubid-backed index" above.
|
|
124
|
+
- The gem supports multi-format serialization: XML, YAML, BibXML (RFC XML)
|
|
125
|
+
- RuboCop follows Ribose OSS style guide; target Ruby version is 3.0
|
|
126
|
+
- The `ext` element in XML/YAML carries PLATEAU-specific metadata (doctype, flavor, editorialgroup, etc.)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
= Relaton::Plateau: retrieve Project PLATEAU Standards for bibliographic use using the ItemData model
|
|
2
|
+
|
|
3
|
+
RelatonPlateau is a Ruby gem that implements the https://github.com/relaton/relaton-model-plateau[ItemData model].
|
|
4
|
+
|
|
5
|
+
You can use it to retrieve metadata of Plateau Standards from the GitHub repository, and access such metadata through the `Relaton::Plateau::ItemData` object.
|
|
6
|
+
|
|
7
|
+
== Usage
|
|
8
|
+
|
|
9
|
+
=== Fetching
|
|
10
|
+
|
|
11
|
+
==== Fetching Technical Reports
|
|
12
|
+
|
|
13
|
+
[source,ruby]
|
|
14
|
+
----
|
|
15
|
+
require "relaton/plateau"
|
|
16
|
+
|
|
17
|
+
Relaton::Plateau::Bibliography.get("PLATEAU Technical Report #00")
|
|
18
|
+
[relaton-plateau] INFO: (PLATEAU Technical Report #00) Fetching ...
|
|
19
|
+
[relaton-plateau] INFO: (PLATEAU Technical Report #00) Found `PLATEAU Technical Report #00 1.0`
|
|
20
|
+
=> #<Relaton::Plateau::ItemData:0x00000001236204e8
|
|
21
|
+
...
|
|
22
|
+
----
|
|
23
|
+
|
|
24
|
+
==== Fetching Handbooks unversioned
|
|
25
|
+
|
|
26
|
+
[source,ruby]
|
|
27
|
+
----
|
|
28
|
+
Relaton::Plateau::Bibliography.get("PLATEAU Handbook #00")
|
|
29
|
+
[relaton-plateau] INFO: (PLATEAU Handbook #00) Fetching ...
|
|
30
|
+
[relaton-plateau] INFO: (PLATEAU Handbook #00) Found `PLATEAU Handbook #00`
|
|
31
|
+
=> #<Relaton::Plateau::ItemData:0x00000001242bd200
|
|
32
|
+
...
|
|
33
|
+
----
|
|
34
|
+
|
|
35
|
+
==== Fetching Handbooks versioned
|
|
36
|
+
|
|
37
|
+
[source,ruby]
|
|
38
|
+
----
|
|
39
|
+
bib = Relaton::Plateau::Bibliography.get("PLATEAU Handbook #00 1.0")
|
|
40
|
+
[relaton-plateau] INFO: (PLATEAU Handbook #00 1.0) Fetching ...
|
|
41
|
+
[relaton-plateau] INFO: (PLATEAU Handbook #00 1.0) Found `PLATEAU Handbook #00 1.0`
|
|
42
|
+
=> #<Relaton::Plateau::ItemData:0x0000000124157320
|
|
43
|
+
...
|
|
44
|
+
----
|
|
45
|
+
|
|
46
|
+
=== Serializing
|
|
47
|
+
|
|
48
|
+
==== XML
|
|
49
|
+
|
|
50
|
+
[source,ruby]
|
|
51
|
+
----
|
|
52
|
+
puts bib.to_xml
|
|
53
|
+
=> "<bibitem id="PLATEAUHandbook0010" type="standard" schema-version="v1.4.1">
|
|
54
|
+
<title language="en" script="Latn" type="main">PLATEAU Guidebook</title>
|
|
55
|
+
<uri type="pdf">https://www.mlit.go.jp/plateau/file/libraries/doc/plateau_doc_0000_ver01.pdf</uri>
|
|
56
|
+
<docidentifier type="PLATEAU" primary="true">PLATEAU Handbook #00 1.0</docidentifier>
|
|
57
|
+
...
|
|
58
|
+
</bibitem>"
|
|
59
|
+
|
|
60
|
+
puts bib.to_xml bibdata: true
|
|
61
|
+
=> "<bibdata type="standard" schema-version="v1.4.1">
|
|
62
|
+
<title language="en" script="Latn" type="main">PLATEAU Guidebook</title>
|
|
63
|
+
<uri type="pdf">https://www.mlit.go.jp/plateau/file/libraries/doc/plateau_doc_0000_ver01.pdf</uri>
|
|
64
|
+
<docidentifier type="PLATEAU" primary="true">PLATEAU Handbook #00 1.0</docidentifier>
|
|
65
|
+
...
|
|
66
|
+
<ext schema-version="v0.0.2">
|
|
67
|
+
<doctype>handbook</doctype>
|
|
68
|
+
<flavor>plateau</flavor>
|
|
69
|
+
<structuredidentifier type="Handbook">
|
|
70
|
+
<agency>PLATEAU</agency>
|
|
71
|
+
<docnumber>00</docnumber>
|
|
72
|
+
<edition>1.0</edition>
|
|
73
|
+
</structuredidentifier>
|
|
74
|
+
<filesize>18381880</filesize>
|
|
75
|
+
</ext>
|
|
76
|
+
</bibdata>"
|
|
77
|
+
----
|
|
78
|
+
|
|
79
|
+
==== YAML
|
|
80
|
+
|
|
81
|
+
[source,ruby]
|
|
82
|
+
----
|
|
83
|
+
bib.to_yaml
|
|
84
|
+
=> "---
|
|
85
|
+
id: PLATEAUHandbook0010
|
|
86
|
+
type: standard
|
|
87
|
+
schema_version: v1.4.1
|
|
88
|
+
..."
|
|
89
|
+
----
|
|
90
|
+
|
|
91
|
+
=== Create from XML
|
|
92
|
+
|
|
93
|
+
[source,ruby]
|
|
94
|
+
----
|
|
95
|
+
Relaton::Plateau::Item.from_xml File.read("spec/fixtures/handbook.xml")
|
|
96
|
+
=> #<Relaton::Plateau::ItemData:0x0000000123b99118
|
|
97
|
+
...
|
|
98
|
+
----
|
|
99
|
+
|
|
100
|
+
=== Create from YAML
|
|
101
|
+
|
|
102
|
+
[source,ruby]
|
|
103
|
+
----
|
|
104
|
+
Relaton::Plateau::Item.from_yaml File.read("spec/fixtures/item.yaml")
|
|
105
|
+
=> #<Relaton::Plateau::ItemData:0x00000001209fd208
|
|
106
|
+
...
|
|
107
|
+
----
|
|
108
|
+
|
|
109
|
+
=== Fetching data
|
|
110
|
+
|
|
111
|
+
Two datasets are available for fetching: `plateau-handbooks` and `plateau-technical-reports`. The format can be `xml`, `yaml`, or `bibxml`.
|
|
112
|
+
|
|
113
|
+
[source,ruby]
|
|
114
|
+
----
|
|
115
|
+
require "relaton/plateau/data_fetcher"
|
|
116
|
+
|
|
117
|
+
Relaton::Plateau::DataFetcher.fetch("plateau-handbooks", output: "dir", format: "xml")
|
|
118
|
+
Started at: 2026-03-02 15:36:03 -0500
|
|
119
|
+
Stopped at: 2026-03-02 15:36:04 -0500
|
|
120
|
+
Done in: 1 sec.
|
|
121
|
+
----
|
|
122
|
+
|
|
123
|
+
== Logging
|
|
124
|
+
|
|
125
|
+
RelatonPlateau uses https://github.com/relaton/relaton-logger[relaton-logger] for logging. By default, it logs to STDERR. To change the log level and output, use `Relaton.logger_pool` and `Relaton.logger`.
|
|
126
|
+
|
|
127
|
+
== Development
|
|
128
|
+
|
|
129
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
130
|
+
|
|
131
|
+
To update the index test fixture (used by tests), run `rake spec:update_index`. This downloads the latest `index-v2.zip` from the https://github.com/relaton/relaton-data-plateau[relaton-data-plateau] repository.
|
|
132
|
+
|
|
133
|
+
== Contributing
|
|
134
|
+
|
|
135
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/relaton/relaton-plateau
|
|
136
|
+
|
|
137
|
+
== License
|
|
138
|
+
|
|
139
|
+
The gem is available as open source under the terms of the https://opensource.org/licenses/MIT[MIT license].
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Dev notes for `Relaton::Sdo` — the SDO organization & logo store.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
A **non-flavor** component that answers metanorma#346 (central logo store) and
|
|
8
|
+
its sister relaton-db#132 (map abbreviation → organisation name/translation).
|
|
9
|
+
It is **not** a bibliographic flavor: it has **no processor**, **no
|
|
10
|
+
`Db::Registry` entry**, and is not reachable from `Db#fetch`. It is a standalone
|
|
11
|
+
top-level store, exposed through `Relaton.organization`.
|
|
12
|
+
|
|
13
|
+
This deliberately honors the scope decision in `lib/relaton/db/CLAUDE.md`
|
|
14
|
+
("org metadata … kept out of the processors"): nothing here touches a processor.
|
|
15
|
+
The user's choice was to still surface it from the `relaton` gem itself (one
|
|
16
|
+
`require`, one entry point) as a **lazily-autoloaded** component — referencing
|
|
17
|
+
`Relaton::Sdo` or calling `Relaton.organization` is what loads it.
|
|
18
|
+
|
|
19
|
+
## Public API
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
org = Relaton.organization("ISO") # case-insensitive; nil if unknown
|
|
23
|
+
org.name # default (untranslated) name
|
|
24
|
+
org.name("fr") # translation, or nil
|
|
25
|
+
org.name(language: "fr") # same, via the language: keyword
|
|
26
|
+
org.logo_query(format:, size:, style:) # all args optional → matching Logo list
|
|
27
|
+
org.logo(format:, size:, style:) # one Logo: nil if 0, the match if 1,
|
|
28
|
+
# raises Sdo::Error if the filter is ambiguous
|
|
29
|
+
logo.content # raw binary (lazy HTTP GET of logo.url, memoized)
|
|
30
|
+
logo.data_uri # "data:<mime>;base64,…"
|
|
31
|
+
logo.save # write to a filename derived from the URL; returns path
|
|
32
|
+
logo.save("/path.eps") # write to a custom path
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Data model & retrieval flow
|
|
36
|
+
|
|
37
|
+
`Store` (singleton) lazily builds an index from a single **`index.yaml`**
|
|
38
|
+
manifest served by the `relaton-data-sdo` data repo, and memoizes it (`reset!`
|
|
39
|
+
drops the memo — used by specs). Shape:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
organizations:
|
|
43
|
+
ISO:
|
|
44
|
+
name:
|
|
45
|
+
- content: International Organization for Standardization # default
|
|
46
|
+
- { language: fr, content: Organisation internationale de normalisation }
|
|
47
|
+
logo:
|
|
48
|
+
- { style: default, format: eps, size: 700x300, url: "https://…/iso.eps" }
|
|
49
|
+
- { style: red, format: svg, url: "https://…/red.svg",
|
|
50
|
+
applicability: "stage>=60" } # opaque text; the store never interprets it
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- **`style`** is the primary discriminator for multiple logos per org (e.g.
|
|
54
|
+
`default`, `red`, `grey`, `iso_1972`, `white_paper_2022`, BIPM `si_aspect_full`).
|
|
55
|
+
- **`applicability`** (year/stage/doctype/cover-color rules) is carried through
|
|
56
|
+
verbatim and exposed; **selection is the consumer's job** (metanorma), not the
|
|
57
|
+
store's.
|
|
58
|
+
|
|
59
|
+
`Config` (`Relaton::Sdo.configuration`) holds the index `url`, the cache
|
|
60
|
+
`storage_dir` (default `~/.relaton/sdo`), the `storage` backend (defaults to
|
|
61
|
+
`Relaton::Index::FileStorage`; swappable, e.g. S3), and the `ttl` (24 h).
|
|
62
|
+
`Fetcher.fetch_index` serves a fresh on-disk copy within the TTL, re-downloads
|
|
63
|
+
otherwise, and falls back to a stale cache if the network fails. A URL with no
|
|
64
|
+
scheme (or `file://`) is read straight off disk — handy for fixtures/specs. Logo
|
|
65
|
+
binaries are fetched on demand and memoized on the `Logo` (no disk cache yet).
|
|
66
|
+
|
|
67
|
+
## Tests
|
|
68
|
+
|
|
69
|
+
`spec/sdo/` is a self-contained suite (auto-discovered by `rake spec`). It uses
|
|
70
|
+
WebMock to stub the index and logo URLs, points `storage_dir` at a fresh
|
|
71
|
+
`Dir.mktmpdir` per example, and resets the store between examples. It
|
|
72
|
+
`require "relaton"` because the public entry point (`Relaton.organization`)
|
|
73
|
+
lives in the root entry file, which the shared spec_helper does not load.
|
|
74
|
+
|
|
75
|
+
## Scope / not yet done
|
|
76
|
+
|
|
77
|
+
- The real `relaton-data-sdo` data repo (assets + build GHA) — see
|
|
78
|
+
`HANDOFFS/relaton__relaton-data-sdo.md`. Until it publishes, `Config#url`
|
|
79
|
+
points at its (future) raw `index.yaml`.
|
|
80
|
+
- No structured interpretation of `applicability`; no on-disk cache of logo
|
|
81
|
+
binaries; no writeback/authoring.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
relaton-un is a Ruby gem that provides bibliographic data models for UN documents, part of the Relaton family of gems. It extends `relaton-bib` with UN-specific metadata using the LutaML-Model serialization framework. Currently on the `lutaml-integration` branch undergoing a major migration from the old `RelatonUn` namespace to `Relaton::Un`.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
bundle install
|
|
14
|
+
|
|
15
|
+
# Run all tests (also the default rake task)
|
|
16
|
+
bundle exec rake spec
|
|
17
|
+
|
|
18
|
+
# Run a specific test file
|
|
19
|
+
bundle exec rspec spec/relaton/un/bibitem_spec.rb
|
|
20
|
+
|
|
21
|
+
# Run a specific test by line number
|
|
22
|
+
bundle exec rspec spec/relaton/un/bibitem_spec.rb:7
|
|
23
|
+
|
|
24
|
+
# Lint
|
|
25
|
+
bundle exec rubocop
|
|
26
|
+
|
|
27
|
+
# Interactive console with gem loaded
|
|
28
|
+
bin/console
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
|
|
33
|
+
### Flavor Model Pattern
|
|
34
|
+
|
|
35
|
+
The gem follows the Relaton flavor pattern: base classes from `relaton-bib` (`Bib::Item`) are extended with a flavor-specific `Ext` class containing UN-specific metadata.
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Bib::ItemData (from relaton-bib)
|
|
39
|
+
└── Relaton::Un::ItemData # UN flavor identity, enables NamespaceHelper#namespace → Relaton::Un
|
|
40
|
+
|
|
41
|
+
Bib::Item (from relaton-bib)
|
|
42
|
+
└── Relaton::Un::Item # model ItemData; adds Ext attribute
|
|
43
|
+
├── Relaton::Un::Bibitem # includes Bib::BibitemShared (for <bibitem> XML)
|
|
44
|
+
└── Relaton::Un::Bibdata # includes Bib::BibdataShared (for <bibdata> XML)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Lookup
|
|
48
|
+
|
|
49
|
+
`Bibliography.get` takes a String (`UN TRADE/CEFACT/2004/32`, the `UN ` token
|
|
50
|
+
optional) or a parsed `Pubid::Un::Identifier`, which renders the document
|
|
51
|
+
symbol without the token (`TRADE/CEFACT/2004/32`) — the form the UN data
|
|
52
|
+
itself writes. Either becomes the symbol the search matches (`document_symbol`).
|
|
53
|
+
`Relaton::Db` routes UN by the `UN ` prefix (`Registry#route` falls back to
|
|
54
|
+
`class_by_ref`): `Pubid::Un` renders the symbol without the token, so a
|
|
55
|
+
`UN …` reference is not an exact parse. A symbol without the token
|
|
56
|
+
(`TRADE/CEFACT/2004/32`) is not routed at all — no flavor claims it — and
|
|
57
|
+
raises `Relaton::UnknownReferenceError`. `Pubid::Un` also parses a bare DOI
|
|
58
|
+
exactly (`10.6028/NIST.IR.8245`), but UN does not claim it (`10.` is a DOI
|
|
59
|
+
prefix), so it does not route to UN either.
|
|
60
|
+
|
|
61
|
+
### Key Classes (all in `lib/relaton/un/`)
|
|
62
|
+
|
|
63
|
+
- **ItemData** — extends `Bib::ItemData`; the UN-specific data container used by `Item` via `model ItemData`
|
|
64
|
+
- **Item** — extends `Bib::Item`, adds `ext` attribute of type `Ext`
|
|
65
|
+
- **Bibitem / Bibdata** — extend Item with shared mixins for two XML serialization formats
|
|
66
|
+
- **Ext** — UN-specific metadata: `doctype`, `distribution`, `session`, `submissionlanguage`, `job_number`; extends `Bib::Ext`
|
|
67
|
+
- **Session** — session metadata (number, date, item numbers/names, collaborator, agenda_id)
|
|
68
|
+
- **Doctype** — restricts document types to: recommendation, plenary, addendum, communication, corrigendum, reissue, agenda, budgetary, sec-gen-notes, expert-report, resolution
|
|
69
|
+
|
|
70
|
+
### LutaML-Model Serialization
|
|
71
|
+
|
|
72
|
+
All model classes use `Lutaml::Model::Serializable`. XML mappings are defined in `xml do` blocks:
|
|
73
|
+
- `map_attribute` for XML attributes (e.g., `schema-version` → `schema_version`)
|
|
74
|
+
- `map_element` for XML elements (e.g., `session-date` → `session_date`)
|
|
75
|
+
- `collection: true` for array attributes
|
|
76
|
+
- `values: [...]` for restricted string values
|
|
77
|
+
|
|
78
|
+
### Schema Validation
|
|
79
|
+
|
|
80
|
+
RelaxNG grammars in `grammars/` validate XML output. The compiled schema is `grammars/relaton-un-compile.rng`. Tests use `ruby-jing` for validation.
|
|
81
|
+
|
|
82
|
+
### Testing Approach
|
|
83
|
+
|
|
84
|
+
Tests are round-trip serialization tests: load a fixture, serialize to XML/YAML, compare against the original fixture. Bibitem and Bibdata specs also validate XML against the RelaxNG schema. Fixtures live in `spec/fixtures/`.
|
|
85
|
+
|
|
86
|
+
## Dependencies
|
|
87
|
+
|
|
88
|
+
- **relaton-bib** (~> 2.0.0-alpha.1) — base bibliographic model with LutaML-Model integration
|
|
89
|
+
- **faraday** — HTTP client
|
|
90
|
+
- **ruby-jing** (dev) — RelaxNG schema validation in tests
|
|
91
|
+
- **equivalent-xml** (dev) — XML comparison in tests
|