relaton 3.0.0.pre.alpha.1 → 3.0.0.pre.alpha.2
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/README.adoc +57 -1
- data/bin/console +0 -1
- data/lib/relaton/3gpp/bibliography.rb +82 -7
- data/lib/relaton/3gpp/data_fetcher.rb +51 -3
- data/lib/relaton/3gpp/docidentifier.rb +114 -0
- data/lib/relaton/3gpp/item.rb +6 -0
- data/lib/relaton/3gpp/parser.rb +1 -1
- data/lib/relaton/3gpp/processor.rb +4 -1
- data/lib/relaton/3gpp.rb +5 -1
- data/lib/relaton/adobe/bibdata.rb +8 -0
- data/lib/relaton/adobe/bibitem.rb +8 -0
- data/lib/relaton/adobe/bibliography.rb +92 -0
- data/lib/relaton/adobe/docidentifier.rb +49 -0
- data/lib/relaton/adobe/doctype.rb +14 -0
- data/lib/relaton/adobe/ext.rb +32 -0
- data/lib/relaton/adobe/item.rb +15 -0
- data/lib/relaton/adobe/item_base.rb +18 -0
- data/lib/relaton/adobe/item_data.rb +6 -0
- data/lib/relaton/adobe/processor.rb +45 -0
- data/lib/relaton/adobe/util.rb +8 -0
- data/lib/relaton/adobe.rb +37 -0
- data/lib/relaton/bib/model/address.rb +2 -2
- data/lib/relaton/bib/model/docidentifier.rb +24 -9
- data/lib/relaton/bib/model/localized_string.rb +1 -1
- data/lib/relaton/bib/model/structured_identifier.rb +10 -9
- data/lib/relaton/bib/sanitizer.rb +202 -6
- data/lib/relaton/bib.rb +0 -2
- data/lib/relaton/bipm/bibliography.rb +159 -10
- data/lib/relaton/bipm/data_fetcher.rb +26 -2
- data/lib/relaton/bipm/data_outcomes_parser.rb +3 -4
- data/lib/relaton/bipm/id_parser.rb +5 -4
- data/lib/relaton/bipm/model/structured_identifier.rb +21 -0
- data/lib/relaton/bipm/processor.rb +2 -2
- data/lib/relaton/bipm/rawdata_bipm_metrologia/fetcher.rb +2 -4
- data/lib/relaton/bipm/si_brochure_parser.rb +5 -3
- data/lib/relaton/bipm.rb +7 -1
- data/lib/relaton/bsi/bibliography.rb +115 -43
- data/lib/relaton/bsi/hit.rb +14 -0
- data/lib/relaton/bsi/hit_collection.rb +15 -16
- data/lib/relaton/bsi/model/docidentifier.rb +99 -1
- data/lib/relaton/bsi/processor.rb +1 -0
- data/lib/relaton/calconnect/bibliography.rb +12 -14
- data/lib/relaton/calconnect/data_fetcher.rb +77 -9
- data/lib/relaton/calconnect/docidentifier.rb +80 -0
- data/lib/relaton/calconnect/hit_collection.rb +65 -57
- data/lib/relaton/calconnect/model/item.rb +7 -0
- data/lib/relaton/calconnect/processor.rb +7 -1
- data/lib/relaton/calconnect.rb +11 -1
- data/lib/relaton/ccsds/data/fetcher.rb +17 -12
- data/lib/relaton/ccsds/data/parser.rb +1 -1
- data/lib/relaton/ccsds/hit_collection.rb +6 -1
- data/lib/relaton/ccsds/model/docidentifier.rb +121 -0
- data/lib/relaton/ccsds/model/item.rb +2 -0
- data/lib/relaton/cen/bibliography.rb +75 -47
- data/lib/relaton/cen/hit.rb +16 -1
- data/lib/relaton/cen/hit_collection.rb +59 -11
- data/lib/relaton/cen/model/docidentifier.rb +92 -1
- data/lib/relaton/cen/processor.rb +13 -8
- data/lib/relaton/cen/scraper.rb +13 -5
- data/lib/relaton/cen.rb +1 -0
- data/lib/relaton/cie/data_fetcher.rb +215 -30
- data/lib/relaton/cie/processor.rb +3 -1
- data/lib/relaton/cie/scrapper.rb +15 -2
- data/lib/relaton/cie.rb +2 -1
- data/lib/relaton/core/data_fetcher.rb +150 -3
- data/lib/relaton/core/governor.rb +320 -0
- data/lib/relaton/core/pacer.rb +134 -0
- data/lib/relaton/core/processor.rb +19 -0
- data/lib/relaton/core/request_error.rb +14 -0
- data/lib/relaton/core.rb +3 -0
- data/lib/relaton/db/registry.rb +41 -1
- data/lib/relaton/doi/crossref.rb +19 -2
- data/lib/relaton/doi/parser.rb +109 -15
- data/lib/relaton/easc/bibdata.rb +8 -0
- data/lib/relaton/easc/bibitem.rb +8 -0
- data/lib/relaton/easc/bibliography.rb +95 -0
- data/lib/relaton/easc/docidentifier.rb +100 -0
- data/lib/relaton/easc/doctype.rb +14 -0
- data/lib/relaton/easc/ext.rb +44 -0
- data/lib/relaton/easc/item.rb +13 -0
- data/lib/relaton/easc/item_base.rb +18 -0
- data/lib/relaton/easc/item_data.rb +6 -0
- data/lib/relaton/easc/processor.rb +46 -0
- data/lib/relaton/easc/util.rb +8 -0
- data/lib/relaton/easc.rb +35 -0
- data/lib/relaton/ecma/bibliography.rb +93 -25
- data/lib/relaton/ecma/data_fetcher.rb +71 -12
- data/lib/relaton/ecma/docidentifier.rb +124 -0
- data/lib/relaton/ecma/item.rb +2 -0
- data/lib/relaton/ecma/memento_parser.rb +1 -1
- data/lib/relaton/ecma/page_fetcher.rb +15 -3
- data/lib/relaton/ecma/parser_common.rb +2 -2
- data/lib/relaton/ecma/processor.rb +4 -1
- data/lib/relaton/ecma/standard_parser.rb +2 -2
- data/lib/relaton/ecma.rb +10 -1
- data/lib/relaton/etsi/bibliography.rb +67 -2
- data/lib/relaton/etsi/data_fetcher.rb +43 -4
- data/lib/relaton/etsi/processor.rb +3 -1
- data/lib/relaton/etsi.rb +2 -1
- data/lib/relaton/gb/bibliography.rb +55 -29
- data/lib/relaton/gb/docidentifier.rb +58 -9
- data/lib/relaton/gb/processor.rb +3 -0
- data/lib/relaton/gb/scraper.rb +27 -10
- data/lib/relaton/gost/bibdata.rb +8 -0
- data/lib/relaton/gost/bibitem.rb +8 -0
- data/lib/relaton/gost/bibliography.rb +107 -0
- data/lib/relaton/gost/docidentifier.rb +80 -0
- data/lib/relaton/gost/doctype.rb +16 -0
- data/lib/relaton/gost/ext.rb +46 -0
- data/lib/relaton/gost/item.rb +15 -0
- data/lib/relaton/gost/item_base.rb +18 -0
- data/lib/relaton/gost/item_data.rb +6 -0
- data/lib/relaton/gost/processor.rb +49 -0
- data/lib/relaton/gost/util.rb +8 -0
- data/lib/relaton/gost.rb +36 -0
- data/lib/relaton/iala/bibdata.rb +8 -0
- data/lib/relaton/iala/bibitem.rb +8 -0
- data/lib/relaton/iala/bibliography.rb +146 -0
- data/lib/relaton/iala/docidentifier.rb +89 -0
- data/lib/relaton/iala/doctype.rb +18 -0
- data/lib/relaton/iala/ext.rb +32 -0
- data/lib/relaton/iala/item.rb +21 -0
- data/lib/relaton/iala/item_base.rb +18 -0
- data/lib/relaton/iala/item_data.rb +6 -0
- data/lib/relaton/iala/processor.rb +43 -0
- data/lib/relaton/iala/relation.rb +7 -0
- data/lib/relaton/iala/util.rb +8 -0
- data/lib/relaton/iala.rb +35 -0
- data/lib/relaton/iana/bibliography.rb +67 -14
- data/lib/relaton/iana/data_fetcher.rb +35 -5
- data/lib/relaton/iana/processor.rb +3 -1
- data/lib/relaton/iana.rb +12 -1
- data/lib/relaton/iec/data_fetcher.rb +7 -1
- data/lib/relaton/iec/hit_collection.rb +1 -1
- data/lib/relaton/iec/model/docidentifier.rb +9 -5
- data/lib/relaton/iec/model/ext.rb +2 -2
- data/lib/relaton/iec/processor.rb +1 -0
- data/lib/relaton/ieee/bibliography.rb +25 -3
- data/lib/relaton/ieee/data_fetcher.rb +158 -17
- data/lib/relaton/ieee/idams_parser.rb +18 -11
- data/lib/relaton/ieee/processor.rb +4 -1
- data/lib/relaton/ieee/rawbib_id_parser.rb +291 -86
- data/lib/relaton/ieee.rb +2 -1
- data/lib/relaton/ietf/data_fetcher.rb +295 -12
- data/lib/relaton/ietf/processor.rb +7 -3
- data/lib/relaton/ietf/rfc/entry.rb +39 -3
- data/lib/relaton/ietf/scraper.rb +69 -36
- data/lib/relaton/ietf.rb +4 -1
- data/lib/relaton/iho/bibliography.rb +1 -1
- data/lib/relaton/iho/docidentifier.rb +1 -1
- data/lib/relaton/index/file_io.rb +11 -11
- data/lib/relaton/index/file_storage.rb +6 -1
- data/lib/relaton/index/pool.rb +6 -1
- data/lib/relaton/index/shard_source.rb +201 -0
- data/lib/relaton/index/type.rb +63 -12
- data/lib/relaton/index.rb +2 -1
- data/lib/relaton/iso/bibliography.rb +20 -15
- data/lib/relaton/iso/data_fetcher.rb +3 -3
- data/lib/relaton/iso/data_parser.rb +17 -3
- data/lib/relaton/iso/hit_collection.rb +27 -15
- data/lib/relaton/iso/item_data.rb +22 -0
- data/lib/relaton/iso/model/docidentifier.rb +24 -12
- data/lib/relaton/iso/processor.rb +1 -0
- data/lib/relaton/iso/scraper.rb +19 -3
- data/lib/relaton/itu/bibliography.rb +9 -4
- data/lib/relaton/itu/data_crawler_r.rb +664 -0
- data/lib/relaton/itu/data_fetcher.rb +496 -50
- data/lib/relaton/itu/data_merge_r.rb +149 -0
- data/lib/relaton/itu/data_parser_r.rb +163 -89
- data/lib/relaton/itu/data_parser_t.rb +228 -0
- data/lib/relaton/itu/family_cache.rb +177 -0
- data/lib/relaton/itu/governor.rb +56 -0
- data/lib/relaton/itu/hit.rb +9 -3
- data/lib/relaton/itu/hit_collection.rb +258 -86
- data/lib/relaton/itu/model/docidentifier.rb +67 -1
- data/lib/relaton/itu/model/structured_identifier.rb +19 -0
- data/lib/relaton/itu/processor.rb +10 -4
- data/lib/relaton/itu/pubid.rb +27 -5
- data/lib/relaton/itu/recommendation_fields.rb +334 -0
- data/lib/relaton/itu/recommendation_parser.rb +18 -149
- data/lib/relaton/itu/scraper.rb +13 -3
- data/lib/relaton/itu.rb +2 -1
- data/lib/relaton/jcgm/bibdata.rb +8 -0
- data/lib/relaton/jcgm/bibitem.rb +8 -0
- data/lib/relaton/jcgm/bibliography.rb +97 -0
- data/lib/relaton/jcgm/data_fetcher.rb +81 -0
- data/lib/relaton/jcgm/docidentifier.rb +102 -0
- data/lib/relaton/jcgm/doctype.rb +12 -0
- data/lib/relaton/jcgm/ext.rb +23 -0
- data/lib/relaton/jcgm/item.rb +20 -0
- data/lib/relaton/jcgm/item_base.rb +18 -0
- data/lib/relaton/jcgm/item_data.rb +6 -0
- data/lib/relaton/jcgm/meetings_parser.rb +175 -0
- data/lib/relaton/jcgm/processor.rb +71 -0
- data/lib/relaton/jcgm/relation.rb +9 -0
- data/lib/relaton/jcgm/structured_identifier.rb +40 -0
- data/lib/relaton/jcgm/util.rb +8 -0
- data/lib/relaton/jcgm.rb +24 -0
- data/lib/relaton/jis/bibliography.rb +8 -10
- data/lib/relaton/jis/data_fetcher.rb +21 -19
- data/lib/relaton/jis/docidentifier.rb +104 -5
- data/lib/relaton/jis/hit.rb +18 -23
- data/lib/relaton/jis/hit_collection.rb +19 -18
- data/lib/relaton/jis/processor.rb +1 -1
- data/lib/relaton/jis.rb +2 -3
- data/lib/relaton/logger/channels/gh_issue.rb +78 -13
- data/lib/relaton/nist/data_fetcher.rb +63 -13
- data/lib/relaton/nist/docidentifier.rb +165 -0
- data/lib/relaton/nist/item.rb +2 -0
- data/lib/relaton/nist/item_base.rb +16 -0
- data/lib/relaton/nist/mods_parser.rb +38 -12
- data/lib/relaton/nist/processor.rb +2 -1
- data/lib/relaton/nist/relation.rb +3 -0
- data/lib/relaton/nist/scraper.rb +6 -3
- data/lib/relaton/oasis/bibliography.rb +147 -6
- data/lib/relaton/oasis/data_fetcher.rb +41 -5
- data/lib/relaton/oasis/data_parser_utils.rb +37 -3
- data/lib/relaton/oasis/docidentifier.rb +54 -0
- data/lib/relaton/oasis/item.rb +3 -0
- data/lib/relaton/oasis/processor.rb +7 -1
- data/lib/relaton/oasis.rb +14 -1
- data/lib/relaton/ogc/data_fetcher.rb +23 -2
- data/lib/relaton/ogc/docidentifier.rb +105 -0
- data/lib/relaton/ogc/hit_collection.rb +78 -3
- data/lib/relaton/ogc/processor.rb +2 -1
- data/lib/relaton/ogc.rb +5 -1
- data/lib/relaton/oiml/bibliography.rb +90 -15
- data/lib/relaton/oiml/docidentifier.rb +18 -3
- data/lib/relaton/omg/docidentifier.rb +67 -0
- data/lib/relaton/omg/item.rb +1 -0
- data/lib/relaton/omg/processor.rb +1 -0
- data/lib/relaton/omg/scraper.rb +61 -16
- data/lib/relaton/omg.rb +1 -0
- data/lib/relaton/plateau/bibliography.rb +10 -3
- data/lib/relaton/plateau/data_fetcher.rb +25 -2
- data/lib/relaton/plateau/handbook_parser.rb +8 -1
- data/lib/relaton/plateau/hit.rb +10 -2
- data/lib/relaton/plateau/hit_collection.rb +31 -11
- data/lib/relaton/plateau/processor.rb +3 -1
- data/lib/relaton/plateau/technical_report_parser.rb +8 -1
- data/lib/relaton/plateau.rb +2 -1
- data/lib/relaton/sdo/config.rb +34 -0
- data/lib/relaton/sdo/fetcher.rb +52 -0
- data/lib/relaton/sdo/logo.rb +95 -0
- data/lib/relaton/sdo/name.rb +26 -0
- data/lib/relaton/sdo/organization.rb +71 -0
- data/lib/relaton/sdo/store.rb +49 -0
- data/lib/relaton/sdo.rb +29 -0
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton/w3c/bibliography.rb +132 -12
- data/lib/relaton/w3c/data_fetcher.rb +194 -16
- data/lib/relaton/w3c/data_parser.rb +3 -3
- data/lib/relaton/w3c/docidentifier.rb +48 -0
- data/lib/relaton/w3c/governor.rb +32 -0
- data/lib/relaton/w3c/item.rb +3 -0
- data/lib/relaton/w3c/pubid.rb +12 -0
- data/lib/relaton/w3c/safe_realize.rb +110 -21
- data/lib/relaton/w3c.rb +12 -1
- data/lib/relaton/xsf/bibliography.rb +61 -1
- data/lib/relaton/xsf/data_fetcher.rb +55 -5
- data/lib/relaton/xsf/docidentifier.rb +46 -0
- data/lib/relaton/xsf/hit_collection.rb +31 -3
- data/lib/relaton/xsf/item.rb +6 -0
- data/lib/relaton/xsf/processor.rb +1 -0
- data/lib/relaton/xsf.rb +5 -1
- data/lib/relaton.rb +42 -0
- metadata +135 -24
- data/lib/relaton/ieee/pub_id.rb +0 -161
- data/lib/relaton/index/id_number.rb +0 -30
data/lib/relaton/nist/scraper.rb
CHANGED
|
@@ -64,9 +64,12 @@ module Relaton
|
|
|
64
64
|
# @param hit [Hash]
|
|
65
65
|
# @return [Array<Bib::Docidentifier>]
|
|
66
66
|
def fetch_docid(hit)
|
|
67
|
-
ids
|
|
67
|
+
# All ids share the Nist::Docidentifier collection type so YAML
|
|
68
|
+
# serialization stays valid; the DOI is not canonical NIST pubid form,
|
|
69
|
+
# so the class keeps it as the raw string (see Docidentifier#content=).
|
|
70
|
+
ids = [Docidentifier.new(content: hit[:code], type: "NIST", primary: true)]
|
|
68
71
|
doi = hit[:json]["doi"]&.split("/")&.last
|
|
69
|
-
ids <<
|
|
72
|
+
ids << Docidentifier.new(content: doi, type: "DOI") if doi
|
|
70
73
|
ids
|
|
71
74
|
end
|
|
72
75
|
|
|
@@ -262,7 +265,7 @@ module Relaton
|
|
|
262
265
|
t = "obsoletes"
|
|
263
266
|
else t = type
|
|
264
267
|
end
|
|
265
|
-
ids = [
|
|
268
|
+
ids = [Docidentifier.new(content: ref, type: "NIST", primary: true)]
|
|
266
269
|
link = [Bib::Uri.new(type: "src", content: uri)]
|
|
267
270
|
bib = ItemData.new(formattedref: Bib::Formattedref.new(content: ref), source: link, docidentifier: ids)
|
|
268
271
|
Relation.new(type: t, description: descr, bibitem: bib)
|
|
@@ -7,11 +7,18 @@ module Relaton
|
|
|
7
7
|
module Bibliography
|
|
8
8
|
ENDPOINT = "https://raw.githubusercontent.com/relaton/relaton-data-oasis/refs/heads/v2/"
|
|
9
9
|
|
|
10
|
+
# The publisher token every OASIS printed id starts with, and the one
|
|
11
|
+
# thing `Pubid::Oasis`'s grammar requires. See #parse_ref.
|
|
12
|
+
PREFIX = "OASIS "
|
|
13
|
+
|
|
14
|
+
# The components a reference may omit. `number` (the specification name)
|
|
15
|
+
# is deliberately absent — see #ignored.
|
|
16
|
+
OPTIONAL = %i[version stage part label].freeze
|
|
17
|
+
|
|
10
18
|
class << self
|
|
11
19
|
def search(text, _year = nil, _opts = {}) # rubocop:disable Metrics/MethodLength
|
|
12
20
|
Util.info "Fetching from Relaton repository ...", key: text
|
|
13
|
-
|
|
14
|
-
row = find_index_entry(code)
|
|
21
|
+
row = find_index_entry(text)
|
|
15
22
|
unless row
|
|
16
23
|
Util.info "Not found.", key: text
|
|
17
24
|
return
|
|
@@ -33,11 +40,145 @@ module Relaton
|
|
|
33
40
|
|
|
34
41
|
private
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
#
|
|
44
|
+
# The pubid `index-v2`. `pubid_class:` is what makes `Relaton::Index`
|
|
45
|
+
# deserialize the rows into identifiers, sort them by
|
|
46
|
+
# `id.root.number`, and let `Type#search` bsearch; `file:` names the
|
|
47
|
+
# local cache, and `Processor#remove_index_file` must name the same
|
|
48
|
+
# one, or `Db#clear` leaves this cache in place.
|
|
49
|
+
#
|
|
50
|
+
# @return [Relaton::Index::Type]
|
|
51
|
+
#
|
|
52
|
+
def index
|
|
53
|
+
Relaton::Index.find_or_create(
|
|
54
|
+
:oasis, url: "#{ENDPOINT}#{INDEXFILE}.zip",
|
|
55
|
+
file: "#{INDEXFILE}.yaml",
|
|
56
|
+
pubid_class: ::Pubid::Oasis::Identifier
|
|
39
57
|
)
|
|
40
|
-
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Find the row that best answers a reference.
|
|
62
|
+
#
|
|
63
|
+
# **Pass the pubid, not the string.** `Type#search_candidates` narrows
|
|
64
|
+
# only when the argument is not a `String`, so passing the reference
|
|
65
|
+
# text would disable the binary search however the index was built.
|
|
66
|
+
#
|
|
67
|
+
# Selection is `Type#search`'s default with no block — pubid's
|
|
68
|
+
# asymmetric subset match (`Pubid::SubsetMatch`): the reference on the
|
|
69
|
+
# left, and a component it omits (`version`, `stage`, `part`, `label`)
|
|
70
|
+
# matches any value, which is what `#ranking_key` then orders.
|
|
71
|
+
#
|
|
72
|
+
# A reference pubid cannot parse finds nothing, and there is no
|
|
73
|
+
# substring fallback. `#parse_ref` supplies the publisher token, so
|
|
74
|
+
# after normalization the only unparseable inputs are a blank string
|
|
75
|
+
# and one over pubid's 1000-character cap — and a substring scan for
|
|
76
|
+
# `""` matches every row in the index, which is worse than a miss.
|
|
77
|
+
# This is also the v1 -> v2 semantic change IANA recorded: v1 matched
|
|
78
|
+
# by substring, so `OASIS amqp` resolved to some `amqp-core` record;
|
|
79
|
+
# v2 matches identifiers, so a partial name no longer resolves.
|
|
80
|
+
#
|
|
81
|
+
# @param text [String] the reference as the caller wrote it
|
|
82
|
+
# @return [Hash, nil] the index row, or nil
|
|
83
|
+
#
|
|
84
|
+
def find_index_entry(text)
|
|
85
|
+
pubid = parse_ref text
|
|
86
|
+
return unless pubid
|
|
87
|
+
|
|
88
|
+
rows = index.search(pubid)
|
|
89
|
+
rows.max_by { |row| ranking_key pubid, row[:id] }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# An OASIS printed id carries the publisher token, and pubid rejects a
|
|
94
|
+
# bare slug — but a caller may well write one ("mqtt-v5.0"), and
|
|
95
|
+
# `Db#fetch` hands the reference through verbatim. Supplying the token
|
|
96
|
+
# is normalization, not identification, so it happens here rather than
|
|
97
|
+
# in the grammar.
|
|
98
|
+
#
|
|
99
|
+
# The token is stripped **case-insensitively** and re-added in its
|
|
100
|
+
# canonical form. pubid's grammar matches the literal `OASIS `, so a
|
|
101
|
+
# lowercase `oasis stix` would otherwise keep its own token, be given a
|
|
102
|
+
# second one, and search for the specification named `oasis stix`.
|
|
103
|
+
# Everything after the token stays verbatim: an OASIS slug is
|
|
104
|
+
# case-sensitive (`STIX`, `amqp-core`, `OpenDocument`).
|
|
105
|
+
#
|
|
106
|
+
# An unrecognized reference **raises**; like ISO, ETSI and 3GPP we let it
|
|
107
|
+
# propagate. relaton-cli rescues `Pubid::Errors::Error` and renders
|
|
108
|
+
# `"..." is not a recognized standards identifier`
|
|
109
|
+
# (`gems/relaton-cli/lib/relaton/cli/command.rb:324`), and `Db#fetch`
|
|
110
|
+
# logs it through the `StandardError` arm at `lib/relaton/db.rb:122`.
|
|
111
|
+
# Rescuing here would collapse "this identifier is malformed" into "no
|
|
112
|
+
# such document", leaving a caller unable to tell them apart.
|
|
113
|
+
#
|
|
114
|
+
# @param text [String]
|
|
115
|
+
# @return [Pubid::Oasis::Identifier]
|
|
116
|
+
# @raise [Pubid::Errors::ParseError]
|
|
117
|
+
#
|
|
118
|
+
def parse_ref(text)
|
|
119
|
+
slug = text.to_s.strip.sub(/\A#{Regexp.escape PREFIX}/i, "")
|
|
120
|
+
::Pubid::Oasis::Identifier.parse "#{PREFIX}#{slug}"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
#
|
|
124
|
+
# The components the reference left out, which the row may therefore
|
|
125
|
+
# carry freely. `#find_index_entry` no longer needs this list — pubid's
|
|
126
|
+
# `===` reads the omission from the reference itself — but
|
|
127
|
+
# `#ranking_key` still counts the components the caller did not ask for.
|
|
128
|
+
# `number` — the specification name — is never optional: it is the whole
|
|
129
|
+
# identity of an OASIS record and the key the index bsearches on.
|
|
130
|
+
#
|
|
131
|
+
# @param pubid [Pubid::Oasis::Identifier]
|
|
132
|
+
# @return [Array<Symbol>]
|
|
133
|
+
#
|
|
134
|
+
def ignored(pubid)
|
|
135
|
+
OPTIONAL.select { |attr| pubid.public_send(attr).nil? }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
#
|
|
139
|
+
# Order the matched rows. Ignoring a component means "don't care", so a
|
|
140
|
+
# loose reference matches the more specific rows too and this key
|
|
141
|
+
# decides between them:
|
|
142
|
+
#
|
|
143
|
+
# 1. an **exact printed id** always wins. Five published records are a
|
|
144
|
+
# bare specification name that also has versioned siblings — `OASIS
|
|
145
|
+
# EDXL`, `OData`, `OSLC`, `SAML`, `WSS` — and each is a real
|
|
146
|
+
# document in its own right. Without this key the "newest version"
|
|
147
|
+
# rule below answers a request for the bare record with its newest
|
|
148
|
+
# sibling; three of the five did exactly that. Published ids are
|
|
149
|
+
# unique (0 duplicates in 605 rows), so at most one row scores here;
|
|
150
|
+
# 2. then the **newest version**, segments compared as integers —
|
|
151
|
+
# `v2.1` beats `v1.2.1`, and `v10` beats `v9`, which a string
|
|
152
|
+
# compare gets wrong;
|
|
153
|
+
# 3. then the **least specific** row, i.e. the fewest components the
|
|
154
|
+
# reference did not ask for — a bare `OASIS STIX` wants `STIX-v2.1`,
|
|
155
|
+
# not `STIX-v2.1-CS02`, and `OASIS STIX-v1.2.1-CS01` wants that
|
|
156
|
+
# record itself, not its `-Pt3-Core` part;
|
|
157
|
+
# 4. then the **later stage revision** (`CS02` over `CS01`). Only the
|
|
158
|
+
# digits are compared: OASIS stage letters have no ranking this code
|
|
159
|
+
# is entitled to invent;
|
|
160
|
+
# 5. then the printed id, so the result never depends on index order.
|
|
161
|
+
#
|
|
162
|
+
# Checked against every published row: all 605 resolve to their own
|
|
163
|
+
# record, with and without the publisher token.
|
|
164
|
+
#
|
|
165
|
+
# @param pubid [Pubid::Oasis::Identifier] the parsed reference
|
|
166
|
+
# @param id [Pubid::Oasis::Identifier] a matched row's id
|
|
167
|
+
# @return [Array]
|
|
168
|
+
#
|
|
169
|
+
def ranking_key(pubid, id)
|
|
170
|
+
exact = id.to_s == pubid.to_s ? 1 : 0
|
|
171
|
+
extra = ignored(pubid).count { |attr| id.public_send(attr) }
|
|
172
|
+
[exact, digits(id.version), -extra, digits(id.stage), id.to_s]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Integer segments of a version or stage token, for numeric ordering
|
|
176
|
+
# ("v1.2.1" -> [1, 2, 1], "CS02" -> [2], nil -> []).
|
|
177
|
+
#
|
|
178
|
+
# @param token [String, nil]
|
|
179
|
+
# @return [Array<Integer>]
|
|
180
|
+
def digits(token)
|
|
181
|
+
token.to_s.scan(/\d+/).map(&:to_i)
|
|
41
182
|
end
|
|
42
183
|
|
|
43
184
|
def fetch_yaml(uri)
|
|
@@ -48,9 +48,13 @@ module Relaton
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
# `pubid_class:` on the producer too: FileIO#save only calls `to_hash`
|
|
52
|
+
# for instances of it, so without it the crawl writes v1-shaped rows
|
|
53
|
+
# under a v2 name, silently.
|
|
51
54
|
def index
|
|
52
55
|
@index ||= Relaton::Index.find_or_create(
|
|
53
|
-
:oasis, file: "#{INDEXFILE}.yaml"
|
|
56
|
+
:oasis, file: "#{INDEXFILE}.yaml",
|
|
57
|
+
pubid_class: ::Pubid::Oasis::Identifier
|
|
54
58
|
)
|
|
55
59
|
end
|
|
56
60
|
|
|
@@ -68,16 +72,48 @@ module Relaton
|
|
|
68
72
|
|
|
69
73
|
def save_doc(doc) # rubocop:disable Metrics/AbcSize
|
|
70
74
|
id = doc.docidentifier.find(&:primary) || doc.docidentifier.first
|
|
71
|
-
|
|
75
|
+
# Distinct docids can sanitize to one filename; take a path of our own
|
|
76
|
+
# rather than overwriting the other document (Core#unique_output_file).
|
|
77
|
+
file = unique_output_file(id.content)
|
|
72
78
|
if @files.include? file
|
|
79
|
+
# Same reserved path == same docid: a genuine duplicate. Checked FIRST,
|
|
80
|
+
# because a disambiguated path stays != output_file forever.
|
|
73
81
|
Util.warn "File #{file} already exists. Document: #{id.content}"
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
elsif file != output_file(id.content)
|
|
83
|
+
Util.warn "File #{output_file id.content} already exists. " \
|
|
84
|
+
"Document: #{id.content}. Writing #{file} instead."
|
|
76
85
|
end
|
|
77
|
-
|
|
86
|
+
@files << file
|
|
87
|
+
add_to_index id, file
|
|
78
88
|
File.write file, serialize(doc), encoding: "UTF-8"
|
|
79
89
|
end
|
|
80
90
|
|
|
91
|
+
#
|
|
92
|
+
# Index the document, or record why it could not be indexed.
|
|
93
|
+
#
|
|
94
|
+
# An id pubid cannot parse is recorded in `@errors` — the inherited
|
|
95
|
+
# `report_errors` logs a String value as the message — and the row is
|
|
96
|
+
# skipped rather than indexed unparsed: `Relaton::Index` rejects the WHOLE
|
|
97
|
+
# index if a single row fails to deserialize, and its sort calls
|
|
98
|
+
# `.root.number` on every id. The data file is still written by the
|
|
99
|
+
# caller, so the document is unindexed, never lost. (The ECMA/W3C/3GPP
|
|
100
|
+
# shape.)
|
|
101
|
+
#
|
|
102
|
+
# `DataParserUtils#record_unparseable_id` already recorded this id when it
|
|
103
|
+
# was built, under the SAME key — the id string. This entry overwrites it
|
|
104
|
+
# with the same sentence plus the output file, so a saved document reports
|
|
105
|
+
# one line, the more informative one. Keep the two keys identical.
|
|
106
|
+
#
|
|
107
|
+
# @param id [Relaton::Oasis::Docidentifier] primary document identifier
|
|
108
|
+
# @param file [String] path the document is written to
|
|
109
|
+
#
|
|
110
|
+
def add_to_index(id, file)
|
|
111
|
+
return index.add_or_update(id.pubid, file) if id.pubid
|
|
112
|
+
|
|
113
|
+
@errors[id.content.to_s] =
|
|
114
|
+
"Unparseable primary id `#{id.content}` was not indexed (#{file})"
|
|
115
|
+
end
|
|
116
|
+
|
|
81
117
|
def to_xml(bib)
|
|
82
118
|
bib.to_xml(bibdata: true)
|
|
83
119
|
end
|
|
@@ -240,16 +240,50 @@ module Relaton
|
|
|
240
240
|
#
|
|
241
241
|
# Parse document identifier.
|
|
242
242
|
#
|
|
243
|
-
# @return [Array<
|
|
243
|
+
# @return [Array<Relaton::Oasis::Docidentifier>] document identifier
|
|
244
244
|
#
|
|
245
245
|
def parse_docid
|
|
246
246
|
id = "OASIS #{parse_docnumber}"
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
docid = Docidentifier.new(type: "OASIS", content: id, primary: true)
|
|
248
|
+
record_unparseable_id docid
|
|
249
|
+
result = [docid]
|
|
249
250
|
@errors[:docid] &&= result.empty?
|
|
250
251
|
result
|
|
251
252
|
end
|
|
252
253
|
|
|
254
|
+
#
|
|
255
|
+
# Surface an id pubid could not parse through the shared error-reporting
|
|
256
|
+
# machinery, so the crawl's "Error fetching documents" GitHub issue names
|
|
257
|
+
# it instead of dropping it silently in the action log.
|
|
258
|
+
#
|
|
259
|
+
# `Core::DataFetcher#report_errors` logs a **String** value verbatim as
|
|
260
|
+
# the message (a boolean means "this field failed for every record" and
|
|
261
|
+
# takes its message from the key), and the parsers share the fetcher's own
|
|
262
|
+
# `@errors` hash, so an entry written here reaches the issue unchanged.
|
|
263
|
+
#
|
|
264
|
+
# **Why here and not only in the fetcher.** W3C, 3GPP and ISO record this
|
|
265
|
+
# at index time, where the output file is known. OASIS records it at build
|
|
266
|
+
# time as well, because this is the one place EVERY id is built — the part
|
|
267
|
+
# ids that only ever become a relation's `formattedref`
|
|
268
|
+
# (`DataParser#parse_relation`, `DataPartParser#parse_relation`) never
|
|
269
|
+
# reach `DataFetcher#save_doc`, so an index-time hook alone cannot see
|
|
270
|
+
# them. `DataFetcher#add_to_index` keys its own entry on the same id
|
|
271
|
+
# string, so a document that IS saved reports once, through the fetcher's
|
|
272
|
+
# message, which additionally names the file.
|
|
273
|
+
#
|
|
274
|
+
# The docidentifier is returned either way: the document is still written,
|
|
275
|
+
# it is only left out of the index — `Relaton::Index` rejects the WHOLE
|
|
276
|
+
# index if a single row fails to deserialize.
|
|
277
|
+
#
|
|
278
|
+
# @param docid [Relaton::Oasis::Docidentifier] the id just built
|
|
279
|
+
#
|
|
280
|
+
def record_unparseable_id(docid)
|
|
281
|
+
return if docid.pubid
|
|
282
|
+
|
|
283
|
+
content = docid.content.to_s
|
|
284
|
+
@errors[content] = "Unparseable primary id `#{content}` was not indexed"
|
|
285
|
+
end
|
|
286
|
+
|
|
253
287
|
#
|
|
254
288
|
# Parse document type.
|
|
255
289
|
#
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Relaton
|
|
2
|
+
module Oasis
|
|
3
|
+
# Structured OASIS document identifier. The docid string is the printed
|
|
4
|
+
# form, which carries the "OASIS " publisher token
|
|
5
|
+
# (e.g. "OASIS OSLC-CoreShapes-3.0-PS01-Pt8"), and it is parsed into a
|
|
6
|
+
# `Pubid::Oasis::Identifier` kept in `@pubid` while the lutaml `content`
|
|
7
|
+
# attribute stays a plain string for serialization.
|
|
8
|
+
#
|
|
9
|
+
# Parsing is **soft**: `content=` lazily requires pubid and rescues
|
|
10
|
+
# `LoadError`/`StandardError`, so a missing pubid gem or non-OASIS content
|
|
11
|
+
# leaves `@pubid` nil rather than raising. A reference without the publisher
|
|
12
|
+
# token ("amqp-core") is not an OASIS printed id, so it leaves `@pubid` nil
|
|
13
|
+
# too; `DataFetcher` always builds the token-carrying form.
|
|
14
|
+
#
|
|
15
|
+
# ## Why the three mutators stay no-ops
|
|
16
|
+
#
|
|
17
|
+
# `Pubid::Oasis::Renderer` echoes the verbatim slug held in `original`, so
|
|
18
|
+
# clearing `part`, `version` or `stage` cannot change the printed id — the
|
|
19
|
+
# mutation would be invisible, and rewriting `original` would invent a
|
|
20
|
+
# reference form OASIS does not publish. OASIS slugs are free-form with an
|
|
21
|
+
# inconsistent internal structure, and no OASIS citation drops a part or a
|
|
22
|
+
# version; there is no "all parts" or "most recent" spelling to render.
|
|
23
|
+
#
|
|
24
|
+
# So this class deliberately does NOT override `remove_part!`,
|
|
25
|
+
# `remove_date!` or `to_all_parts!`. Since `dfbd26c72` the `Bib::Docidentifier`
|
|
26
|
+
# defaults are no-ops rather than `NotImplementedError` raises, so
|
|
27
|
+
# `Bib::ItemData#to_all_parts` and `#to_most_recent_reference` return the
|
|
28
|
+
# item unchanged instead of blowing up. That is the honest OASIS answer.
|
|
29
|
+
# (Contrast `Relaton::Ogc::Docidentifier`, whose components really do
|
|
30
|
+
# render, so its mutators re-render the content.)
|
|
31
|
+
class Docidentifier < Bib::Docidentifier
|
|
32
|
+
attr_reader :pubid
|
|
33
|
+
|
|
34
|
+
def initialize(attrs = {}, options = {})
|
|
35
|
+
pubid = attrs.is_a?(Hash) ? attrs.delete(:pubid) : nil
|
|
36
|
+
attrs[:content] ||= pubid.to_s if pubid
|
|
37
|
+
super
|
|
38
|
+
@pubid = pubid if pubid
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def content=(value)
|
|
42
|
+
super
|
|
43
|
+
return unless value
|
|
44
|
+
|
|
45
|
+
@pubid = begin
|
|
46
|
+
require "pubid"
|
|
47
|
+
::Pubid::Oasis::Identifier.parse(value.to_s)
|
|
48
|
+
rescue LoadError, StandardError
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/relaton/oasis/item.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require_relative "docidentifier"
|
|
1
2
|
require_relative "ext"
|
|
2
3
|
|
|
3
4
|
module Relaton
|
|
@@ -5,6 +6,8 @@ module Relaton
|
|
|
5
6
|
class Item < Bib::Item
|
|
6
7
|
model ItemData
|
|
7
8
|
|
|
9
|
+
attribute :docidentifier, Docidentifier, collection: true,
|
|
10
|
+
initialize_empty: true
|
|
8
11
|
attribute :ext, Ext
|
|
9
12
|
end
|
|
10
13
|
end
|
|
@@ -11,6 +11,7 @@ module Relaton
|
|
|
11
11
|
@defaultprefix = %r{^OASIS\s}
|
|
12
12
|
@idtype = "OASIS"
|
|
13
13
|
@datasets = %w[oasis-open]
|
|
14
|
+
@pubid_flavor = :Oasis
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
# @param code [String]
|
|
@@ -59,9 +60,14 @@ module Relaton
|
|
|
59
60
|
#
|
|
60
61
|
# Remove index file
|
|
61
62
|
#
|
|
63
|
+
# `url: true` names the cached file. No `pubid_class:`: `Type#remove_file`
|
|
64
|
+
# deletes the file and never reads the index.
|
|
65
|
+
#
|
|
62
66
|
def remove_index_file
|
|
63
67
|
require_relative "../oasis"
|
|
64
|
-
Relaton::Index.find_or_create(
|
|
68
|
+
Relaton::Index.find_or_create(
|
|
69
|
+
:oasis, url: true, file: "#{INDEXFILE}.yaml"
|
|
70
|
+
).remove_file
|
|
65
71
|
end
|
|
66
72
|
end
|
|
67
73
|
end
|
data/lib/relaton/oasis.rb
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Not lazy: DataFetcher names ::Pubid::Oasis::Identifier as the index
|
|
4
|
+
# `pubid_class:`, and Docidentifier parses every docid through it.
|
|
5
|
+
# (The IANA/IHO/IALA/OGC/ECMA form; spec/relaton/lazy_loading_spec.rb guards
|
|
6
|
+
# that this file is not itself loaded when a Db is built.)
|
|
7
|
+
require "pubid"
|
|
3
8
|
require "relaton/index"
|
|
4
9
|
require "relaton/bib"
|
|
5
10
|
require_relative "version"
|
|
@@ -12,7 +17,15 @@ require_relative "oasis/bibliography"
|
|
|
12
17
|
|
|
13
18
|
module Relaton
|
|
14
19
|
module Oasis
|
|
15
|
-
|
|
20
|
+
# The pubid index, both written and read: rows are
|
|
21
|
+
# `Pubid::Oasis::Identifier` hashes (`_type: pubid:oasis:standard`), built
|
|
22
|
+
# and read with `pubid_class: ::Pubid::Oasis::Identifier`.
|
|
23
|
+
#
|
|
24
|
+
# This gem does not produce `index-v1` any more; `relaton-data-oasis`'s
|
|
25
|
+
# crawler derives it from the v2 rows for relaton v2 consumers (the
|
|
26
|
+
# IANA/BIPM/W3C/ECMA shape).
|
|
27
|
+
INDEXFILE = "index-v2".freeze
|
|
28
|
+
|
|
16
29
|
class Error < StandardError; end
|
|
17
30
|
# Your code goes here...
|
|
18
31
|
|
|
@@ -23,7 +23,12 @@ module Relaton
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def index
|
|
26
|
-
|
|
26
|
+
# `pubid_class:` on the producer too: FileIO#save only calls `to_hash`
|
|
27
|
+
# when the value is an instance of it, so without it the crawl writes
|
|
28
|
+
# v1-shaped rows under a v2 name, silently.
|
|
29
|
+
@index ||= Relaton::Index.find_or_create(
|
|
30
|
+
:ogc, file: "#{INDEXFILE}.yaml", pubid_class: ::Pubid::Ogc::Identifier
|
|
31
|
+
)
|
|
27
32
|
end
|
|
28
33
|
|
|
29
34
|
def fetch(_source = nil) # rubocop:disable Metrics/AbcSize
|
|
@@ -60,10 +65,26 @@ module Relaton
|
|
|
60
65
|
|
|
61
66
|
@docids << docid
|
|
62
67
|
file = file_name bib
|
|
63
|
-
index.add_or_update docid, file
|
|
68
|
+
index.add_or_update index_id(docid), file
|
|
64
69
|
File.write file, serialize(bib), encoding: "UTF-8"
|
|
65
70
|
end
|
|
66
71
|
|
|
72
|
+
#
|
|
73
|
+
# The index key. Stored as a `Pubid::Ogc::Identifier` so the published
|
|
74
|
+
# index-v2 rows are pubid hashes the consumer can narrow on. A docid
|
|
75
|
+
# pubid rejects is logged and indexed as the plain string, so one bad
|
|
76
|
+
# record never aborts a crawl.
|
|
77
|
+
#
|
|
78
|
+
# @param docid [String]
|
|
79
|
+
# @return [Pubid::Ogc::Identifier, String]
|
|
80
|
+
#
|
|
81
|
+
def index_id(docid)
|
|
82
|
+
::Pubid::Ogc::Identifier.parse docid
|
|
83
|
+
rescue StandardError => e
|
|
84
|
+
Util.warn "Failed to parse pubid `#{docid}`: #{e.message}"
|
|
85
|
+
docid
|
|
86
|
+
end
|
|
87
|
+
|
|
67
88
|
def file_name(bib)
|
|
68
89
|
name = bib.docidentifier[0].content.upcase.gsub(/[\s:.]/, "_")
|
|
69
90
|
"#{@output}/#{name}.#{@ext}"
|
|
@@ -1,6 +1,111 @@
|
|
|
1
1
|
module Relaton
|
|
2
2
|
module Ogc
|
|
3
|
+
# Structured OGC document identifier. The docid string is the canonical
|
|
4
|
+
# printed form, which carries no publisher token (e.g. "19-025r1"), and it
|
|
5
|
+
# is parsed into a `Pubid::Ogc::Identifier` kept in `@pubid` while the
|
|
6
|
+
# lutaml `content` attribute stays a plain string for serialization.
|
|
7
|
+
#
|
|
8
|
+
# Parsing is **soft**: `content=` lazily requires pubid and rescues
|
|
9
|
+
# `LoadError`/`StandardError`, so a missing pubid gem or non-OGC content
|
|
10
|
+
# leaves `@pubid` nil rather than raising.
|
|
11
|
+
#
|
|
12
|
+
# Before this class had a body it inherited `Bib::Docidentifier`, whose
|
|
13
|
+
# `remove_part!` / `remove_date!` / `to_all_parts!` each raise
|
|
14
|
+
# `NotImplementedError` — and `Bib::ItemData` broadcasts all three to every
|
|
15
|
+
# docidentifier, so `#to_all_parts` and `#to_most_recent_reference` raised
|
|
16
|
+
# on **every** OGC item. `NotImplementedError` descends from `ScriptError`,
|
|
17
|
+
# so a caller's `rescue => e` did not even catch it.
|
|
3
18
|
class Docidentifier < Bib::Docidentifier
|
|
19
|
+
attr_reader :pubid
|
|
20
|
+
|
|
21
|
+
# Capture the inherited (LocalizedMarkedUpString) content setter before
|
|
22
|
+
# overriding #content=, so #refresh_content! can write the re-rendered
|
|
23
|
+
# string back WITHOUT re-parsing (a re-parse would rebuild @pubid from the
|
|
24
|
+
# string and discard in-place mutations such as `all_parts = true`).
|
|
25
|
+
alias_method :store_content, :content=
|
|
26
|
+
|
|
27
|
+
def initialize(attrs = {}, options = {})
|
|
28
|
+
pubid = attrs.is_a?(Hash) ? attrs.delete(:pubid) : nil
|
|
29
|
+
attrs[:content] ||= pubid.to_s if pubid
|
|
30
|
+
super
|
|
31
|
+
@pubid = pubid if pubid
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def content=(value)
|
|
35
|
+
super
|
|
36
|
+
return unless value
|
|
37
|
+
|
|
38
|
+
@pubid = begin
|
|
39
|
+
require "pubid"
|
|
40
|
+
::Pubid::Ogc::Identifier.parse(value)
|
|
41
|
+
rescue LoadError, StandardError
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# `Pubid::Ogc::Identifier` models only `year`/`number`/`revision`, so the
|
|
47
|
+
# mapping is OGC-specific:
|
|
48
|
+
#
|
|
49
|
+
# - **`remove_date!` → clears `revision`.** OGC carries no date component;
|
|
50
|
+
# `revision` is its version discriminator — the same component a
|
|
51
|
+
# reference may omit, which `HitCollection#best_match` then treats as a
|
|
52
|
+
# wildcard — so clearing it yields
|
|
53
|
+
# the version-agnostic ("most recent") reference: `12-128r19` →
|
|
54
|
+
# `12-128`.
|
|
55
|
+
# - **`year` is never cleared.** It looks date-like but is half the
|
|
56
|
+
# document number (`12-128`), not a publication qualifier; dropping it
|
|
57
|
+
# would leave `-128`, which identifies nothing.
|
|
58
|
+
# - **`remove_part!` → clears the (unused) `part`/`subpart` attributes.**
|
|
59
|
+
# A no-op for the rendered string today: OGC has no part component.
|
|
60
|
+
# Implemented anyway so it never raises, and it starts working
|
|
61
|
+
# automatically if pubid-ogc ever models one. (The IALA precedent.)
|
|
62
|
+
# - **`to_all_parts!` → both, then wraps `@pubid` in pubid's `AllParts`.**
|
|
63
|
+
# `content` stays the plain stripped id — OGC's own renderer has no
|
|
64
|
+
# "(all parts)" marker, and `content` is cached from the pre-wrap
|
|
65
|
+
# pubid on purpose. `#pubid` itself, read directly, now answers
|
|
66
|
+
# `all_parts? == true` and renders WITH pubid's generic marker
|
|
67
|
+
# (`#to_s`), since it's the wrapper.
|
|
68
|
+
#
|
|
69
|
+
# All three no-op safely when `@pubid` is nil, so `Bib::ItemData`'s
|
|
70
|
+
# `#to_all_parts` / `#to_most_recent_reference` never raise on OGC items.
|
|
71
|
+
#
|
|
72
|
+
# `refresh_content!` renders a bare `to_s`: the OGC printed form has no
|
|
73
|
+
# publisher token and the stored `content` does not carry one either, so
|
|
74
|
+
# unlike 3GPP this must NOT pass `with_publisher: true`.
|
|
75
|
+
|
|
76
|
+
def remove_part!
|
|
77
|
+
clear_attr!(:part)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def remove_date!
|
|
81
|
+
clear_attr!(:revision)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def to_all_parts!
|
|
85
|
+
return if !@pubid || @pubid.all_parts?
|
|
86
|
+
|
|
87
|
+
# `#exclude` (no args) rebuilds a full independent copy — `remove_part!`
|
|
88
|
+
# / `remove_date!` mutate `@pubid` in place, so a bare reference here
|
|
89
|
+
# would lose the original revision to that mutation too.
|
|
90
|
+
original = @pubid.exclude
|
|
91
|
+
remove_part!
|
|
92
|
+
remove_date!
|
|
93
|
+
@pubid = original.to_all_parts
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def clear_attr!(attr)
|
|
99
|
+
return unless @pubid && @pubid.respond_to?("#{attr}=")
|
|
100
|
+
|
|
101
|
+
@pubid.public_send("#{attr}=", nil)
|
|
102
|
+
@pubid.subpart = nil if attr == :part && @pubid.respond_to?(:subpart=)
|
|
103
|
+
refresh_content!
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def refresh_content!
|
|
107
|
+
store_content(@pubid.to_s) if @pubid
|
|
108
|
+
end
|
|
4
109
|
end
|
|
5
110
|
end
|
|
6
111
|
end
|