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,280 @@
1
+ = Relaton::Iec: retrieve IEC Standards for bibliographic use using the BibliographicItem model
2
+
3
+ Relaton:Iec 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 IEC Standards from https://www.iec.ch, and access such metadata through the `Relaton::Iec::ItemData` object.
6
+
7
+ == Usage
8
+
9
+ === Search for a standard using keywords
10
+
11
+ `Relaton::Iec::Bibliography.search(ref, year)` method returns hits collection. Each hit can be used to fetch a document.
12
+
13
+ - `ref` - a reference to search document
14
+ - `year` - filter by year (optional)
15
+
16
+ [source,ruby]
17
+ ----
18
+ require 'relaton/iec'
19
+ => true
20
+
21
+ hit_collection = Relaton::Iec::Bibliography.search("IEC 60050")
22
+ => <Relaton::Iec::HitCollection:0x00000000005650 @ref=IEC 60050 @fetched=false>
23
+
24
+ hit_collection.first
25
+ => <Relaton::Iec::Hit:0x00000000006260 @reference="IEC 60050" @fetched="false" @docidentifier="IEC 60050-05:1935">
26
+
27
+ item = hit_collection[2].item
28
+ => #<Relaton::Iec::ItemData:0x000000012cbc72a8
29
+ ...
30
+
31
+ item.docidentifier[0].type
32
+ => "IEC"
33
+
34
+ item.docidentifier[0].primary
35
+ => true
36
+
37
+ item.docidentifier[0].content
38
+ => "IEC 60050-07:1956"
39
+
40
+ item.docidentifier[1].type
41
+ => "URN"
42
+
43
+ item.docidentifier[1].content
44
+ => "urn:iec:std:iec:60050-07:1956-01:::"
45
+ ----
46
+
47
+ === Fetch document by keywords
48
+
49
+ `Relaton::Iec::Bibliography.get(ref, year, opts)` method returns the document.
50
+
51
+ - `ref` - a reference to search document
52
+ - `year` - filter by year (optional)
53
+ - `opts` - hash of options (optional). Supported options are `:all_parts` (boolean), `:keep_year` (boolean).
54
+
55
+ [source,ruby]
56
+ ----
57
+ item = Relaton::Iec::Bibliography.get("IEC 60050-112:2010")
58
+ [relaton-iec] INFO: (IEC 60050-112:2010) Fetching from Relaton repsitory ...
59
+ [relaton-iec] INFO: (IEC 60050-112:2010) Found: `IEC 60050-112:2010`
60
+ => #<Relaton::Iec::ItemData:0x000000012e5c6410
61
+ ...
62
+
63
+ item = Relaton::Iec::Bibliography.get("IEC 60050-112", "2010", all_parts: true)
64
+ [relaton-iec] INFO: (IEC 60050-112:2010) Fetching from Relaton repsitory ...
65
+ [relaton-iec] INFO: (IEC 60050-112:2010) Found: `IEC 60050 (all parts)`
66
+ => #<Relaton::Iec::ItemData:0x000000012e1ebb88
67
+ ...
68
+
69
+ item.docidentifier.first.content
70
+ => "IEC 60050 (all parts)"
71
+
72
+ item = Relaton::Iec::Bibliography.get("IEC 60050-112", "2010")
73
+ [relaton-iec] INFO: (IEC 60050-112:2010) Fetching from Relaton repsitory ...
74
+ [relaton-iec] INFO: (IEC 60050-112:2010) Found: `IEC 60050-112:2010`
75
+ => #<Relaton::Iec::ItemData:0x000000012f0c6b80
76
+
77
+ item.docidentifier.first.content
78
+ => "IEC 60050-112:2010"
79
+ ----
80
+
81
+ === Search for ISO/IEC Directives
82
+
83
+ The following references are allowed to fetch:
84
+
85
+ - `IEC 61360-4 DB` - IEC/SC 3D - Common Data Dictionary (CDD - V2.0015.0001)
86
+ - `ISO/IEC DIR 1 IEC SUP` - Procedures for the technical work - Procedures specific to IEC
87
+ - `ISO/IEC DIR 2 IEC` - Principles and rules for the structure and drafting of ISO and IEC documents
88
+ - 'ISO/IEC DIR IEC SUP' - Procedures specific to IEC
89
+
90
+ === XML serialization
91
+
92
+ Possible options:
93
+
94
+ - *bibdata* - If true then wrap item with _bibdata_ element and add _ext_ element.
95
+ - *note* - Array of hashes `{ text: "Note", type: "note" }`. These notes will be added to XML.
96
+
97
+ [source,ruby]
98
+ ----
99
+ item.to_xml
100
+ => "<bibitem id="IEC600501122010" type="standard" schema-version="v1.5.6">
101
+ <fetched>2026-02-02</fetched>
102
+ <title language="en" script="Latn" type="title-main">International Electrotechnical Vocabulary (IEV)</title>
103
+ <title language="en" script="Latn" type="title-part">Part 112: Quantities and units</title>
104
+ <title language="en" script="Latn" type="main">International Electrotechnical Vocabulary (IEV) - Part 112: Quantities and units</title>
105
+ <title language="fr" script="Latn" type="title-main">Vocabulaire Electrotechnique International (IEV)</title>
106
+ <title language="fr" script="Latn" type="title-part">Partie 112: Grandeurs et unités</title>
107
+ <title language="fr" script="Latn" type="main">Vocabulaire Electrotechnique International (IEV) - Partie 112: Grandeurs et unités</title>
108
+ <title language="es" script="Latn" type="title-intro">Versión Oficial En español</title>
109
+ <title language="es" script="Latn" type="title-main">Vocabulario Electrotécnico Internacional. Parte 112: Magnitudes y unidades.</title>
110
+ <title language="es" script="Latn" type="main">Versión Oficial En español - Vocabulario Electrotécnico Internacional. Parte 112: Magnitudes y unidades.</title>
111
+ <uri type="src">https://webstore.iec.ch/publication/162</uri>
112
+ <uri type="obp">https://webstore.iec.ch/preview/info_iec60050-112{ed1.0}b.pdf</uri>
113
+ <docidentifier type="IEC" primary="true">IEC 60050-112:2010</docidentifier>
114
+ <docidentifier type="URN">urn:iec:std:iec:60050-112:2010-01:::</docidentifier>
115
+ ...
116
+ </bibitem>"
117
+
118
+ item.to_xml bibdata: true
119
+ => "<bibdata type="standard" schema-version="v1.5.6">
120
+ <fetched>2026-02-02</fetched>
121
+ <title language="en" script="Latn" type="title-main">International Electrotechnical Vocabulary (IEV)</title>
122
+ <title language="en" script="Latn" type="title-part">Part 112: Quantities and units</title>
123
+ <title language="en" script="Latn" type="main">International Electrotechnical Vocabulary (IEV) - Part 112: Quantities and units</title>
124
+ <title language="fr" script="Latn" type="title-main">Vocabulaire Electrotechnique International (IEV)</title>
125
+ <title language="fr" script="Latn" type="title-part">Partie 112: Grandeurs et unités</title>
126
+ <title language="fr" script="Latn" type="main">Vocabulaire Electrotechnique International (IEV) - Partie 112: Grandeurs et unités</title>
127
+ <title language="es" script="Latn" type="title-intro">Versión Oficial En español</title>
128
+ <title language="es" script="Latn" type="title-main">Vocabulario Electrotécnico Internacional. Parte 112: Magnitudes y unidades.</title>
129
+ <title language="es" script="Latn" type="main">Versión Oficial En español - Vocabulario Electrotécnico Internacional. Parte 112: Magnitudes y unidades.</title>
130
+ <uri type="src">https://webstore.iec.ch/publication/162</uri>
131
+ <uri type="obp">https://webstore.iec.ch/preview/info_iec60050-112{ed1.0}b.pdf</uri>
132
+ <docidentifier type="IEC" primary="true">IEC 60050-112:2010</docidentifier>
133
+ <docidentifier type="URN">urn:iec:std:iec:60050-112:2010-01:::</docidentifier>
134
+ ...
135
+ <ext schema-version="v1.1.2">
136
+ <doctype>international-standard</doctype>
137
+ ...
138
+ </ext>
139
+ </bibdata>"
140
+
141
+ item.to_xml note: [{ content: "Note", type: "note" }]
142
+ => "<bibitem id="IEC600501122010" type="standard" schema-version="v1.5.6">
143
+ ...
144
+ <note type="note">Note</note>
145
+ ...
146
+ </bibitem>"
147
+ ----
148
+
149
+ === Typed source links
150
+
151
+ Each IEC document has `src` type link source and optional `obp` type link source.
152
+
153
+ [source,ruby]
154
+ ----
155
+ item.source[0].type
156
+ => "src"
157
+
158
+ item.source[0].content
159
+ => "https://webstore.iec.ch/publication/162"
160
+
161
+ item.source[1].type
162
+ => "obp"
163
+
164
+ item.source[1].content
165
+ => "https://webstore.iec.ch/preview/info_iec60050-112{ed1.0}b.pdf"
166
+ ----
167
+
168
+ === Create bibliographic item from XML or YAML
169
+
170
+ [source,ruby]
171
+ ----
172
+ Relaton::Iec::Item.from_xml File.read("spec/fixtures/bibitem.xml")
173
+ => #<Relaton::Iec::ItemData:0x000000012e5c9d90
174
+ ...
175
+
176
+ Relaton::Iec::Item.from_yaml File.read("spec/fixtures/item.yaml")
177
+ => #<Relaton::Iec::ItemData:0x000000012f282460
178
+ ...
179
+ ----
180
+
181
+ === Converting reference to URN
182
+
183
+ URN is a document identifier format. It has fields delimited by a colon. If any field is absent then its place is empty. All values are in lower-case.
184
+
185
+ URN structure: +
186
+ `urn:sdo_namespace:content_type_namespace:header:project_number:date:type:deliverable:language:relation:adjunct_type:adjunct_number:date[#/=]component_or_related_asset`
187
+
188
+ * prefix
189
+ - `urn` - value: urn
190
+ - `sdo_namespace` - value: iec
191
+ - `content_type_namespace` - value: std
192
+ * base document information
193
+ - `header` - possible values are: iec, iso, iec-iso, iec-ieee, iec-itu, iec-astm
194
+ - `project_number` - number and partnumber. For example 67654, 60601-1, 61076-7-101
195
+ - `date` - document date (optional). Examples: 2010-03, 2010, 2010-10-11 etc.
196
+ - `type` - documant type (optional). Possible values: ts, tr, pas, guide, is, ser.
197
+ - `deliverable` - (optional) possible values: prv, csv, exv, rlv, cmv
198
+ - `language` - (optional) examples: en, fr, ru, en-fr, en-fr-ru etc.
199
+ * adjunct document information (optional)
200
+ - `relation` - "plus" for consolidations of ajancts with a base document or "/" for ajancts itself
201
+ - `adjunct_type` - possible values: amd, cor, ish
202
+ - `adjunct_number` - adjunct number. Examples: 1, 2, 3, etc.
203
+ - `date` - adjanct date. Example: 2009
204
+ * component or related asset information (optional)
205
+ - `component_or_related_asset` - # or = followed by component id or related asset. Exammples: #fig-1, #sec-1, =forum
206
+
207
+ For more information see https://github.com/relaton/relaton-iec/issues/22
208
+
209
+ The method `Relaton::Iec.code_to_urn(code, lang)` converts document identifier to URN.
210
+
211
+ * `code` is a document identifier
212
+ * `lang` is a laguage code (optional). Examples: en, fr, en-fr etc.
213
+
214
+ [source,ruby]
215
+ ----
216
+ Relaton::Iec.code_to_urn "IEC 60050-102:2007/AMD1:2017"
217
+ => "urn:iec:std:iec:60050-102:2007:::::amd:1:2017"
218
+
219
+ Relaton::Iec.code_to_urn "IEC 60034-1:1969+AMD1:1977+AMD2:1979+AMD3:1980 CSV", "en-fr"
220
+ => "urn:iec:std:iec:60034-1:1969::csv:en-fr:plus:amd:1:1977:plus:amd:2:1979:plus:amd:3:1980"
221
+ ----
222
+
223
+ The method `Relaton::Iec.urn_to_code(urn)` converts URN to document identifier.
224
+
225
+ [source,ruby]
226
+ ----
227
+ Relaton::Iec.urn_to_code "urn:iec:std:iec:60050-102:2007:::::amd:1:2017"
228
+ => ["IEC 60050-102:2007/AMD1:2017", ""]
229
+
230
+ Relaton::Iec.urn_to_code "urn:iec:std:iec:60034-1:1969::csv:en-fr:plus:amd:1:1977:plus:amd:2:1979:plus:amd:3:1980"
231
+ => ["IEC 60034-1:1969+AMD1:1977+AMD2:1979+AMD3:1980 CSV", "en-fr"]
232
+ ----
233
+
234
+ === Fetch data
235
+
236
+ This gem uses the https://bitbucket.org/sdo-hapi/api-specifications/wiki/Guidelines[Harmonized API] as a data source. The following options are available:
237
+ - `iec-harmonized-all` - fetches all the documents using the API
238
+ - `iec-harmonized-latest` - fetches the latest documents using the API
239
+
240
+ The method `Relaton::Iec::DataFetcher.fetch(source, output: "data", format: "yaml") fetches IEC documents from the dataset and saves them to the `./data` folder in YAML format.
241
+ Arguments:
242
+
243
+ - `source` - data source. Possible values: `iec-harmonized-all`, `iec-harmonized-latest` (default `iec-harmonized-latest`).
244
+ - `output` - folder to save documents (default './data').
245
+ - `format` - the format in which the documents are saved. Possible formats are: `yaml`, `xml`, `bibxxml` (default `yaml`).
246
+
247
+ [source,ruby]
248
+ ----
249
+ Relaton::Iec::DataFetcher.fetch
250
+ Started at: 2022-06-23 09:36:55 +0200
251
+ Stopped at: 2022-06-23 09:36:58 +0200
252
+ Done in: 752 sec.
253
+ => nil
254
+ ----
255
+
256
+ === Logging
257
+
258
+ Relaton::Iec 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.
259
+
260
+ == Development
261
+
262
+ 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.
263
+
264
+ 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-iec[relaton-data-iec] repository.
265
+
266
+ 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).
267
+
268
+ == Exceptional Citations
269
+
270
+ This gem retrieves bibliographic descriptions of ISO documents by doing searches on the ISO website, http://www.iso.org, and screenscraping the document that matches the queried document identifier. The following documents are not returned as search results from the ISO website, and the gem returns manually generated references to them.
271
+
272
+ * `IEV`: used in the metanorma-iso gem to reference Electropedia entries generically. Is resolved to an "all parts" reference to IEC 60050, which in turn is resolved into the specific documents cited by their top-level clause.
273
+
274
+ == Contributing
275
+
276
+ Bug reports and pull requests are welcome on GitHub at https://github.com/metanorma/relaton-iec.
277
+
278
+ == License
279
+
280
+ The gem is available as open source under the terms of the https://opensource.org/licenses/MIT[MIT License].
@@ -19,9 +19,10 @@ module Relaton
19
19
  def fetch(source = "iec-harmonised-latest") # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
20
20
  @all = source == "iec-harmonised-all"
21
21
 
22
- if @all
23
- FileUtils.rm_rf @output
24
- end
22
+ # A prune run keeps the tree and lets prune_unwritten remove stale
23
+ # files behind the 90% guard; the wipe is only the no-prune legacy
24
+ # path (a partial prune run must never wipe the dataset).
25
+ FileUtils.rm_rf @output if @all && !@prune
25
26
  FileUtils.mkdir_p @output
26
27
  rebuild_index
27
28
  fetch_all
@@ -35,7 +36,22 @@ module Relaton
35
36
  def last_change
36
37
  return @last_change if defined? @last_change
37
38
 
38
- @last_change = File.read(LAST_CHANGE_FILE, encoding: "UTF-8") if File.exist? LAST_CHANGE_FILE
39
+ @last_change = File.read(last_change_file, encoding: "UTF-8") if File.exist? last_change_file
40
+ end
41
+
42
+ # Overridable source knobs: the projects API shares the OAuth app,
43
+ # pagination and change cursor with publications but has its own
44
+ # endpoint, list key and cursor file.
45
+ def entrypoint
46
+ ENTRYPOINT
47
+ end
48
+
49
+ def last_change_file
50
+ LAST_CHANGE_FILE
51
+ end
52
+
53
+ def list_key
54
+ "publication"
39
55
  end
40
56
 
41
57
  def last_change_max
@@ -49,7 +65,7 @@ module Relaton
49
65
  def save_last_change
50
66
  return if last_change_max.empty?
51
67
 
52
- File.write LAST_CHANGE_FILE, last_change_max, encoding: "UTF-8"
68
+ File.write last_change_file, last_change_max, encoding: "UTF-8"
53
69
  end
54
70
 
55
71
  def index
@@ -120,7 +136,7 @@ module Relaton
120
136
  break
121
137
  end
122
138
  json = JSON.parse res.body
123
- json["publication"].each { |pub| fetch_pub pub }
139
+ json[list_key].each { |pub| fetch_pub pub }
124
140
  page += 1
125
141
  next_page = res["link"]&.include? "rel=\"last\""
126
142
  end
@@ -150,7 +166,7 @@ module Relaton
150
166
  # @return [Net::HTTP::Response] response
151
167
  #
152
168
  def fetch_page(page)
153
- url = "#{ENTRYPOINT}#{page}"
169
+ url = "#{entrypoint}#{page}"
154
170
  if !@all && last_change
155
171
  url += "&lastChangeTimestampFrom=#{last_change}"
156
172
  end
@@ -202,7 +218,7 @@ module Relaton
202
218
  end
203
219
  ts = pub["lastChangeTimestamp"]
204
220
  @last_change_max = ts if ts && last_change_max < ts
205
- File.write file, serialize(bib), encoding: "UTF-8"
221
+ force_write file, serialize(bib)
206
222
  end
207
223
 
208
224
  def parse_pubid(content)
@@ -0,0 +1,48 @@
1
+ module Relaton
2
+ module Iec
3
+ # Fetches in-development projects from the IEC Harmonized API
4
+ # (/harmonized/projects). The projects endpoint shares the OAuth app,
5
+ # pagination and lastChangeTimestampFrom cursor with publications —
6
+ # the credential's PROJ_PUBS name covers both — but carries the stage
7
+ # lifecycle and project relations inline, so there is no webstore
8
+ # round-trip.
9
+ class ProjectFetcher < DataFetcher
10
+ PROJECT_ENTRYPOINT = "https://api.iec.ch/harmonized/projects?size=100&sortBy=urn&page=".freeze
11
+ PROJECT_LAST_CHANGE_FILE = "last_change_projects.txt".freeze
12
+
13
+ def fetch(source = "iec-projects-latest")
14
+ @all = source.end_with?("-all")
15
+ # The wipe is the no-prune legacy path (see DataFetcher#fetch).
16
+ FileUtils.rm_rf @output if @all && !@prune
17
+ FileUtils.mkdir_p @output
18
+ fetch_all
19
+ save_last_change
20
+ report_errors
21
+ end
22
+
23
+ private
24
+
25
+ def entrypoint
26
+ PROJECT_ENTRYPOINT
27
+ end
28
+
29
+ def last_change_file
30
+ PROJECT_LAST_CHANGE_FILE
31
+ end
32
+
33
+ def list_key
34
+ "project"
35
+ end
36
+
37
+ def fetch_pub(project)
38
+ bib = ProjectParser.new(project, @errors).parse
39
+ did = bib.docidentifier.detect(&:primary)
40
+ file = unique_output_file(did.to_s)
41
+ @files << file
42
+ ts = project["lastChangeTimestamp"]
43
+ @last_change_max = ts if ts && last_change_max < ts
44
+ File.write file, to_yaml(bib), encoding: "UTF-8"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,111 @@
1
+ module Relaton
2
+ module Iec
3
+ # Parses Harmonized API project records (in-development standards) into
4
+ # Relaton items. Field reference: the IEC/ISO Harmonized APIs technical
5
+ # documentation, section "HAPI - Projects".
6
+ class ProjectParser < DataParser
7
+ # projectRelation types have no IEC-side reference, only a URN; map
8
+ # them onto the bibdata relation vocabulary. Agreements carrying an
9
+ # externalProject (Frankfurt agreement) have no URN and are skipped.
10
+ RELATION_TYPES = {
11
+ "AMENDS" => "updates",
12
+ "CORRECTS" => "updates",
13
+ "CORRECTED_BY" => "updatedBy",
14
+ "REVISED_BY" => "updatedBy",
15
+ "REPLACED_BY" => "obsoletedBy",
16
+ "MERGED_INTO" => "mergedInto",
17
+ "SPLIT_FROM" => "derivedFrom",
18
+ "INTERPRETS" => "commentaryOf",
19
+ }.freeze
20
+
21
+ private
22
+
23
+ # The project URN namespace differs from publications (iec:proj: vs
24
+ # iec:std:), so the parent's URN-from-reference derivation does not
25
+ # apply; the record's own urn is taken verbatim.
26
+ def docidentifier
27
+ ids = [iec_docid]
28
+ ids << Docidentifier.new(content: @pub["urn"], type: "URN") if @pub["urn"]
29
+ @errors[:docidentifier] &&= ids.compact.empty?
30
+ ids.compact
31
+ end
32
+
33
+ def date
34
+ result = {
35
+ "published" => @pub["publicationDate"] || @pub["editionDate"],
36
+ "created" => @pub["initialProjectDate"],
37
+ "forecast" => @pub["forecastPublicationDate"],
38
+ }.filter_map do |k, v|
39
+ next unless v
40
+
41
+ Bib::Date.new(type: k, at: v)
42
+ end
43
+ @errors[:date] &&= result.empty?
44
+ result
45
+ end
46
+
47
+ # The stage lifecycle is the project's status: the CURRENT stage when
48
+ # present, else the latest by effective date. stageCode is the IEC
49
+ # abbreviation (CFDIS, WPUB, DELPUB...), harmonizedStageCode the
50
+ # ISO-style numeric stage.
51
+ def status
52
+ stage = current_stage || Array(@pub["stages"]).last
53
+ return unless stage
54
+
55
+ result = Bib::Status.new(
56
+ stage: Bib::Status::Stage.new(
57
+ content: stage["harmonizedStageCode"], abbreviation: stage["stageCode"],
58
+ ),
59
+ iteration: stage["iteration"]&.to_s,
60
+ )
61
+ @errors[:status] &&= result.nil?
62
+ result
63
+ end
64
+
65
+ def current_stage
66
+ Array(@pub["stages"]).find { |s| s["status"] == "CURRENT" }
67
+ end
68
+
69
+ def contributor
70
+ super + [owner_contributor].compact
71
+ end
72
+
73
+ def owner_contributor
74
+ return unless @pub.dig("owner", "displayName")
75
+
76
+ orgname = Bib::TypedLocalizedString.new(content: "International Electrotechnical Commission",
77
+ language: "en", script: "Latn")
78
+ abbr = Bib::LocalizedString.new(content: "IEC", language: "en", script: "Latn")
79
+ tcname = Bib::TypedLocalizedString.new(content: @pub["owner"]["displayName"],
80
+ language: "en", script: "Latn")
81
+ subdivision = Bib::Subdivision.new(
82
+ type: "technical-committee",
83
+ name: [tcname],
84
+ )
85
+ org = Bib::Organization.new(name: [orgname], abbreviation: abbr, subdivision: [subdivision])
86
+ desc = Bib::LocalizedMarkedUpString.new(content: "committee")
87
+ role = Bib::Contributor::Role.new(type: "author", description: [desc])
88
+ Bib::Contributor.new(organization: org, role: [role])
89
+ end
90
+
91
+ def relation
92
+ rels = Array(@pub["projectRelations"]).filter_map { |r| project_relation r } +
93
+ Array(@pub["publications"]).filter_map { |p| urn_relation "hasSuccessor", p["urn"] }
94
+ @errors[:relation] &&= rels.empty?
95
+ rels
96
+ end
97
+
98
+ def project_relation(rel)
99
+ urn_relation RELATION_TYPES.fetch(rel["type"], "related"), rel["urn"]
100
+ end
101
+
102
+ def urn_relation(type, urn)
103
+ return unless urn
104
+
105
+ docid = Docidentifier.new(content: urn, type: "URN")
106
+ bibitem = ItemData.new(formattedref: Bib::Formattedref.new(content: urn), docidentifier: [docid])
107
+ Relation.new(type: type, bibitem: bibitem)
108
+ end
109
+ end
110
+ end
111
+ end
data/lib/relaton/iec.rb CHANGED
@@ -20,6 +20,11 @@ require_relative "iec/model/bibdata"
20
20
 
21
21
  module Relaton
22
22
  module Iec
23
+ autoload :DataFetcher, "relaton/iec/data_fetcher"
24
+ autoload :DataParser, "relaton/iec/data_parser"
25
+ autoload :ProjectFetcher, "relaton/iec/project_fetcher"
26
+ autoload :ProjectParser, "relaton/iec/project_parser"
27
+
23
28
  INDEXFILE = "index-v2".freeze
24
29
  # The machine index on the data repo's Pages site (relaton#206) —
25
30
  # manifest + per-shard rows read by HitCollection's index; the zip stays