relaton 3.0.6 → 3.0.8
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/bin/relaton +20 -0
- data/lib/relaton/bib/model/docidentifier.rb +17 -2
- data/lib/relaton/bibcollection.rb +146 -0
- data/lib/relaton/bibdata.rb +92 -0
- data/lib/relaton/bipm/data_outcomes_parser.rb +6 -1
- data/lib/relaton/cli/base_convertor.rb +134 -0
- data/lib/relaton/cli/command.rb +390 -0
- data/lib/relaton/cli/data_fetcher.rb +20 -0
- data/lib/relaton/cli/frontend/dist/404.html +18 -0
- data/lib/relaton/cli/frontend/dist/app.iife.js +1 -0
- data/lib/relaton/cli/frontend/dist/style.css +3 -0
- data/lib/relaton/cli/frontend/index.html +14 -0
- data/lib/relaton/cli/frontend/package-lock.json +2945 -0
- data/lib/relaton/cli/frontend/package.json +29 -0
- data/lib/relaton/cli/frontend/public/404.html +18 -0
- data/lib/relaton/cli/frontend/src/App.test.ts +501 -0
- data/lib/relaton/cli/frontend/src/App.vue +506 -0
- data/lib/relaton/cli/frontend/src/app.ts +90 -0
- data/lib/relaton/cli/frontend/src/components/DocumentDetail.test.ts +142 -0
- data/lib/relaton/cli/frontend/src/components/DocumentDetail.vue +228 -0
- data/lib/relaton/cli/frontend/src/components/DocumentRow.vue +88 -0
- data/lib/relaton/cli/frontend/src/components/Icon.test.ts +44 -0
- data/lib/relaton/cli/frontend/src/components/Icon.vue +55 -0
- data/lib/relaton/cli/frontend/src/components/Pagination.vue +26 -0
- data/lib/relaton/cli/frontend/src/dev/main.ts +100 -0
- data/lib/relaton/cli/frontend/src/dev/sample-data.json +71 -0
- data/lib/relaton/cli/frontend/src/lib/filter.test.ts +88 -0
- data/lib/relaton/cli/frontend/src/lib/filter.ts +95 -0
- data/lib/relaton/cli/frontend/src/lib/hydrate.test.ts +102 -0
- data/lib/relaton/cli/frontend/src/lib/hydrate.ts +55 -0
- data/lib/relaton/cli/frontend/src/lib/shards.test.ts +319 -0
- data/lib/relaton/cli/frontend/src/lib/shards.ts +183 -0
- data/lib/relaton/cli/frontend/src/lib/types.ts +148 -0
- data/lib/relaton/cli/frontend/src/lib/url.test.ts +151 -0
- data/lib/relaton/cli/frontend/src/lib/url.ts +111 -0
- data/lib/relaton/cli/frontend/src/shims-vue.d.ts +5 -0
- data/lib/relaton/cli/frontend/src/styles/index.css +27 -0
- data/lib/relaton/cli/frontend/src/test/fetch.ts +58 -0
- data/lib/relaton/cli/frontend/tsconfig.json +20 -0
- data/lib/relaton/cli/frontend/vite.config.ts +42 -0
- data/lib/relaton/cli/frontend/vitest.config.ts +11 -0
- data/lib/relaton/cli/frontend_assets.rb +58 -0
- data/lib/relaton/cli/full_text_search.rb +98 -0
- data/lib/relaton/cli/i18n.yaml +1 -0
- data/lib/relaton/cli/index_item_normalizer.rb +380 -0
- data/lib/relaton/cli/index_site_generator.rb +1015 -0
- data/lib/relaton/cli/relaton_file.rb +290 -0
- data/lib/relaton/cli/subcommand_collection.rb +263 -0
- data/lib/relaton/cli/subcommand_db.rb +81 -0
- data/lib/relaton/cli/templates/_document.liquid +111 -0
- data/lib/relaton/cli/templates/_index.liquid +61 -0
- data/lib/relaton/cli/templates/index/page.liquid +20 -0
- data/lib/relaton/cli/templates/index-style.css +1017 -0
- data/lib/relaton/cli/util.rb +8 -0
- data/lib/relaton/cli/version.rb +11 -0
- data/lib/relaton/cli/xml_convertor.rb +47 -0
- data/lib/relaton/cli/xml_to_html_renderer.rb +117 -0
- data/lib/relaton/cli/yaml_convertor.rb +102 -0
- data/lib/relaton/cli.rb +113 -0
- data/lib/relaton/doi/CLAUDE.md +1 -1
- data/lib/relaton/element_finder.rb +29 -0
- data/lib/relaton/gb/CLAUDE.md +1 -1
- data/lib/relaton/ietf/CLAUDE.md +1 -1
- data/lib/relaton/iho/CLAUDE.md +3 -3
- data/lib/relaton/iho/bibliography.rb +41 -27
- data/lib/relaton/iho/processor.rb +3 -2
- data/lib/relaton/nist/CLAUDE.md +11 -1
- data/lib/relaton/nist/README.adoc +7 -1
- data/lib/relaton/nist/hit_collection.rb +25 -1
- data/lib/relaton/nist/mods_parser.rb +32 -8
- data/lib/relaton/nist/pubs_export.rb +69 -11
- data/lib/relaton/ogc/CLAUDE.md +1 -1
- data/lib/relaton/omg/CLAUDE.md +1 -1
- data/lib/relaton/plateau/CLAUDE.md +1 -1
- data/lib/relaton/render/general.rb +319 -0
- data/lib/relaton/render/iso690/csl_import.rb +129 -0
- data/lib/relaton/render/iso690/element.rb +153 -0
- data/lib/relaton/render/iso690/elements/access.rb +44 -0
- data/lib/relaton/render/iso690/elements/authorizer.rb +45 -0
- data/lib/relaton/render/iso690/elements/citeid.rb +39 -0
- data/lib/relaton/render/iso690/elements/component_part.rb +97 -0
- data/lib/relaton/render/iso690/elements/creator.rb +267 -0
- data/lib/relaton/render/iso690/elements/edition.rb +97 -0
- data/lib/relaton/render/iso690/elements/extent.rb +71 -0
- data/lib/relaton/render/iso690/elements/identifier.rb +46 -0
- data/lib/relaton/render/iso690/elements/location.rb +73 -0
- data/lib/relaton/render/iso690/elements/medium.rb +32 -0
- data/lib/relaton/render/iso690/elements/numeration.rb +26 -0
- data/lib/relaton/render/iso690/elements/production.rb +111 -0
- data/lib/relaton/render/iso690/elements/pub_date.rb +63 -0
- data/lib/relaton/render/iso690/elements/series.rb +66 -0
- data/lib/relaton/render/iso690/elements/size.rb +45 -0
- data/lib/relaton/render/iso690/elements/status.rb +30 -0
- data/lib/relaton/render/iso690/elements/stddoc.rb +40 -0
- data/lib/relaton/render/iso690/elements/title.rb +56 -0
- data/lib/relaton/render/iso690/elements/updated.rb +38 -0
- data/lib/relaton/render/iso690/elements.rb +67 -0
- data/lib/relaton/render/iso690/fields.rb +142 -0
- data/lib/relaton/render/iso690/i18n/en.yml +48 -0
- data/lib/relaton/render/iso690/i18n/fr.yml +14 -0
- data/lib/relaton/render/iso690/i18n/ja.yml +38 -0
- data/lib/relaton/render/iso690/i18n.rb +83 -0
- data/lib/relaton/render/iso690/identifier_kinds.rb +29 -0
- data/lib/relaton/render/iso690/index_renderer.rb +57 -0
- data/lib/relaton/render/iso690/kinds.rb +53 -0
- data/lib/relaton/render/iso690/renderer.rb +150 -0
- data/lib/relaton/render/iso690/rules/bipm.rb +186 -0
- data/lib/relaton/render/iso690/rules/jis.rb +103 -0
- data/lib/relaton/render/iso690/rules/nist.rb +384 -0
- data/lib/relaton/render/iso690/rules.rb +227 -0
- data/lib/relaton/render/iso690/style/locale.rb +59 -0
- data/lib/relaton/render/iso690/style/name_form.rb +87 -0
- data/lib/relaton/render/iso690/style/scheme.rb +33 -0
- data/lib/relaton/render/iso690/style/sort_rule.rb +25 -0
- data/lib/relaton/render/iso690/style/template_map.rb +40 -0
- data/lib/relaton/render/iso690/style/type_template.rb +45 -0
- data/lib/relaton/render/iso690/style.rb +227 -0
- data/lib/relaton/render/iso690/styles/apa.yml +45 -0
- data/lib/relaton/render/iso690/styles/author-date.yml +31 -0
- data/lib/relaton/render/iso690/styles/chicago.yml +49 -0
- data/lib/relaton/render/iso690/styles/ieee-sa.yml +45 -0
- data/lib/relaton/render/iso690/styles/jis-en.yml +68 -0
- data/lib/relaton/render/iso690/styles/jis-ja.yml +67 -0
- data/lib/relaton/render/iso690/styles/lncs.yml +54 -0
- data/lib/relaton/render/iso690/styles/mla.yml +56 -0
- data/lib/relaton/render/iso690/template.rb +248 -0
- data/lib/relaton/render/iso690.rb +28 -0
- data/lib/relaton/render/version.rb +5 -0
- data/lib/relaton/un/CLAUDE.md +1 -1
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton-cli.rb +17 -0
- data/lib/relaton-render.rb +13 -0
- metadata +192 -21
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
module Rules
|
|
7
|
+
# The JIS rule set, moved verbatim from the metanorma-jis
|
|
8
|
+
# flavor's JisElements: the host-title-first component part
|
|
9
|
+
# (with the 1.x orphaned close paren), the host-series
|
|
10
|
+
# fallback, and the book-family extent. Select from pack data:
|
|
11
|
+
# rules: { component_part: jis_component_part, ... }
|
|
12
|
+
module Jis
|
|
13
|
+
# The host of a part citation, 1.x parity: the host title,
|
|
14
|
+
# then the host's principal creator, closed by a paren the
|
|
15
|
+
# 1.x cleanup had orphaned when the host role came out empty
|
|
16
|
+
# ("Collected Essays UNICEF)")
|
|
17
|
+
class JisComponentPart < Elements::ComponentPart
|
|
18
|
+
def render
|
|
19
|
+
return "" if host_title_text.empty?
|
|
20
|
+
|
|
21
|
+
"#{host_title_text} #{host_creators}#{close_paren}".strip
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def host_creators
|
|
27
|
+
author = Array(host&.contributor)
|
|
28
|
+
.find { |c| has_role?(c, "author") } or return ""
|
|
29
|
+
|
|
30
|
+
person = author.person
|
|
31
|
+
if person.nil?
|
|
32
|
+
Array(author.organization&.name).map { |n| localized(n) }
|
|
33
|
+
.reject(&:empty?).join(", ")
|
|
34
|
+
else
|
|
35
|
+
host_person_name(author, first: true)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def close_paren
|
|
40
|
+
@i18n.punct_fetch("close-paren", ")")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# A part cites its host's series when it carries none of its
|
|
45
|
+
# own (the 1.x series fallback to the host document)
|
|
46
|
+
class JisSeries < Elements::Series
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def series
|
|
50
|
+
super || Array(host_relation&.bibitem&.series).first
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def host_relation
|
|
54
|
+
Array(@model.relation).find do |r|
|
|
55
|
+
Elements::ComponentPart::HOST_RELATION_TYPES.include?(r.type)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The book-family extent carries the volume and the page
|
|
61
|
+
# only, and repeated localities of one type collapse to the
|
|
62
|
+
# last declared (the 1.x per-type merge)
|
|
63
|
+
class JisExtent < Elements::Extent
|
|
64
|
+
def render
|
|
65
|
+
return super unless book_family?
|
|
66
|
+
|
|
67
|
+
[volume_part, page_part].reject(&:empty?).join(" ")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def book_family?
|
|
73
|
+
%w[book inbook incollection inproceedings proceedings]
|
|
74
|
+
.include?(@model.type.to_s)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def volume_part
|
|
78
|
+
loc = pick("volume") or return ""
|
|
79
|
+
loc.reference_from.to_s.empty? ? "" :
|
|
80
|
+
unit("volume", loc.reference_from)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def page_part
|
|
84
|
+
loc = pick("page") or return ""
|
|
85
|
+
from = loc.reference_from.to_s
|
|
86
|
+
to = loc.reference_to.to_s
|
|
87
|
+
if to.empty? || to == from
|
|
88
|
+
unit("page", from)
|
|
89
|
+
else
|
|
90
|
+
unit("pages", "#{from}#{@i18n.label('date_range')}#{to}")
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The last locality of a type wins (the 1.x merge)
|
|
95
|
+
def pick(type)
|
|
96
|
+
localities.reverse.find { |l| l.type == type }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
module Rules
|
|
7
|
+
# The NIST rule set, moved verbatim from the metanorma-nist
|
|
8
|
+
# flavor's NistElements: the corporate creator forms, the
|
|
9
|
+
# series derivation from nist-long identifiers, the draft
|
|
10
|
+
# stage forms, the identifier order, and the component-part
|
|
11
|
+
# host citation. Select from pack data:
|
|
12
|
+
# rules: { creator: nist_series_publisher, ... }
|
|
13
|
+
module Nist
|
|
14
|
+
NIST_AND_ABBREV =
|
|
15
|
+
["NIST", "National Institute of Standards and Technology"].freeze
|
|
16
|
+
|
|
17
|
+
STAGE_PRINT = {
|
|
18
|
+
"draft-internal" => "Internal Draft",
|
|
19
|
+
"draft-wip" => "Work-in-Progress Draft",
|
|
20
|
+
"draft-prelim" => "Preliminary Draft",
|
|
21
|
+
"draft-public" => "Public Draft",
|
|
22
|
+
"draft-approval" => "Approval Draft",
|
|
23
|
+
"final" => "Final",
|
|
24
|
+
"final-review" => "Under Review",
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
FIPS_PUBLISHER = "U.S. Department of Commerce, Washington, D.C."
|
|
28
|
+
NIST_PUBLISHER = "National Institute of Standards and Technology, " \
|
|
29
|
+
"Gaithersburg, MD"
|
|
30
|
+
|
|
31
|
+
HOST_RELATION_TYPES = %w[partOf includedIn].freeze
|
|
32
|
+
|
|
33
|
+
# The partOf/includedIn host and its publication year: shared
|
|
34
|
+
# by the component part and the host-date fallback of the
|
|
35
|
+
# date element
|
|
36
|
+
module HostDate
|
|
37
|
+
def relation_host
|
|
38
|
+
Array(@model.relation).find do |r|
|
|
39
|
+
HOST_RELATION_TYPES.include?(r.type)
|
|
40
|
+
end&.bibitem
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def host_date_year
|
|
44
|
+
h = relation_host or return ""
|
|
45
|
+
d = Array(h.date).find(&:published) ||
|
|
46
|
+
Array(h.date).find { |x| x.type.nil? } ||
|
|
47
|
+
Array(h.date).find { |x| x.type == "issued" } ||
|
|
48
|
+
Array(h.date).first or return ""
|
|
49
|
+
v = d.at || d.from || d.to or return ""
|
|
50
|
+
begin
|
|
51
|
+
v.to_date.year.to_s
|
|
52
|
+
rescue ArgumentError, TypeError
|
|
53
|
+
v.to_s[/\d{4}/].to_s
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# NIST-aware element base: NIST Standard Reference documents
|
|
59
|
+
# are detected by identifier type or publisher
|
|
60
|
+
class Base < Element
|
|
61
|
+
def present?
|
|
62
|
+
!render.to_s.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def nist?
|
|
68
|
+
return true if Array(@model.docidentifier).any? do |d|
|
|
69
|
+
d.type.to_s.start_with?("NIST")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Array(@model.contributor).select { |c| has_role?(c, "publisher") }
|
|
73
|
+
.any? do |c|
|
|
74
|
+
org = c.organization or next false
|
|
75
|
+
|
|
76
|
+
Array(org.name).any? { |n| NIST_AND_ABBREV.include?(n.content) } ||
|
|
77
|
+
org.abbreviation&.content == "NIST"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def series_title
|
|
82
|
+
Array(@model.series).first&.title&.first&.content.to_s
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# The series publisher block, parenthesized, after the title
|
|
87
|
+
class NistPublisher < Base
|
|
88
|
+
def render
|
|
89
|
+
if series_title == "NIST Federal Information Processing Standards"
|
|
90
|
+
return " (#{FIPS_PUBLISHER})"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
nist? ? " (#{NIST_PUBLISHER})" : ""
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# The NIST draft form ("Draft (Third Public Draft)")
|
|
98
|
+
class NistDraft < Base
|
|
99
|
+
def render
|
|
100
|
+
stage = @model.status&.stage&.content.to_s
|
|
101
|
+
return "" unless stage.start_with?("draft") && nist?
|
|
102
|
+
|
|
103
|
+
"Draft (#{iteration(stage)} #{STAGE_PRINT.fetch(stage, stage)})"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def iteration(stage)
|
|
109
|
+
iter = @model.status&.iteration.to_s
|
|
110
|
+
return "Initial" if iter.empty? || iter == "1"
|
|
111
|
+
return "Final" if iter.casecmp("final").zero?
|
|
112
|
+
|
|
113
|
+
spellout_ordinal(iter.to_i)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The language packs carry ordinal word labels; beyond
|
|
117
|
+
# their reach the numeric suffix form carries the value
|
|
118
|
+
def spellout_ordinal(num)
|
|
119
|
+
word = @i18n.label("ordinal_word_#{num}")
|
|
120
|
+
return word.capitalize unless word == "ordinal_word_#{num}"
|
|
121
|
+
|
|
122
|
+
"#{num}#{ordinal_suffix(num)}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def ordinal_suffix(num)
|
|
126
|
+
case num % 100
|
|
127
|
+
when 11, 12, 13 then "th"
|
|
128
|
+
else
|
|
129
|
+
case num % 10
|
|
130
|
+
when 1 then "st"
|
|
131
|
+
when 2 then "nd"
|
|
132
|
+
when 3 then "rd"
|
|
133
|
+
else "th"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# The NIST series form ("NIST Special Publication (SP)
|
|
140
|
+
# 800-116 Rev. 1"). A series carrying a formattedref renders
|
|
141
|
+
# it verbatim; the number joins the partnumber ("800-116.1"),
|
|
142
|
+
# and the edition carries the revision. NIST documents
|
|
143
|
+
# without a series element derive it from the nist-long
|
|
144
|
+
# identifier
|
|
145
|
+
class NistSeries < Base
|
|
146
|
+
def render
|
|
147
|
+
s = Array(@model.series).first
|
|
148
|
+
return derived_series unless s
|
|
149
|
+
|
|
150
|
+
formatted = localized(s.formattedref)
|
|
151
|
+
return formatted unless formatted.empty?
|
|
152
|
+
|
|
153
|
+
title = localized(Array(s.title).first)
|
|
154
|
+
return "" if title.empty?
|
|
155
|
+
|
|
156
|
+
[title, parens(s), number(s)].reject(&:empty?).join(" ")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
|
|
161
|
+
def derived_series
|
|
162
|
+
long = Array(@model.docidentifier).find do |d|
|
|
163
|
+
d.type == "nist-long"
|
|
164
|
+
end&.content.to_s
|
|
165
|
+
return "" if long.empty?
|
|
166
|
+
|
|
167
|
+
title = long[/\A(NIST [A-Za-z ]+?) \d/, 1] || ""
|
|
168
|
+
return "" if title.empty?
|
|
169
|
+
|
|
170
|
+
[title, parens_derived(long), number_derived(long)]
|
|
171
|
+
.reject(&:empty?).join(" ")
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def parens_derived(long)
|
|
175
|
+
# strip the NIST sigla before the whitespace strip: the
|
|
176
|
+
# 1.x order left a bare "NIST" parenthesized
|
|
177
|
+
abbr = long[/\A[A-Z.]+ /, 0].to_s.sub(/\ANIST /, "").strip
|
|
178
|
+
abbr.empty? ? "" : "(#{abbr})"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def number_derived(long)
|
|
182
|
+
num = long[/\A[NISTa-z. ]*([0-9][0-9A-Za-z.-]*)/, 1].to_s
|
|
183
|
+
num.empty? ? num : with_revision(num)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def parens(s)
|
|
187
|
+
abbr = localized(s.abbreviation).sub(/\ANIST /, "")
|
|
188
|
+
abbr.empty? ? "" : "(#{abbr})"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def number(s)
|
|
192
|
+
num = s.number.to_s
|
|
193
|
+
unless s.partnumber.to_s.empty?
|
|
194
|
+
num = num.empty? ? s.partnumber.to_s : "#{num}.#{s.partnumber}"
|
|
195
|
+
end
|
|
196
|
+
num = @model.docnumber.to_s if num.empty? && nist?
|
|
197
|
+
num.empty? ? num : with_revision(num)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def with_revision(num)
|
|
201
|
+
rev = @model.edition&.content.to_s.sub(/\ARevision /, "")
|
|
202
|
+
rev.empty? ? num : "#{num} Rev. #{rev}"
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
module Relaton
|
|
212
|
+
module Render
|
|
213
|
+
module Iso690
|
|
214
|
+
module Rules
|
|
215
|
+
module Nist
|
|
216
|
+
# The NIST identifier order: the authoritative identifiers
|
|
217
|
+
# (ISO, IEC, ...) before the kind-rendered ISBN/DOI/ISSN
|
|
218
|
+
# group; NIST documents cite the NIST identifier alone (the
|
|
219
|
+
# biblio tag)
|
|
220
|
+
class NistIdentifier < Elements::Identifier
|
|
221
|
+
OTHER_TYPES = %w[ISBN ISSN DOI].freeze
|
|
222
|
+
|
|
223
|
+
def render
|
|
224
|
+
return "" if nist?
|
|
225
|
+
|
|
226
|
+
auth, other = unscoped_ids.partition do |d|
|
|
227
|
+
!OTHER_TYPES.include?(d.type)
|
|
228
|
+
end
|
|
229
|
+
(auth + other).map { |d| render_id(d) }.reject(&:empty?)
|
|
230
|
+
.join(". ")
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
private
|
|
234
|
+
|
|
235
|
+
def nist?
|
|
236
|
+
Array(@model.docidentifier).any? do |d|
|
|
237
|
+
d.type.to_s.start_with?("NIST")
|
|
238
|
+
end || Array(@model.contributor).any? do |c|
|
|
239
|
+
next false unless has_role?(c, "publisher")
|
|
240
|
+
|
|
241
|
+
org = c.organization or next false
|
|
242
|
+
|
|
243
|
+
Array(org.name).any? { |n| NIST_AND_ABBREV.include?(n.content) } ||
|
|
244
|
+
org.abbreviation&.content == "NIST"
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def unscoped_ids
|
|
249
|
+
Array(@model.docidentifier).reject do |d|
|
|
250
|
+
Elements::Identifier::INTERNAL_TYPES.include?(d.type) ||
|
|
251
|
+
!d.scope.to_s.empty? || d.content.to_s.strip.empty?
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# The NIST ISBN and ISSN kinds cite the kind label with a
|
|
256
|
+
# colon
|
|
257
|
+
def render_id(docidentifier)
|
|
258
|
+
return "#{docidentifier.type}: #{docidentifier.content}" if
|
|
259
|
+
%w[ISBN ISSN].include?(docidentifier.type)
|
|
260
|
+
|
|
261
|
+
super
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# The NIST component-part order: the host editors before the
|
|
266
|
+
# host title, the host date after the production
|
|
267
|
+
# ("In: Pellegrini AD, Smith PK (Eds.) <em>The nature of
|
|
268
|
+
# play</em> (New York, NY: Guilford Press), 2005")
|
|
269
|
+
class NistComponentPart < Elements::ComponentPart
|
|
270
|
+
include HostDate
|
|
271
|
+
|
|
272
|
+
def render
|
|
273
|
+
h = relation_host or return ""
|
|
274
|
+
out = +"#{lead}#{host_names(h)}"
|
|
275
|
+
eds = host_editors(h)
|
|
276
|
+
out += " (#{@i18n.label(eds.one? ? "ed" : "eds")})" unless
|
|
277
|
+
eds.empty?
|
|
278
|
+
out += " #{host_title}" unless host_title_text.empty?
|
|
279
|
+
production = host_production_text(h)
|
|
280
|
+
out += " (#{production})" unless production.empty?
|
|
281
|
+
date = host_date_year
|
|
282
|
+
out += ", #{date}" unless date.empty?
|
|
283
|
+
out
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
private
|
|
287
|
+
|
|
288
|
+
def host_editors(h)
|
|
289
|
+
Array(h.contributor).select { |c| has_role?(c, "editor") }
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def host_names(h)
|
|
293
|
+
names = host_editors(h).map { |c|
|
|
294
|
+
person = c.person or next ""
|
|
295
|
+
|
|
296
|
+
[person_surname(person), person_given(person)].reject(&:empty?)
|
|
297
|
+
.join(" ")
|
|
298
|
+
}.reject(&:empty?)
|
|
299
|
+
join_names(names)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def host_production_text(h)
|
|
303
|
+
Elements::Production.new(h, style: @style, i18n: @i18n)
|
|
304
|
+
.render.to_s
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# A component part with no date of its own cites the host's
|
|
309
|
+
class NistDate < Elements::PubDate
|
|
310
|
+
include HostDate
|
|
311
|
+
|
|
312
|
+
def render
|
|
313
|
+
text = super.to_s
|
|
314
|
+
text.empty? ? host_date_year : text
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# The series-position date segment of the 1.x templates: the
|
|
319
|
+
# date carries its own leading comma ("<series>, 2018
|
|
320
|
+
# (updated November 2018)"), so an absent date removes the
|
|
321
|
+
# comma with it
|
|
322
|
+
class NistSerialDate < Base
|
|
323
|
+
def render
|
|
324
|
+
text = pub_date or return ""
|
|
325
|
+
|
|
326
|
+
", #{text}#{updated_date}"
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
private
|
|
330
|
+
|
|
331
|
+
def pub_date
|
|
332
|
+
t = Elements::PubDate.new(@model, style: @style, i18n: @i18n)
|
|
333
|
+
.render.to_s
|
|
334
|
+
t.empty? ? nil : t
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def updated_date
|
|
338
|
+
Elements::Updated.new(@model, style: @style, i18n: @i18n).render
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# The FIPS creator form: the series names the corporate
|
|
343
|
+
# creator; standards without personal creators cite their
|
|
344
|
+
# publisher's name, monographs cite nothing (their "(n.d.)"
|
|
345
|
+
# comes from the perType fallback)
|
|
346
|
+
class NistCreator < Elements::Creator
|
|
347
|
+
def render
|
|
348
|
+
return fips_creator if fips_series?
|
|
349
|
+
|
|
350
|
+
super
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def plain_render
|
|
354
|
+
return fips_creator if fips_series?
|
|
355
|
+
|
|
356
|
+
super
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
private
|
|
360
|
+
|
|
361
|
+
def fallback_name
|
|
362
|
+
return "" if %w[monograph continuing component_part]
|
|
363
|
+
.include?(Kinds.kind_for(@model.type))
|
|
364
|
+
|
|
365
|
+
publishers = contributors("publisher").filter_map do |c|
|
|
366
|
+
localized(Array(c.organization&.name).first)
|
|
367
|
+
end
|
|
368
|
+
publishers.reject(&:empty?).first.to_s
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def fips_series?
|
|
372
|
+
Array(@model.series).first&.title&.first&.content ==
|
|
373
|
+
"NIST Federal Information Processing Standards"
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def fips_creator
|
|
377
|
+
"National Institute of Standards and Technology"
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
end
|