relaton 3.0.2 → 3.0.3
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/bipm.rb +0 -1
- data/lib/relaton/core/processor.rb +1 -1
- data/lib/relaton/db/registry.rb +1 -1
- data/lib/relaton/db.rb +3 -3
- data/lib/relaton/nist/CLAUDE.md +2 -1
- data/lib/relaton/nist/bibliography.rb +31 -0
- data/lib/relaton/nist/cswp.rb +137 -0
- data/lib/relaton/nist/cswp.yaml +155 -0
- data/lib/relaton/nist/processor.rb +20 -0
- data/lib/relaton/nist.rb +1 -0
- data/lib/relaton/version.rb +1 -1
- metadata +40 -76
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a774b326943089257e3aef6e5402fc1e2d53d4ff557e8b19f845a62d64b9a99b
|
|
4
|
+
data.tar.gz: 665fa378d2380f79a4e2952df1ff3d0f7e1de6d91ead262d75261555a4170e5c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bfa2af357a4e288f0ce97fb82ff78ac58b39bc8f8fc8659584ebb29a4568a50175137b8b8cd32b6710aff65b8413cb4ab0d1ea674918187edd9a74592e331a6c
|
|
7
|
+
data.tar.gz: e2ad6a9822a6ffa5f9a625bb4095260b81b3906fcff8ba0cf4fbdcea0d543f9e2b14133c7dd29dad0f165c26713b16fc0f06ebfc06d134384d4d0f280ee873b1
|
data/lib/relaton/bipm.rb
CHANGED
|
@@ -67,7 +67,7 @@ module Relaton
|
|
|
67
67
|
# @return [Pubid::Identifier, nil]
|
|
68
68
|
def cache_pubid(ref)
|
|
69
69
|
pubid_class&.parse(ref)
|
|
70
|
-
rescue ArgumentError, ::Pubid::Errors::Error
|
|
70
|
+
rescue ArgumentError, ::Pubid::Errors::Error
|
|
71
71
|
# relaton-bib carries the log facade; core specs load without it.
|
|
72
72
|
require "relaton/bib"
|
|
73
73
|
Relaton::Bib::Util.info "does not parse as this flavor's pubid; " \
|
data/lib/relaton/db/registry.rb
CHANGED
data/lib/relaton/db.rb
CHANGED
|
@@ -226,7 +226,7 @@ module Relaton
|
|
|
226
226
|
# reference they cannot read is not-found, not a failure (relaton#412).
|
|
227
227
|
def unreadable_reference?(error)
|
|
228
228
|
(defined?(Pubid::Errors::Error) && error.is_a?(Pubid::Errors::Error)) ||
|
|
229
|
-
|
|
229
|
+
false
|
|
230
230
|
end
|
|
231
231
|
|
|
232
232
|
# The flavor routing picks for `fetch_async`'s per-flavor queue; nil
|
|
@@ -389,7 +389,7 @@ module Relaton
|
|
|
389
389
|
return unless docid&.content
|
|
390
390
|
|
|
391
391
|
cache_key docid.content, nil, {}, stdclass
|
|
392
|
-
rescue ::Pubid::Errors::Error
|
|
392
|
+
rescue ::Pubid::Errors::Error
|
|
393
393
|
nil
|
|
394
394
|
end
|
|
395
395
|
|
|
@@ -456,7 +456,7 @@ module Relaton
|
|
|
456
456
|
def copublisher_query(code, opts, stdclass, publisher)
|
|
457
457
|
query = begin
|
|
458
458
|
@registry[stdclass].query_pubid(code, opts)
|
|
459
|
-
rescue ::Pubid::Errors::Error
|
|
459
|
+
rescue ::Pubid::Errors::Error
|
|
460
460
|
nil
|
|
461
461
|
end
|
|
462
462
|
return query if query
|
data/lib/relaton/nist/CLAUDE.md
CHANGED
|
@@ -64,7 +64,8 @@ All data models inherit from `Lutaml::Model::Serializable` and use declarative a
|
|
|
64
64
|
- **Per-record resilience (mirrors the ISO flavor).** A single bad record must never abort the crawl. `#write_file` skips (never `id.content`-crashes on) a record whose MODS entry yields **no docidentifier** (e.g. a DOI stored only in `<identifier type="doi">`, which `ModsParser#parse_doi` doesn't read), and records ids that `#pubid` can't parse (new series like `NIST RB`/`NIST CHIPS`) as "not indexed" — the YAML is still written, only the index-v2 entry is skipped. Both classes accumulate in `#failures`; the `#report_errors` override emits each at `:error` (via `#log_error` → `Util.error`), which the shared `Core::DataFetcher` gh_issue machinery turns into one "Error fetching documents" GitHub issue in CI (`GITHUB_REPOSITORY` + `GITHUB_TOKEN`). `#pubid` no longer warns per-failure; reporting is centralized in `#report_errors`.
|
|
65
65
|
- **Draft-stage rows come from CSRC (relaton#313).** The MODS collection has no draft records, so `#fetch_csrc` adds the CSRC pubs-export feed (`PubsExport.instance.data`) after the MODS pass. It builds each row **exactly as the runtime builds a CSRC hit** — `HitCollection#hit_data` (which calls `#pubs_export_id`) → `Scraper.parse_page` — so the crawled id and the live id are one string, with the stage, revision and update from the row's uri and DOI (`NIST FIPS 197/Upd1 ipd`, `NIST SP 800-108r1 ipd`, `NIST SP 1800-12 2pd`). Only a row whose id carries a **stage** is written; finals come from MODS, so a CSRC row never shadows a base document. On the 914-row fixture feed this writes 302 staged records. Don't go back to a hand-built `"NIST #{series} #{docnumber} #{stage}"` id: it dropped the numbered drafts (`2pd`…), the `/UpdN`, and spelled revisions `Rev. 1`. A stage that CSRC does not list (e.g. `NIST FIPS 197 fpd`) still answers through the consumer's #303 family fallback. Three more rules: `#csrc_bib` clears the `fetched` date the runtime stamps, or every draft changes each day and `Core#force_write` rewrites ~300 files per incremental crawl; CSRC lists a republished draft twice (`…/ipd` and `…/ipd-(1)`, one DOI, so one id), so each id is written once and the plain uri wins; and only the build step is rescued (to a `#failures` entry) — a write error stops the crawl, as in the MODS pass. `#pubs_export_id` must not mutate its row (`sub`, not `sub!`): the crawler and the runtime share the `PubsExport` data.
|
|
66
66
|
- **A CSRC relation names the related document (relaton#314).** `Scraper#related_id` finds the related feed row by its uri and derives its id with `HitCollection.pubs_export_id` (the class method the instance method delegates to). The entry's own `docidentifier` drops the update and the part, and the hit's code is the record's own id, so neither is the related id. `HitCollection#search_filter` ends in an `ensure` that returns `arr`: every branch must set `arr`, because an earlier `return` is overridden there.
|
|
67
|
-
- **CSWP comes from CSRC, not the NIST Library (relaton-nist#104).** The NIST Library announced CSWP data, but its MODS release (`allrecords-MODS.xml`, and the MARC `allrecords.xml`) holds **no** CSWP record — 0 on the Sept2026 release. It publishes CSWPs only as RIS/BibTeX files under `bib/` on its `nist-pages` branch. So the index has only the CSRC draft CSWP rows (`#fetch_csrc`), and a final CSWP answers from CSRC at runtime: `HitCollection#search` asks the CSRC feed (`from_json`) and asks the index (`from_ga`) only when CSRC gives no hit. That is the chosen rule — CSRC wins, no merge — because CSRC lists every numbered CSWP with more metadata (affiliations, status, supersedes, comment period).
|
|
67
|
+
- **CSWP comes from CSRC, not the NIST Library (relaton-nist#104).** The NIST Library announced CSWP data, but its MODS release (`allrecords-MODS.xml`, and the MARC `allrecords.xml`) holds **no** CSWP record — 0 on the Sept2026 release. It publishes CSWPs only as RIS/BibTeX files under `bib/` on its `nist-pages` branch. So the index has only the CSRC draft CSWP rows (`#fetch_csrc`), and a final CSWP answers from CSRC at runtime: `HitCollection#search` asks the CSRC feed (`from_json`) and asks the index (`from_ga`) only when CSRC gives no hit. That is the chosen rule — CSRC wins, no merge — because CSRC lists every numbered CSWP with more metadata (affiliations, status, supersedes, comment period). `hit_collection_spec.rb` pins the CSRC answer.
|
|
68
|
+
- **Legacy dated CSWP ids and CSWP translations come from a static table (relaton#406).** CSRC lists neither the ~30 **legacy dated ids** (`NIST CSWP 01142020`, the same paper as `CSWP 9`, from before NIST numbered the series) nor the translations (`NIST.CSWP.6.spa`). `cswp.yaml` holds both, built once from the 84 RIS files (header of the file says how), and `Cswp` reads it. `Bibliography.get` asks `Cswp.lookup` **first** — the parenthetical-date regex after it would strip `(spa)`. A legacy id fetches the numbered id through the normal CSRC path and adds the dated id as a non-primary docidentifier (`06222021-draft` → the CSRC `CSWP 19 ipd`); a translation, dated or numbered, answers an offline record from the table (`NIST CSWP 6(spa)`, the RIS title/authors/year/DOI, `language`/`script` from `Cswp::LANGUAGES`, a `translatedFrom` relation to the original). `normalize` reads `NIST CSWP 6 spa`, `NIST CSWP 6(spa)` and `NIST.CSWP.6.spa` as one key. `Processor#cache_pubid` returns nil (so `Db` hands `get` the String and does not cache) for **every legacy id** and for a translation that pubid does not render back. A legacy answer is the numbered record plus the dated id, and `Db` would store it under the numbered id's row, so a later `NIST CSWP 9` would carry `NIST CSWP 01142020`. pubid reads `04162018ar` as `04162018a`, `6 spa` as `6(spa)`, and fails on `04162018bg`/`02122014pl`. A translation answers only for its own RIS year. Not mapped, on purpose: `02042022-1`…`-5` have no SN and share the title "Cybersecurity White Paper: EO Response", so they still answer not-found. The CSRC `ipd` rows of `27`/`29`/`32` already answer, so the table leaves out their RIS files. A new translation means a new table row.
|
|
68
69
|
- **`#write_file` serializes before it indexes**, so a record that fails to serialize leaves no index row naming a file that was never written. That is how a `Bib::Date` in `Scraper.fetch_dates` hid: `Nist::ItemData` takes `Nist::Date`, and YAML serialization rejects the parent class (the same strictness as the docidentifier note below).
|
|
69
70
|
- `ModsParser` — maps MODS XML (via `loc_mods`) to `ItemData`
|
|
70
71
|
- `Scraper` — fetches items from GitHub YAML or CSRC JSON
|
|
@@ -39,6 +39,9 @@ module Relaton
|
|
|
39
39
|
# read back as its printed form; the pubid itself is not changed.
|
|
40
40
|
ref = ref.to_s unless ref.is_a?(String)
|
|
41
41
|
return fetch_ref_err(ref, year, []) if ref.match?(/\sEP$/)
|
|
42
|
+
# Before the parsing below, which reads "(spa)" as a date.
|
|
43
|
+
cswp = Cswp.lookup(ref)
|
|
44
|
+
return cswp_get(ref, cswp, year, opts) if cswp
|
|
42
45
|
|
|
43
46
|
/^(?<code2>[^(]+)(?:\((?<date2>\w+\s(?:\d{2},\s)?\d{4})\))?\s?\(?(?:(?<=\()(?<stage>(?:I|F|\d)PD))?/ =~ ref
|
|
44
47
|
stage ||= /(?<=\.)PD-\w+(?=\.)/.match(ref)&.to_s
|
|
@@ -62,6 +65,34 @@ module Relaton
|
|
|
62
65
|
|
|
63
66
|
private
|
|
64
67
|
|
|
68
|
+
#
|
|
69
|
+
# Get a CSWP that CSRC does not list (relaton#406). A legacy dated id
|
|
70
|
+
# answers the numbered CSRC record, with the dated id as an extra
|
|
71
|
+
# docidentifier; a translation answers its record from the RIS table.
|
|
72
|
+
#
|
|
73
|
+
# @param ref [String] reference
|
|
74
|
+
# @param cswp [Array] the Cswp.lookup result
|
|
75
|
+
# @param year [String, nil] year
|
|
76
|
+
# @param opts [Hash] options
|
|
77
|
+
#
|
|
78
|
+
# @return [Relaton::Nist::ItemData, nil] bibliographic item
|
|
79
|
+
#
|
|
80
|
+
def cswp_get(ref, cswp, year, opts)
|
|
81
|
+
type, id, dated = cswp
|
|
82
|
+
if type == :translation
|
|
83
|
+
return fetch_ref_err(ref, year, [id[:year]]) if year && year.to_s != id[:year]
|
|
84
|
+
|
|
85
|
+
item = Cswp.translation_item(id)
|
|
86
|
+
Util.info "Found: `#{item.docidentifier.first.content}`", key: ref
|
|
87
|
+
return item
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
Util.info "Legacy dated CSWP id, fetching `#{id}`", key: ref
|
|
91
|
+
item = nistbib_get(id, year, opts)
|
|
92
|
+
item&.docidentifier&.<< Docidentifier.new(content: dated, type: "NIST")
|
|
93
|
+
item
|
|
94
|
+
end
|
|
95
|
+
|
|
65
96
|
#
|
|
66
97
|
# Get NIST document by reference
|
|
67
98
|
#
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Nist
|
|
5
|
+
#
|
|
6
|
+
# CSWP ids the CSRC pubs-export feed does not list (relaton#406): the
|
|
7
|
+
# legacy dated ids from before the series was numbered, and the
|
|
8
|
+
# translations. The table (`cswp.yaml`) is built from the NIST Library RIS
|
|
9
|
+
# files; see the header of that file.
|
|
10
|
+
#
|
|
11
|
+
# This file loads no flavor model at require time, so the processor can
|
|
12
|
+
# ask #lookup on the cold path. #translation_item needs the models.
|
|
13
|
+
#
|
|
14
|
+
module Cswp
|
|
15
|
+
# ISO 639-2 code of a translation => [ISO 639-1 code, ISO 15924 script]
|
|
16
|
+
LANGUAGES = {
|
|
17
|
+
"ara" => %w[ar Arab], "bul" => %w[bg Cyrl], "fre" => %w[fr Latn],
|
|
18
|
+
"gre" => %w[el Grek], "ind" => %w[id Latn], "jpn" => %w[ja Jpan],
|
|
19
|
+
"kor" => %w[ko Kore], "may" => %w[ms Latn], "nor" => %w[no Latn],
|
|
20
|
+
"pol" => %w[pl Latn], "por" => %w[pt Latn], "spa" => %w[es Latn],
|
|
21
|
+
"ukr" => %w[uk Cyrl]
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
class << self
|
|
25
|
+
# @return [Hash] the table as written in cswp.yaml
|
|
26
|
+
def table
|
|
27
|
+
@table ||= YAML.load_file File.expand_path("cswp.yaml", __dir__)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# The comparable form of a CSWP reference: no publisher, the
|
|
32
|
+
# separators (".", "(...)") read as spaces, upper case.
|
|
33
|
+
# "NIST CSWP 6(spa)", "NIST.CSWP.6.spa" and "NIST CSWP 6 spa" all
|
|
34
|
+
# give "CSWP 6 SPA".
|
|
35
|
+
#
|
|
36
|
+
# @param ref [String]
|
|
37
|
+
# @return [String]
|
|
38
|
+
def normalize(ref)
|
|
39
|
+
ref.to_s.sub(/\ANIST[.\s]+/i, "").gsub(/[().]/, " ").squeeze(" ").strip.upcase
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# Find a reference in the table.
|
|
44
|
+
#
|
|
45
|
+
# @param ref [String]
|
|
46
|
+
# @return [Array, nil] `[:legacy, numbered id, dated id]` for a
|
|
47
|
+
# legacy id of an English CSWP, `[:translation, entry]` for a
|
|
48
|
+
# translation (dated or numbered), nil otherwise
|
|
49
|
+
def lookup(ref)
|
|
50
|
+
key = normalize ref
|
|
51
|
+
return unless key.start_with? "CSWP "
|
|
52
|
+
|
|
53
|
+
key = key.delete_prefix "CSWP "
|
|
54
|
+
dated, target = legacy[key]
|
|
55
|
+
entry = translations[(target || key).upcase]
|
|
56
|
+
return [:translation, entry] if entry
|
|
57
|
+
|
|
58
|
+
[:legacy, "NIST CSWP #{target}", "NIST CSWP #{dated}"] if target
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#
|
|
62
|
+
# Build the record of a translation from its RIS fields.
|
|
63
|
+
#
|
|
64
|
+
# @param entry [Hash] a translation entry from #lookup
|
|
65
|
+
# @return [Relaton::Nist::ItemData]
|
|
66
|
+
def translation_item(entry) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
67
|
+
number, lang_code = entry[:id].split
|
|
68
|
+
language, script = LANGUAGES.fetch lang_code
|
|
69
|
+
id = "NIST CSWP #{number}(#{lang_code})"
|
|
70
|
+
ItemData.new(
|
|
71
|
+
type: "standard",
|
|
72
|
+
docidentifier: [
|
|
73
|
+
Docidentifier.new(content: id, type: "NIST", primary: true),
|
|
74
|
+
Docidentifier.new(content: entry[:doi].split("/").last, type: "DOI"),
|
|
75
|
+
],
|
|
76
|
+
title: [Bib::Title.new(content: entry[:title], language: "en", script: "Latn")],
|
|
77
|
+
source: [Bib::Uri.new(type: "doi", content: "https://doi.org/#{entry[:doi]}")],
|
|
78
|
+
date: [Date.new(type: "published", at: entry[:year])],
|
|
79
|
+
contributor: entry[:authors].map { |name| author name } << publisher,
|
|
80
|
+
language: [language],
|
|
81
|
+
script: [script],
|
|
82
|
+
relation: [original_relation("NIST CSWP #{number}")],
|
|
83
|
+
place: [Bib::Place.new(city: "Gaithersburg", region: [Bib::Place::RegionType.new(iso: "MD")])],
|
|
84
|
+
ext: Ext.new(doctype: Doctype.new(content: "standard"), flavor: "nist"),
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# dated id (upper case) => [dated id, numbered id]
|
|
91
|
+
def legacy
|
|
92
|
+
@legacy ||= table["legacy"].to_h { |dated, numbered| [dated.upcase, [dated, numbered]] }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# translation id (upper case) => entry
|
|
96
|
+
def translations
|
|
97
|
+
@translations ||= table["translations"].to_h do |id, fields|
|
|
98
|
+
[id.upcase, fields.transform_keys(&:to_sym).merge(id: id, authors: fields["authors"] || [])]
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @param name [String] RIS author, "Surname, Forename"
|
|
103
|
+
# @return [Bib::Contributor]
|
|
104
|
+
def author(name)
|
|
105
|
+
surname, forename = name.split(/,\s*/, 2)
|
|
106
|
+
fullname = Bib::FullName.new(
|
|
107
|
+
surname: Bib::LocalizedString.new(content: surname, language: "en", script: "Latn"),
|
|
108
|
+
forename: [Bib::FullNameType::Forename.new(content: forename, language: "en", script: "Latn")],
|
|
109
|
+
)
|
|
110
|
+
Bib::Contributor.new(
|
|
111
|
+
person: Bib::Person.new(name: fullname),
|
|
112
|
+
role: [Bib::Contributor::Role.new(type: "author")],
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @return [Bib::Contributor]
|
|
117
|
+
def publisher
|
|
118
|
+
org = Bib::Organization.new(
|
|
119
|
+
name: [Bib::TypedLocalizedString.new(content: "National Institute of Standards and Technology")],
|
|
120
|
+
abbreviation: Bib::LocalizedString.new(content: "NIST"),
|
|
121
|
+
)
|
|
122
|
+
Bib::Contributor.new(organization: org, role: [Bib::Contributor::Role.new(type: "publisher")])
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# @param id [String] the original's id
|
|
126
|
+
# @return [Relaton::Nist::Relation]
|
|
127
|
+
def original_relation(id)
|
|
128
|
+
bib = ItemData.new(
|
|
129
|
+
formattedref: Bib::Formattedref.new(content: id),
|
|
130
|
+
docidentifier: [Docidentifier.new(content: id, type: "NIST", primary: true)],
|
|
131
|
+
)
|
|
132
|
+
Relation.new(type: "translatedFrom", bibitem: bib)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# CSWP ids the CSRC pubs-export feed does not list (relaton#406).
|
|
2
|
+
#
|
|
3
|
+
# Source: the RIS files `bib/NIST.CSWP.*.ris` on the `nist-pages` branch of
|
|
4
|
+
# usnistgov/NIST-Tech-Pubs (the NIST Library MODS/MARC releases hold no CSWP).
|
|
5
|
+
#
|
|
6
|
+
# legacy: a dated id from before the series was numbered -> the numbered id,
|
|
7
|
+
# matched by the exact RIS title (TI). A dated translation maps to the
|
|
8
|
+
# numbered translation. `06222021-draft` has no numbered RIS; its title is
|
|
9
|
+
# the CSRC `CSWP 19` initial public draft.
|
|
10
|
+
# Not mapped: `02042022-1`..`-5` have no SN and share the title
|
|
11
|
+
# "Cybersecurity White Paper: EO Response", so no numbered id matches.
|
|
12
|
+
#
|
|
13
|
+
# translations: numbered id + ISO 639-2 language code -> the RIS fields (TI,
|
|
14
|
+
# PY, DO, AU). The original is the numbered id without the language code.
|
|
15
|
+
legacy:
|
|
16
|
+
"01142020": "9"
|
|
17
|
+
"01162020es": "10 spa"
|
|
18
|
+
"01162020id": "10 ind"
|
|
19
|
+
"01162020pt": "10 por"
|
|
20
|
+
"01262018": "5"
|
|
21
|
+
"02042020-1": "11"
|
|
22
|
+
"02042020-2": "11A"
|
|
23
|
+
"02042020-3": "11B"
|
|
24
|
+
"02042020-4": "11C"
|
|
25
|
+
"02042020-5": "11D"
|
|
26
|
+
"02042020-6": "11E"
|
|
27
|
+
"02042020-7": "11F"
|
|
28
|
+
"02122014": "1"
|
|
29
|
+
"02122014pl": "1 pol"
|
|
30
|
+
"02192014": "2"
|
|
31
|
+
"04162018": "6"
|
|
32
|
+
"04162018ar": "6 ara"
|
|
33
|
+
"04162018bg": "6 bul"
|
|
34
|
+
"04162018es": "6 spa"
|
|
35
|
+
"04162018fr": "6 fre"
|
|
36
|
+
"04162018id": "6 ind"
|
|
37
|
+
"04162018pt": "6 por"
|
|
38
|
+
"04212016": "4"
|
|
39
|
+
"04222019": "8"
|
|
40
|
+
"04232020": "13"
|
|
41
|
+
"04282021": "15"
|
|
42
|
+
"06032014": "3"
|
|
43
|
+
"06222021-draft": "19 ipd"
|
|
44
|
+
"09102018": "7"
|
|
45
|
+
"09292021": "21"
|
|
46
|
+
translations:
|
|
47
|
+
"1 pol":
|
|
48
|
+
title: Framework for Improving Critical Infrastructure Cybersecurity, Version 1.0 (Polish translation)
|
|
49
|
+
year: "2014"
|
|
50
|
+
doi: 10.6028/NIST.CSWP.1.pol
|
|
51
|
+
authors:
|
|
52
|
+
- Stine, Kevin
|
|
53
|
+
"6 ara":
|
|
54
|
+
title: Framework for Improving Critical Infrastructure Cybersecurity, Version 1.1 (Arabic translation)
|
|
55
|
+
year: "2018"
|
|
56
|
+
doi: 10.6028/NIST.CSWP.6.ara
|
|
57
|
+
authors:
|
|
58
|
+
- Stine, Kevin
|
|
59
|
+
"6 bul":
|
|
60
|
+
title: Framework for Improving Critical Infrastructure Cybersecurity, Version 1.1 (Bulgarian translation)
|
|
61
|
+
year: "2018"
|
|
62
|
+
doi: 10.6028/NIST.CSWP.6.bul
|
|
63
|
+
authors:
|
|
64
|
+
- Stine, Kevin
|
|
65
|
+
"6 fre":
|
|
66
|
+
title: Framework for Improving Critical Infrastructure Cybersecurity, Version 1.1 (French Translation)
|
|
67
|
+
year: "2018"
|
|
68
|
+
doi: 10.6028/NIST.CSWP.6.fre
|
|
69
|
+
authors:
|
|
70
|
+
- Stine, Kevin
|
|
71
|
+
"6 gre":
|
|
72
|
+
title: Greek Translation of the Framework for Improving Critical Infrastructure Cybersecurity
|
|
73
|
+
year: "2018"
|
|
74
|
+
doi: 10.6028/NIST.CSWP.6.gre
|
|
75
|
+
authors:
|
|
76
|
+
- Stine, Kevin
|
|
77
|
+
"6 ind":
|
|
78
|
+
title: Framework for Improving Critical Infrastructure Cybersecurity, Version 1.1 (Indonesian Translation)
|
|
79
|
+
year: "2018"
|
|
80
|
+
doi: 10.6028/NIST.CSWP.6.ind
|
|
81
|
+
authors:
|
|
82
|
+
- Stine, Kevin
|
|
83
|
+
"6 jpn":
|
|
84
|
+
title: Japanese Translation of Framework for Improving Critical Infrastructure Cybersecurity Version 1.1 (Cybersecurity Framework)
|
|
85
|
+
year: "2018"
|
|
86
|
+
doi: 10.6028/NIST.CSWP.6.jpn
|
|
87
|
+
authors:
|
|
88
|
+
- Stine, Kevin
|
|
89
|
+
"6 kor":
|
|
90
|
+
title: Korean Translation of the Framework for Improving Critical Infrastructure Cybersecurity Version 1.1
|
|
91
|
+
year: "2024"
|
|
92
|
+
doi: 10.6028/NIST.CSWP.6.kor
|
|
93
|
+
authors:
|
|
94
|
+
- Stine, Kevin
|
|
95
|
+
"6 may":
|
|
96
|
+
title: Malay Translation of the Framework for Improving Critical Infrastructure Cybersecurity V1.1
|
|
97
|
+
year: "2018"
|
|
98
|
+
doi: 10.6028/NIST.CSWP.6.may
|
|
99
|
+
authors:
|
|
100
|
+
- Stine, Kevin
|
|
101
|
+
"6 nor":
|
|
102
|
+
title: Norwegian Translation of the Framework for Improving Critical Infrastructure Cybersecurity Version 1.1
|
|
103
|
+
year: "2018"
|
|
104
|
+
doi: 10.6028/NIST.CSWP.6.nor
|
|
105
|
+
authors:
|
|
106
|
+
- Stine, Kevin
|
|
107
|
+
"6 por":
|
|
108
|
+
title: Portuguese Translation of the Framework for Improving Critical Infrastructure Cybersecurity Version 1.1 (Cybersecurity Framework)
|
|
109
|
+
year: "2018"
|
|
110
|
+
doi: 10.6028/NIST.CSWP.6.por
|
|
111
|
+
authors:
|
|
112
|
+
- Stine, Kevin
|
|
113
|
+
"6 spa":
|
|
114
|
+
title: Framework for Improving Critical Infrastructure Cybersecurity, Version 1.1 (Spanish translation)
|
|
115
|
+
year: "2018"
|
|
116
|
+
doi: 10.6028/NIST.CSWP.6.spa
|
|
117
|
+
authors:
|
|
118
|
+
- Stine, Kevin
|
|
119
|
+
"6 ukr":
|
|
120
|
+
title: Ukranian Translation of the Framework for Improving Critical Infrastructure Cybersecurity Version 1.1 (Cybersecurity Framework)
|
|
121
|
+
year: "2018"
|
|
122
|
+
doi: 10.6028/NIST.CSWP.6.ukr
|
|
123
|
+
authors:
|
|
124
|
+
- Stine, Kevin
|
|
125
|
+
"10 ara":
|
|
126
|
+
title: "NIST Privacy Framework: A Tool for Improving Privacy Through Enterprise Risk Management, Version 1.0 (Arabic translation)"
|
|
127
|
+
year: "2022"
|
|
128
|
+
doi: 10.6028/NIST.CSWP.10.ara
|
|
129
|
+
authors:
|
|
130
|
+
- Lefkovitz, Naomi
|
|
131
|
+
- Boeckl, Katie
|
|
132
|
+
"10 ind":
|
|
133
|
+
title: Indonesian Translation of the NIST Privacy Framework Version 1.0
|
|
134
|
+
year: "2020"
|
|
135
|
+
doi: 10.6028/NIST.CSWP.10.ind
|
|
136
|
+
authors:
|
|
137
|
+
- Lefkovitz, Naomi
|
|
138
|
+
"10 may":
|
|
139
|
+
title: "NIST Privacy Framework: A Tool for Improving Privacy Through Enterprise Risk Management, Version 1.0 (Malay translation)"
|
|
140
|
+
year: "2024"
|
|
141
|
+
doi: 10.6028/NIST.CSWP.10.may
|
|
142
|
+
authors:
|
|
143
|
+
- Lefkovitz, Naomi
|
|
144
|
+
"10 por":
|
|
145
|
+
title: Portuguese Translation of the NIST Privacy Framework Version 1.0
|
|
146
|
+
year: "2021"
|
|
147
|
+
doi: 10.6028/NIST.CSWP.10.por
|
|
148
|
+
authors:
|
|
149
|
+
- Lefkovitz, Naomi
|
|
150
|
+
"10 spa":
|
|
151
|
+
title: Spanish Translation of the NIST Privacy Framework Version 1.0
|
|
152
|
+
year: "2021"
|
|
153
|
+
doi: 10.6028/NIST.CSWP.10.spa
|
|
154
|
+
authors:
|
|
155
|
+
- Lefkovitz, Naomi
|
|
@@ -21,6 +21,26 @@ module Relaton
|
|
|
21
21
|
Bibliography.get(code, date, opts)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
# Two kinds of Cswp table reference reach `get` as written and are not
|
|
25
|
+
# cached (relaton#406). A legacy dated id answers the numbered record
|
|
26
|
+
# with the dated id added, and Db would store that record under the
|
|
27
|
+
# numbered id's row, so a later "NIST CSWP 9" would carry the dated id.
|
|
28
|
+
# A translation that pubid reads in another form ("NIST CSWP
|
|
29
|
+
# 04162018ar" as "...04162018a", "NIST CSWP 6 spa" as "...6(spa)").
|
|
30
|
+
#
|
|
31
|
+
# @param ref [String]
|
|
32
|
+
# @return [Pubid::Nist::Identifier, nil]
|
|
33
|
+
def cache_pubid(ref)
|
|
34
|
+
pubid = super
|
|
35
|
+
return if pubid.nil?
|
|
36
|
+
|
|
37
|
+
require_relative "cswp"
|
|
38
|
+
type, = Cswp.lookup(ref)
|
|
39
|
+
return pubid if type.nil? || (type == :translation && pubid.to_s == ref)
|
|
40
|
+
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
24
44
|
#
|
|
25
45
|
# Fetch all the documents from a source
|
|
26
46
|
#
|
data/lib/relaton/nist.rb
CHANGED
|
@@ -12,6 +12,7 @@ require_relative "nist/pubs_export"
|
|
|
12
12
|
require_relative "nist/hit"
|
|
13
13
|
require_relative "nist/hit_collection"
|
|
14
14
|
require_relative "nist/scraper"
|
|
15
|
+
require_relative "nist/cswp"
|
|
15
16
|
require_relative "nist/bibliography"
|
|
16
17
|
# require_relative "nist/tech_pubs_parser"
|
|
17
18
|
|
data/lib/relaton/version.rb
CHANGED
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.3
|
|
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-10-
|
|
11
|
+
date: 2026-10-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: addressable
|
|
@@ -42,30 +42,30 @@ dependencies:
|
|
|
42
42
|
name: base64
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0'
|
|
47
|
+
version: '0.3'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0'
|
|
54
|
+
version: '0.3'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: bibtex-ruby
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - "
|
|
59
|
+
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
61
|
+
version: '6.2'
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- - "
|
|
66
|
+
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
68
|
+
version: '6.2'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: cnccs
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -98,16 +98,16 @@ dependencies:
|
|
|
98
98
|
name: sqlite3
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- - "
|
|
101
|
+
- - "~>"
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
103
|
+
version: '2.10'
|
|
104
104
|
type: :runtime
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
|
-
- - "
|
|
108
|
+
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
110
|
+
version: '2.10'
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
112
|
name: csv
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -224,16 +224,16 @@ dependencies:
|
|
|
224
224
|
name: iso639
|
|
225
225
|
requirement: !ruby/object:Gem::Requirement
|
|
226
226
|
requirements:
|
|
227
|
-
- - "
|
|
227
|
+
- - "~>"
|
|
228
228
|
- !ruby/object:Gem::Version
|
|
229
|
-
version: '
|
|
229
|
+
version: '1.4'
|
|
230
230
|
type: :runtime
|
|
231
231
|
prerelease: false
|
|
232
232
|
version_requirements: !ruby/object:Gem::Requirement
|
|
233
233
|
requirements:
|
|
234
|
-
- - "
|
|
234
|
+
- - "~>"
|
|
235
235
|
- !ruby/object:Gem::Version
|
|
236
|
-
version: '
|
|
236
|
+
version: '1.4'
|
|
237
237
|
- !ruby/object:Gem::Dependency
|
|
238
238
|
name: isoics
|
|
239
239
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -282,20 +282,14 @@ dependencies:
|
|
|
282
282
|
requirements:
|
|
283
283
|
- - "~>"
|
|
284
284
|
- !ruby/object:Gem::Version
|
|
285
|
-
version:
|
|
286
|
-
- - ">="
|
|
287
|
-
- !ruby/object:Gem::Version
|
|
288
|
-
version: 0.2.5
|
|
285
|
+
version: 0.2.8
|
|
289
286
|
type: :runtime
|
|
290
287
|
prerelease: false
|
|
291
288
|
version_requirements: !ruby/object:Gem::Requirement
|
|
292
289
|
requirements:
|
|
293
290
|
- - "~>"
|
|
294
291
|
- !ruby/object:Gem::Version
|
|
295
|
-
version:
|
|
296
|
-
- - ">="
|
|
297
|
-
- !ruby/object:Gem::Version
|
|
298
|
-
version: 0.2.5
|
|
292
|
+
version: 0.2.8
|
|
299
293
|
- !ruby/object:Gem::Dependency
|
|
300
294
|
name: lutaml-model
|
|
301
295
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -370,30 +364,30 @@ dependencies:
|
|
|
370
364
|
name: moxml
|
|
371
365
|
requirement: !ruby/object:Gem::Requirement
|
|
372
366
|
requirements:
|
|
373
|
-
- - "
|
|
367
|
+
- - "~>"
|
|
374
368
|
- !ruby/object:Gem::Version
|
|
375
|
-
version:
|
|
369
|
+
version: 0.5.174
|
|
376
370
|
type: :runtime
|
|
377
371
|
prerelease: false
|
|
378
372
|
version_requirements: !ruby/object:Gem::Requirement
|
|
379
373
|
requirements:
|
|
380
|
-
- - "
|
|
374
|
+
- - "~>"
|
|
381
375
|
- !ruby/object:Gem::Version
|
|
382
|
-
version:
|
|
376
|
+
version: 0.5.174
|
|
383
377
|
- !ruby/object:Gem::Dependency
|
|
384
378
|
name: leptris
|
|
385
379
|
requirement: !ruby/object:Gem::Requirement
|
|
386
380
|
requirements:
|
|
387
|
-
- - "
|
|
381
|
+
- - "~>"
|
|
388
382
|
- !ruby/object:Gem::Version
|
|
389
|
-
version: 1.9.
|
|
383
|
+
version: 1.9.391
|
|
390
384
|
type: :runtime
|
|
391
385
|
prerelease: false
|
|
392
386
|
version_requirements: !ruby/object:Gem::Requirement
|
|
393
387
|
requirements:
|
|
394
|
-
- - "
|
|
388
|
+
- - "~>"
|
|
395
389
|
- !ruby/object:Gem::Version
|
|
396
|
-
version: 1.9.
|
|
390
|
+
version: 1.9.391
|
|
397
391
|
- !ruby/object:Gem::Dependency
|
|
398
392
|
name: parallel
|
|
399
393
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -410,92 +404,60 @@ dependencies:
|
|
|
410
404
|
version: '1.26'
|
|
411
405
|
- !ruby/object:Gem::Dependency
|
|
412
406
|
name: parsanol
|
|
413
|
-
requirement: !ruby/object:Gem::Requirement
|
|
414
|
-
requirements:
|
|
415
|
-
- - ">="
|
|
416
|
-
- !ruby/object:Gem::Version
|
|
417
|
-
version: 1.3.114
|
|
418
|
-
- - "<"
|
|
419
|
-
- !ruby/object:Gem::Version
|
|
420
|
-
version: '1.4'
|
|
421
|
-
type: :runtime
|
|
422
|
-
prerelease: false
|
|
423
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
424
|
-
requirements:
|
|
425
|
-
- - ">="
|
|
426
|
-
- !ruby/object:Gem::Version
|
|
427
|
-
version: 1.3.114
|
|
428
|
-
- - "<"
|
|
429
|
-
- !ruby/object:Gem::Version
|
|
430
|
-
version: '1.4'
|
|
431
|
-
- !ruby/object:Gem::Dependency
|
|
432
|
-
name: parslet
|
|
433
407
|
requirement: !ruby/object:Gem::Requirement
|
|
434
408
|
requirements:
|
|
435
409
|
- - "~>"
|
|
436
410
|
- !ruby/object:Gem::Version
|
|
437
|
-
version:
|
|
411
|
+
version: 1.3.114
|
|
438
412
|
type: :runtime
|
|
439
413
|
prerelease: false
|
|
440
414
|
version_requirements: !ruby/object:Gem::Requirement
|
|
441
415
|
requirements:
|
|
442
416
|
- - "~>"
|
|
443
417
|
- !ruby/object:Gem::Version
|
|
444
|
-
version:
|
|
418
|
+
version: 1.3.114
|
|
445
419
|
- !ruby/object:Gem::Dependency
|
|
446
420
|
name: pubid
|
|
447
421
|
requirement: !ruby/object:Gem::Requirement
|
|
448
422
|
requirements:
|
|
449
|
-
- - "
|
|
423
|
+
- - "~>"
|
|
450
424
|
- !ruby/object:Gem::Version
|
|
451
425
|
version: 2.0.1
|
|
452
|
-
- - "<"
|
|
453
|
-
- !ruby/object:Gem::Version
|
|
454
|
-
version: '2.1'
|
|
455
426
|
type: :runtime
|
|
456
427
|
prerelease: false
|
|
457
428
|
version_requirements: !ruby/object:Gem::Requirement
|
|
458
429
|
requirements:
|
|
459
|
-
- - "
|
|
430
|
+
- - "~>"
|
|
460
431
|
- !ruby/object:Gem::Version
|
|
461
432
|
version: 2.0.1
|
|
462
|
-
- - "<"
|
|
463
|
-
- !ruby/object:Gem::Version
|
|
464
|
-
version: '2.1'
|
|
465
433
|
- !ruby/object:Gem::Dependency
|
|
466
434
|
name: yeptris
|
|
467
435
|
requirement: !ruby/object:Gem::Requirement
|
|
468
436
|
requirements:
|
|
469
|
-
- - "
|
|
437
|
+
- - "~>"
|
|
470
438
|
- !ruby/object:Gem::Version
|
|
471
439
|
version: 0.6.51
|
|
472
440
|
type: :runtime
|
|
473
441
|
prerelease: false
|
|
474
442
|
version_requirements: !ruby/object:Gem::Requirement
|
|
475
443
|
requirements:
|
|
476
|
-
- - "
|
|
444
|
+
- - "~>"
|
|
477
445
|
- !ruby/object:Gem::Version
|
|
478
446
|
version: 0.6.51
|
|
479
447
|
- !ruby/object:Gem::Dependency
|
|
480
448
|
name: relaton-render
|
|
481
449
|
requirement: !ruby/object:Gem::Requirement
|
|
482
450
|
requirements:
|
|
483
|
-
- - "
|
|
484
|
-
- !ruby/object:Gem::Version
|
|
485
|
-
version: 3.0.0.pre.alpha.1
|
|
486
|
-
- - "<"
|
|
451
|
+
- - "~>"
|
|
487
452
|
- !ruby/object:Gem::Version
|
|
488
|
-
version: '
|
|
453
|
+
version: '3.0'
|
|
489
454
|
type: :runtime
|
|
490
455
|
prerelease: false
|
|
491
456
|
version_requirements: !ruby/object:Gem::Requirement
|
|
492
457
|
requirements:
|
|
493
|
-
- - "
|
|
494
|
-
- !ruby/object:Gem::Version
|
|
495
|
-
version: 3.0.0.pre.alpha.1
|
|
496
|
-
- - "<"
|
|
458
|
+
- - "~>"
|
|
497
459
|
- !ruby/object:Gem::Version
|
|
498
|
-
version: '
|
|
460
|
+
version: '3.0'
|
|
499
461
|
- !ruby/object:Gem::Dependency
|
|
500
462
|
name: rfcxml
|
|
501
463
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -1159,6 +1121,8 @@ files:
|
|
|
1159
1121
|
- lib/relaton/nist/bibitem.rb
|
|
1160
1122
|
- lib/relaton/nist/bibliography.rb
|
|
1161
1123
|
- lib/relaton/nist/comment_period.rb
|
|
1124
|
+
- lib/relaton/nist/cswp.rb
|
|
1125
|
+
- lib/relaton/nist/cswp.yaml
|
|
1162
1126
|
- lib/relaton/nist/data_fetcher.rb
|
|
1163
1127
|
- lib/relaton/nist/date.rb
|
|
1164
1128
|
- lib/relaton/nist/docidentifier.rb
|