relaton 3.0.0.pre.alpha.16 → 3.0.0.pre.alpha.18

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/data/equivalence/adoption-chains.yaml +38 -0
  3. data/lib/relaton/3gpp/CLAUDE.md +187 -0
  4. data/lib/relaton/3gpp/README.adoc +149 -0
  5. data/lib/relaton/adobe/CLAUDE.md +104 -0
  6. data/lib/relaton/bib/CLAUDE.md +130 -0
  7. data/lib/relaton/bib/README.adoc +330 -0
  8. data/lib/relaton/bib/model/series.rb +1 -1
  9. data/lib/relaton/bipm/CLAUDE.md +173 -0
  10. data/lib/relaton/bipm/README.adoc +352 -0
  11. data/lib/relaton/bipm/data_fetcher.rb +3 -2
  12. data/lib/relaton/bsi/CLAUDE.md +35 -0
  13. data/lib/relaton/bsi/README.adoc +112 -0
  14. data/lib/relaton/calconnect/CLAUDE.md +177 -0
  15. data/lib/relaton/calconnect/README.adoc +140 -0
  16. data/lib/relaton/ccsds/CLAUDE.md +74 -0
  17. data/lib/relaton/ccsds/README.adoc +154 -0
  18. data/lib/relaton/cen/CLAUDE.md +219 -0
  19. data/lib/relaton/cen/README.adoc +155 -0
  20. data/lib/relaton/cie/CLAUDE.md +90 -0
  21. data/lib/relaton/cie/README.adoc +121 -0
  22. data/lib/relaton/core/CLAUDE.md +140 -0
  23. data/lib/relaton/core/README.adoc +64 -0
  24. data/lib/relaton/core/data_fetcher.rb +50 -3
  25. data/lib/relaton/db/CLAUDE.md +373 -0
  26. data/lib/relaton/db.rb +19 -1
  27. data/lib/relaton/doi/CLAUDE.md +105 -0
  28. data/lib/relaton/doi/README.adoc +89 -0
  29. data/lib/relaton/easc/CLAUDE.md +85 -0
  30. data/lib/relaton/ecma/CLAUDE.md +217 -0
  31. data/lib/relaton/ecma/README.adoc +178 -0
  32. data/lib/relaton/equivalence.rb +89 -0
  33. data/lib/relaton/etsi/CLAUDE.md +219 -0
  34. data/lib/relaton/etsi/README.adoc +137 -0
  35. data/lib/relaton/evs/CLAUDE.md +120 -0
  36. data/lib/relaton/evs/README.adoc +27 -0
  37. data/lib/relaton/gb/CLAUDE.md +47 -0
  38. data/lib/relaton/gb/README.adoc +169 -0
  39. data/lib/relaton/gost/CLAUDE.md +100 -0
  40. data/lib/relaton/iala/CLAUDE.md +97 -0
  41. data/lib/relaton/iana/CLAUDE.md +105 -0
  42. data/lib/relaton/iana/README.adoc +107 -0
  43. data/lib/relaton/iec/CLAUDE.md +13 -0
  44. data/lib/relaton/iec/README.adoc +280 -0
  45. data/lib/relaton/iec/data_fetcher.rb +24 -8
  46. data/lib/relaton/iec/project_fetcher.rb +48 -0
  47. data/lib/relaton/iec/project_parser.rb +111 -0
  48. data/lib/relaton/iec.rb +5 -0
  49. data/lib/relaton/ieee/CLAUDE.md +176 -0
  50. data/lib/relaton/ieee/README.adoc +131 -0
  51. data/lib/relaton/ietf/CLAUDE.md +357 -0
  52. data/lib/relaton/ietf/README.adoc +167 -0
  53. data/lib/relaton/iho/CLAUDE.md +70 -0
  54. data/lib/relaton/iho/README.adoc +119 -0
  55. data/lib/relaton/index/CLAUDE.md +207 -0
  56. data/lib/relaton/index/README.adoc +221 -0
  57. data/lib/relaton/index/dataset_lock.rb +122 -0
  58. data/lib/relaton/index/family.rb +63 -0
  59. data/lib/relaton/index/type.rb +32 -0
  60. data/lib/relaton/index.rb +3 -0
  61. data/lib/relaton/isbn/CLAUDE.md +47 -0
  62. data/lib/relaton/isbn/README.adoc +91 -0
  63. data/lib/relaton/iso/CLAUDE.md +38 -0
  64. data/lib/relaton/iso/README.adoc +370 -0
  65. data/lib/relaton/iso/data_fetcher.rb +16 -1
  66. data/lib/relaton/itu/CLAUDE.md +685 -0
  67. data/lib/relaton/itu/README.adoc +188 -0
  68. data/lib/relaton/jcgm/CLAUDE.md +107 -0
  69. data/lib/relaton/jis/CLAUDE.md +64 -0
  70. data/lib/relaton/jis/README.adoc +167 -0
  71. data/lib/relaton/logger/CLAUDE.md +37 -0
  72. data/lib/relaton/logger/README.adoc +120 -0
  73. data/lib/relaton/nist/CLAUDE.md +180 -0
  74. data/lib/relaton/nist/README.adoc +389 -0
  75. data/lib/relaton/nist/bibliography.rb +17 -1
  76. data/lib/relaton/nist/data_fetcher.rb +60 -4
  77. data/lib/relaton/nist/hit_collection.rb +121 -59
  78. data/lib/relaton/nist/scraper.rb +21 -7
  79. data/lib/relaton/oasis/CLAUDE.md +251 -0
  80. data/lib/relaton/oasis/README.adoc +132 -0
  81. data/lib/relaton/ogc/CLAUDE.md +242 -0
  82. data/lib/relaton/ogc/README.adoc +134 -0
  83. data/lib/relaton/oiml/CLAUDE.md +47 -0
  84. data/lib/relaton/oiml/README.adoc +70 -0
  85. data/lib/relaton/omg/CLAUDE.md +137 -0
  86. data/lib/relaton/omg/README.adoc +101 -0
  87. data/lib/relaton/plateau/CLAUDE.md +126 -0
  88. data/lib/relaton/plateau/README.adoc +139 -0
  89. data/lib/relaton/sdo/CLAUDE.md +81 -0
  90. data/lib/relaton/un/CLAUDE.md +91 -0
  91. data/lib/relaton/un/README.adoc +125 -0
  92. data/lib/relaton/version.rb +1 -1
  93. data/lib/relaton/w3c/CLAUDE.md +369 -0
  94. data/lib/relaton/w3c/README.adoc +140 -0
  95. data/lib/relaton/w3c/data_fetcher.rb +1 -1
  96. data/lib/relaton/xsf/CLAUDE.md +189 -0
  97. data/lib/relaton/xsf/README.adoc +127 -0
  98. data/lib/relaton.rb +1 -0
  99. metadata +83 -2
@@ -0,0 +1,188 @@
1
+ = Relaton::Itu: retrieve ITU Standards for bibliographic use using the BibliographicItem model
2
+
3
+ RelatonItu is a Ruby gem that implements the https://github.com/metanorma/metanorma-model-iso#iso-bibliographic-item[IsoBibliographicItem model].
4
+
5
+ == Usage
6
+
7
+ === Search for a standard using keywords
8
+
9
+ [source,ruby]
10
+ ----
11
+ require 'relaton/itu'
12
+ => true
13
+
14
+ hit_collection = Relaton::Itu::Bibliography.search("ITU-T L.163")
15
+ => <Relaton::Itu::HitCollection:0x00000000001700 @ref=ITU-T L.163 @fetched=false>
16
+
17
+ item = hit_collection[1].item
18
+ => #<Relaton::Itu::ItemData:0x000000012541b8f8
19
+ ...
20
+ ----
21
+
22
+ === XML serialization
23
+
24
+ [source,ruby]
25
+ ----
26
+ item.to_xml
27
+ => "<bibitem id="ITUTLSuppl39092020" type="standard" schema-version="v1.4.1">
28
+ <fetched>2026-02-24</fetched>
29
+ <title language="en" script="Latn" type="title-intro">ITU-T L.1470</title>
30
+ <title language="en" script="Latn" type="title-main">Optical fibre cable Recommendations and standardization guideline</title>
31
+ <title language="en" script="Latn" type="main">ITU-T L.1470 - Optical fibre cable Recommendations and standardization guideline</title>
32
+ <uri type="src">https://handle.itu.int/11.1002/1000/14547</uri>
33
+ <uri type="pdf">https://www.itu.int/rec/dologin_pub.asp?lang=e&amp;id=T-REC-L.Sup39-202009-I!!PDF-E&amp;type=items</uri>
34
+ <docidentifier type="ITU" primary="true">ITU-T L Suppl. 39 (09/2020)</docidentifier>
35
+ ...
36
+ </bibitem>"
37
+ ----
38
+
39
+ With `bibdata: true` option XML output is wrapped with `bibdata` element and `ext` element added.
40
+
41
+ [source,ruby]
42
+ ----
43
+ item.to_xml bibdata: true
44
+ => "<bibdata type="standard" schema-version="v1.4.1">
45
+ <fetched>2026-02-24</fetched>
46
+ <title language="en" script="Latn" type="title-intro">ITU-T L.1470</title>
47
+ <title language="en" script="Latn" type="title-main">Optical fibre cable Recommendations and standardization guideline</title>
48
+ <title language="en" script="Latn" type="main">ITU-T L.1470 - Optical fibre cable Recommendations and standardization guideline</title>
49
+ <uri type="src">https://handle.itu.int/11.1002/1000/14547</uri>
50
+ <uri type="pdf">https://www.itu.int/rec/dologin_pub.asp?lang=e&amp;id=T-REC-L.Sup39-202009-I!!PDF-E&amp;type=items</uri>
51
+ <docidentifier type="ITU" primary="true">ITU-T L Suppl. 39 (09/2020)</docidentifier>
52
+ ...
53
+ <ext schema-version="v1.0.2">
54
+ <doctype>recommendation</doctype>
55
+ <flavor>itu</flavor>
56
+ </ext>
57
+ </bibdata>"
58
+ ----
59
+
60
+ === Get document by code and year
61
+ [source,ruby]
62
+ ----
63
+ Relaton::Itu::Bibliography.get("ITU-T L.163", "2018", {})
64
+ [relaton-itu] INFO: (ITU-T L.163 (2018)) Fetching from www.itu.int ...
65
+ [relaton-itu] INFO: (ITU-T L.163 (2018)) Found: `ITU-T L.163 (11/2018)`
66
+ => #<Relaton::Itu::ItemData:0x000000010f92a288
67
+ ...
68
+ ----
69
+
70
+ === Get amendment
71
+ [source,ruby]
72
+ ----
73
+ Relaton::Itu::Bibliography.get "ITU-T G.989.2 (2019)/Amd 1"
74
+ [relaton-itu] INFO: (ITU-T G.989.2 (2019)) Fetching from www.itu.int ...
75
+ [relaton-itu] INFO: (ITU-T G.989.2 (2019)) Found: `ITU-T G.989.2 (02/2019)`
76
+ => #<Relaton::Itu::ItemData:0x000000010fa4f3c0
77
+ ...
78
+ ----
79
+
80
+ === Get ITU-R documents
81
+
82
+ [source,ruby]
83
+ ----
84
+ Relaton::Itu::Bibliography.get "ITU-R BO.600-1"
85
+ [relaton-itu] INFO: (ITU-R BO.600-1) Fetching from Relaton repository ...
86
+ [relaton-itu] INFO: (ITU-R BO.600-1) Found: `ITU-R BO.600-1`
87
+ => #<Relaton::Itu::ItemData:0x000000010fa4a3c0
88
+ ...
89
+ ----
90
+
91
+ === Get ITU-R Radio Regulations (RR)
92
+
93
+ [source,ruby]
94
+ ----
95
+ Relaton::Itu::Bibliography.get 'ITU-R RR (2020)'
96
+ [relaton-itu] INFO: (ITU-R RR (2020)) Fetching from www.itu.int ...
97
+ [relaton-itu] INFO: (ITU-R RR (2020)) Found: `ITU-R RR (2020)`
98
+ => #<Relaton::Itu::ItemData:0x000000010fa41e00
99
+ ...
100
+ ----
101
+
102
+ === Typed source links
103
+
104
+ Each ITU document has `src` type link and optional `obp` and `word` link types.
105
+
106
+ [source,ruby]
107
+ ----
108
+ item.source[0].type
109
+ => "src"
110
+
111
+ item.source[0].content
112
+ => "https://handle.itu.int/11.1002/1000/14547"
113
+ ----
114
+
115
+ === Create a bibliographic item from XML
116
+
117
+ [source,ruby]
118
+ ----
119
+ item = Relaton::Itu::Item.from_xml File.read("spec/fixtures/bibdata.xml")
120
+ => #<Relaton::Itu::ItemData:0x000000010fa28ea0
121
+ ...
122
+ ----
123
+
124
+ === Create a bibliographic item from YAML
125
+
126
+ [source,ruby]
127
+ ----
128
+ item = Relaton::Itu::Item.from_yaml File.read("spec/fixtures/item.yaml")
129
+ => #<Relaton::Itu::ItemData:0x000000010f9848a0
130
+ ...
131
+ ----
132
+
133
+ === Fetch data
134
+
135
+ The method `Relaton::Itu::DataFetcher.fetch("itu-t", output: "data", format: "yaml")` harvests every ITU-T recommendation edition (from the `mws/api/recommendations/searchRecs` index) and saves the documents to the `./data` folder in YAML format.
136
+ Arguments:
137
+
138
+ - `source` - source name (`itu-t`).
139
+ - `output` - folder to save documents (default `data`).
140
+ - `format` - the format in which the documents are saved. Possible formats are: `yaml`, `xml`, `bibxxml` (default `yaml`).
141
+
142
+ [source,ruby]
143
+ ----
144
+ Relaton::Itu::DataFetcher.fetch "itu-t", output: "dir", format: "xml"
145
+ Started at: 2026-08-12 09:21:16 -0400
146
+ Stopped at: 2026-08-12 11:27:45 -0400
147
+ Done in: 7589 sec.
148
+ => nil
149
+ ----
150
+
151
+ NOTE: **ITU-R harvesting is disabled.** ITU decommissioned the RunSearch bulk-enumeration endpoint the ITU-R crawler paged through, so `fetch("itu-r")` (and the argument-less `fetch`) raises a `Relaton::RequestError` pointing at https://github.com/relaton/relaton/issues/75[issue #75] instead of rebuilding an empty dataset. The published ITU-R records are preserved in https://github.com/relaton/relaton-data-itu[relaton-data-itu] and re-indexed on each crawl via `DataFetcher#index_files("data/itu-r-*.yaml")`; runtime ITU-R lookups are unaffected.
152
+
153
+ `Relaton::Itu::DataCrawlerR` prototypes a replacement crawl over ITU's still-server-rendered `/pub` + `/rec` pages (Recommendations and Reports), and `Relaton::Itu::DataMergeR` merges what it finds into the existing dataset without ever rewriting a published date. Neither is wired into `fetch` — reaching them takes an explicit `require`:
154
+
155
+ [source,ruby]
156
+ ----
157
+ require "relaton/itu/data_crawler_r"
158
+ require "relaton/itu/data_merge_r"
159
+
160
+ fetcher = Relaton::Itu::DataFetcher.new "data", "yaml"
161
+ crawler = Relaton::Itu::DataCrawlerR.new
162
+ items = crawler.harvest("BO", only: %w[R-REC-BO.1130 R-REC-BO.1212]) +
163
+ crawler.harvest("BO", family: "R-REP", only: %w[R-REP-BO.1227 R-REP-BO.2006])
164
+ Relaton::Itu::DataMergeR.write_all items, fetcher
165
+ => {added: 0, backfilled: 4, unchanged: 6, skipped: 0, collisions: []}
166
+ ----
167
+
168
+ Those counts are from that ten-record run against the published dataset: four records gained the PDF link they were missing, six were left byte-identical, and no publication date was touched. Drop `only:` to harvest a whole series (54 recommendation documents / 82 editions for `BO`).
169
+
170
+ === Logging
171
+
172
+ RelatonItu 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.
173
+
174
+ == Development
175
+
176
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
177
+
178
+ The index test fixture (used by tests) is a trimmed copy of the published pubid-structured `index-v2.zip` (rows are `_type: pubid:itu:…` hashes) from the `main` branch of the combined https://github.com/relaton/relaton-data-itu[relaton-data-itu] repository, kept at `spec/fixtures/index-v2.zip`. Refresh it with the regeneration snippet in `lib/relaton/itu/CLAUDE.md` (it must deserialize under the pinned pubid).
179
+
180
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
181
+
182
+ == Contributing
183
+
184
+ Bug reports and pull requests are welcome on GitHub at https://github.com/relaton/relaton-itu.
185
+
186
+ == License
187
+
188
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,107 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with
4
+ code in this repository.
5
+
6
+ ## Project Overview
7
+
8
+ `Relaton::Jcgm` retrieves **JCGM** (Joint Committee for Guides in Metrology)
9
+ publications — the metrology **guides/GUM/VIM** and the committee **meeting**
10
+ proceedings. It is **index-backed** (no scraping): a reference is parsed with
11
+ `Pubid::Jcgm`, matched against a pre-built index, and the matching per-document
12
+ YAML is fetched from the `relaton/relaton-data-jcgm` GitHub repo.
13
+
14
+ JCGM was previously served **inside the BIPM flavor** (its records lived under
15
+ `relaton-data-bipm`). It is now its own SDO/flavor: the BIPM flavor no longer
16
+ matches `JCGM` in its default-prefix, no longer parses JCGM ids, and no longer
17
+ harvests the `jcgm` dir.
18
+
19
+ ## Architecture
20
+
21
+ Namespace `Relaton::Jcgm`; require path `relaton/jcgm`. Retrieval flow:
22
+
23
+ 1. **Bibliography** (`bibliography.rb`) — `get`/`search`: parses the reference
24
+ with `::Pubid::Jcgm.parse`, looks it up in the index, fetches the matching
25
+ YAML over HTTP. `ENDPOINT` points at `relaton-data-jcgm`. An unparseable
26
+ reference **raises** `Pubid::Errors::ParseError`; the `search` rescue lists
27
+ transport errors only, so it does not swallow it.
28
+ 2. **Index** — `Relaton::Index.find_or_create(:jcgm, url:, file:, pubid_class:
29
+ ::Pubid::Jcgm::Identifier)`. Because rows are stored as `Pubid::Jcgm`
30
+ identifiers, the generated index carries the structured `_type:
31
+ pubid:jcgm:{guide,gum-guide,amendment,meeting}` form (not BIPM's bespoke
32
+ `{group,type,number,year}` hash). Matching is `pubid_match?`: pubid's
33
+ asymmetric subset match (`query === row_id`, `Pubid::SubsetMatch`) plus an
34
+ optional exact-year filter for the `year` argument. Guide editions
35
+ (`200:2008` vs `200:2012`) differ only by year, so a year-less reference
36
+ reaches both and the latest is chosen via `max_by(&:year)`; meetings differ
37
+ by number, which the reference states. The document type is the identifier's
38
+ class, and `===` requires the same class, so a guide never answers for its
39
+ corrigendum.
40
+ 3. **Model** (`item.rb`, `ext.rb`, `doctype.rb`, `structured_identifier.rb`,
41
+ `docidentifier.rb`, …) — the records are **BIPM-shaped** (meetings are
42
+ `type: proceedings` / `ext.doctype: meeting-report`; guides are `type:
43
+ standard`), so the model mirrors `Relaton::Bipm`'s (a JCGM `Doctype`, a single
44
+ `structuredidentifier`) rather than OIML's. `docidentifier.rb` is pubid-backed
45
+ like OIML's. The bibliography/index *wiring* follows OIML; the *model* follows
46
+ BIPM.
47
+ 4. **Processor** (`processor.rb`) — `@prefix = "JCGM"`, `@defaultprefix =
48
+ %r{^JCGM\s}`, `@pubid_flavor = :Jcgm` (prefixes sourced from
49
+ `Pubid::Jcgm.prefixes`). Lazy-`require_relative`s `../jcgm` in its methods.
50
+ 5. **DataFetcher** (`data_fetcher.rb`, `meetings_parser.rb`) — (re)builds the
51
+ `relaton-data-jcgm` dataset. `fetch("bipm-data-outcomes")` harvests meeting
52
+ proceedings from a local checkout of `metanorma/bipm-data-outcomes`'s
53
+ `jcgm/meetings-{en,fr}` dirs (the JCGM-only slice of BIPM's
54
+ `DataOutcomesParser`; JCGM has no sub-resolutions or parts). The curated
55
+ guide/GUM/VIM records are **not** harvested — they are hand-maintained YAMLs
56
+ in the data repo's top-level `static/` dir, so `relaton-data-jcgm`'s
57
+ `crawler.rb` indexes them itself (like relaton-data-bipm's crawler) by looping
58
+ `static/**` and calling the public, guarded `DataFetcher#add_to_index`. Rows
59
+ are indexed via the `Pubid::Jcgm::Identifier` object (with `pubid_class:` on
60
+ the index), so `Relaton::Index` sorts the index by id number on save and
61
+ serialises each id to its `_type: pubid:jcgm:*` hash — the published index is
62
+ already sorted (no "not sorted by id number" warning on consumer fetch).
63
+ `add_to_index` **guards** each id: an unparseable one (the legacy `JCGM GUM` /
64
+ `JCGM VIM-3` / `Corrigendum` records) is skipped with a warning rather than
65
+ corrupting the whole index.
66
+
67
+ ## The naive ordinal (11st / 12nd / 13rd)
68
+
69
+ Meeting docnumbers print the ordinal with a **naive last-digit rule** (1→st,
70
+ 2→nd, 3→rd, else th) and **no** 11/12/13 teens exception, so the real records
71
+ read `JCGM 11st Meeting (2006)`, `12nd`, `13rd`. This matches the source data and
72
+ `Pubid::Jcgm::Identifiers::Meeting.ordinal`, so the printed form round-trips
73
+ through pubid. The DataFetcher delegates to `Meeting.ordinal` (single source of
74
+ truth) rather than re-implementing it. Any validation MUST expect `11st`, not
75
+ `11th`.
76
+
77
+ ## Record types & the index guard
78
+
79
+ The five `Pubid::Jcgm` types the index carries: `pubid:jcgm:{guide, gum-guide,
80
+ amendment, corrigendum, meeting}`. The bare `GUM`/`VIM-N` records parse as
81
+ `guide`, and `JCGM 200:2008 Corrigendum` parses as `corrigendum` (whose hash
82
+ nests its `base` guide) — all on pubid **main** (see Dependencies). `Relaton::Index`
83
+ rejects the whole index if a single row fails `from_hash`, so
84
+ `DataFetcher#add_to_index` **guards** each id defensively and skips an unparseable
85
+ docnumber with a warning rather than corrupting the index. Every current JCGM
86
+ record parses; the guard protects against a future malformed one.
87
+
88
+ ## Testing
89
+
90
+ RSpec with WebMock. The offline index fixture `spec/jcgm/fixtures/index-v1.zip`
91
+ is pre-loaded into the `Relaton::Index` pool in `before(:suite)`
92
+ (`spec/jcgm/support/webmock.rb`); per-document requests are served from
93
+ `spec/jcgm/fixtures/{data,static}/**`. `spec/jcgm/fixtures/bipm-data-outcomes/**`
94
+ holds minimal source fixtures for the DataFetcher spec (the real upstream is not
95
+ vendored). `spec/jcgm/relaton/jcgm/pubid_spec.rb` guards the naive ordinals and
96
+ the `_type` forms.
97
+
98
+ ## Dependencies
99
+
100
+ `pubid` (umbrella gem, provides `Pubid::Jcgm`), `relaton-bib`, `relaton-index`,
101
+ `relaton-core`.
102
+
103
+ > **Dependency pin:** the JCGM support (meetings, bare `GUM`/`VIM-N` guides, the
104
+ > `Corrigendum` type, and the flattened compact `to_hash`) first shipped in the
105
+ > released pubid `2.0.0.pre.alpha.13`, which the gemspec pins. Its `lib/` is
106
+ > identical to the pubid `main` that built the published `relaton-data-jcgm`
107
+ > index — a mismatched pubid would make `Relaton::Index` reject that index.
@@ -0,0 +1,64 @@
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-jis is a Ruby gem that retrieves Japanese Industrial Standards (JIS) metadata from webdesk.jsa.or.jp and models them as Relaton bibliographic items with XML/YAML serialization and RelaxNG schema validation.
8
+
9
+ ## Commands
10
+
11
+ - `bundle exec rake spec` — run all tests
12
+ - `bundle exec rspec spec/relaton/jis/item_spec.rb` — run a single test file
13
+ - `bundle exec rspec spec/relaton/jis/item_spec.rb:15` — run a single test by line number
14
+ - `bundle exec rake rubocop` — lint
15
+ - `bundle exec rake` — default task (runs specs)
16
+
17
+ ## Architecture
18
+
19
+ The gem is currently on the `lutaml-integration` branch, a major refactoring from the old `RelatonJis::` namespace to `Relaton::Jis::` using lutaml-model for data modeling.
20
+
21
+ ### Class Hierarchy
22
+
23
+ All classes live under `lib/relaton/jis/`:
24
+
25
+ - **`Item`** (extends `Iso::Item`) — core bibliographic item; defines the `Ext` attribute for JIS extensions; uses model `Bib::ItemData`
26
+ - **`Bibitem`** (extends `Item`, includes `Bib::BibitemShared`) — XML bibitem serialization
27
+ - **`Bibdata`** (extends `Item`, includes `Bib::BibdataShared`) — XML bibdata wrapper
28
+ - **`Ext`** (extends `Iso::Ext`) — JIS-specific extension data (schema_version, doctype)
29
+ - **`Docidentifier`** (extends `Bib::Docidentifier`) — `#pubid` parses `content` with `Pubid::Jis::Identifier` on first use (lazy, memoized, soft: nil if it does not parse). The mutators change the pubid and render it back; there is no regex. `remove_part!` clears every part level (`JIS C 0364-2-21` → `JIS C 0364`), `remove_date!` clears the year and the reaffirmation `R`, and on a supplement both act on the base — the supplement keeps its own year, because pubid renders a year-less supplement as `…/AMD 1:`. `to_all_parts!` wraps `@pubid` in pubid's `AllParts` (so `#pubid.all_parts?` reads true) but writes `content`'s own marker ` (all parts)` from the pre-wrap rendering, not pubid's `(規格群)` (which is what `#pubid.to_s`, read directly, would print). The `JIS ` publisher is rendered only if the source has it (`TR Z 0010:2008` stays without it); everything else is the pubid canonical spelling (`AMENDMENT 1` → `AMD 1`).
30
+ - **`Doctype`** (extends `Bib::Doctype`) — allowed types: `japanese-industrial-standard`, `technical-report`, `technical-specification`, `amendment`
31
+ - **`Scraper`** — scrapes individual JIS document pages from webdesk.jsa.or.jp; returns `Bib::ItemData`; editorial group is modeled as a contributor with `Bib::Subdivision` (not `EditorialGroup`)
32
+ - **`DataFetcher`** (extends `Core::DataFetcher`) — bulk-fetches all JIS documents via threaded scraping; implements `to_yaml`/`to_xml`/`to_bibxml` for serialization dispatch; loaded on-demand via `require "relaton/jis/data_fetcher"`
33
+ - **`Processor`** (extends `Core::Processor`) — Relaton processor registration; provides `get`, `fetch_data`, `from_xml`, `from_yaml`, `grammar_hash`; prefix `JIS`, defaultprefix `^(JIS|TR)\s`
34
+ - **`Util`** (includes `Relaton::Bib::Util`) — logging with PROGNAME "relaton-jis"
35
+
36
+ ### Key Dependencies
37
+
38
+ - **relaton-iso / relaton-bib** — parent bibliographic item models this gem extends
39
+ - **lutaml-model** — DSL for `attribute` definitions and serialization
40
+ - **mechanize** — web scraping from JSA website
41
+
42
+ ### Serialization & Validation
43
+
44
+ - YAML and XML round-trip serialization via lutaml-model
45
+ - RelaxNG grammars in `grammars/` validate XML output; `relaton-jis.rng` defines JIS-specific elements (DocumentType, structuredidentifier, stagename)
46
+ - Tests validate XML against these grammars using ruby-jing
47
+
48
+ ### Test Patterns
49
+
50
+ - **Round-trip tests**: YAML → Object → YAML and XML → Object → XML (fixtures in `spec/fixtures/`)
51
+ - **Schema validation**: Jing validates generated XML against RelaxNG grammars
52
+ - **HTTP mocking**: VCR cassettes (`spec/vcr_cassettes/`) record external HTTP interactions; WebMock disables real network calls in tests
53
+
54
+ ## Code Conventions
55
+
56
+ - All files use `# frozen_string_literal: true`
57
+ - Linting follows [Ribose OSS style](https://github.com/riboseinc/oss-guides); target Ruby 3.1
58
+ - Ruby >= 3.1.0 required
59
+
60
+ ## Testing
61
+
62
+ - **Index fixture:** `spec/fixtures/index-v2.zip` (the pubid-based `index-v2`) is deserialized via `Pubid::Jis::Identifier` and pre-loaded into the `Relaton::Index` pool in `before(:suite)` (configured in `spec/support/webmock.rb`). No rake task refreshes it: download `index-v2.zip` from the `v2` branch of relaton-data-jis into `spec/jis/fixtures/`.
63
+ - **Lookup path:** `Bibliography.get`/`search` parse the reference with `pubid`. An unrecognized reference raises `Pubid::Errors::ParseError`; do not rescue it to nil. `HitCollection` takes the candidates that share the base series and number from `index-v2` (a supplement is filed under its base number). `Hit#matches?` is `Pubid::Identifier#matches?` with `ignore: %i[year reaffirmed]` (plus `:parts` for all parts), so the base document of a supplement, its parts, and the `SYMBOL` are compared. The reaffirmation mark `R` goes with the year, because `exclude(:year)` keeps it. For a dated reference, `find_by_year` picks the exact printed id first, then the same id without `R`. Two pubid gaps shape this code. `Pubid::Jis::Identifier#==` does not compare the class (`JIS TR X 0014:1999 == JIS X 0014:1999`), so `Hit#matches?` checks `instance_of?`. `SupplementIdentifier#==` ignores `symbol` and `reaffirmed`, so the exact printed id comes first. Before this rule, 301 of the 21,496 published ids resolved to a different record; `hit_collection_spec.rb` holds one example for each shape. The `DataFetcher` writes `index-v2` only. relaton-data-jis rebuilds the legacy string `index-v1` from `data/` in its own crawler, because the released `relaton-jis` gem still reads `index-v1.zip` from the `v2` branch.
64
+ - **pubid dependency:** the gemspec requires `pubid ~> 2.0.0.pre.alpha.3`, the published release carrying the working lutaml-model `from_hash` (the earlier `2.0.0.pre.alpha.2` was broken). Override to a local checkout with `bundle config set local.pubid /path/to/pubid`.
@@ -0,0 +1,167 @@
1
+ = Relaton::Jis: retrieve JIS Standards for bibliographic use using the BibliographicItem model
2
+
3
+ RelatonJis is a Ruby gem that implements the https://github.com/metanorma/metanorma-model-iso#iso-bibliographic-item[IsoBibliographicItem model].
4
+
5
+ You can use it to retrieve metadata of JIS Standards from https://webdesk.jsa.or.jp, and access such metadata through the `Relaton::Jis::ItemData` object.
6
+
7
+ == Usage
8
+
9
+ === Search for standards using keywords
10
+
11
+ [source,ruby]
12
+ ----
13
+ require 'relaton/jis'
14
+ => true
15
+
16
+ hit_collection = Relaton::Jis::Bibliography.search("JIS X 0208")
17
+ => <Relaton::Jis::HitCollection:0x000000000014a0 @ref=JIS X 0208 @fetched=false>
18
+
19
+ hit_collection.first
20
+ => <Relaton::Jis::Hit:0x00000000001a20 @reference="JIS X 0208" @fetched="false" @docidentifier="">
21
+
22
+ item = hit_collection[1].item
23
+ => #<Relaton::Jis::ItemData:0x000000012a880790
24
+ ...
25
+
26
+ item.docidentifier[0].type
27
+ => "JIS"
28
+
29
+ item.docidentifier[0].content
30
+ => "JIS X 0208:1997/AMENDMENT 1:2012"
31
+ ----
32
+
33
+ === Fetch document by reference and year
34
+
35
+ [source,ruby]
36
+ ----
37
+ item = Relaton::Jis::Bibliography.get "JIS X 0208:1997"
38
+ [relaton-jis] INFO: (JIS X 0208:1997) Fetching from webdesk.jsa.or.jp ...
39
+ [relaton-jis] INFO: (JIS X 0208:1997) Found: `JIS X 0208:1997`
40
+ => #<Relaton::Jis::ItemData:0x000000012c0f2440
41
+ ...
42
+
43
+ item = Relaton::Jis::Bibliography.get "JIS X 0208", "1997"
44
+ [relaton-jis] INFO: (JIS X 0208) Fetching from webdesk.jsa.or.jp ...
45
+ [relaton-jis] INFO: (JIS X 0208) Found: `JIS X 0208:1997`
46
+ => #<Relaton::Jis::ItemData:0x000000012c1d7810
47
+ ...
48
+
49
+ item.docidentifier[0].content
50
+ => "JIS X 0208:1997"
51
+ ----
52
+
53
+ === Fetch all parts of a standard
54
+
55
+ [source,ruby]
56
+ ----
57
+ item = Relaton::Jis::Bibliography.get "JIS B 0060 (all parts)"
58
+ [relaton-jis] INFO: (JIS B 0060 (all parts)) Fetching from webdesk.jsa.or.jp ...
59
+ [relaton-jis] INFO: (JIS B 0060 (all parts)) Found: `JIS B 0060 (all parts)`
60
+ => #<Relaton::Jis::ItemData:0x00000001273c8840
61
+ ...
62
+
63
+ item.docidentifier[0].content
64
+ => "JIS B 0060 (all parts)"
65
+
66
+ item = Relaton::Jis::Bibliography.get "JIS B 0060 (規格群)"
67
+ [relaton-jis] INFO: (JIS B 0060 (規格群)) Fetching from webdesk.jsa.or.jp ...
68
+ [relaton-jis] INFO: (JIS B 0060 (規格群)) Found: `JIS B 0060 (all parts)`
69
+ => #<Relaton::Jis::ItemData:0x000000012cb367d0
70
+ ...
71
+
72
+ item.docidentifier[0].content
73
+ => "JIS B 0060 (all parts)"
74
+ ----
75
+
76
+ === XML serialization
77
+
78
+ Possible options:
79
+
80
+ - *bibdata* - If true then wrapp item with _bibdata_ element and add _ext_ element.
81
+
82
+ [source,ruby]
83
+ ----
84
+ item.to_xml
85
+ => "<bibitem id="JISB006012015" type="standard" schema-version="v1.4.1">
86
+ <fetched>2026-02-25</fetched>
87
+ <title language="ja" script="Jpan">デジタル製品技術文書情報―第1部:総則</title>
88
+ <title language="en" script="Latn">Digital technical product documentation (DTPD) -- Part 1: General code of practices</title>
89
+ <uri type="src">https://webdesk.jsa.or.jp/books/W11M0090/index/?bunsyo_id=JIS+B+0060-1%3A2015</uri>
90
+ <docidentifier type="JIS" primary="true">JIS B 0060 (all parts)</docidentifier>
91
+ ...
92
+ </bibitem>"
93
+
94
+ item.to_xml bibdata: true
95
+ => "<bibdata type="standard" schema-version="v1.4.1">
96
+ <fetched>2026-02-25</fetched>
97
+ <title language="ja" script="Jpan">デジタル製品技術文書情報―第1部:総則</title>
98
+ <title language="en" script="Latn">Digital technical product documentation (DTPD) -- Part 1: General code of practices</title>
99
+ <uri type="src">https://webdesk.jsa.or.jp/books/W11M0090/index/?bunsyo_id=JIS+B+0060-1%3A2015</uri>
100
+ <docidentifier type="JIS" primary="true">JIS B 0060 (all parts)</docidentifier>
101
+ ...
102
+ <ext schema-version="v0.0.1">
103
+ <doctype>japanese-industrial-standard</doctype>
104
+ <flavor>jis</flavor>
105
+ <ics>
106
+ <code>01.110</code>
107
+ <text>Technical product documentation</text>
108
+ </ics>
109
+ <structuredidentifier type="JIS">
110
+ <project-number>B0060 (all parts)</project-number>
111
+ </structuredidentifier>
112
+ </ext>
113
+ </bibdata>"
114
+ ----
115
+
116
+ === Typed source links
117
+
118
+ Each JIS document has `src` type source link and optional `pdf`.
119
+
120
+ [source,ruby]
121
+ ----
122
+ item.source[0].type
123
+ => "src"
124
+
125
+ item.source[0].content
126
+ => "https://webdesk.jsa.or.jp/books/W11M0090/index/?bunsyo_id=JIS+B+0060-1%3A2015"
127
+ ----
128
+
129
+ === Fetch data
130
+
131
+ This gem scrapes the https://webdesk.jsa.or.jp/books/W11M0270 pages to fetch the JIS Standards metadata. By default the data is saved in the `./data` folder in YAML format.
132
+
133
+ The method `Relaton::Jis::DataFetcher.fetch(output: "data", format: "yaml")` fetches all the documents from the dataset and saves them to the `./data` folder in YAML format.
134
+ Arguments:
135
+
136
+ - `output` - folder to save documents (default './data').
137
+ - `format` - the format in which the documents are saved. Possible formats are: `yaml`, `xml`, `bibxml` (default `yaml`).
138
+
139
+ [source,ruby]
140
+ ----
141
+ require "relaton/jis/data_fetcher"
142
+
143
+ Relaton::Jis::DataFetcher.fetch
144
+ Started at: 2024-09-27 17:49:40 -0400
145
+ Done in: 3031 sec.
146
+ => nil
147
+ ----
148
+
149
+ === Logging
150
+
151
+ RelatonJis 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.
152
+
153
+ == Development
154
+
155
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
156
+
157
+ To update the index test fixture (used by tests), download the latest `index-v2.zip` from the `v2` branch of the https://github.com/relaton/relaton-data-jis[relaton-data-jis] repository into `spec/jis/fixtures/`.
158
+
159
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
160
+
161
+ == Contributing
162
+
163
+ Bug reports and pull requests are welcome on GitHub at https://github.com/relaton/relaton-jis.
164
+
165
+ == License
166
+
167
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,37 @@
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-logger is the logging infrastructure for the Relaton family. It extends Ruby's stdlib `Logger` with a **logger pool** (named loggers), **per-logger level sets** (fine-grained filtering instead of a single threshold), pluggable formatters (string and JSON), and a GitHub-issue reporting channel for bulk-fetch error summaries. Flavor gems log through it (e.g. `Relaton::Bib::Util` extends it with a `PROGNAME`).
8
+
9
+ ## Development
10
+
11
+ ```bash
12
+ bundle exec rake # default task → rspec
13
+ bundle exec rspec spec/relaton/logger/log_spec.rb # single file
14
+ bundle exec rake rubocop # lint (separate task)
15
+ ```
16
+
17
+ ## Architecture
18
+
19
+ Namespace: `Relaton::Logger`. Key classes in `lib/relaton/logger/`:
20
+
21
+ - **`Log`** (`log.rb`) — subclass of `::Logger`. Replaces the single severity threshold with a `levels` Set (`add_level`/`remove_level`); `Log#add` writes only when the severity is in `levels`. Each call accepts a `progname` and a `key:` keyword used by formatters.
22
+ - **`Pool`** (`pool.rb`) — a container of named loggers (`[:default]`, `[:file]`, …); logging calls fan out to every logger in the pool.
23
+ - **`Config`** (`config.rb`) — `Relaton.configure { |c| ... }` / `Relaton.configuration`; the default `Configuration` seeds a `Pool` with a `:default` stderr logger at levels info/warn/error/fatal.
24
+ - **Formatters** — `FormatterString` emits `[progname] SEVERITY: (key) message`; `FormatterJSON` emits a JSON line merging the call's keyword args.
25
+ - **`Channels::GhIssue`** (`channels/gh_issue.rb`) — accumulates de-duplicated log lines and opens a GitHub issue via the REST API on `close` (needs `GITHUB_TOKEN`; silently skips when unset or empty). Used by `Relaton::Core::DataFetcher` to report bulk-ingest errors.
26
+
27
+ ### Entry point
28
+
29
+ `Relaton.logger_pool` returns the configured pool; `Relaton.logger_pool.info "msg"` broadcasts to all loggers, and `Relaton.logger_pool[:default]` accesses one by name.
30
+
31
+ ## External dependencies
32
+
33
+ `logger ~> 1.6`.
34
+
35
+ ## Testing
36
+
37
+ RSpec with SimpleCov; specs mirror the lib structure under `spec/relaton/logger/`.