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,129 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
# Imports a CSL style's common properties into a CitationStyle instance
|
|
7
|
+
# (styles as data, the downgrade direction: CSL's element-list engine
|
|
8
|
+
# is strictly richer, so the import covers what the instance format can
|
|
9
|
+
# express and lists everything it dropped in `requires`).
|
|
10
|
+
#
|
|
11
|
+
# Mapped: the info title, the citation/reference variable runs (text
|
|
12
|
+
# elements over the CSL variables, via the crosswalk below), the
|
|
13
|
+
# name-form scalars (initialize-with, name-as-sort-order, et-al
|
|
14
|
+
# lengths), the year-suffix disambiguation, and the delimiters.
|
|
15
|
+
module CslImport
|
|
16
|
+
# CSL variable -> the ISO 690 slot the engine resolves.
|
|
17
|
+
VARIABLE_SLOTS = {
|
|
18
|
+
"author" => "creator", "editor" => "creator",
|
|
19
|
+
"title" => "title", "container-title" => "series",
|
|
20
|
+
"edition" => "edition", "publisher" => "production",
|
|
21
|
+
"publisher-place" => "location", "issued" => "date",
|
|
22
|
+
"DOI" => "identifier", "URL" => "identifier", "PMID" => "identifier",
|
|
23
|
+
"number" => "numeration", "volume" => "numeration",
|
|
24
|
+
"page" => "numeration", "medium" => "medium",
|
|
25
|
+
"accessed" => "access", "version" => "edition",
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
# CSL features the import drops, reported in `requires` so a resolver
|
|
29
|
+
# fails loudly instead of silently mis-rendering.
|
|
30
|
+
DROPPED_FEATURES = [
|
|
31
|
+
"csl macros (macro elements are not data-expressible)",
|
|
32
|
+
"csl groups with conditional rendering (match= attributes)",
|
|
33
|
+
"csl per-locator templates",
|
|
34
|
+
].freeze
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
# Build a CitationStyle instance from a parsed CSL style JSON.
|
|
38
|
+
#
|
|
39
|
+
# @param csl [Hash] parsed CSL style
|
|
40
|
+
# @return [Style]
|
|
41
|
+
def style(csl)
|
|
42
|
+
Style.new(
|
|
43
|
+
name: style_name(csl),
|
|
44
|
+
family: "iso690",
|
|
45
|
+
requires: dropped_features(csl),
|
|
46
|
+
scheme: scheme(csl),
|
|
47
|
+
templates: templates(csl),
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Parse a CSL style JSON string and build the instance.
|
|
52
|
+
#
|
|
53
|
+
# @param [String] json
|
|
54
|
+
# @return [Style]
|
|
55
|
+
def from_json(json)
|
|
56
|
+
style(JSON.parse(json))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def style_name(csl)
|
|
62
|
+
title = csl.dig("info", "title").to_s
|
|
63
|
+
title.empty? ? "Imported CSL style" : "#{title} (CSL import)"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def dropped_features(csl)
|
|
67
|
+
feats = DROPPED_FEATURES.dup
|
|
68
|
+
feats << "csl bibliography section" if csl["bibliography"]
|
|
69
|
+
feats << "csl locales" if csl["locales"]
|
|
70
|
+
feats
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def scheme(csl)
|
|
74
|
+
Style::Scheme.new(
|
|
75
|
+
system: "name-date",
|
|
76
|
+
name_form: name_form(csl),
|
|
77
|
+
locale: Style::Locale.new(no_date: "n.d."),
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def name_form(csl)
|
|
82
|
+
citation = csl["citation"] || {}
|
|
83
|
+
initialize_with = citation["initialize-with"]
|
|
84
|
+
Style::NameForm.new(
|
|
85
|
+
initials: !initialize_with.nil?,
|
|
86
|
+
initials_separator: initialize_with.is_a?(String) ? initialize_with : " ",
|
|
87
|
+
initials_period: initialize_with.to_s.include?("."),
|
|
88
|
+
inverted_all: citation["name-as-sort-order"].to_s == "all",
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def templates(csl)
|
|
93
|
+
citation_elements = csl.dig("citation", "elements") || []
|
|
94
|
+
reference_elements = csl.dig("bibliography", "elements") || []
|
|
95
|
+
Style::TemplateMap.new(
|
|
96
|
+
citation: element_template(
|
|
97
|
+
citation_elements, csl.dig("citation", "delimiter") || ", ",
|
|
98
|
+
"{{creator}}, {{date}}{{disambiguator}}",
|
|
99
|
+
),
|
|
100
|
+
reference: element_template(
|
|
101
|
+
reference_elements, csl.dig("bibliography", "delimiter") || ". ",
|
|
102
|
+
"{{creator}}. {{title}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{identifier}}. {{location}}.",
|
|
103
|
+
),
|
|
104
|
+
name: "{{surname}}, {{givenNames}}",
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Flatten CSL text/variable elements into a slot template. Non-text
|
|
109
|
+
# elements (macros, groups, conditions) contribute nothing: the
|
|
110
|
+
# import covers flat variable runs only.
|
|
111
|
+
def element_template(elements, delimiter, fallback)
|
|
112
|
+
slots = elements.filter_map do |el|
|
|
113
|
+
next unless el.is_a?(Hash)
|
|
114
|
+
|
|
115
|
+
# A CSL text element nests its variable: {"text": {"variable": ...}}
|
|
116
|
+
variable = el.dig("text", "variable") || el["variable"]
|
|
117
|
+
slot = variable && VARIABLE_SLOTS[variable]
|
|
118
|
+
"{{#{slot}}}" if slot
|
|
119
|
+
end
|
|
120
|
+
slots = slots.uniq
|
|
121
|
+
return fallback if slots.empty?
|
|
122
|
+
|
|
123
|
+
slots.join(delimiter)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
# Base data element (ISO 690 clause 7). An element wraps typed data
|
|
7
|
+
# taken from the relaton model instance; #present? is the omission
|
|
8
|
+
# predicate, #render the element's formatting method. Punctuation
|
|
9
|
+
# between elements belongs to the kind/style, not the element.
|
|
10
|
+
class Element
|
|
11
|
+
def initialize(model, style:, i18n:, kind: nil, short: false)
|
|
12
|
+
@model = model
|
|
13
|
+
@style = style
|
|
14
|
+
@i18n = i18n
|
|
15
|
+
@kind = kind
|
|
16
|
+
@short = short
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def present?
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def render
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def localized(value)
|
|
30
|
+
value&.content.to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Localizable values scoped to the render language: the variants
|
|
34
|
+
# declared in that language, or all of them when none matches
|
|
35
|
+
def titles_in_lang(values)
|
|
36
|
+
titles = Array(values)
|
|
37
|
+
in_lang = titles.select { |t| Array(t.language).include?(@i18n.lang) }
|
|
38
|
+
in_lang.empty? ? titles : in_lang
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def contributors(role)
|
|
42
|
+
Array(@model.contributor).select { |c| has_role?(c, role) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def has_role?(contributor, role)
|
|
46
|
+
Array(contributor.role).any? do |r|
|
|
47
|
+
r.is_a?(String) ? r == role : r.type == role
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def org_name(contributor)
|
|
52
|
+
shown = ->(n) do
|
|
53
|
+
text = localized(n)
|
|
54
|
+
@style.scheme.name_form.org_upcase ? text.upcase : text
|
|
55
|
+
end
|
|
56
|
+
name = Array(contributor.organization&.name)
|
|
57
|
+
.map(&shown).join(", ")
|
|
58
|
+
abbrev = localized(contributor.organization&.abbreviation)
|
|
59
|
+
return name if name.empty? || abbrev.empty?
|
|
60
|
+
|
|
61
|
+
"#{name} (#{abbrev})"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def item_kind
|
|
65
|
+
@kind || @style.kind_for(@model.type)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def person_completename(person)
|
|
69
|
+
localized(person.name&.completename)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def person_surname(person)
|
|
73
|
+
localized(person.name&.surname)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def person_given(person)
|
|
77
|
+
parts = Array(person.name&.forename).map do |f|
|
|
78
|
+
content = localized(f)
|
|
79
|
+
next content unless content.empty?
|
|
80
|
+
next initial(f.initial) if f.initial.to_s.length == 1
|
|
81
|
+
|
|
82
|
+
""
|
|
83
|
+
end.reject(&:empty?)
|
|
84
|
+
sep = @style.scheme.name_form.initials_separator.to_s
|
|
85
|
+
return reinitials(localized(person.name&.formatted_initials)) if
|
|
86
|
+
parts.empty?
|
|
87
|
+
return given_with_first_full(parts, sep) if initials?
|
|
88
|
+
|
|
89
|
+
parts.join(" ")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The document-history name form: the first forename cites in
|
|
93
|
+
# full, the rest as initials ("Milena S.")
|
|
94
|
+
def given_with_first_full(parts, sep)
|
|
95
|
+
initials = parts.map { |p| initial(p) }
|
|
96
|
+
return initials.join(sep) unless
|
|
97
|
+
@style.scheme.name_form.subsequent_initials
|
|
98
|
+
|
|
99
|
+
rest = parts.drop(1).map { |p| initial(p) }.join(sep)
|
|
100
|
+
rest.empty? ? parts.first : "#{parts.first}#{sep}#{rest}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Declared initials are a list in string form; rejoin them with
|
|
104
|
+
# the style's separator
|
|
105
|
+
def reinitials(raw)
|
|
106
|
+
sep = @style.scheme.name_form.initials_separator.to_s
|
|
107
|
+
dots = @style.scheme.name_form.initials_period
|
|
108
|
+
raw.split(/\s+/).reject(&:empty?).map { |i| dots ? i : i.delete(".") }
|
|
109
|
+
.join(sep)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def initial(name)
|
|
113
|
+
@style.scheme.name_form.initials_period ? "#{name[0]}." : name[0]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def initials?
|
|
117
|
+
@style.scheme.name_form.initials
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def join_names(names)
|
|
121
|
+
# A style with no join word renders a plain serial list,
|
|
122
|
+
# separated per the locale (the comma, or the CJK 、)
|
|
123
|
+
if @i18n.label("and").empty? && names.size > 1
|
|
124
|
+
sep = @i18n.label("list_separator")
|
|
125
|
+
sep = ", " if sep == "list_separator"
|
|
126
|
+
return names.join(sep)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
oxford = @i18n.label("oxford_comma")
|
|
130
|
+
if serial_list? && names.size > 1 && !oxford.empty?
|
|
131
|
+
return "#{names[0..-2].join(', ')}#{oxford} " \
|
|
132
|
+
"#{@i18n.label('and')} #{names.last}"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
case names.size
|
|
136
|
+
when 0 then ""
|
|
137
|
+
when 1 then names.first
|
|
138
|
+
when 2 then names.join(" #{@i18n.label('and')} ")
|
|
139
|
+
else
|
|
140
|
+
"#{names[0..-2].join(', ')}#{oxford} " \
|
|
141
|
+
"#{@i18n.label('and')} #{names.last}"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Serial list style: the oxford comma appears at every gap of a
|
|
146
|
+
# name list, including between two names
|
|
147
|
+
def serial_list?
|
|
148
|
+
@style.scheme.name_form.list_style == "serial"
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
|
|
5
|
+
module Relaton
|
|
6
|
+
module Render
|
|
7
|
+
module Iso690
|
|
8
|
+
module Elements
|
|
9
|
+
# Date of access (ISO 690 clause 7.12): "[viewed: September 3,
|
|
10
|
+
# 2019]" for online resources consulted.
|
|
11
|
+
class Access < Element
|
|
12
|
+
def present?
|
|
13
|
+
!date_text.empty?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def render
|
|
17
|
+
"[#{@i18n.label('viewed')}: #{date_text}]"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def date_text
|
|
23
|
+
d = Array(@model.date).find { |x| x.type == "accessed" } or return ""
|
|
24
|
+
value = (d.at || d.from || d.to).to_s
|
|
25
|
+
parts = value.split("-")
|
|
26
|
+
case parts.size
|
|
27
|
+
when 3
|
|
28
|
+
date = ::Date.parse(value)
|
|
29
|
+
"#{month(date.month)} #{date.day}, #{date.year}"
|
|
30
|
+
when 2
|
|
31
|
+
"#{month(parts[1].to_i)} #{parts[0]}"
|
|
32
|
+
else
|
|
33
|
+
value
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def month(num)
|
|
38
|
+
@i18n.label("month_#{num}")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
module Elements
|
|
7
|
+
# The authorizing body of a standard (the IETF RFC Series, the
|
|
8
|
+
# W3C Recommendation process): the organization carrying the
|
|
9
|
+
# authorizer role, cited after the status
|
|
10
|
+
class Authorizer < Element
|
|
11
|
+
def present?
|
|
12
|
+
!authorizer_name.empty?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def render
|
|
16
|
+
if (form = authorizer_form) && !form.empty?
|
|
17
|
+
return Template.new(form).evaluate(
|
|
18
|
+
"authorizer" => Template::Field[true, authorizer_name],
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
authorizer_name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The kind's declared form for this slot: the first entry of
|
|
26
|
+
# the kind carrying one (a home variant may shadow the type)
|
|
27
|
+
def authorizer_form
|
|
28
|
+
kind = @style.kind_for(@model.type)
|
|
29
|
+
@style.per_type.find do |t|
|
|
30
|
+
t.type == kind && !t.authorizer.to_s.empty?
|
|
31
|
+
end&.authorizer
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def authorizer_name
|
|
37
|
+
contributors("authorizer").map do |c|
|
|
38
|
+
Array(c.organization&.name).map { |n| localized(n) }.join(", ")
|
|
39
|
+
end.reject(&:empty?).first.to_s
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
module Elements
|
|
7
|
+
# The cited identifier with the item's status beside it and the
|
|
8
|
+
# list comma ("OGC 05-020r27 (Draft)," / "ISO 712,"): the comma
|
|
9
|
+
# stays with the identifier whichever side of the status it
|
|
10
|
+
# follows
|
|
11
|
+
class Citeid < Element
|
|
12
|
+
def present?
|
|
13
|
+
identifier_element.present?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def render
|
|
17
|
+
text = identifier_element.render
|
|
18
|
+
stage = status_element.present? ? status_element.render : ""
|
|
19
|
+
stage.empty? ? "#{text}," : "#{text}#{stage},"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def identifier_element
|
|
25
|
+
@identifier_element ||=
|
|
26
|
+
Identifier.new(@model, style: @style, i18n: @i18n, kind: @kind,
|
|
27
|
+
short: @short)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def status_element
|
|
31
|
+
@status_element ||=
|
|
32
|
+
Status.new(@model, style: @style, i18n: @i18n, kind: @kind,
|
|
33
|
+
short: @short)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
module Elements
|
|
7
|
+
# Component part within a host (ISO 690 clause 7.4): host title
|
|
8
|
+
# (emphasised), host editors, host edition, host place and
|
|
9
|
+
# publisher. Host data comes from the typed partOf/includedIn
|
|
10
|
+
# relation.
|
|
11
|
+
class ComponentPart < Element
|
|
12
|
+
HOST_RELATION_TYPES = %w[partOf includedIn].freeze
|
|
13
|
+
|
|
14
|
+
def present?
|
|
15
|
+
!host_title_text.empty?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def render
|
|
19
|
+
"#{lead}#{host_title}#{host_editors}#{host_edition}" \
|
|
20
|
+
"#{host_production}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def lead
|
|
26
|
+
label = @i18n.label("in")
|
|
27
|
+
label.empty? ? "" : "#{label} "
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def relation
|
|
31
|
+
Array(@model.relation).find do |r|
|
|
32
|
+
HOST_RELATION_TYPES.include?(r.type)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def host
|
|
37
|
+
relation&.bibitem
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def host_title_text
|
|
41
|
+
return localized(relation&.description) if host.nil?
|
|
42
|
+
|
|
43
|
+
titles_in_lang(host.title).map { |t| localized(t) }
|
|
44
|
+
.join(" ").strip
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def host_title
|
|
48
|
+
return "" if host_title_text.empty?
|
|
49
|
+
|
|
50
|
+
"#{@style.templates.title_open}#{host_title_text}" \
|
|
51
|
+
"#{@style.templates.title_close}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def host_editors
|
|
55
|
+
eds = Array(host&.contributor).select { |c| has_role?(c, "editor") }
|
|
56
|
+
names = eds.each_with_index
|
|
57
|
+
.map { |c, i| host_person_name(c, first: i.zero?) }
|
|
58
|
+
.reject(&:empty?)
|
|
59
|
+
return "" if names.empty?
|
|
60
|
+
|
|
61
|
+
" (#{@i18n.label(eds.one? ? 'ed' : 'eds')} #{join_names(names)})"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# ISO 690 clause 7.2 host editors: the first name inverted
|
|
65
|
+
# (surname, initials), subsequent names in direct order, all in
|
|
66
|
+
# mixed case
|
|
67
|
+
def host_person_name(contributor, first:)
|
|
68
|
+
person = contributor.person or return ""
|
|
69
|
+
|
|
70
|
+
surname = person_surname(person)
|
|
71
|
+
given = person_given(person)
|
|
72
|
+
if first
|
|
73
|
+
[surname, given].reject(&:empty?).join(", ")
|
|
74
|
+
else
|
|
75
|
+
[given, surname].reject(&:empty?).join(" ")
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def host_edition
|
|
80
|
+
return "" if host.nil?
|
|
81
|
+
|
|
82
|
+
edition = Edition.new(host, style: @style, i18n: @i18n,
|
|
83
|
+
kind: item_kind)
|
|
84
|
+
edition.present? ? ". #{edition.render}" : ""
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def host_production
|
|
88
|
+
return "" if host.nil?
|
|
89
|
+
|
|
90
|
+
production = Production.new(host, style: @style, i18n: @i18n)
|
|
91
|
+
production.present? ? ". #{production.render}" : ""
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|