relaton-nist 2.0.0.pre.alpha.3 → 2.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f241e09f50957db23bc91820f9bba18b14ed8fdf237646e0fdaa51f8ebc8f46
4
- data.tar.gz: da8e0ac7ffc24a64f02624467c479369129125f6fdda3fe6da950e05fe2fa9bc
3
+ metadata.gz: 44c06fc2b378b7ac0ad228f82dbfe6d962d5cd22fb27fa8c6f19cfcde20589f7
4
+ data.tar.gz: 96e9c89fdf092af8933e65dc02b98f4d19d70593de2b12a18a18740d85b47d27
5
5
  SHA512:
6
- metadata.gz: fd8257cfae0044309acc0b1818e903be60595e08722c961853f2f663f98395a18202749a89a96cbf587b9ed2b4cdf2a2d33a683fd65944dd5eefef06798e4fe3
7
- data.tar.gz: 2087de5a12a59076d95eb2cc03f920d2dd9c39512ec8cb9e5392f7f0d60b19e7fb59949a4e2e3cca62d4d6e6abb22281098d32c83068646fb08c26b6b7da5c34
6
+ metadata.gz: ca9c2ecb226ceec065fd82db6ce7d4584a0c11176364235102a97c5e3673fb156b60f68631afb5655c91bd313a1d370fe2377ec8c5c6498f06b46e57a478f459
7
+ data.tar.gz: 76bcdb75f303654bbb08bb9cc70c1859795d4ea41d73ee1db0b6f854a595b4871d2038ce169146c8112c08f6fad4631d33b80445b024ae56ff71dd1d7100107c
@@ -7,6 +7,7 @@ on:
7
7
  branches: [ master, main ]
8
8
  tags: [ v* ]
9
9
  pull_request:
10
+ workflow_dispatch:
10
11
 
11
12
  jobs:
12
13
  rake:
data/CLAUDE.md CHANGED
@@ -82,6 +82,21 @@ errors = schema.validate(file)
82
82
 
83
83
  Tests use VCR with WebMock. Cassettes are stored in `spec/vcr_cassettes/` and re-record every 7 days.
84
84
 
85
+ ### Test Data Stubbing
86
+
87
+ Tests pre-load both the NIST index and CSRC pubs-export data from local fixtures in `before(:suite)` (see `spec/support/webmock.rb`), avoiding all HTTP requests for these data sources. VCR is configured to ignore both `index-v1.zip` and `pubs-export` requests (`spec/support/vcr.rb`).
88
+
89
+ - **Index**: A `Relaton::Index::Type` instance is created with `@index` set directly from `spec/fixtures/index-v1.zip`, then injected into `Relaton::Index.pool`. Run `rake spec:update_index` to refresh.
90
+ - **PubsExport**: The `PubsExport` singleton's `@data` is set directly from `spec/fixtures/pubs-export.zip`. Run `rake spec:update_pubs_export` to refresh.
91
+
92
+ To apply the index stubbing pattern to other relaton gems:
93
+
94
+ 1. Add `spec:update_index` rake task (downloads `index-v1.zip` from the gem's GitHub data repo)
95
+ 2. Run `rake spec:update_index` to create `spec/fixtures/index-v1.zip`
96
+ 3. In `spec/support/webmock.rb`: parse the zip once, create a `Type` instance with `@index` set directly, override `actual?` to return `true`, inject into `Relaton::Index.pool`
97
+ 4. In `spec/support/vcr.rb`: add `ignore_request` for `index-v1.zip`
98
+ 5. Remove any `allow_any_instance_of(Relaton::Index::Type)` workarounds from specs
99
+
85
100
  ## Key Dependencies
86
101
 
87
102
  - `relaton-bib` — base bibliographic models and shared mixins
data/Gemfile CHANGED
@@ -3,6 +3,7 @@ source "https://rubygems.org"
3
3
  # Specify your gem's dependencies in relaton_nist.gemspec
4
4
  gemspec
5
5
 
6
+
6
7
  gem "equivalent-xml", "~> 0.6"
7
8
  gem "pry-byebug"
8
9
  gem "rake", "~> 13.0"
data/README.adoc CHANGED
@@ -405,6 +405,25 @@ refer to the https://github.com/relaton/relaton-logger#usage[relaton-logger]
405
405
  documentation.
406
406
 
407
407
 
408
+ == Development
409
+
410
+ === Updating test fixtures
411
+
412
+ The test suite uses local copies of the NIST index and CSRC pubs-export data
413
+ to avoid network requests. To update the fixtures:
414
+
415
+ [source,sh]
416
+ ----
417
+ $ rake spec:update_index
418
+ $ rake spec:update_pubs_export
419
+ ----
420
+
421
+ `spec:update_index` downloads the latest `index-v1.zip` from the
422
+ https://github.com/relaton/relaton-data-nist[relaton-data-nist] repository.
423
+
424
+ `spec:update_pubs_export` downloads the latest `pubs-export.zip` from
425
+ the NIST Cybersecurity Resource Center (CSRC).
426
+
408
427
  == Contributing
409
428
 
410
429
  Bug reports and pull requests are welcome.
data/Rakefile CHANGED
@@ -4,3 +4,45 @@ require "rspec/core/rake_task"
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  task :default => :spec
7
+
8
+ namespace :spec do
9
+ desc "Download latest NIST index fixture from relaton-data-nist"
10
+ task :update_index do
11
+ require "net/http"
12
+ require "uri"
13
+
14
+ url = "https://raw.githubusercontent.com/relaton/relaton-data-nist/data-v2/index-v1.zip"
15
+ dest = File.join(__dir__, "spec", "fixtures", "index-v1.zip")
16
+
17
+ puts "Downloading #{url} ..."
18
+ uri = URI.parse(url)
19
+ response = Net::HTTP.get_response(uri)
20
+
21
+ if response.is_a?(Net::HTTPSuccess)
22
+ File.binwrite(dest, response.body)
23
+ puts "Updated #{dest} (#{response.body.bytesize} bytes)"
24
+ else
25
+ abort "Failed to download: HTTP #{response.code}"
26
+ end
27
+ end
28
+
29
+ desc "Download latest NIST pubs-export fixture from CSRC"
30
+ task :update_pubs_export do
31
+ require "net/http"
32
+ require "uri"
33
+
34
+ url = "https://csrc.nist.gov/CSRC/media/feeds/metanorma/pubs-export.zip"
35
+ dest = File.join(__dir__, "spec", "fixtures", "pubs-export.zip")
36
+
37
+ puts "Downloading #{url} ..."
38
+ uri = URI.parse(url)
39
+ response = Net::HTTP.get_response(uri)
40
+
41
+ if response.is_a?(Net::HTTPSuccess)
42
+ File.binwrite(dest, response.body)
43
+ puts "Updated #{dest} (#{response.body.bytesize} bytes)"
44
+ else
45
+ abort "Failed to download: HTTP #{response.code}"
46
+ end
47
+ end
48
+ end
data/grammars/biblio.rng CHANGED
@@ -2015,15 +2015,11 @@ provided that it is not the entire bibliographic item that is so related</a:docu
2015
2015
  <a:documentation>A version of the bibliographic item (within an edition). Can be used for drafts</a:documentation>
2016
2016
  <element name="version">
2017
2017
  <optional>
2018
- <ref name="revision-date">
2019
- <a:documentation>The date at which the current version of the bibliographic item was produced</a:documentation>
2020
- </ref>
2021
- </optional>
2022
- <optional>
2023
- <ref name="draft">
2024
- <a:documentation>The identifier for the current draft of the bibliographic item</a:documentation>
2025
- </ref>
2018
+ <attribute name="type">
2019
+ <a:documentation>Versioning scheme, in case of multiple versioning schemes</a:documentation>
2020
+ </attribute>
2026
2021
  </optional>
2022
+ <text/>
2027
2023
  </element>
2028
2024
  </define>
2029
2025
  <define name="vedition">
@@ -1,6 +1,7 @@
1
1
  module Relaton
2
2
  module Nist
3
3
  class Bibdata < Item
4
+ model ItemData
4
5
  include Bib::BibdataShared
5
6
  end
6
7
  end
@@ -1,6 +1,7 @@
1
1
  module Relaton
2
2
  module Nist
3
3
  class Bibitem < Item
4
+ model ItemData
4
5
  include Bib::BibitemShared
5
6
  end
6
7
  end
@@ -4,17 +4,13 @@ require_relative "comment_period"
4
4
  module Relaton
5
5
  module Nist
6
6
  class Ext < Bib::Ext
7
- attribute :schema_version, method: :get_schema_version
8
7
  attribute :doctype, Doctype
9
8
  attribute :commentperiod, CommentPeriod
10
9
 
11
- xml do
12
- map_element "commentperiod", to: :commentperiod
13
- end
10
+ xml { map_element "commentperiod", to: :commentperiod }
11
+ key_value { map_element "commentperiod", to: :commentperiod }
14
12
 
15
- def get_schema_version
16
- Relaton.schema_versions["relaton-model-nist"]
17
- end
13
+ def get_schema_version = Relaton.schema_versions["relaton-model-nist"]
18
14
  end
19
15
  end
20
16
  end
@@ -169,14 +169,32 @@ module Relaton
169
169
  #
170
170
  def sort_hits!
171
171
  @array.sort! do |a, b|
172
- code = a.hit[:code] <=> b.hit[:code]
173
- next code unless code.zero?
172
+ base_a, upd_a = base_and_update(a.hit[:code])
173
+ base_b, upd_b = base_and_update(b.hit[:code])
174
+
175
+ cmp = base_a <=> base_b
176
+ next cmp unless cmp.zero?
177
+
178
+ # Same base code: prefer higher /UpdN (latest update wins).
179
+ cmp = upd_b <=> upd_a
180
+ next cmp unless cmp.zero?
174
181
 
175
182
  b.hit[:release_date] <=> a.hit[:release_date]
176
183
  end
177
184
  self
178
185
  end
179
186
 
187
+ # Split a code like "NIST FIPS 140-2/Upd2" into ["NIST FIPS 140-2", 2].
188
+ # Codes without an update suffix return update 0.
189
+ def base_and_update(code)
190
+ code = code.to_s
191
+ if (m = code.match(%r{\A(.*?)/Upd(\d+)\z}))
192
+ [m[1], m[2].to_i]
193
+ else
194
+ [code, 0]
195
+ end
196
+ end
197
+
180
198
  def pubid(id = ref)
181
199
  Pubid::Nist::Identifier.parse(id).to_s
182
200
  rescue StandardError
@@ -230,12 +248,16 @@ module Relaton
230
248
  id.sub!(/(?:-draft\d*|\.\wpd)$/, "")
231
249
  id = id.gsub(".", " ").sub(/-Add(\d*)$/, ' Add\1') if id.match?(/-Add\d*$/)
232
250
  pid = ::Pubid::Nist::Identifier.parse(id)
233
- case json["iteration"]
234
- when "final"
235
- pid.stage = ::Pubid::Nist::Stage.new id: "f", type: "pd"
251
+
252
+ # Stage: URI is authoritative, fall back to iteration. "final" => no stage.
253
+ uri_stage = json["uri"] && json["uri"][%r{/(final|ipd|fpd|\dpd)(?:-\(\d+\))?(?:/|$)}, 1]
254
+ stage_src = uri_stage || json["iteration"]
255
+ case stage_src
256
+ when nil, "final"
257
+ # no stage — "final" means published
236
258
  when "fpd"
237
259
  pid.stage = ::Pubid::Nist::Stage.new id: "f", type: "pd"
238
- when /(\w)pd/
260
+ when /\A(\w)pd\z/
239
261
  pid.stage = ::Pubid::Nist::Stage.new id: Regexp.last_match(1), type: "pd"
240
262
  end
241
263
 
@@ -243,7 +265,7 @@ module Relaton
243
265
  pid.update = Pubid::Nist::Update.new number: upd if upd
244
266
  pid.to_s
245
267
  rescue StandardError
246
- id += " #{json["iteration"].sub('final', 'fpd')}" if json["iteration"]
268
+ id += " #{json["iteration"]}" if json["iteration"] && json["iteration"] != "final"
247
269
  id
248
270
  end
249
271
 
@@ -1,5 +1,5 @@
1
1
  module Relaton
2
2
  module Nist
3
- VERSION = "2.0.0-alpha.3".freeze
3
+ VERSION = "2.1.0".freeze
4
4
  end
5
5
  end
@@ -25,9 +25,9 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_dependency "base64"
27
27
  spec.add_dependency "mechanize", "~> 2.0"
28
- spec.add_dependency "loc_mods", "~> 0.2.0"
28
+ spec.add_dependency "loc_mods", "~> 0.3.0"
29
29
  spec.add_dependency "pubid", "~> 1.15.6"
30
- spec.add_dependency "relaton-bib", "~> 2.0.0-alpha.7"
30
+ spec.add_dependency "relaton-bib", "~> 2.1.0"
31
31
  spec.add_dependency "relaton-core", "~> 0.0.13"
32
32
  spec.add_dependency "relaton-index", "~> 0.2.0"
33
33
  spec.add_dependency "rubyzip"
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relaton-nist
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre.alpha.3
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-05-04 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: base64
@@ -43,14 +44,14 @@ dependencies:
43
44
  requirements:
44
45
  - - "~>"
45
46
  - !ruby/object:Gem::Version
46
- version: 0.2.0
47
+ version: 0.3.0
47
48
  type: :runtime
48
49
  prerelease: false
49
50
  version_requirements: !ruby/object:Gem::Requirement
50
51
  requirements:
51
52
  - - "~>"
52
53
  - !ruby/object:Gem::Version
53
- version: 0.2.0
54
+ version: 0.3.0
54
55
  - !ruby/object:Gem::Dependency
55
56
  name: pubid
56
57
  requirement: !ruby/object:Gem::Requirement
@@ -71,14 +72,14 @@ dependencies:
71
72
  requirements:
72
73
  - - "~>"
73
74
  - !ruby/object:Gem::Version
74
- version: 2.0.0.pre.alpha.7
75
+ version: 2.1.0
75
76
  type: :runtime
76
77
  prerelease: false
77
78
  version_requirements: !ruby/object:Gem::Requirement
78
79
  requirements:
79
80
  - - "~>"
80
81
  - !ruby/object:Gem::Version
81
- version: 2.0.0.pre.alpha.7
82
+ version: 2.1.0
82
83
  - !ruby/object:Gem::Dependency
83
84
  name: relaton-core
84
85
  requirement: !ruby/object:Gem::Requirement
@@ -165,14 +166,14 @@ files:
165
166
  - lib/relaton/nist/relation.rb
166
167
  - lib/relaton/nist/scraper.rb
167
168
  - lib/relaton/nist/series.yaml
168
- - lib/relaton/nist/tech_pubs_parser.rb
169
169
  - lib/relaton/nist/util.rb
170
170
  - lib/relaton/nist/version.rb
171
- - relaton_nist.gemspec
171
+ - relaton-nist.gemspec
172
172
  homepage: https://github.com/metanorma/relaton-nist
173
173
  licenses:
174
174
  - MIT
175
175
  metadata: {}
176
+ post_install_message:
176
177
  rdoc_options: []
177
178
  require_paths:
178
179
  - lib
@@ -187,7 +188,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
188
  - !ruby/object:Gem::Version
188
189
  version: '0'
189
190
  requirements: []
190
- rubygems_version: 3.6.9
191
+ rubygems_version: 3.5.22
192
+ signing_key:
191
193
  specification_version: 4
192
194
  summary: 'Relaton::Nist: retrive NIST standards.'
193
195
  test_files: []
@@ -1,321 +0,0 @@
1
- module Relaton
2
- module Nist
3
- class TechPubsParser
4
- RELATION_TYPES = {
5
- "replaces" => "obsoletes",
6
- "isVersionOf" => "editionOf",
7
- "hasTranslation" => "hasTranslation",
8
- "isTranslationOf" => "translatedFrom",
9
- "hasPreprint" => "hasReprint",
10
- "isPreprintOf" => "hasDraft",
11
- "isSupplementTo" => "complements",
12
- "isPartOf" => "partOf",
13
- "hasPart" => "hasPart",
14
- }.freeze
15
-
16
- ATTRS = %i[docidentifier title source abstract date edition contributor
17
- relation status place series].freeze
18
- NS = "http://www.crossref.org/relations.xsd".freeze
19
-
20
- def initialize(doc, series)
21
- @doc = doc
22
- @series = series
23
- end
24
-
25
- #
26
- # Parse XML document
27
- #
28
- # @param doc [Nokogiri::XML::Element] XML document
29
- # @param series [Hash] series hash map
30
- #
31
- # @return [Relaton::Nist::ItemData] bibliographic item
32
- #
33
- def self.parse(doc, series)
34
- new(doc, series).parse
35
- end
36
-
37
- #
38
- # Create document instance
39
- #
40
- # @return [Relaton::Nist::ItemData] bibliographic item
41
- #
42
- def parse
43
- ItemData.new(
44
- type: "standard", language: [@doc["language"]], script: ["Latn"],
45
- ext: Ext.new(doctype: parse_doctype), **args
46
- )
47
- end
48
-
49
- def args
50
- ATTRS.to_h { |a| [a, send("parse_#{a}")] }
51
- end
52
-
53
- # @return [Array<Bib::Docidentifier>]
54
- def parse_docidentifier
55
- [
56
- { type: "NIST", content: pub_id, primary: true },
57
- { type: "DOI", content: doi },
58
- ].map { |id| Bib::Docidentifier.new(**id) }
59
- end
60
-
61
- #
62
- # Parse document's ID from XML
63
- #
64
- # @return [String] document's ID
65
- #
66
- def pub_id
67
- if doi
68
- doi.split("/")[1..].join("/").gsub(".", " ").sub(/^[\D]+/, &:upcase)
69
- else
70
- @doc.at("publisher_item/item_number").text
71
- end
72
- end
73
-
74
- def doi # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
75
- return @doi if defined? @doi
76
-
77
- @doi = begin
78
- id = @doc.at("doi_data/doi")&.text
79
- case id
80
- when "10.6028/NBS.CIRC.e2e" then "10.6028/NBS.CIRC.2e2"
81
- when "10.6028/NBS.CIRC.sup" then "10.6028/NBS.CIRC.24e7sup"
82
- when "10.6028/NBS.CIRC.supJun1925-Jun1926" then "10.6028/NBS.CIRC.24e7sup2"
83
- when "10.6028/NBS.CIRC.supJun1925-Jun1927" then "10.6028/NBS.CIRC.24e7sup3"
84
- when "10.6028/NBS.CIRC.24supJuly1922" then "10.6028/NBS.CIRC.24e6sup"
85
- when "10.6028/NBS.CIRC.24supJan1924" then "10.6028/NBS.CIRC.24e6sup2"
86
- else id
87
- end
88
- end
89
- end
90
-
91
- # @return [Array<Bib::Title>]
92
- def parse_title
93
- t = @doc.xpath("titles/title|titles/subtitle")
94
- return [] unless t.any?
95
-
96
- [Bib::Title.new(content: t.map(&:text).join("\n"), language: "en", script: "Latn")]
97
- end
98
-
99
- # @return [Array<Bib::Uri>]
100
- def parse_source
101
- pdf_url = @doc.at("doi_data/resource").text
102
- doi_url = "https://doi.org/#{doi}"
103
- [
104
- Bib::Uri.new(type: "doi", content: doi_url),
105
- Bib::Uri.new(type: "pdf", content: pdf_url),
106
- ]
107
- end
108
-
109
- # @return [Array<Bib::LocalizedMarkedUpString>]
110
- def parse_abstract
111
- @doc.xpath(
112
- "jats:abstract/jats:p", "jats" => "http://www.ncbi.nlm.nih.gov/JATS1"
113
- ).each_with_object([]) do |a, m|
114
- next if a.text.empty?
115
-
116
- m << Bib::Abstract.new(
117
- content: a.text, language: @doc["language"], script: "Latn",
118
- )
119
- end
120
- end
121
-
122
- # @return [Array<Bib::Date>]
123
- def parse_date
124
- @doc.xpath("publication_date|approval_date").map do |dt|
125
- on = dt.at("year").text
126
- if (m = dt.at "month")
127
- on += "-#{m.text}"
128
- d = dt.at "day"
129
- on += "-#{d.text}" if d
130
- end
131
- type = dt.name == "publication_date" ? "published" : "confirmed"
132
- Bib::Date.new(type: type, at: on)
133
- end
134
- end
135
-
136
- def parse_doctype
137
- Doctype.new(content: "standard")
138
- end
139
-
140
- # @return [String]
141
- def parse_edition
142
- @doc.at("edition_number")&.text
143
- end
144
-
145
- # @return [Array<Bib::Contributor>]
146
- def parse_contributor # rubocop:disable Metrics/AbcSize
147
- contribs = @doc.xpath("contributors/person_name").map do |p|
148
- person = Bib::Person.new(
149
- name: fullname(p), affiliation: affiliation, identifier: identifier(p),
150
- )
151
- Bib::Contributor.new(
152
- person: person,
153
- role: [Bib::Contributor::Role.new(type: p["contributor_role"])],
154
- )
155
- end
156
- contribs + @doc.xpath("publisher").map do |p|
157
- Bib::Contributor.new(
158
- organization: create_org(p),
159
- role: [Bib::Contributor::Role.new(type: "publisher")],
160
- )
161
- end
162
- end
163
-
164
- def identifier(person)
165
- person.xpath("ORCID").map do |id|
166
- Bib::Person::Identifier.new(type: "orcid", content: id.text)
167
- end
168
- end
169
-
170
- #
171
- # Create full name object from person name element.
172
- #
173
- # @param [Nokogiri::XML::Element] person name element
174
- #
175
- # @return [Bib::FullName] full name object
176
- #
177
- def fullname(person)
178
- fname, initials = forename_initial person
179
- surname = localized_string person.at("surname")&.text
180
- completename = localized_string person.text unless surname
181
- Bib::FullName.new(
182
- surname: surname, forename: fname, formatted_initials: initials,
183
- completename: completename,
184
- )
185
- end
186
-
187
- #
188
- # Create affiliation organization
189
- #
190
- # @return [Array<Bib::Affiliation>] affiliation
191
- #
192
- def affiliation
193
- @doc.xpath("./institution/institution_department").map do |id|
194
- org = Bib::Organization.new(
195
- name: [Bib::TypedLocalizedString.new(content: id.text)],
196
- )
197
- Bib::Affiliation.new(organization: org)
198
- end
199
- end
200
-
201
- #
202
- # Create forename and initials objects from person name element.
203
- #
204
- # @param [Nokogiri::XML::Element] person person name element
205
- #
206
- # @return [Array<Array<Bib::FullNameType::Forename>, Bib::LocalizedString>]
207
- #
208
- def forename_initial(person) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
209
- fnames = []
210
- fname = person.at("given_name")&.text
211
- if fname
212
- if /^(?:(?<name>\w+)\s)?(?<inits>(?:\w(?:\.|\b)\s?)+)/ =~ fname
213
- ints = inits.split(/[.\s]*/)
214
- fnames << forename(name, ints.shift)
215
- ints.each { |i| fnames << forename(nil, i) }
216
- else
217
- fn = forename(fname)
218
- fnames << fn if fn
219
- end
220
- end
221
- initials = localized_string inits unless inits.nil? || inits.empty?
222
- [fnames, initials]
223
- end
224
-
225
- #
226
- # Create forename object
227
- #
228
- # @param [String, nil] cnt forename content
229
- # @param [String, nil] init initial content
230
- #
231
- # @return [Bib::FullNameType::Forename] forename object
232
- #
233
- def forename(cnt, init = nil)
234
- return if (cnt.nil? || cnt.empty?) && (init.nil? || init.empty?)
235
-
236
- Bib::FullNameType::Forename.new(
237
- content: cnt, language: @doc["language"], script: "Latn", initial: init,
238
- )
239
- end
240
-
241
- #
242
- # Create publisher organization
243
- #
244
- # @param [Nokogiri::XML::Element] pub publisher element
245
- #
246
- # @return [Bib::Organization] publisher organization
247
- #
248
- def create_org(pub) # rubocop:disable Metrics/AbcSize
249
- name = pub.at("publisher_name").text
250
- abbr = pub.at("../institution[institution_name[.='#{name}']]/institution_acronym")&.text
251
- place = pub.at("./publisher_place") ||
252
- pub.at("../institution[institution_name[.='#{name}']]/institution_place")
253
- cont = []
254
- if place
255
- city, state = place.text.split(", ")
256
- cont << Bib::Address.new(street: [], city: city, state: state, country: "US")
257
- end
258
- Bib::Organization.new(
259
- name: [Bib::TypedLocalizedString.new(content: name)],
260
- abbreviation: abbr ? Bib::LocalizedString.new(content: abbr) : nil,
261
- address: cont,
262
- )
263
- end
264
-
265
- # @return [Array<Nist::Relation>]
266
- def parse_relation # rubocop:disable Metrics/AbcSize
267
- @doc.xpath("./ns:program/ns:related_item", ns: NS).map do |rel|
268
- rdoi = rel.at_xpath("ns:intra_work_relation|ns:inter_work_relation", ns: NS)
269
- id = rdoi.text.split("/")[1..].join("/").gsub(".", " ")
270
- fref = Bib::Formattedref.new(content: id)
271
- docid = Bib::Docidentifier.new(type: "NIST", content: id, primary: true)
272
- bibitem = ItemData.new(formattedref: fref, docidentifier: [docid])
273
- type = RELATION_TYPES[rdoi["relationship-type"]]
274
- warn "Relation type #{rdoi['relationship-type']} not found" unless type
275
- Relation.new(type: type, bibitem: bibitem)
276
- end
277
- end
278
-
279
- def parse_status
280
- s = @doc.at("./ns:program/ns:related_item/ns:*[@relationship-type='isPreprintOf']", ns: NS)
281
- return unless s
282
-
283
- Bib::Status.new(stage: Bib::Status::Stage.new(content: "preprint"))
284
- end
285
-
286
- # @return [Array<Bib::Place>]
287
- def parse_place
288
- @doc.xpath("institution/institution_place").map do |p|
289
- city, state = p.text.split(", ")
290
- Bib::Place.new(city: city, region: [Bib::Place::RegionType.new(iso: state)])
291
- end
292
- end
293
-
294
- #
295
- # Fetches series
296
- #
297
- # @return [Array<Bib::Series>] series
298
- #
299
- def parse_series
300
- prf, srs, num = pub_id.split
301
- sname = @series[srs] || srs
302
- title = Bib::Title.new(content: "#{prf} #{sname}")
303
- abbr = Bib::LocalizedString.new(content: srs)
304
- [Bib::Series.new(title: [title], abbreviation: abbr, number: num)]
305
- end
306
-
307
- #
308
- # Create localized string
309
- #
310
- # @param [String] content content of string
311
- #
312
- # @return [Bib::LocalizedString] localized string
313
- #
314
- def localized_string(content)
315
- return unless content
316
-
317
- Bib::LocalizedString.new(content: content, language: @doc["language"], script: "Latn")
318
- end
319
- end
320
- end
321
- end