nist-pubid 0.1.2 → 0.1.6
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/.github/workflows/release.yml +46 -0
- data/README.adoc +3 -2
- data/exe/nist-pubid +54 -0
- data/lib/nist_pubid/document.rb +220 -28
- data/lib/nist_pubid/errors.rb +5 -0
- data/lib/nist_pubid/nist_tech_pubs.rb +104 -0
- data/lib/nist_pubid/publisher.rb +1 -1
- data/lib/nist_pubid/serie.rb +4 -2
- data/lib/nist_pubid/stage.rb +23 -8
- data/lib/nist_pubid/version.rb +1 -1
- data/lib/nist_pubid.rb +6 -4
- data/nist_pubid.gemspec +6 -0
- data/series.yaml +1 -1
- data/stages.yaml +1 -1
- metadata +79 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6cbdcaa4e1cfa7c75b6709f34cfd19670e8a3b2d3bd31473cbc5a5d439843b7
|
4
|
+
data.tar.gz: 4dcb0a4b147990872fe4f72c8eecac96ba3a865bcaa477a5158404ab04fc8e42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6331d9887c149a7dbcf49c46a0ce7c121bf973cd239e3467658065820daf8c18f752e68b977d52e08155dfa2d947d9be5fa80bb431f462453ed337e02fc1616
|
7
|
+
data.tar.gz: 35660adeef1ec90862ada64b2150162008d0b25cf01a8e9a7b15f909b6ac64265a04cc2bdf1da7ea9a7d08e99754eb8d49910de9d19119b4548b40f3870876db
|
@@ -0,0 +1,46 @@
|
|
1
|
+
name: release
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- '*'
|
7
|
+
workflow_dispatch:
|
8
|
+
inputs:
|
9
|
+
next_version:
|
10
|
+
description: |
|
11
|
+
Next release version. Possible values: x.y.z, major, minor, patch or pre|rc|etc
|
12
|
+
required: true
|
13
|
+
default: 'skip'
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
release:
|
17
|
+
runs-on: ubuntu-18.04
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v2
|
20
|
+
|
21
|
+
- uses: ruby/setup-ruby@v1
|
22
|
+
with:
|
23
|
+
ruby-version: '2.6'
|
24
|
+
bundler-cache: true
|
25
|
+
|
26
|
+
- run: bundle exec rake
|
27
|
+
|
28
|
+
- run: gem install gem-release
|
29
|
+
|
30
|
+
- run: |
|
31
|
+
git config user.name github-actions
|
32
|
+
git config user.email github-actions@github.com
|
33
|
+
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.next_version != 'skip'
|
34
|
+
run: gem bump --version ${{ github.event.inputs.next_version }} --tag --push
|
35
|
+
|
36
|
+
- name: Publish to rubygems.org
|
37
|
+
env:
|
38
|
+
RUBYGEMS_API_KEY: ${{secrets.METANORMA_CI_RUBYGEMS_API_KEY}}
|
39
|
+
run: |
|
40
|
+
gem install gem-release
|
41
|
+
cat > ~/.gem/credentials << EOF
|
42
|
+
---
|
43
|
+
:rubygems_api_key: ${RUBYGEMS_API_KEY}
|
44
|
+
EOF
|
45
|
+
chmod 0600 ~/.gem/credentials
|
46
|
+
gem release
|
data/README.adoc
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
NIST publications are numbered according to an identification scheme.
|
6
6
|
|
7
|
-
This gem implements a mechanism to parse and utilize NIST publication
|
7
|
+
This gem implements a mechanism to parse and utilize NIST publication identifiers
|
8
8
|
provided in the https://github.com/usnistgov/NIST-Tech-Pubs[NIST-Tech-Pubs]
|
9
9
|
repository.
|
10
10
|
|
@@ -296,9 +296,10 @@ A "Part" can also be indicated by an appended alphabetic character to the end.
|
|
296
296
|
| Section | Sec. | `sec`
|
297
297
|
| Supplement | Suppl. | `sup`
|
298
298
|
| Index | Index | `indx`
|
299
|
-
| Addendum | Add. | `add` (
|
299
|
+
| Addendum | Add. | `add` (TBC with NIST)
|
300
300
|
| Insert | Ins. | `ins` (TBC with NIST)
|
301
301
|
| Errata | Err. | `err` (TBC with NIST)
|
302
|
+
| Appendix | App. | `app` (TBC with NIST)
|
302
303
|
|
303
304
|
|===
|
304
305
|
|
data/exe/nist-pubid
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler/setup"
|
5
|
+
require_relative "../lib/nist_pubid"
|
6
|
+
require "thor"
|
7
|
+
require "csv"
|
8
|
+
|
9
|
+
class NistPubidCLI < Thor
|
10
|
+
desc "report", "Create report for NIST Tech Pubs database (fetches from GitHub)"
|
11
|
+
option :csv, type: :boolean, desc: "Export to CSV format"
|
12
|
+
def report
|
13
|
+
if options[:csv]
|
14
|
+
NistPubid::NistTechPubs.status.each do |doc|
|
15
|
+
puts [doc[:finalPubId] == doc[:id] && doc[:mr] == doc[:doi] ? "-" : "+",
|
16
|
+
doc[:finalPubId], doc[:id], doc[:doi], doc[:mr], doc[:title]]
|
17
|
+
.to_csv
|
18
|
+
end
|
19
|
+
else
|
20
|
+
puts "Changed | New PubID | Document ID | DOI | New MR | Title + subtitle"
|
21
|
+
NistPubid::NistTechPubs.status.each do |doc|
|
22
|
+
puts "#{doc[:finalPubId] == doc[:id] && doc[:mr] == doc[:doi] ? ' -' : '✅'}"\
|
23
|
+
" | #{doc[:finalPubId]} | #{doc[:id]} | #{doc[:doi]} | #{doc[:mr]} | #{doc[:title]}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "convert", "Convert legacy NIST Tech Pubs ID to NIST PubID"
|
29
|
+
option :style, aliases: "-s", type: :string,
|
30
|
+
desc: "Convert to PubID style (short|long|mr|abbrev)",
|
31
|
+
default: "short"
|
32
|
+
option :format, aliases: "-f", type: :string,
|
33
|
+
desc: "Render in format (JSON, string)",
|
34
|
+
default: "string"
|
35
|
+
def convert(code)
|
36
|
+
unless %w[mr long short abbrev].include?(options[:style])
|
37
|
+
raise "Invalid PubID style"
|
38
|
+
end
|
39
|
+
|
40
|
+
raise "wrong conversion format" unless %w[string json].include? options[:format]
|
41
|
+
|
42
|
+
unless code.empty?
|
43
|
+
if options[:format] == "string"
|
44
|
+
puts NistPubid::Document.parse(code).to_s(options[:style].to_sym)
|
45
|
+
else
|
46
|
+
puts NistPubid::Document.parse(code).to_json
|
47
|
+
end
|
48
|
+
end
|
49
|
+
rescue NistPubid::Errors::ParseError
|
50
|
+
puts "[Error] This does not seem to be a valid NIST Tech Pubs legacy identifier"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
NistPubidCLI.start(ARGV)
|
data/lib/nist_pubid/document.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "json"
|
2
3
|
|
3
4
|
REVISION_DESC = {
|
4
5
|
long: ", Revision ",
|
@@ -35,47 +36,200 @@ EDITION_DESC = {
|
|
35
36
|
mr: "e",
|
36
37
|
}.freeze
|
37
38
|
|
39
|
+
SUPPLEMENT_DESC = {
|
40
|
+
long: " Supplement ",
|
41
|
+
abbrev: " Suppl. ",
|
42
|
+
short: "sup",
|
43
|
+
mr: "sup",
|
44
|
+
}.freeze
|
45
|
+
|
46
|
+
SECTION_DESC = {
|
47
|
+
long: " Section ",
|
48
|
+
abbrev: " Sec. ",
|
49
|
+
short: "sec",
|
50
|
+
mr: "sec",
|
51
|
+
}.freeze
|
52
|
+
|
53
|
+
APPENDIX_DESC = {
|
54
|
+
long: " Appendix ",
|
55
|
+
abbrev: " App. ",
|
56
|
+
short: "app",
|
57
|
+
mr: "app",
|
58
|
+
}.freeze
|
59
|
+
|
60
|
+
ERRATA_DESC = {
|
61
|
+
long: " Errata ",
|
62
|
+
abbrev: " Err. ",
|
63
|
+
short: "err",
|
64
|
+
mr: "err",
|
65
|
+
}.freeze
|
66
|
+
|
67
|
+
INDEX_DESC = {
|
68
|
+
long: " Index ",
|
69
|
+
abbrev: " Index. ",
|
70
|
+
short: "indx",
|
71
|
+
mr: "indx",
|
72
|
+
}.freeze
|
73
|
+
|
74
|
+
INSERT_DESC = {
|
75
|
+
long: " Insert ",
|
76
|
+
abbrev: " Ins. ",
|
77
|
+
short: "ins",
|
78
|
+
mr: "ins",
|
79
|
+
}.freeze
|
80
|
+
|
38
81
|
module NistPubid
|
39
82
|
class Document
|
40
83
|
attr_accessor :serie, :code, :revision, :publisher, :version, :volume,
|
41
|
-
:part, :addendum, :stage, :translation, :
|
84
|
+
:part, :addendum, :stage, :translation, :update_number,
|
85
|
+
:edition, :supplement, :update_year, :section, :appendix,
|
86
|
+
:errata, :index, :insert
|
42
87
|
|
43
|
-
def initialize(publisher:, serie:, docnumber:,
|
88
|
+
def initialize(publisher:, serie:, docnumber:, **opts)
|
44
89
|
@publisher = Publisher.new(publisher: publisher)
|
45
90
|
@serie = Serie.new(serie: serie)
|
46
91
|
@code = docnumber
|
47
|
-
@stage = Stage.new(stage: stage)
|
48
92
|
opts.each { |key, value| send("#{key}=", value) }
|
49
93
|
end
|
50
94
|
|
95
|
+
# returns weight based on amount of defined attributes
|
96
|
+
def weight
|
97
|
+
instance_variables.inject(0) do |sum, var|
|
98
|
+
sum + (instance_variable_get(var).nil? ? 0 : 1)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def merge(document)
|
103
|
+
instance_variables.each do |var|
|
104
|
+
val = document.instance_variable_get(var)
|
105
|
+
instance_variable_set(var, val) unless val.nil?
|
106
|
+
end
|
107
|
+
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.update_old_code(code)
|
112
|
+
code = code.gsub("FIPS", "FIPS PUB") unless code.include?("FIPS PUB")
|
113
|
+
code.gsub("NBS MONO", "NBS MN").gsub("NIST MONO", "NIST MN")
|
114
|
+
.gsub("NIST MP", "NBS MP")
|
115
|
+
.gsub("NIST SP 304a-2017", "NIST SP 304A-2017")
|
116
|
+
.gsub("NIST SP 260-162 2006ed.", "NIST SP 260-162e2006")
|
117
|
+
.gsub("NBS CIRC 154suprev", "NBS CIRC 154r1sup")
|
118
|
+
.gsub("NIST SP 260-126 rev 2013", "NIST SP 260-126r2013")
|
119
|
+
.gsub("NIST CSWP", "NIST CSRC White Paper")
|
120
|
+
.gsub("NIST.CSWP.01162020pt", "NIST.CSWP.01162020(por)")
|
121
|
+
.gsub(/(?<=NBS MP )(\d+)\((\d+)\)/, '\1e\2')
|
122
|
+
.gsub(/(?<=\d)es/, "(spa)")
|
123
|
+
.gsub(/(?<=\d)chi/, "(zho)")
|
124
|
+
.gsub(/(?<=\d)viet/, "(vie)")
|
125
|
+
.gsub(/(?<=\d)port/, "(por)")
|
126
|
+
# .gsub(/^LCIRC/, "NBS LC")
|
127
|
+
end
|
128
|
+
|
51
129
|
def self.parse(code)
|
130
|
+
code = update_old_code(code)
|
52
131
|
matches = {
|
53
132
|
publisher: match(Publisher.regexp, code) || "NIST",
|
54
|
-
serie: match(Serie.regexp, code)
|
55
|
-
stage:
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
addendum: match(/(?<=(\.))?(add(?(1)-)\d+|Addendum)/, code),
|
63
|
-
translation: match(/(?<=\()\w{3}(?=\))/, code),
|
64
|
-
update: match(/(?<=Upd\s)([\d:]+)/, code),
|
65
|
-
edition: /(?<=[^a-z])(?<=(\.))?(?:e(?(1)-)|Ed\.\s)(\d+)/
|
133
|
+
serie: match(Serie.regexp, code),
|
134
|
+
stage: Stage.parse(code),
|
135
|
+
part: /(?<=(\.))?(?<![a-z])+(?:pt|Pt|p)(?(1)-)([A-Z\d]+)/.match(code)
|
136
|
+
&.[](2),
|
137
|
+
version:
|
138
|
+
/(?<=\.)?(?:(?:ver)((?(1)[-\d]|[.\d])+|\d+)|(?:v)(\d+\.[.\d]+))/
|
139
|
+
.match(code).to_a[1..-1]&.compact&.first&.gsub(/-/, "."),
|
140
|
+
revision: /[\da](?:r|Rev\.\s|([0-9]+[A-Za-z]*-[0-9]+[A-Za-z]*-))([\da]+)/
|
66
141
|
.match(code)&.[](2),
|
142
|
+
addendum: match(/(?<=(\.))?(add(?:-\d+)?|Addendum)/, code),
|
143
|
+
edition: /(?<=[^a-z])(?<=\.)?(?:e(?(1)-)|Ed\.\s)(\d+)|
|
144
|
+
NBS\sFIPS\sPUB\s[0-9]+[A-Za-z]*-[0-9]+[A-Za-z]*-([A-Za-z\d]+)
|
145
|
+
/x.match(code)&.captures&.join,
|
146
|
+
section: /(?<=sec)\d+/.match(code)&.to_s,
|
147
|
+
appendix: /\d+app/.match(code)&.to_s,
|
148
|
+
errata: /-errata|\d+err(?:ata)?/.match(code)&.to_s,
|
149
|
+
index: /\d+index|\d+indx/.match(code)&.to_s,
|
150
|
+
insert: /\d+ins(?:ert)?/.match(code)&.to_s
|
67
151
|
}
|
152
|
+
supplement = /(?:(?:supp?)-?(\d*)|Supplement|Suppl.)/
|
153
|
+
.match(code)
|
154
|
+
unless supplement.nil?
|
155
|
+
matches[:supplement] = supplement[1].nil? ? "" : supplement[1]
|
156
|
+
end
|
157
|
+
|
158
|
+
update = code.scan(/((?<=Upd)\s?[\d:]+|-upd)-?(\d*)/).first
|
159
|
+
|
160
|
+
(matches[:update_number], matches[:update_year]) = update if update
|
161
|
+
|
162
|
+
unless matches[:serie]
|
163
|
+
raise Errors::ParseError.new("failed to parse serie for #{code}")
|
164
|
+
end
|
165
|
+
|
166
|
+
unless matches[:stage].nil?
|
167
|
+
code = code.gsub(matches[:stage].original_code, "")
|
168
|
+
end
|
169
|
+
|
170
|
+
unless ["NBS CSM", "NBS CS"].include?(matches[:serie])
|
171
|
+
matches[:volume] = /(?<=(\.))?v(?(1)-)(\d+)(?!\.\d+)/.match(code)&.[](2)
|
172
|
+
end
|
173
|
+
|
174
|
+
matches[:revision] = nil if matches[:addendum]
|
175
|
+
|
176
|
+
matches[:docnumber] = parse_docnumber(matches[:serie], code)
|
177
|
+
|
178
|
+
matches[:serie] = SERIES["mr"].invert[matches[:serie]] || matches[:serie]
|
179
|
+
# matches[:serie].gsub!(/\./, " ")
|
180
|
+
matches[:translation] = match(/(?<=\()\w{3}(?=\))/, code)
|
181
|
+
|
68
182
|
new(**matches)
|
69
183
|
end
|
70
184
|
|
185
|
+
def self.parse_docnumber(serie, code)
|
186
|
+
localities = "[Pp]t\\d+|r(?:\\d+|[A-Za-z]?)|e\\d+|p|v|sec\\d+|inde?x|err(?:ata)?|ins(?:ert)?"
|
187
|
+
excluded_parts = "(?!#{localities}|supp?)"
|
188
|
+
|
189
|
+
if ["NBS CSM", "NBS CS"].include?(serie)
|
190
|
+
docnumber = /v(\d+)n(\d+)/.match(code).to_a[1..-1]&.join("-")
|
191
|
+
else
|
192
|
+
# match docnumbers with localities in the first part, like NBS CIRC 11e2-1915
|
193
|
+
docnumber =
|
194
|
+
/(?:#{serie.gsub(" ", "\s|\.")})(?:\s|\.)?([0-9]+)(?:#{localities})(-[0-9]+)?/
|
195
|
+
.match(code)&.captures&.join
|
196
|
+
|
197
|
+
docnumber ||=
|
198
|
+
/(?:#{serie.gsub(" ", "\s|\.")})(?:\s|\.)? # match serie
|
199
|
+
([0-9]+ # first part of report number
|
200
|
+
(?:#{excluded_parts}[A-Za-z]+)? # with letter but without localities
|
201
|
+
(?:-m)? # for NBS CRPL 4-m-5
|
202
|
+
(?:-[A-Za]+)? # for NIST SP 1075-NCNR, NIST SP 1113-BFRL, NIST IR 6529-a
|
203
|
+
(?:-[0-9.]+)? # second part
|
204
|
+
(?:
|
205
|
+
(?: # only big letter
|
206
|
+
(#{excluded_parts}[A-Z]|(?![a-z]))+|#{excluded_parts}[a-z]?|#{excluded_parts}[a-z]+
|
207
|
+
)? # or small letter but without localities
|
208
|
+
)
|
209
|
+
)/x
|
210
|
+
.match(code)&.[](1)&.upcase
|
211
|
+
end
|
212
|
+
|
213
|
+
unless docnumber
|
214
|
+
raise Errors::ParseError.new(
|
215
|
+
"failed to parse document identifier for #{code}",
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
docnumber
|
220
|
+
end
|
221
|
+
|
71
222
|
def self.match(regex, code)
|
72
223
|
regex.match(code)&.to_s
|
73
224
|
end
|
74
225
|
|
75
|
-
def to_s(format)
|
76
|
-
result =
|
77
|
-
|
78
|
-
|
226
|
+
def to_s(format = :short)
|
227
|
+
result = render_serie(format)
|
228
|
+
result += " " unless format == :short || stage.nil?
|
229
|
+
result += "#{stage&.to_s(format)}"\
|
230
|
+
" #{code}#{render_part(format)}#{render_edition(format)}"\
|
231
|
+
"#{render_localities(format)}"\
|
232
|
+
"#{render_update(format)}#{render_translation(format)}"
|
79
233
|
result = render_addendum(result, format)
|
80
234
|
|
81
235
|
return result.gsub(" ", ".") if format == :mr
|
@@ -83,14 +237,32 @@ module NistPubid
|
|
83
237
|
result
|
84
238
|
end
|
85
239
|
|
240
|
+
def to_json(*args)
|
241
|
+
result = {
|
242
|
+
styles: {
|
243
|
+
short: to_s(:short),
|
244
|
+
abbrev: to_s(:abbrev),
|
245
|
+
long: to_s(:long),
|
246
|
+
mr: to_s(:mr),
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
instance_variables.each do |var|
|
251
|
+
val = instance_variable_get(var)
|
252
|
+
result[var.to_s.gsub('@', '')] = val unless val.nil?
|
253
|
+
end
|
254
|
+
result.to_json(*args)
|
255
|
+
end
|
256
|
+
|
86
257
|
def render_serie(format)
|
87
|
-
|
258
|
+
if serie.to_s(format).include?(publisher.to_s(format))
|
259
|
+
return serie.to_s(format)
|
260
|
+
end
|
88
261
|
|
89
|
-
"#{publisher.to_s(format)} #{serie.to_s(format)}
|
262
|
+
"#{publisher.to_s(format)} #{serie.to_s(format)}"
|
90
263
|
end
|
91
264
|
|
92
265
|
def render_part(format)
|
93
|
-
# TODO: Section, Supplement, Index, Insert, Errata
|
94
266
|
result = ""
|
95
267
|
result += "#{VOLUME_DESC[format]}#{volume}" unless volume.nil?
|
96
268
|
result += "#{PART_DESC[format]}#{part}" unless part.nil?
|
@@ -99,24 +271,44 @@ module NistPubid
|
|
99
271
|
|
100
272
|
def render_edition(format)
|
101
273
|
result = ""
|
102
|
-
|
274
|
+
|
275
|
+
result += "#{REVISION_DESC[format]}#{revision.to_s.upcase}" if revision
|
103
276
|
result += "#{VERSION_DESC[format]}#{version}" unless version.nil?
|
104
277
|
result += "#{EDITION_DESC[format]}#{edition}" unless edition.nil?
|
105
278
|
result
|
106
279
|
end
|
107
280
|
|
281
|
+
def render_localities(format)
|
282
|
+
result = ""
|
283
|
+
result += "#{SUPPLEMENT_DESC[format]}#{supplement}" unless supplement.nil?
|
284
|
+
result += "#{SECTION_DESC[format]}#{section}" unless section.nil?
|
285
|
+
result += "#{APPENDIX_DESC[format]}" unless appendix.nil?
|
286
|
+
result += "#{ERRATA_DESC[format]}" unless errata.nil?
|
287
|
+
result += INDEX_DESC[format] unless index.nil?
|
288
|
+
result += INSERT_DESC[format] unless insert.nil?
|
289
|
+
|
290
|
+
result
|
291
|
+
end
|
292
|
+
|
108
293
|
def render_update(format)
|
109
|
-
return "" if
|
294
|
+
return "" if update_year.nil?
|
295
|
+
|
296
|
+
if update_number.match?(/\d+/)
|
297
|
+
update_text = update_number
|
298
|
+
update_text += "-#{update_year}" if update_year
|
299
|
+
else
|
300
|
+
update_text = "1"
|
301
|
+
end
|
110
302
|
|
111
303
|
case format
|
112
304
|
when :long
|
113
|
-
" Update #{
|
305
|
+
" Update #{update_text}"
|
114
306
|
when :abbrev
|
115
|
-
" Upd. #{
|
307
|
+
" Upd. #{update_text}"
|
116
308
|
when :short
|
117
|
-
"/Upd
|
309
|
+
"/Upd#{update_text}"
|
118
310
|
when :mr
|
119
|
-
".u#{
|
311
|
+
".u#{update_text}"
|
120
312
|
end
|
121
313
|
end
|
122
314
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "relaton_nist/data_fetcher"
|
2
|
+
require "nokogiri"
|
3
|
+
require "open-uri"
|
4
|
+
|
5
|
+
module NistPubid
|
6
|
+
class NistTechPubs
|
7
|
+
URL = "https://raw.githubusercontent.com/usnistgov/NIST-Tech-Pubs/nist-pages/xml/allrecords.xml".freeze
|
8
|
+
|
9
|
+
@converted_id = @converted_doi = {}
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
attr_accessor :documents, :converted_id, :converted_doi
|
14
|
+
|
15
|
+
def fetch
|
16
|
+
@documents ||= Nokogiri::XML(URI.open(URL))
|
17
|
+
.xpath("/body/query/doi_record/report-paper/report-paper_metadata")
|
18
|
+
.map { |doc| parse_docid doc }
|
19
|
+
rescue StandardError => e
|
20
|
+
warn e.message
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
|
24
|
+
def convert(doc)
|
25
|
+
id = @converted_id[doc[:id]] ||= NistPubid::Document.parse(doc[:id])
|
26
|
+
return id unless doc.key?(:doi)
|
27
|
+
|
28
|
+
begin
|
29
|
+
doi = @converted_doi[doc[:doi]] ||=
|
30
|
+
NistPubid::Document.parse(doc[:doi])
|
31
|
+
rescue Errors::ParseError
|
32
|
+
return id
|
33
|
+
end
|
34
|
+
# return more complete pubid
|
35
|
+
id.merge(doi)
|
36
|
+
rescue Errors::ParseError
|
37
|
+
@converted_doi[doc[:doi]] ||= NistPubid::Document.parse(doc[:doi])
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_docid(doc)
|
41
|
+
id = doc.at("publisher_item/item_number", "publisher_item/identifier")
|
42
|
+
.text.sub(%r{^/}, "")
|
43
|
+
doi = doc.at("doi_data/doi").text.gsub("10.6028/", "")
|
44
|
+
title = doc.at("titles/title").text
|
45
|
+
title += " #{doc.at('titles/subtitle').text}" if doc.at("titles/subtitle")
|
46
|
+
case doi
|
47
|
+
when "10.6028/NBS.CIRC.12e2revjune" then id.sub!("13e", "12e")
|
48
|
+
when "10.6028/NBS.CIRC.36e2" then id.sub!("46e", "36e")
|
49
|
+
when "10.6028/NBS.HB.67suppJune1967" then id.sub!("1965", "1967")
|
50
|
+
when "10.6028/NBS.HB.105-1r1990" then id.sub!("105-1-1990", "105-1r1990")
|
51
|
+
when "10.6028/NIST.HB.150-10-1995" then id.sub!(/150-10$/, "150-10-1995")
|
52
|
+
end
|
53
|
+
|
54
|
+
{ id: id, doi: doi, title: title }
|
55
|
+
end
|
56
|
+
|
57
|
+
def comply_with_pubid
|
58
|
+
fetch.select do |doc|
|
59
|
+
convert(doc).to_s == doc[:id]
|
60
|
+
rescue Errors::ParseError
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def different_with_pubid
|
66
|
+
fetch.reject do |doc|
|
67
|
+
convert(doc).to_s == doc[:id]
|
68
|
+
rescue Errors::ParseError
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_fail_with_pubid
|
74
|
+
fetch.select do |doc|
|
75
|
+
convert(doc).to_s && false
|
76
|
+
rescue Errors::ParseError
|
77
|
+
true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# returning current document id, doi, title and final PubID
|
82
|
+
def status
|
83
|
+
fetch.map do |doc|
|
84
|
+
final_doc = convert(doc)
|
85
|
+
{
|
86
|
+
id: doc[:id],
|
87
|
+
doi: doc[:doi],
|
88
|
+
title: doc[:title],
|
89
|
+
finalPubId: final_doc.to_s,
|
90
|
+
mr: final_doc.to_s(:mr),
|
91
|
+
}
|
92
|
+
rescue Errors::ParseError
|
93
|
+
{
|
94
|
+
id: doc[:id],
|
95
|
+
doi: doc[:doi],
|
96
|
+
title: doc[:title],
|
97
|
+
finalPubId: "parse error",
|
98
|
+
mr: "parse_error"
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/nist_pubid/publisher.rb
CHANGED
data/lib/nist_pubid/serie.rb
CHANGED
@@ -8,7 +8,7 @@ module NistPubid
|
|
8
8
|
@serie = serie == "NISTIR" ? "NIST IR" : serie
|
9
9
|
end
|
10
10
|
|
11
|
-
def to_s(format)
|
11
|
+
def to_s(format = :short)
|
12
12
|
return @serie if %i[short mr].include?(format)
|
13
13
|
|
14
14
|
result = SERIES[format.to_s][@serie]
|
@@ -18,7 +18,9 @@ module NistPubid
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.regexp
|
21
|
-
/(#{(SERIES["long"].keys + SERIES["mr"].values
|
21
|
+
/(#{(SERIES["long"].keys + SERIES["mr"].values
|
22
|
+
.map { |v| v.gsub(".", '\.') } + ["NISTIR"])
|
23
|
+
.sort_by(&:length).reverse.join('|')})/
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
data/lib/nist_pubid/stage.rb
CHANGED
@@ -2,21 +2,36 @@ STAGES = YAML.load_file(File.join(File.dirname(__FILE__), "../../stages.yaml"))
|
|
2
2
|
|
3
3
|
module NistPubid
|
4
4
|
class Stage
|
5
|
-
attr_accessor :stage
|
5
|
+
attr_accessor :stage, :original_code
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
|
7
|
+
def initialize(original_code)
|
8
|
+
self.original_code = original_code
|
9
|
+
@stage = self.class.regexp.match(original_code)&.[](1)
|
9
10
|
end
|
10
11
|
|
11
|
-
def to_s(format)
|
12
|
-
return "" if
|
13
|
-
return "#{@stage} " if %i[short mr].include?(format)
|
12
|
+
def to_s(format = :short)
|
13
|
+
return "" if nil?
|
14
14
|
|
15
|
-
|
15
|
+
case format
|
16
|
+
when :short
|
17
|
+
"(#{@stage})"
|
18
|
+
when :mr
|
19
|
+
@stage
|
20
|
+
else
|
21
|
+
STAGES[@stage]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.parse(code)
|
26
|
+
new(regexp.match(code)&.to_s)
|
16
27
|
end
|
17
28
|
|
18
29
|
def self.regexp
|
19
|
-
|
30
|
+
/\((#{STAGES.keys.join('|')})\)/
|
31
|
+
end
|
32
|
+
|
33
|
+
def nil?
|
34
|
+
@stage.nil?
|
20
35
|
end
|
21
36
|
end
|
22
37
|
end
|
data/lib/nist_pubid/version.rb
CHANGED
data/lib/nist_pubid.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "yaml"
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
require_relative "nist_pubid/document"
|
5
|
+
require_relative "nist_pubid/publisher"
|
6
|
+
require_relative "nist_pubid/serie"
|
7
|
+
require_relative "nist_pubid/stage"
|
8
|
+
require_relative "nist_pubid/errors"
|
9
|
+
require_relative "nist_pubid/nist_tech_pubs"
|
data/nist_pubid.gemspec
CHANGED
@@ -28,4 +28,10 @@ Gem::Specification.new do |spec|
|
|
28
28
|
|
29
29
|
spec.add_development_dependency "rake", "~> 13.0"
|
30
30
|
spec.add_development_dependency "rspec", "~> 3.0"
|
31
|
+
spec.add_development_dependency "vcr"
|
32
|
+
spec.add_development_dependency "webmock"
|
33
|
+
|
34
|
+
spec.add_dependency "relaton-nist"
|
35
|
+
spec.add_dependency "nokogiri"
|
36
|
+
spec.add_dependency "thor"
|
31
37
|
end
|
data/series.yaml
CHANGED
data/stages.yaml
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nist-pubid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,24 +38,99 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: vcr
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: webmock
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: relaton-nist
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: nokogiri
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: thor
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
41
111
|
description: Library to generate, parse and manipulate NIST PubID.
|
42
112
|
email:
|
43
113
|
- open.source@ribose.com
|
44
|
-
executables:
|
114
|
+
executables:
|
115
|
+
- nist-pubid
|
45
116
|
extensions: []
|
46
117
|
extra_rdoc_files:
|
47
118
|
- README.adoc
|
48
119
|
- LICENSE.txt
|
49
120
|
files:
|
50
121
|
- ".github/workflows/rake.yml"
|
122
|
+
- ".github/workflows/release.yml"
|
51
123
|
- ".rspec"
|
52
124
|
- ".rubocop.yml"
|
53
125
|
- Gemfile
|
54
126
|
- LICENSE.txt
|
55
127
|
- README.adoc
|
56
128
|
- Rakefile
|
129
|
+
- exe/nist-pubid
|
57
130
|
- lib/nist_pubid.rb
|
58
131
|
- lib/nist_pubid/document.rb
|
132
|
+
- lib/nist_pubid/errors.rb
|
133
|
+
- lib/nist_pubid/nist_tech_pubs.rb
|
59
134
|
- lib/nist_pubid/publisher.rb
|
60
135
|
- lib/nist_pubid/serie.rb
|
61
136
|
- lib/nist_pubid/stage.rb
|
@@ -83,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
158
|
- !ruby/object:Gem::Version
|
84
159
|
version: '0'
|
85
160
|
requirements: []
|
86
|
-
rubygems_version: 3.
|
161
|
+
rubygems_version: 3.3.3
|
87
162
|
signing_key:
|
88
163
|
specification_version: 4
|
89
164
|
summary: Library to generate, parse and manipulate NIST PubID.
|