relaton-render 3.0.0.pre.alpha.34 → 3.0.0.pre.alpha.35

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: '00382747d147cd5b989c4233a23f0fdaa8bd3e524a6a115d5418819ec0b8924b'
4
- data.tar.gz: fc17121ece9f630269b54eb2f8729b7878869218dcfdecbc804d1d4a6cdf53c8
3
+ metadata.gz: 81c57319ba531b5c63b0adcad897b4abbefac37099990a625993dab5357c7a32
4
+ data.tar.gz: 1316576d47fdfccd9007c5ef98dfa3d40d0ca4ab5dca8a3de4cc822ebccdb657
5
5
  SHA512:
6
- metadata.gz: 84031ca7bcbdfd2b34e499a27793bbdbcf0a1ed7f26bc5f6c71a53c647f0f8fbdf4df2f07b27d03210bd44fc78758fbd1b5913e9c21c0d4f7590c00024e001a3
7
- data.tar.gz: e2fe7991124254b4c4009053070eba05bab6cf520bf79127da9c137f28a35f4fae113a607a567d9876b9997c0d2ccf74a34ba8f5e377f904701f51cdb626d25d
6
+ metadata.gz: 36b05f7515bddf6f44a728174a57f365398c0f28aa55b2e3228ea651eadbf0d8c7a7c02ddd70c2b4375b53df83aa13bb896b6be27298e4d8e675a394aeca3d23
7
+ data.tar.gz: a8d0e79f9349ccd80efb408c04789f791dea1b21e510ab3cfd2ce5cfd65d912ef1a5d6b42047d8ad60cec88c65c0a92e8a3c90981e5bb9739d622837ee02aa1f
@@ -290,7 +290,7 @@ is a rule to promote:
290
290
  |Flavor override |Becomes rule
291
291
 
292
292
  |`ItuIdentifier` |**[impl]** promoted: `identifier: itu_identifier`
293
- |`NistIdentifier`, `NistCreator`, `NistDate`, `SerialDate`, `NistSeries`, `NistComponentPart`, `NistPublisher`, `Draft` |the NIST author-year rule set
293
+ |`NistIdentifier`, `NistCreator`, `NistDate`, `SerialDate`, `NistSeries`, `NistComponentPart`, `NistPublisher`, `Draft` |**[impl]** promoted: `nist_identifier`, `nist_creator`, `nist_date`, `nist_serial_date`, `nist_series`, `nist_component_part`, `nist_publisher`, `nist_draft`
294
294
  |`IeeeIdentifier`, `IeeeComponentPart`, `IeeeAccess`, `IeeeMedium` |**[impl]** promoted: `ieee_identifier`, `ieee_component_part`, `ieee_access`, `ieee_medium`
295
295
  |`BipmCreator`, `BipmComponentPart`, `BipmProduction`, `BipmExtent`, `BipmMedium`, `BipmEdition`, `BipmVolume` |the BIPM rule set
296
296
  |`IhoEdition`, `IhoCreator` |affiliation-composite creators
@@ -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
@@ -106,6 +106,9 @@ module Relaton
106
106
  end
107
107
  end
108
108
 
109
+ # The NIST rule set lives in its own autoloaded section
110
+ autoload :Nist, "relaton/render/iso690/rules/nist"
111
+
109
112
  REGISTRY = {
110
113
  "status_bare" => BareStatus,
111
114
  "itu_identifier" => ItuIdentifier,
@@ -113,6 +116,14 @@ module Relaton
113
116
  "ieee_component_part" => IeeeComponentPart,
114
117
  "ieee_access" => IeeeAccess,
115
118
  "ieee_medium" => IeeeMedium,
119
+ "nist_creator" => Nist::NistCreator,
120
+ "nist_date" => Nist::NistDate,
121
+ "nist_serial_date" => Nist::NistSerialDate,
122
+ "nist_series" => Nist::NistSeries,
123
+ "nist_component_part" => Nist::NistComponentPart,
124
+ "nist_identifier" => Nist::NistIdentifier,
125
+ "nist_publisher" => Nist::NistPublisher,
126
+ "nist_draft" => Nist::NistDraft,
116
127
  }.freeze
117
128
 
118
129
  class << self
@@ -1,5 +1,5 @@
1
1
  module Relaton
2
2
  module Render
3
- VERSION = "3.0.0.pre.alpha.34".freeze
3
+ VERSION = "3.0.0.pre.alpha.35".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relaton-render
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.pre.alpha.34
4
+ version: 3.0.0.pre.alpha.35
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -148,6 +148,7 @@ files:
148
148
  - lib/relaton/render/iso690/kinds.rb
149
149
  - lib/relaton/render/iso690/renderer.rb
150
150
  - lib/relaton/render/iso690/rules.rb
151
+ - lib/relaton/render/iso690/rules/nist.rb
151
152
  - lib/relaton/render/iso690/style.rb
152
153
  - lib/relaton/render/iso690/style/locale.rb
153
154
  - lib/relaton/render/iso690/style/name_form.rb