relaton 3.0.3 → 3.0.5
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/lib/relaton/3gpp/data_fetcher.rb +3 -2
- data/lib/relaton/bib/CLAUDE.md +24 -4
- data/lib/relaton/bib/README.adoc +64 -0
- data/lib/relaton/bib/converter/bibxml/from_rfcxml.rb +12 -1
- data/lib/relaton/bib/converter/bibxml/to_rfcxml.rb +32 -8
- data/lib/relaton/bib/converter/bibxml/to_rfcxml_referencegroup.rb +10 -3
- data/lib/relaton/bib/converter/bibxml/to_rfcxml_referencegroup_v3.rb +43 -0
- data/lib/relaton/bib/converter/bibxml/to_rfcxml_v3.rb +416 -0
- data/lib/relaton/bib/converter/bibxml.rb +21 -9
- data/lib/relaton/bib/item_data.rb +19 -7
- data/lib/relaton/bib/model/abstract.rb +5 -0
- data/lib/relaton/bib/model/localized_string.rb +6 -1
- data/lib/relaton/bib/sanitizer.rb +20 -5
- data/lib/relaton/bipm/data_outcomes_parser.rb +2 -1
- data/lib/relaton/bipm/si_brochure_parser.rb +3 -2
- data/lib/relaton/core/data_fetcher.rb +3 -2
- data/lib/relaton/core/processor.rb +29 -0
- data/lib/relaton/db/CLAUDE.md +14 -2
- data/lib/relaton/db/cache.rb +5 -2
- data/lib/relaton/db.rb +7 -3
- data/lib/relaton/ecma/processor.rb +8 -0
- data/lib/relaton/equivalence.rb +2 -2
- data/lib/relaton/gb/scraper.rb +2 -2
- data/lib/relaton/ieee/data_fetcher.rb +2 -1
- data/lib/relaton/ietf/bibxml_parser.rb +6 -0
- data/lib/relaton/iho/CLAUDE.md +4 -2
- data/lib/relaton/iho/bibliography.rb +44 -13
- data/lib/relaton/iho/processor.rb +6 -0
- data/lib/relaton/index/file_io.rb +9 -8
- data/lib/relaton/index/shard_source.rb +3 -2
- data/lib/relaton/iso/hit_collection.rb +20 -3
- data/lib/relaton/jcgm/meetings_parser.rb +2 -2
- data/lib/relaton/nist/cswp.rb +2 -2
- data/lib/relaton/nist/data_fetcher.rb +3 -2
- data/lib/relaton/sdo/store.rb +3 -1
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton/xsf/hit.rb +2 -1
- metadata +10 -8
|
@@ -134,6 +134,21 @@ module Relaton
|
|
|
134
134
|
copy
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
+
# A copy of `pubid` with each given component the parse leaves nil, for
|
|
138
|
+
# #item_cache_key. `pubid` itself when there is nothing to add.
|
|
139
|
+
#
|
|
140
|
+
# @param pubid [Pubid::Identifier]
|
|
141
|
+
# @param values [Hash{Symbol => String, nil}]
|
|
142
|
+
# @return [Pubid::Identifier]
|
|
143
|
+
def with_components(pubid, **values)
|
|
144
|
+
values = values.select { |attr, value| value && pubid.public_send(attr).nil? }
|
|
145
|
+
return pubid if values.empty?
|
|
146
|
+
|
|
147
|
+
copy = pubid.class.from_hash pubid.to_hash
|
|
148
|
+
values.each { |attr, value| copy.public_send "#{attr}=", value }
|
|
149
|
+
copy
|
|
150
|
+
end
|
|
151
|
+
|
|
137
152
|
# The cache key for a query: the parsed pubid with the `year` and
|
|
138
153
|
# `all_parts` options folded in. The publication date range is not part
|
|
139
154
|
# of the identity, so it never enters the key.
|
|
@@ -153,6 +168,20 @@ module Relaton
|
|
|
153
168
|
pubid
|
|
154
169
|
end
|
|
155
170
|
|
|
171
|
+
# The cache key of a fetched document: its primary docidentifier as
|
|
172
|
+
# parsed (`pubid`), plus the components that docid omits by design and
|
|
173
|
+
# the item keeps elsewhere. A flavor whose printed docid drops the
|
|
174
|
+
# edition (IHO `B-12`, ECMA `ECMA-262`) overrides this, or every
|
|
175
|
+
# edition gets one key and one cache file (relaton#408). The same set
|
|
176
|
+
# as relaton-cli's `MachineIndex::REFINABLE_KEYS`.
|
|
177
|
+
#
|
|
178
|
+
# @param pubid [Pubid::Identifier] the docid's parse; not mutated
|
|
179
|
+
# @param _item [Relaton::Bib::ItemData] the fetched document
|
|
180
|
+
# @return [Pubid::Identifier]
|
|
181
|
+
def item_cache_key(pubid, _item)
|
|
182
|
+
pubid
|
|
183
|
+
end
|
|
184
|
+
|
|
156
185
|
def initialize
|
|
157
186
|
raise "This is an abstract class!"
|
|
158
187
|
end
|
data/lib/relaton/db/CLAUDE.md
CHANGED
|
@@ -223,6 +223,17 @@ relaton#189 item 2 / relaton#204. Two lutaml-store `FileSystem` stores under
|
|
|
223
223
|
both naming the same file. There are no redirect entries. A document is
|
|
224
224
|
deleted with the last row that points to it; a row whose document is gone is
|
|
225
225
|
a miss.
|
|
226
|
+
- **The item row's key must tell editions apart (relaton#408).** `Db#item_key`
|
|
227
|
+
parses the primary docidentifier and passes it through
|
|
228
|
+
`Core::Processor#item_cache_key(pubid, item)`. A flavor whose printed docid
|
|
229
|
+
omits the edition by design overrides the hook to add it from the item:
|
|
230
|
+
IHO adds `version` from `edition` (`IHO B-12` → `IHO B-12 3.0.0`), ECMA adds
|
|
231
|
+
`edition` and the `volume` extent (`ECMA-262` → `ECMA-262 ed16`), through
|
|
232
|
+
`#with_components`, which fills only components the parse leaves nil, on a
|
|
233
|
+
copy. Without it every edition got one item key and one file, and a fetch of
|
|
234
|
+
`IHO B-12 2.0.3` overwrote the file the `IHO B-12 3.0.0` query row named. A
|
|
235
|
+
cache with such a file is dropped by the next `Relaton::VERSION` bump
|
|
236
|
+
(`grammar_hash`), so no separate cache-version bump was made.
|
|
226
237
|
|
|
227
238
|
Matching: the **exact** row first (canonical `to_hash`, not pubid `==`, which
|
|
228
239
|
is false after a `from_hash` round trip for some flavors, e.g. UN). Only a
|
|
@@ -233,8 +244,9 @@ still applies and it never answers with another query's year-stripped copy.
|
|
|
233
244
|
`ISO 19115:2003 === ISO 19115-1:2003` (and the same for IEC, BSI, JIS, GB).
|
|
234
245
|
`Cache#subset_of?` therefore also requires that every component the row adds
|
|
235
246
|
(at any depth) is allowed: only a language for the dated fallback
|
|
236
|
-
(`LANGUAGE_COMPONENTS`), a year/date/month
|
|
237
|
-
`
|
|
247
|
+
(`LANGUAGE_COMPONENTS`), a year/date/month, an edition/version (the
|
|
248
|
+
`item_cache_key` components; not a volume, which names another document) or a
|
|
249
|
+
language for the date-range `candidates` (`EDITION_COMPONENTS`). A row with no `root.number` (DOI, ISBN)
|
|
238
250
|
goes to one of 256 digest buckets (`<flavor>/~<hex>`).
|
|
239
251
|
|
|
240
252
|
Expiry (`Cache#valid_row?`): an undated row, and **every** `not_found` row,
|
data/lib/relaton/db/cache.rb
CHANGED
|
@@ -36,8 +36,11 @@ module Relaton
|
|
|
36
36
|
# reads an omitted `part` as "any part" (`ISO 19115:2003 ===
|
|
37
37
|
# ISO 19115-1:2003`), which names another document.
|
|
38
38
|
LANGUAGE_COMPONENTS = %w[language languages].freeze
|
|
39
|
-
# What a row may add to a key and still be one of its editions.
|
|
40
|
-
|
|
39
|
+
# What a row may add to a key and still be one of its editions. An
|
|
40
|
+
# `edition` or a `version` comes from Core::Processor#item_cache_key
|
|
41
|
+
# (IHO, ECMA; relaton#408). A `volume` names another document.
|
|
42
|
+
EDITION_COMPONENTS =
|
|
43
|
+
(%w[year date month edition version] + LANGUAGE_COMPONENTS).freeze
|
|
41
44
|
|
|
42
45
|
# @return [String]
|
|
43
46
|
attr_reader :dir
|
data/lib/relaton/db.rb
CHANGED
|
@@ -382,13 +382,17 @@ module Relaton
|
|
|
382
382
|
[query, query && processor.cache_key(code, year, opts, query)]
|
|
383
383
|
end
|
|
384
384
|
|
|
385
|
-
# The key of a fetched document, from its primary identifier
|
|
386
|
-
# identifier
|
|
385
|
+
# The key of a fetched document, from its primary identifier and what
|
|
386
|
+
# that identifier omits (Core::Processor#item_cache_key, relaton#408).
|
|
387
|
+
# The identifier is data, so an unparseable one gives no key.
|
|
387
388
|
def item_key(bib, stdclass)
|
|
388
389
|
docid = bib.docidentifier.detect(&:primary) || bib.docidentifier.first
|
|
389
390
|
return unless docid&.content
|
|
390
391
|
|
|
391
|
-
cache_key docid.content, nil, {}, stdclass
|
|
392
|
+
key = cache_key docid.content, nil, {}, stdclass
|
|
393
|
+
return key unless key.is_a? ::Pubid::Identifier
|
|
394
|
+
|
|
395
|
+
@registry[stdclass].item_cache_key key, bib
|
|
392
396
|
rescue ::Pubid::Errors::Error
|
|
393
397
|
nil
|
|
394
398
|
end
|
|
@@ -21,6 +21,14 @@ module Relaton
|
|
|
21
21
|
Bibliography.get(code, date, opts)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
# An ECMA record prints `ECMA-262` with no ` ed<N>`/` vol<N>`, and keeps
|
|
25
|
+
# them in `edition` and in a `volume` extent (relaton#408).
|
|
26
|
+
def item_cache_key(pubid, item)
|
|
27
|
+
volume = item.extent.flat_map(&:locality)
|
|
28
|
+
.detect { |l| l.type == "volume" }&.reference_from
|
|
29
|
+
with_components pubid, edition: item.edition&.content, volume: volume
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
#
|
|
25
33
|
# Fetch all the documents from a source
|
|
26
34
|
#
|
data/lib/relaton/equivalence.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "yeptris/psych"
|
|
2
2
|
|
|
3
3
|
module Relaton
|
|
4
4
|
# Cross-SDO equivalence as data: chain patterns and explicit equivalences
|
|
@@ -23,7 +23,7 @@ module Relaton
|
|
|
23
23
|
else
|
|
24
24
|
[path]
|
|
25
25
|
end
|
|
26
|
-
files.each { |f| tables <<
|
|
26
|
+
files.each { |f| tables << Yeptris::Psych.safe_load_file(f, aliases: true) }
|
|
27
27
|
tables
|
|
28
28
|
end
|
|
29
29
|
|
data/lib/relaton/gb/scraper.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
require "yeptris/psych"
|
|
1
2
|
# encoding: UTF-8
|
|
2
3
|
# frozen_string_literal: true
|
|
3
4
|
|
|
4
|
-
require "yaml"
|
|
5
5
|
require "gb_agencies"
|
|
6
6
|
|
|
7
7
|
module Relaton
|
|
@@ -132,7 +132,7 @@ module Relaton
|
|
|
132
132
|
# @param pref [String]
|
|
133
133
|
# @return [Hash{String=>String}]
|
|
134
134
|
def prefix(pref)
|
|
135
|
-
@prefixes ||=
|
|
135
|
+
@prefixes ||= Yeptris::Psych.load_file File.join(__dir__, "yaml/prefixes.yaml")
|
|
136
136
|
@prefixes[pref]
|
|
137
137
|
end
|
|
138
138
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "yeptris/psych"
|
|
1
2
|
require "etc"
|
|
2
3
|
require "zip"
|
|
3
4
|
require_relative "../ieee"
|
|
@@ -77,7 +78,7 @@ module Relaton
|
|
|
77
78
|
# @param file [String]
|
|
78
79
|
# @return [String, nil]
|
|
79
80
|
def primary_docid(file)
|
|
80
|
-
yaml =
|
|
81
|
+
yaml = Yeptris::Psych.safe_load(File.read(file, encoding: "UTF-8"),
|
|
81
82
|
permitted_classes: [Symbol, Date, Time])
|
|
82
83
|
id = yaml && yaml["docidentifier"]&.find do |i|
|
|
83
84
|
i["type"] == "IEEE" && i["primary"] == true && i["trademark"].nil?
|
|
@@ -131,6 +131,12 @@ module Relaton
|
|
|
131
131
|
BibXMLParser.pubid_type(id)
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
# The base parser keeps <stream> as a `type="stream"` series, for items
|
|
135
|
+
# with no other slot. This flavor carries the stream in `ext.stream`.
|
|
136
|
+
def stream_series
|
|
137
|
+
[]
|
|
138
|
+
end
|
|
139
|
+
|
|
134
140
|
def contributor # rubocop:disable Metrics/MethodLength
|
|
135
141
|
contribs = []
|
|
136
142
|
unless @reference.anchor&.match?(/^I-D/)
|
data/lib/relaton/iho/CLAUDE.md
CHANGED
|
@@ -55,9 +55,11 @@ In `item.rb`, `require_relative "relation"` is placed **after** the `Item` class
|
|
|
55
55
|
|
|
56
56
|
`Bibliography.search`/`.get` fetches YAML from the relaton-data-iho GitHub repo via `Relaton::Index`, then deserializes into model objects.
|
|
57
57
|
|
|
58
|
-
**Editions.** The pubid `version` is the edition (`IHO B-12 3.0.0`; the grammar takes `a.b.c` only). A reference with no version answers with the **latest** edition: `
|
|
58
|
+
**Editions and series.** The pubid `version` is the edition (`IHO B-12 3.0.0`; the grammar takes `a.b.c` only). A reference with no version answers with the **latest** edition: `recency_key` compares the segments as integers (`2.10.0` after `2.9.0`). It used to be `min_by` on the string, which returned the oldest.
|
|
59
59
|
|
|
60
|
-
**
|
|
60
|
+
**Series are identified by year or volume, not an edition (relaton#407).** B-7, P-5 and P-6 carry a `year` (`IHO P-5 2024`), the IHR (P-1) a `volume` with an optional `issue` (`IHO P-1 Vol. 30 (2)`) — plain scalars added by pubid#635, mutually exclusive with `version` (the grammar's tail picks exactly one). The same `recency_key` orders each kind numerically, so a bare series query answers with the latest year/volume/issue. Matching (`pubid_match?`) treats a component the query omits as a wildcard: `IHO P-1 Vol. 30` matches any issue of volume 30. The comparison runs through pubid's `#exclude` — excluding `:volume` nils the `issue` with it (the pair is one scalar cluster) — the way BIPM's `stem_keys` does. The subdivisions (part/appendix/annex/supplement) stay strict: this flavor cannot use the `===` subset match, because pubid does not declare `subset_strict` for IHO's subdivisions and a nil `part` would read as "any part" (`IHO S-100` would answer with a part row).
|
|
61
|
+
|
|
62
|
+
**The edition reaches the index only through the committed row.** A record prints `B-12` and keeps its edition in `edition:`, so `relaton index` cannot read a version from the docid. `MachineIndex#refine` (relaton-cli) takes the committed `index-v3.yaml` row when it adds only a key in `REFINABLE_KEYS` to the parse — `version`/`edition`/`volume`/`year`/`issue` (relaton#407 added the year/issue pair for the series rows). Before that, the Pages index (generated 2026-10-29) had no `version` in any of its 325 rows, so every versioned reference answered not-found (relaton-data-iho#20). The suite did not see it: `spec/fixtures/index-v3.zip` is the committed index, which has versions. The suite's fixture currently carries the **re-keyed** series rows (year/volume) ahead of the data repo: the placeholder `1.0.0` rows for p-1/p-1-2x/p-5/p-6/b-7 are replaced by `year`/`volume` rows — refresh the fixture from the live published zip once relaton-data-iho re-keys, and reconcile any file-name drift then.
|
|
61
63
|
|
|
62
64
|
### Test Infrastructure
|
|
63
65
|
|
|
@@ -21,7 +21,7 @@ module Relaton
|
|
|
21
21
|
# Pubid::Iho::Identifiers::* (Relaton::Index deserialized it via the
|
|
22
22
|
# `pubid_class` passed in `#index`), so `pubid_match?` compares pubids.
|
|
23
23
|
row = index.search(pubid) { |r| pubid_match?(r[:id], pubid) }
|
|
24
|
-
.max_by { |r|
|
|
24
|
+
.max_by { |r| recency_key(r[:id]) }
|
|
25
25
|
unless row
|
|
26
26
|
Util.info "Not found.", key: pubid.to_s
|
|
27
27
|
return
|
|
@@ -96,26 +96,57 @@ module Relaton
|
|
|
96
96
|
)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
# The sort key for the latest
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
# The sort key for the latest record in a bucket (relaton#407). Each
|
|
100
|
+
# IHO identity carries exactly one trailing discriminator — a dotted
|
|
101
|
+
# `version` (an edition, `B-12 3.0.0`), a series `year` (`P-5 2024`)
|
|
102
|
+
# or a series `volume` with its `issue` (`P-1 Vol. 30 (2)`) — and the
|
|
103
|
+
# key orders by that component, numerically: version segments compare
|
|
104
|
+
# as integers (2.10.0 is later than 2.9.0), as do year, volume and
|
|
105
|
+
# issue. A row with no discriminator at all is the oldest. Rows in
|
|
106
|
+
# one bucket share the discriminator kind once the data is keyed;
|
|
107
|
+
# while kinds coexist the array compare is deterministic, and a
|
|
108
|
+
# year's bare [2024] beats a placeholder edition's [1, 0, 0].
|
|
109
|
+
def recency_key(id)
|
|
110
|
+
if id.year
|
|
111
|
+
[id.year.to_i]
|
|
112
|
+
elsif id.volume
|
|
113
|
+
[id.volume.to_i, id.issue.to_i]
|
|
114
|
+
else
|
|
115
|
+
id.version.to_s.split(".").map(&:to_i)
|
|
116
|
+
end
|
|
103
117
|
end
|
|
104
118
|
|
|
119
|
+
# The components that make an IHO document the one it is beyond the
|
|
120
|
+
# series and subdivisions: the edition (`version`), or — for the
|
|
121
|
+
# series identified by year or volume instead (B-7, P-1, P-5, P-6;
|
|
122
|
+
# relaton#407) — the `year` or the `volume`/`issue` pair.
|
|
123
|
+
DISCRIMINATOR_KEYS = %i[version year volume issue].freeze
|
|
124
|
+
|
|
105
125
|
# Both `row_id` and `query` are Pubid::Iho::Identifiers::* instances.
|
|
106
126
|
# Class identity pins the series (S/P/M/B/C). Subdivision keys
|
|
107
127
|
# (part/appendix/annex/supplement) use strict equality — a nil query
|
|
108
128
|
# must match a nil row (the umbrella), not an arbitrary subdivision
|
|
109
|
-
# under the same
|
|
110
|
-
#
|
|
129
|
+
# under the same number. That is why this flavor does not use the
|
|
130
|
+
# `===` subset match: pubid reads a nil `part` there as "any part"
|
|
131
|
+
# (pubid's `subset_strict` is not declared for the IHO subdivisions),
|
|
132
|
+
# so `IHO S-100` would answer with a part row.
|
|
133
|
+
#
|
|
134
|
+
# The discriminator keys stay nil-tolerant: an unqualified `IHO B-11`
|
|
135
|
+
# finds the latest edition, an unqualified `IHO P-5` the latest year,
|
|
136
|
+
# and `IHO P-1 Vol. 30` any issue of that volume — while a stated
|
|
137
|
+
# component must match exactly. The comparison runs through pubid's
|
|
138
|
+
# `#exclude` (the primitive `matches?` is built on), so the rules the
|
|
139
|
+
# flavor declares there ride along: excluding `:volume` nils the
|
|
140
|
+
# `issue` with it. `stem_keys` in the BIPM flavor is the same shape.
|
|
111
141
|
def pubid_match?(row_id, query)
|
|
112
142
|
row_id.class == query.class &&
|
|
113
|
-
row_id.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
143
|
+
row_id.exclude(*wildcards(query)) == query.exclude(*wildcards(query))
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# The discriminators the query leaves unset: wildcards for the
|
|
147
|
+
# search, significant whenever the query states one.
|
|
148
|
+
def wildcards(query)
|
|
149
|
+
DISCRIMINATOR_KEYS.select { |key| query.public_send(key).nil? }
|
|
119
150
|
end
|
|
120
151
|
end
|
|
121
152
|
end
|
|
@@ -25,6 +25,12 @@ module Relaton
|
|
|
25
25
|
Bibliography.get(code, date, opts)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# An IHO record prints `B-12` and keeps its edition in `edition`, so
|
|
29
|
+
# the edition goes on the key as the version (relaton#408).
|
|
30
|
+
def item_cache_key(pubid, item)
|
|
31
|
+
with_components pubid, version: item.edition&.content
|
|
32
|
+
end
|
|
33
|
+
|
|
28
34
|
# @param xml [String]
|
|
29
35
|
# @return [Relaton::Iho::ItemData]
|
|
30
36
|
def from_xml(xml)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "yeptris/psych"
|
|
1
2
|
module Relaton
|
|
2
3
|
module Index
|
|
3
4
|
#
|
|
@@ -219,12 +220,12 @@ module Relaton
|
|
|
219
220
|
end
|
|
220
221
|
|
|
221
222
|
def load_index(yaml, save = false)
|
|
222
|
-
index =
|
|
223
|
+
index = Yeptris::Psych.safe_load(yaml, permitted_classes: [Symbol])
|
|
223
224
|
save index if save
|
|
224
225
|
return deserialize_pubid(index) if check_format(index)
|
|
225
226
|
|
|
226
227
|
report_invalid_index(save, "Wrong structure of")
|
|
227
|
-
rescue Psych::SyntaxError
|
|
228
|
+
rescue Yeptris::Psych::SyntaxError
|
|
228
229
|
report_invalid_index(save, "YAML parsing error when reading")
|
|
229
230
|
rescue InvalidIndexError
|
|
230
231
|
report_invalid_index(save, "Wrong structure of")
|
|
@@ -430,7 +431,7 @@ module Relaton
|
|
|
430
431
|
end
|
|
431
432
|
yaml = yaml.read unless yaml.is_a?(String)
|
|
432
433
|
Util.info "Downloaded index from `#{url}` for sqlite materialization", progname
|
|
433
|
-
raw =
|
|
434
|
+
raw = Yeptris::Psych.safe_load(yaml, permitted_classes: [Symbol])
|
|
434
435
|
return nil unless check_format(raw)
|
|
435
436
|
|
|
436
437
|
Enumerator.new do |y|
|
|
@@ -439,7 +440,7 @@ module Relaton
|
|
|
439
440
|
y << [number, number, r[:id], r[:file]]
|
|
440
441
|
end
|
|
441
442
|
end
|
|
442
|
-
rescue Psych::SyntaxError, SocketError, OpenURI::HTTPError, Errno::ECONNRESET,
|
|
443
|
+
rescue Yeptris::Psych::SyntaxError, SocketError, OpenURI::HTTPError, Errno::ECONNRESET,
|
|
443
444
|
OpenSSL::SSL::SSLError => e
|
|
444
445
|
Util.info "SQLite index build failed (#{e.message}); falling back", progname
|
|
445
446
|
nil
|
|
@@ -512,8 +513,8 @@ module Relaton
|
|
|
512
513
|
return unless yaml
|
|
513
514
|
|
|
514
515
|
begin
|
|
515
|
-
raw =
|
|
516
|
-
rescue Psych::SyntaxError
|
|
516
|
+
raw = Yeptris::Psych.safe_load(yaml, permitted_classes: [Symbol])
|
|
517
|
+
rescue Yeptris::Psych::SyntaxError
|
|
517
518
|
warn_local_index_error("YAML parsing error when reading")
|
|
518
519
|
delete_sidecar
|
|
519
520
|
return [[], []]
|
|
@@ -613,7 +614,7 @@ module Relaton
|
|
|
613
614
|
yaml = zip.entries.first.get_input_stream.read
|
|
614
615
|
end
|
|
615
616
|
Util.info "Downloaded index from `#{url}`", progname
|
|
616
|
-
raw =
|
|
617
|
+
raw = Yeptris::Psych.safe_load(yaml, permitted_classes: [Symbol])
|
|
617
618
|
if check_format(raw)
|
|
618
619
|
save raw
|
|
619
620
|
raw = nil # release the parsed copy; read_raw_file loads the sidecar's
|
|
@@ -622,7 +623,7 @@ module Relaton
|
|
|
622
623
|
warn_remote_index_error "Wrong structure of"
|
|
623
624
|
[[], []]
|
|
624
625
|
end
|
|
625
|
-
rescue Psych::SyntaxError
|
|
626
|
+
rescue Yeptris::Psych::SyntaxError
|
|
626
627
|
warn_remote_index_error "YAML parsing error when reading"
|
|
627
628
|
[[], []]
|
|
628
629
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "yeptris/psych"
|
|
1
2
|
require "yeptris"
|
|
2
3
|
require "json"
|
|
3
4
|
require "net/http"
|
|
@@ -152,11 +153,11 @@ module Relaton
|
|
|
152
153
|
yaml = unzip(body)
|
|
153
154
|
raise Error, "empty archive at `#{url(path)}`" unless yaml
|
|
154
155
|
|
|
155
|
-
index =
|
|
156
|
+
index = Yeptris::Psych.safe_load(yaml, permitted_classes: [Symbol])
|
|
156
157
|
raise Error, "wrong structure of `#{url(path)}`" unless @file_io.check_basic_format(index)
|
|
157
158
|
|
|
158
159
|
@file_io.deserialize_pubid(index)
|
|
159
|
-
rescue FileIO::InvalidIndexError, Psych::SyntaxError, Zip::Error, Zlib::Error => e
|
|
160
|
+
rescue FileIO::InvalidIndexError, Yeptris::Psych::SyntaxError, Zip::Error, Zlib::Error => e
|
|
160
161
|
raise Error, "cannot read `#{url(path)}`: #{e.message}"
|
|
161
162
|
end
|
|
162
163
|
end
|
|
@@ -88,13 +88,30 @@ module Relaton
|
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def pubid_match?(pubid)
|
|
91
|
-
match_excludings =
|
|
92
|
-
|
|
91
|
+
match_excludings = base_match_excludings
|
|
92
|
+
unless pubid.typed_stage&.abbr&.include?("DIR")
|
|
93
|
+
match_excludings = match_excludings + [:edition]
|
|
94
|
+
end
|
|
93
95
|
# Only the candidate is built via .create (from the index) and so may
|
|
94
96
|
# carry a compound part; `ref_pubid_no_year` is always a parsed pubid,
|
|
95
97
|
# already split, so it needs no normalization.
|
|
96
98
|
cand = normalize_compound_part(exclude_id_attrs(pubid, *match_excludings))
|
|
97
|
-
cand ==
|
|
99
|
+
cand == ref_excluded(match_excludings)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# The candidate's excludings set varies only by the DIR exception; the
|
|
103
|
+
# reference side is invariant per distinct set. Exclude the ref's
|
|
104
|
+
# (possibly deep) base chain once per set, not once per candidate —
|
|
105
|
+
# on a large vocabulary compile this chain ran per candidate per
|
|
106
|
+
# lookup and dominated the bibitem-resolution phase (relaton#423).
|
|
107
|
+
def base_match_excludings
|
|
108
|
+
@base_match_excludings ||= translate_excludings(excludings) + [:all_parts]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def ref_excluded(match_excludings)
|
|
112
|
+
@ref_excluded ||= {}
|
|
113
|
+
@ref_excluded[match_excludings] ||=
|
|
114
|
+
exclude_id_attrs(ref_pubid_no_year, *match_excludings)
|
|
98
115
|
end
|
|
99
116
|
|
|
100
117
|
# @TODO TEMP WORKAROUND (pubid 2.x migration): the v1-generated index
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
require "yeptris/psych"
|
|
1
2
|
require "fileutils"
|
|
2
|
-
require "yaml"
|
|
3
3
|
require "date"
|
|
4
4
|
|
|
5
5
|
module Relaton::Jcgm
|
|
@@ -65,7 +65,7 @@ module Relaton::Jcgm
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def load_yaml(file)
|
|
68
|
-
|
|
68
|
+
Yeptris::Psych.safe_load File.read(file, encoding: "UTF-8"), permitted_classes: [Date, Time]
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
# "JCGM 17th Meeting (2012)" — ordinal via pubid's Meeting.ordinal.
|
data/lib/relaton/nist/cswp.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "yeptris/psych"
|
|
2
2
|
|
|
3
3
|
module Relaton
|
|
4
4
|
module Nist
|
|
@@ -24,7 +24,7 @@ module Relaton
|
|
|
24
24
|
class << self
|
|
25
25
|
# @return [Hash] the table as written in cswp.yaml
|
|
26
26
|
def table
|
|
27
|
-
@table ||=
|
|
27
|
+
@table ||= Yeptris::Psych.load_file File.expand_path("cswp.yaml", __dir__)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
#
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "yeptris/psych"
|
|
4
|
+
|
|
4
5
|
require "mechanize"
|
|
5
6
|
require "loc_mods"
|
|
6
7
|
require_relative "../nist"
|
|
@@ -183,7 +184,7 @@ module Relaton
|
|
|
183
184
|
end
|
|
184
185
|
|
|
185
186
|
def series
|
|
186
|
-
@series ||=
|
|
187
|
+
@series ||= Yeptris::Psych.load_file File.expand_path("series.yaml", __dir__)
|
|
187
188
|
end
|
|
188
189
|
end
|
|
189
190
|
end
|
data/lib/relaton/sdo/store.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "yeptris/psych"
|
|
4
|
+
|
|
3
5
|
module Relaton
|
|
4
6
|
module Sdo
|
|
5
7
|
# Singleton registry of organizations, built lazily from the index manifest
|
|
@@ -35,7 +37,7 @@ module Relaton
|
|
|
35
37
|
|
|
36
38
|
def build_index
|
|
37
39
|
yaml = Fetcher.fetch_index
|
|
38
|
-
data = yaml.nil? || yaml.empty? ? {} :
|
|
40
|
+
data = yaml.nil? || yaml.empty? ? {} : Yeptris::Psych.safe_load(yaml)
|
|
39
41
|
# A corrupt/unexpected index (non-mapping YAML) degrades to "no orgs"
|
|
40
42
|
# rather than crashing every lookup with a TypeError.
|
|
41
43
|
organizations = data.is_a?(Hash) ? (data["organizations"] || {}) : {}
|
data/lib/relaton/version.rb
CHANGED
data/lib/relaton/xsf/hit.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "yeptris/psych"
|
|
1
2
|
module Relaton
|
|
2
3
|
module Xsf
|
|
3
4
|
class Hit < Relaton::Core::Hit
|
|
@@ -6,7 +7,7 @@ module Relaton
|
|
|
6
7
|
|
|
7
8
|
agent = Mechanize.new
|
|
8
9
|
resp = agent.get hit[:url]
|
|
9
|
-
hash =
|
|
10
|
+
hash = Yeptris::Psych.safe_load resp.body
|
|
10
11
|
hash["fetched"] = Date.today.to_s
|
|
11
12
|
@doc = Relaton::Xsf::Item.from_yaml hash.to_yaml
|
|
12
13
|
rescue StandardError => e
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: relaton
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-11-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: addressable
|
|
@@ -366,14 +366,14 @@ dependencies:
|
|
|
366
366
|
requirements:
|
|
367
367
|
- - "~>"
|
|
368
368
|
- !ruby/object:Gem::Version
|
|
369
|
-
version: 0.
|
|
369
|
+
version: 0.6.0
|
|
370
370
|
type: :runtime
|
|
371
371
|
prerelease: false
|
|
372
372
|
version_requirements: !ruby/object:Gem::Requirement
|
|
373
373
|
requirements:
|
|
374
374
|
- - "~>"
|
|
375
375
|
- !ruby/object:Gem::Version
|
|
376
|
-
version: 0.
|
|
376
|
+
version: 0.6.0
|
|
377
377
|
- !ruby/object:Gem::Dependency
|
|
378
378
|
name: leptris
|
|
379
379
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -408,28 +408,28 @@ dependencies:
|
|
|
408
408
|
requirements:
|
|
409
409
|
- - "~>"
|
|
410
410
|
- !ruby/object:Gem::Version
|
|
411
|
-
version: 1.3.
|
|
411
|
+
version: 1.3.121
|
|
412
412
|
type: :runtime
|
|
413
413
|
prerelease: false
|
|
414
414
|
version_requirements: !ruby/object:Gem::Requirement
|
|
415
415
|
requirements:
|
|
416
416
|
- - "~>"
|
|
417
417
|
- !ruby/object:Gem::Version
|
|
418
|
-
version: 1.3.
|
|
418
|
+
version: 1.3.121
|
|
419
419
|
- !ruby/object:Gem::Dependency
|
|
420
420
|
name: pubid
|
|
421
421
|
requirement: !ruby/object:Gem::Requirement
|
|
422
422
|
requirements:
|
|
423
423
|
- - "~>"
|
|
424
424
|
- !ruby/object:Gem::Version
|
|
425
|
-
version: 2.0.
|
|
425
|
+
version: 2.0.3
|
|
426
426
|
type: :runtime
|
|
427
427
|
prerelease: false
|
|
428
428
|
version_requirements: !ruby/object:Gem::Requirement
|
|
429
429
|
requirements:
|
|
430
430
|
- - "~>"
|
|
431
431
|
- !ruby/object:Gem::Version
|
|
432
|
-
version: 2.0.
|
|
432
|
+
version: 2.0.3
|
|
433
433
|
- !ruby/object:Gem::Dependency
|
|
434
434
|
name: yeptris
|
|
435
435
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -566,6 +566,8 @@ files:
|
|
|
566
566
|
- lib/relaton/bib/converter/bibxml/from_rfcxml_referencegroup.rb
|
|
567
567
|
- lib/relaton/bib/converter/bibxml/to_rfcxml.rb
|
|
568
568
|
- lib/relaton/bib/converter/bibxml/to_rfcxml_referencegroup.rb
|
|
569
|
+
- lib/relaton/bib/converter/bibxml/to_rfcxml_referencegroup_v3.rb
|
|
570
|
+
- lib/relaton/bib/converter/bibxml/to_rfcxml_v3.rb
|
|
569
571
|
- lib/relaton/bib/converter/csl.rb
|
|
570
572
|
- lib/relaton/bib/converter/ris.rb
|
|
571
573
|
- lib/relaton/bib/converter/titles.rb
|