relaton 3.0.0.pre.alpha.17 → 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,330 @@
1
+ = Relaton::Bib
2
+
3
+ Relaton::Bib is a Ruby gem that implements the https://github.com/metanorma/relaton-models#bibliography-uml-models[BibliographicItem model].
4
+
5
+ == Usage
6
+
7
+ [source,ruby]
8
+ ----
9
+ require 'relaton/bib'
10
+ => true
11
+ ----
12
+
13
+ === Create bibliographic item
14
+
15
+ [source,ruby]
16
+ ----
17
+ yaml = File.read 'spec/fixtures/item.yaml'
18
+ => "id: ISO1231994\ntype: standard\nschema_version: 1.0.0\nfetched: \"2022-05-02\"\nformattedref: ISO 123:1994\ntitle..."
19
+
20
+ item = Relaton::Bib::Item.from_yaml yaml
21
+ => #<Relaton::Bib::ItemData:0x000000012838bfc0 ...
22
+ ----
23
+
24
+ === Title
25
+
26
+ [source,ruby]
27
+ ----
28
+ item.title
29
+ => [#<Relaton::Bib::Title:0x00000001270a6810
30
+ @content="Geographic information -- Metadata",
31
+ @format=nil,
32
+ @language="en",
33
+ @locale="en-US",
34
+ @script="Latn",
35
+ @type=nil>,
36
+ #<Relaton::Bib::Title:0x00000001270a5cd0
37
+ @content="Information géographique -- Métadonnées",
38
+ @format=nil,
39
+ @language="fr",
40
+ @locale="fr-FR",
41
+ @script="Latn",
42
+ @type=nil>]
43
+
44
+ item.title "fr"
45
+ => [#<Relaton::Bib::Title:0x00000001270a5cd0
46
+ @content="Information géographique -- Métadonnées",
47
+ @format=nil,
48
+ @language="fr",
49
+ @locale="fr-FR",
50
+ @script="Latn",
51
+ @type=nil>]
52
+ ----
53
+
54
+ === Abstract
55
+
56
+ [source,ruby]
57
+ ----
58
+ item.abstract
59
+ => [#<Relaton::Bib::LocalizedMarkedUpString:0x0000000126c05748
60
+ @content="This is an abstract. <em>This is emphasized</em>",
61
+ @language="en",
62
+ @locale="en-US",
63
+ @script="Latn">]
64
+
65
+ item.abstract("en")
66
+ => [#<Relaton::Bib::LocalizedMarkedUpString:0x0000000126c05748
67
+ @content="This is an abstract. <em>This is emphasized</em>",
68
+ @language="en",
69
+ @locale="en-US",
70
+ @script="Latn">]
71
+ ----
72
+
73
+ === Document identifier
74
+
75
+ [source,ruby]
76
+ ----
77
+ item.docidentifier
78
+ => [#<Relaton::Bib::Docidentifier:0x00000001270a4b00
79
+ @content="ISO 123:1994",
80
+ @language="en",
81
+ @locale="en-US",
82
+ @primary=true,
83
+ @scope="global",
84
+ @script="Latn",
85
+ @type="ISO">,
86
+ #<Relaton::Bib::Docidentifier:0x00000001270a46a0
87
+ @content="10.1007/978-3-319-99155-2_1",
88
+ @language=nil,
89
+ @locale=nil,
90
+ @primary=nil,
91
+ @scope=nil,
92
+ @script=nil,
93
+ @type="DOI">]
94
+ ----
95
+
96
+ === XML serialization
97
+
98
+ [source,ruby]
99
+ ----
100
+ item.to_xml
101
+ => "<bibitem id="ISO1231994" type="standard" schema-version="1.0.0">
102
+ <fetched>2022-05-02</fetched>
103
+ <formattedref>ISO 123:1994</formattedref>
104
+ <title language="en" locale="en-US" script="Latn">Geographic information -- Metadata</title>
105
+ <title language="fr" locale="fr-FR" script="Latn">Information géographique -- Métadonnées</title>
106
+ <uri type="src">https://www.iso.org/standard/22722.html</uri>
107
+ <uri type="doi">10.1007/978-3-319-99155-2_1</uri>
108
+ ...
109
+ </bibitem>"
110
+ ----
111
+
112
+ The default root element is `bibitem`. With argument `bibdata: true` the XML wrapped with `bibdata` element.
113
+
114
+ [source,ruby]
115
+ ----
116
+ item.to_xml bibdata: true
117
+ => "<bibdata type="standard" schema-version="1.0.0">
118
+ <fetched>2022-05-02</fetched>
119
+ <formattedref>ISO 123:1994</formattedref>
120
+ <title language="en" locale="en-US" script="Latn">Geographic information -- Metadata</title>
121
+ ...
122
+ <ext schema-version="1.0.0">
123
+ <doctype abbreviation="std">Standard</doctype>
124
+ <subdoctype>Technical Report</subdoctype>
125
+ ...
126
+ </ext>
127
+ </bibdata>"
128
+ ----
129
+
130
+ ==== Adding notes
131
+
132
+ [source,ruby]
133
+ ----
134
+ item.to_xml note: [{ content: "Note", type: "note" }]
135
+ => "<bibitem id="ISO1231994" type="standard" schema-version="1.0.0">
136
+ ...
137
+ <note type="note">Note</note>
138
+ ...
139
+ </bibitem>"
140
+ ----
141
+
142
+ === Create bibliographic item form YAML
143
+
144
+ [source,ruby]
145
+ ----
146
+ yaml = File.read 'spec/fixtures/item.yaml'
147
+ => "id: ISO1231994\ntype: standard\nschema_version: 1.0.0\nfetched: \"2022-05-02\"\nformattedref: ISO 123:1994\ntitle..."
148
+
149
+ Relaton::Bib::Item.from_yaml yaml
150
+ => #<Relaton::Bib::ItemData:0x000000011dc9e118 ...
151
+ ----
152
+
153
+ === Create bibliographic item from RFC XML
154
+
155
+ [source,ruby]
156
+ ----
157
+ xml = File.read 'spec/fixtures/rfc.xml'
158
+ => "<reference anchor=\"RFC1\" target=\"10.17487/RFC0001\">\n <front>\n <title>Title RFC1</title>\n <seriesInf..."
159
+
160
+ Relaton::Bib::Converter::BibXml.to_item xml
161
+ => #<Relaton::Bib::ItemData:0x000000011dc9fc98 ...
162
+ ----
163
+
164
+ === Create bibliographic item from XML
165
+ [source,ruby]
166
+ ----
167
+ xml = File.read 'spec/fixtures/bibitem.xml'
168
+ => "<bibitem id=\"ISO1231994\" type=\"standard\" schema-version=\"1.0.0\">\n <fetched>2022-05-02</fetched>\n <forma..."
169
+
170
+ item = Relaton::Bib::Bibitem.from_xml xml
171
+ => #<Relaton::Bib::ItemData:0x000000011d4b7580 ...
172
+
173
+ xml = File.read 'spec/fixtures/bibdata.xml'
174
+ item = Relaton::Bib::Bibdata.from_xml xml
175
+ => #<Relaton::Bib::ItemData:0x000000011d4daa08 ...
176
+ ----
177
+
178
+ === Create bibliographic item from BibTeX (@TODO: add support for BibTeX)
179
+
180
+ [source,ruby]
181
+ ----
182
+ Relaton::Bib::BibtexParser.from_bibtex File.read('spec/fixtures/techreport.bib')
183
+ => {"ISOTC211"=>
184
+ #<Relaton::Bib::Item:0x007fedee0a2ab0
185
+ ...
186
+ ----
187
+
188
+ === Export bibliographic item to YAML
189
+
190
+ [source,ruby]
191
+ ----
192
+ item.to_yaml
193
+ ---
194
+ type: standard
195
+ schema_version: 1.0.0
196
+ fetched: '2022-05-02'
197
+ formattedref: ISO 123:1994
198
+ ...
199
+ ----
200
+
201
+ === Export bibliographic item to Hash
202
+
203
+ [source,ruby]
204
+ ----
205
+ item.to_h
206
+ => {"id"=>"ISO1231994",
207
+ "type"=>"standard",
208
+ "schema_version"=>"...",
209
+ "title"=>[...],
210
+ ...}
211
+ ----
212
+
213
+ === Export bibliographic item to BibTeX
214
+
215
+ [source,ruby]
216
+ ----
217
+ item.to_bibtex
218
+ @misc{doe1994a,
219
+ title = {Geographic information -- Metadata},
220
+ author = {Doe, John},
221
+ edition = {First edition},
222
+ publisher = {International Organization for Standardization},
223
+ year = {1994},
224
+ month = {jan},
225
+ address = {Geneva, Switzerland, Geneva, Geneva},
226
+ pages = {1--10},
227
+ keywords = {information},
228
+ timestamp = {2022-05-02},
229
+ url = {https://www.iso.org/standard/22722.html},
230
+ doi = {10.1007/978-3-319-99155-2_1},
231
+ month_numeric = {1}
232
+ }
233
+ ----
234
+
235
+ === Export bibliographic item to Citeproc (@TODO: add support for Citeproc)
236
+
237
+ [source,ruby]
238
+ ----
239
+ item.to_citeproc
240
+ => [{"title"=>"Geographic information",
241
+ "edition"=>"Edition 1",
242
+ "author"=>[{"family"=>"Bierman", "given"=>"A."}, {"family"=>"Bierman", "given"=>"Arnold"}, {"family"=>"Bierman", "given"=>"Arnold B"}],
243
+ "publisher"=>"Institute of Electrical and Electronics Engineers",
244
+ "publisher-place"=>"bib place",
245
+ ...
246
+ ----
247
+
248
+ === Exporting bibliographic item to AsciiBib (@TODO: add support for AsciiBib)
249
+
250
+ [source,ruby]
251
+ ----
252
+ item.to_asciibib
253
+ => [%bibitem]
254
+ == {blank}
255
+ id:: ISOTC211
256
+ fetched:: 2022-05-02
257
+ title::
258
+ title.type:: title-main
259
+ title.content:: Geographic information
260
+ title.format:: text/plain
261
+ ...
262
+ ----
263
+
264
+ === Export bibliographic item to RFC XML
265
+
266
+ [source,ruby]
267
+ ----
268
+ item.to_rfcxml
269
+ <reference anchor="ISO 123:1994" target="https://www.iso.org/standard/22722.html">
270
+ <front>
271
+ <title>Geographic information -- Metadata</title>
272
+ <seriesInfo name="DOI" value="10.1007/978-3-319-99155-2_1"/>
273
+ <seriesInfo name="ISO 123" value="1"/>
274
+ <author initials="J.D." surname="Doe" fullname="Prof. John Doe PhD">
275
+ <organization>International Organization for Standardization</organization>
276
+ <address>
277
+ <postal>
278
+ <street>1, rue de Varembé</street>
279
+ <city>Geneva</city>
280
+ <code>1211</code>
281
+ <country>Switzerland</country>
282
+ <postalLine>1, rue de Varembé,&lt;br/&gt;Geneva, Switzerland, 1211</postalLine>
283
+ </postal>
284
+ <phone>+41 22 749 01 11</phone>
285
+ <email>jdoe@email.org</email>
286
+ <uri>https://orcid.org/0000-0002-1825-0097</uri>
287
+ </address>
288
+ </author>
289
+ <author>
290
+ <organization abbrev="ISO">International Organization for Standardization</organization>
291
+ <address>
292
+ <postal>
293
+ <street>1, rue de Varembé</street>
294
+ <city>Geneva</city>
295
+ <code>1211</code>
296
+ <country>Switzerland</country>
297
+ <postalLine>1, rue de Varembé,&lt;br/&gt;Geneva, Switzerland, 1211</postalLine>
298
+ </postal>
299
+ <phone>+41 22 749 01 11</phone>
300
+ <email>office@iso.org</email>
301
+ <uri>https://www.iso.org</uri>
302
+ </address>
303
+ </author>
304
+ <date day="01" month="January" year="1994"></date>
305
+ <workgroup>Geographic information</workgroup>
306
+ <keyword>information</keyword>
307
+ <abstract>
308
+ <t>This is an abstract. &lt;em&gt;This is emphasized&lt;/em&gt;</t>
309
+ </abstract>
310
+ </front>
311
+ </reference>
312
+ ----
313
+
314
+ === Logging
315
+
316
+ RelatonBib 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.
317
+
318
+ == Development
319
+
320
+ 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.
321
+
322
+ 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).
323
+
324
+ == Contributing
325
+
326
+ Bug reports and pull requests are welcome on GitHub at https://github.com/metanorma/relaton-bib.
327
+
328
+ == License
329
+
330
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -3,7 +3,7 @@ require_relative "type/string_date"
3
3
  module Relaton
4
4
  module Bib
5
5
  class Series < Lutaml::Model::Serializable
6
- attribute :type, :string, values: %w[main alt]
6
+ attribute :type, :string, values: %w[main alt stream]
7
7
  attribute :formattedref, Formattedref
8
8
  attribute :title, Title, collection: (1..)
9
9
  attribute :place, Place
@@ -0,0 +1,173 @@
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-bipm is a Ruby gem that retrieves BIPM (Bureau International des Poids et Mesures) standards metadata for bibliographic use. It's part of the larger Relaton family of gems that handle bibliographic data for standards organizations.
8
+
9
+ ## Common Commands
10
+
11
+ - **Install dependencies:** `bundle install`
12
+ - **Run all tests:** `bundle exec rake spec`
13
+ - **Run a single test file:** `bundle exec rspec spec/relaton/bipm/bibliography_spec.rb`
14
+ - **Run a single test by line:** `bundle exec rspec spec/relaton/bipm/bibliography_spec.rb:42`
15
+ - **Interactive console:** `bin/console`
16
+
17
+ ## Architecture
18
+
19
+ ### Namespace & Module Structure
20
+
21
+ All code lives under `Relaton::Bipm` (in `lib/relaton/bipm/`). The gem name is `relaton-bipm`, the require path is `relaton/bipm`.
22
+
23
+ ### Pubid-backed `index-v2` (the runtime index)
24
+
25
+ The flavor's runtime index is the **pubid-backed `index-v2`** (`INDEXFILE =
26
+ "index-v2"`), whose rows are `Pubid::Bipm` identifiers serialized as
27
+ `_type: pubid:bipm:{committee-document,meeting,metrologia-article,si-brochure}`
28
+ — mirroring the JCGM/OIML/JIS convention, not BIPM's old bespoke
29
+ `{group,type,number,year}` hash. The `DataFetcher` builds it (`pubid_class:
30
+ ::Pubid::Bipm::Identifier`), and the consumer reads it.
31
+
32
+ The **legacy bespoke `index-v1`** (the old `{group,type,number,year}` hash form)
33
+ is no longer produced or read by this flavor. It is still published by
34
+ `relaton-data-bipm`'s own `crawler.rb`, which builds it with the **retained**
35
+ `Relaton::Bipm::Id` (this flavor keeps `Id` public for exactly that). So `Id` is
36
+ now used in **one place only** — the crawler's `index-v1` generation. It was
37
+ also this flavor's consumer query parser until pubid's grammar widened enough to
38
+ replace it; see **Pubid-to-pubid lookup** below.
39
+
40
+ ### Key Components
41
+
42
+ - **`Bibliography`** (`bibliography.rb`) - Main entry point. Parses the user
43
+ reference with `::Pubid::Bipm.parse` (`#parse_ref`; an unparseable ref raises
44
+ `Pubid::Errors::ParseError`, while the machine-derived `#year_number_retry`
45
+ probe rescues it to nil) and matches the pubid `index-v2` rows as
46
+ pubid objects — see **Pubid-to-pubid lookup** below for the stem and the two
47
+ escapes under it. The latest edition wins via
48
+ `max_by { |r| [r[:id].year.to_i, r[:file]] }` (the file path only breaks a
49
+ tie — Metrologia and SI Brochure rows carry no year, so all 6206 of them
50
+ score 0 and the index sort is not stable).
51
+ - **`Id`** (`id_parser.rb`) - The flexible bespoke regex parser. Parses BIPM
52
+ reference strings into `{group,type,number,year,…}` hashes; the `TYPES` hash
53
+ maps full EN/FR type names to abbreviations, and `normalize_hash` applies
54
+ `CCDS→CCTF` and leading-zero stripping. **Retained solely** as the
55
+ `relaton-data-bipm` crawler's `index-v1` builder — it no longer parses
56
+ queries, and it is **not** used to write this flavor's `index-v2`.
57
+ `bibliography.rb` does not require it; `lib/relaton/bipm.rb` does, which is
58
+ what keeps `Relaton::Bipm::Id` reachable for the crawler. JCGM is not handled
59
+ here.
60
+ - **`Processor`** (`processor.rb`) - Relaton framework integration point (extends
61
+ `Relaton::Core::Processor`). Registers prefix `BIPM` and default prefix pattern
62
+ matching BIPM, CCTF, CCDS, CGPM, CIPM, JCRB (JCGM was split out into the `jcgm`
63
+ flavor). `remove_index_file` targets `index-v2`.
64
+ - **`DataFetcher`** (`data_fetcher.rb`) - Bulk fetches from three data sources:
65
+ `bipm-data-outcomes`, `bipm-si-brochure`, `rawdata-bipm-metrologia`. Delegates
66
+ to specialized parsers, which route every index write through the public,
67
+ **guarded** `#add_to_index(docnumber, path)` — it parses `docnumber` with
68
+ `::Pubid::Bipm.parse` and stores the identifier object, or **warns and skips**
69
+ an unparseable id rather than aborting the crawl (mirrors
70
+ `Relaton::Jcgm::DataFetcher#add_to_index`; `Relaton::Index` rejects a whole
71
+ index if one row fails to deserialize). Public so `relaton-data-bipm`'s crawler
72
+ can index its curated `static/` docs through the same guarded path.
73
+ - **`Item`** / **`ItemData`** (`model/item.rb`, `item_data.rb`) - The
74
+ bibliographic item model, extending `Relaton::Bib::Item`. Supports XML, YAML,
75
+ and JSON serialization.
76
+ - **`model/`** directory - Lutaml model classes (Bibdata, Bibitem, Ext, etc.) for
77
+ XML/YAML serialization.
78
+
79
+ ### Pubid-to-pubid lookup
80
+
81
+ `#get_bipm` parses the reference with `::Pubid::Bipm.parse` and matches the
82
+ index rows as pubid objects — the same shape ISO, OIML and JCGM use. The
83
+ bespoke `Id` grammar takes **no part in a query**. That became possible with
84
+ pubid `a96e9f45`, which accepts the loose consumer forms this flavor once
85
+ needed `Id` for and *normalizes* them to BIPM's canonical spelling
86
+ (`CCDS Recommendation 2 (2009)` → `CCTF Recommendation 2 (2009)`,
87
+ `CIPM 111e Réunion (2022)` → `CIPM 111<sup>e</sup> réunion (2022)`).
88
+
89
+ **The stem.** Committee-document and meeting rows are stored language- and
90
+ form-neutral, while a reference may name a language (`(2009, E)`) and always
91
+ names a form (short `CCTF REC 2` vs long `CCTF Recommendation 2`). So
92
+ `#pubid_match?` compares `exclude(:language, :form)`, adding `:year` when the
93
+ **query** carries none — `CIPM Meeting 43` has no year, its row has 1950. That
94
+ last clause is what `Id#==` did with
95
+ `other_hash.delete(:year) unless hash[:year]`; without it the lookup regresses.
96
+
97
+ **Two escapes sit under the narrowing**, each for a case where the query's
98
+ bsearch key cannot equal its row's:
99
+
100
+ 1. **A bare `SI Brochure` names no edition**, so it keys to `""` while its row
101
+ keys to `"9e"`. `#search_index` rescans the whole index. A brochure query
102
+ with a nil edition is a *partial* reference and deliberately matches any
103
+ brochure row — what the old `{group: "SI", type: "Brochure"}` projection
104
+ meant. `Part N` names a section inside the brochure, not a document, so it
105
+ stays out of the key exactly as `Id#==` kept `:part` out.
106
+ 2. **`CCTF Recommendation 2009-02` parses as the literal number `2009-02`**,
107
+ while the row keys on `2`. A rescan cannot help — no row carries that number
108
+ — so `#year_number_retry` re-reads a trailing `YYYY-NN` as number plus year.
109
+ It runs **only after a miss**, because `NNNN-NN` is also a real BIPM number
110
+ (`CIPM 2005-06`), so the literal reading must win.
111
+
112
+ **One rule survives from `Id#==` and must not be dropped.** It treated a
113
+ document numbered `"1"` and a number-less one as the same document when both
114
+ carried a year, so `CIPM Resolution 1 (1879)` reached `CIPM RES (1879)`. pubid
115
+ has no such rule, and the six ordinal-less declarations
116
+ (`CGPM DECL (1889)`, `CIPM RES (1879)`, …) are the only rows it applies to — but
117
+ they are addressable *both* ways, so removing it silently broke
118
+ `CIPM Resolution 1 (1879)` and `CGPM Declaration 1 (1889)`. `#number_collapses?`
119
+ restores it by excluding `:number` from that one comparison. Both forms are in
120
+ the pinned baseline. Note the corpus has **no two rows** the rule could join
121
+ (6 number-less against 83 numbered `"1"`, no shared group/type/year), so it only
122
+ ever widens a query, never merges records.
123
+
124
+ **Cost.** `#exclude` copies the identifier, so reducing per candidate row is
125
+ expensive — roughly **165x** a plain attribute read. Two things keep the lookup
126
+ at or below what the `Id` grammar cost: the query is reduced **once per search**,
127
+ not once per row, and `#pubid_match?` rejects on `CHEAP_KEYS`
128
+ (`number group year issue article`) before reducing anything. Those are exactly
129
+ the attributes the stem never removes, so stem equality implies all of them and
130
+ the rejects cannot change an answer — a spec asserts that over the corpus rather
131
+ than trusting the argument. Without both, a bare-brochure rescan built ~7,900
132
+ copies and took **2.3 s**; with them the same lookup is 2.8 ms and a narrowed
133
+ one 0.4–0.5 ms, against 0.5–0.7 ms under `Id`.
134
+
135
+ **The regression guard.** `spec/bipm/relaton/bipm/bibliography_spec.rb` pins,
136
+ literally, the file each of the 29 references the suite exercises resolved to
137
+ under the `Id` grammar, captured before it was removed. Any change to matching
138
+ that moves a lookup fails there by name. That is the evidence for the swap —
139
+ `Id#==` was fuzzier than the stem match in ways no spec pinned (it collapsed
140
+ number `"1"` with nil, dropped `:part`/`:append`), so equivalence had to be
141
+ demonstrated rather than argued.
142
+
143
+ `Relaton::Bipm::Id` and `id_parser.rb` **stay** — `relaton-data-bipm`'s crawler
144
+ builds `index-v1` with them, and `id_parser_spec.rb` still covers them. Only
145
+ `bibliography.rb` stopped requiring the file.
146
+
147
+ ### Data Sources
148
+
149
+ The gem fetches from three external datasets:
150
+
151
+ 1. **bipm-data-outcomes** - CGPM/CIPM/committee resolutions, recommendations, decisions (the `jcgm` meeting dir is now harvested by the `Relaton::Jcgm::DataFetcher` instead)
152
+ 2. **bipm-si-brochure** - SI Brochure documents
153
+ 3. **rawdata-bipm-metrologia** - Metrologia journal articles (parsed from CrossRef-style data)
154
+
155
+ ### Testing
156
+
157
+ - **Index fixture:** `spec/bipm/fixtures/index-v2.zip` (the pubid `index-v2`) is
158
+ deserialized via `Pubid::Bipm::Identifier` and pre-loaded into the
159
+ `Relaton::Index` pool in `before(:suite)` (`spec/bipm/support/webmock.rb`,
160
+ mirroring the JCGM/JIS setup). It was regenerated from the real
161
+ `relaton-data-bipm` docs' docnumbers (each parsed with `Pubid::Bipm`); the
162
+ handful that pubid can't parse — JCGM orphans, `CIPM 2005-06`, docs removed
163
+ upstream — are absent by design.
164
+ - **Parser specs** assert the parsers call `data_fetcher.add_to_index(docnumber,
165
+ path)` with the right docnumber string (the pubid parsing/guarding lives on the
166
+ mocked `DataFetcher`, keeping the parser tests format-agnostic).
167
+ - Tests use RSpec with VCR cassettes (`spec/bipm/vcr_cassettes/`) and WebMock.
168
+
169
+ ### Dependencies
170
+
171
+ Key runtime dependencies: `pubid` (provides `Pubid::Bipm`), `relaton-bib` (core
172
+ bibliographic model), `relaton-index` (index management), `relaton-core`
173
+ (framework base), `parslet`, `mechanize` (HTTP), `faraday`, `rubyzip`.