relaton-render 0.4.2 → 3.0.0.pre.alpha.26
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/rake.yml +6 -1
- data/.github/workflows/release.yml +24 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +2 -2
- data/Gemfile +17 -1
- data/README.adoc +13 -258
- data/docs/citation-style-pack.adoc +370 -0
- data/lib/relaton/render/general.rb +305 -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 +30 -0
- data/lib/relaton/render/iso690/elements/citeid.rb +39 -0
- data/lib/relaton/render/iso690/elements/component_part.rb +99 -0
- data/lib/relaton/render/iso690/elements/creator.rb +258 -0
- data/lib/relaton/render/iso690/elements/edition.rb +92 -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 +92 -0
- data/lib/relaton/render/iso690/elements/pub_date.rb +56 -0
- data/lib/relaton/render/iso690/elements/series.rb +66 -0
- data/lib/relaton/render/iso690/elements/size.rb +41 -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 +47 -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 +148 -0
- data/lib/relaton/render/iso690/rules.rb +36 -0
- data/lib/relaton/render/iso690/style/locale.rb +53 -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 +37 -0
- data/lib/relaton/render/iso690/style.rb +222 -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 +48 -0
- data/lib/relaton/render/iso690/styles/ieee-sa.yml +45 -0
- data/lib/relaton/render/iso690/styles/lncs.yml +54 -0
- data/lib/relaton/render/iso690/template.rb +248 -0
- data/lib/relaton/render/iso690.rb +27 -0
- data/lib/relaton/render/version.rb +1 -1
- data/lib/relaton-render.rb +11 -5
- data/relaton-render.gemspec +6 -13
- metadata +61 -116
- data/lib/isodoc/i18n.rb +0 -33
- data/lib/isodoc-yaml/i18n-ar.yaml +0 -44
- data/lib/isodoc-yaml/i18n-de.yaml +0 -43
- data/lib/isodoc-yaml/i18n-en.yaml +0 -40
- data/lib/isodoc-yaml/i18n-es.yaml +0 -47
- data/lib/isodoc-yaml/i18n-fr.yaml +0 -48
- data/lib/isodoc-yaml/i18n-ru.yaml +0 -51
- data/lib/isodoc-yaml/i18n-zh-Hans.yaml +0 -40
- data/lib/relaton/render/fields/date.rb +0 -45
- data/lib/relaton/render/fields/fields.rb +0 -245
- data/lib/relaton/render/general/citations.rb +0 -96
- data/lib/relaton/render/general/config.yml +0 -79
- data/lib/relaton/render/general/render.rb +0 -185
- data/lib/relaton/render/general/render_classes.rb +0 -129
- data/lib/relaton/render/parse/parse.rb +0 -64
- data/lib/relaton/render/parse/parse_contributors.rb +0 -132
- data/lib/relaton/render/parse/parse_extract.rb +0 -180
- data/lib/relaton/render/template/liquid.rb +0 -15
- data/lib/relaton/render/template/template.rb +0 -188
- data/lib/relaton/render/utils/utils.rb +0 -27
|
@@ -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,30 @@
|
|
|
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
|
+
authorizer_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def authorizer_name
|
|
22
|
+
contributors("authorizer").map do |c|
|
|
23
|
+
Array(c.organization&.name).map { |n| localized(n) }.join(", ")
|
|
24
|
+
end.reject(&:empty?).first.to_s
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
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,99 @@
|
|
|
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 @style.scheme.name_form.inverted_all
|
|
73
|
+
@style.render_name(surname: surname, given: given)
|
|
74
|
+
elsif first
|
|
75
|
+
[surname, given].reject(&:empty?).join(", ")
|
|
76
|
+
else
|
|
77
|
+
[given, surname].reject(&:empty?).join(" ")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def host_edition
|
|
82
|
+
return "" if host.nil?
|
|
83
|
+
|
|
84
|
+
edition = Edition.new(host, style: @style, i18n: @i18n,
|
|
85
|
+
kind: item_kind)
|
|
86
|
+
edition.present? ? ". #{edition.render}" : ""
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def host_production
|
|
90
|
+
return "" if host.nil?
|
|
91
|
+
|
|
92
|
+
production = Production.new(host, style: @style, i18n: @i18n)
|
|
93
|
+
production.present? ? ". #{production.render}" : ""
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
module Elements
|
|
7
|
+
# Name(s) of creator(s) (ISO 690 clause 7.2). The first creator is
|
|
8
|
+
# given inverted per the style's name form (SURNAME, forenames),
|
|
9
|
+
# subsequent creators in direct order (forenames SURNAME); name
|
|
10
|
+
# parts come from the typed model, never decomposed from a
|
|
11
|
+
# rendered string.
|
|
12
|
+
class Creator < Element
|
|
13
|
+
def present?
|
|
14
|
+
!creators.empty? || !fallback_name.empty?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render
|
|
18
|
+
return plain_render if @short
|
|
19
|
+
|
|
20
|
+
joined = if (truncated = truncated_creators)
|
|
21
|
+
truncated
|
|
22
|
+
elsif creators.empty?
|
|
23
|
+
fallback_name
|
|
24
|
+
elsif (form = @style.templates.creators) && !form.empty?
|
|
25
|
+
::Relaton::Render::Iso690::Template.new(form).evaluate(
|
|
26
|
+
"names" => Template::Field[true, join(names)],
|
|
27
|
+
)
|
|
28
|
+
else
|
|
29
|
+
join(names)
|
|
30
|
+
end
|
|
31
|
+
case role_placement
|
|
32
|
+
when "afterPeriod"
|
|
33
|
+
# the in-slot trailing space separates the (eds.) marker
|
|
34
|
+
# from the next element, which follows directly in the
|
|
35
|
+
# template; a lone editor is unmarked unless declared
|
|
36
|
+
if editors? && marked?
|
|
37
|
+
"#{period(joined)}#{role_space}#{role_parenthesis} "
|
|
38
|
+
else
|
|
39
|
+
"#{period(joined)} "
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
marker = editors? && marked? ? "#{role_space}#{role_parenthesis}" : ''
|
|
43
|
+
"#{joined}#{marker}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The short cite splits after the creators: they render as a
|
|
48
|
+
# plain join, without the wrap and sentence period (1.x
|
|
49
|
+
# short-cite templates carried no wrap)
|
|
50
|
+
def plain_render
|
|
51
|
+
marker = editors? && marked? ? "#{role_space}#{role_parenthesis}" : ''
|
|
52
|
+
"#{join(names)}#{marker}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# The editor role marker's parentheses follow the locale
|
|
56
|
+
# (ASCII for Latin scripts, fullwidth for CJK)
|
|
57
|
+
def role_parenthesis
|
|
58
|
+
open = @i18n.punct_fetch("open-paren", "(")
|
|
59
|
+
close = @i18n.punct_fetch("close-paren", ")")
|
|
60
|
+
"#{open}#{role_word}#{close}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# CJK cites the role marker tight against the name list
|
|
64
|
+
def role_space
|
|
65
|
+
@i18n.punct_fetch("marker-space", " ")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# The template-level role slot ("{{role}}"): the marker with
|
|
69
|
+
# its locale spacing, when the creators are all editors
|
|
70
|
+
def role_marker
|
|
71
|
+
editors? ? "#{role_space}#{role_parenthesis}" : ""
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def role_placement
|
|
75
|
+
@style.scheme.name_form.role_placement || "glue"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def period(text)
|
|
79
|
+
text.end_with?(".") ? text : "#{text}."
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def marked?
|
|
83
|
+
name_form.editors_marked &&
|
|
84
|
+
(creators.size > 1 || name_form.lone_editor_marked)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def role_word
|
|
88
|
+
@i18n.label(creators.one? ? "ed" : "eds")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# In-text (name-and-date) form: the principal creator only;
|
|
92
|
+
# at the style's et-al threshold the cite truncates
|
|
93
|
+
# ("Aluffi <em>et al.</em>")
|
|
94
|
+
def in_text
|
|
95
|
+
return in_text_etal if in_text_etal?
|
|
96
|
+
|
|
97
|
+
name = creators.first ? in_text_name(creators.first) : ""
|
|
98
|
+
etal? ? "#{name} <em>et al.</em>" : name
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# The in-text cite truncates at its own threshold: at
|
|
102
|
+
# inTextEtalCount creators it shows the first
|
|
103
|
+
# inTextEtalDisplay surnames ("Aluffi <em>et al.</em>")
|
|
104
|
+
def in_text_etal
|
|
105
|
+
names = creators.first(name_form.in_text_etal_display)
|
|
106
|
+
.map { |c| in_text_name(c) }
|
|
107
|
+
"#{join(names)} <em>et al.</em>"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# The in-text cite names by surname alone (the 1.x
|
|
111
|
+
# authorcitetemplate), never by initials
|
|
112
|
+
def in_text_name(contributor)
|
|
113
|
+
person = contributor.person or return org_name(contributor)
|
|
114
|
+
complete = completename(person)
|
|
115
|
+
return complete unless complete.nil?
|
|
116
|
+
|
|
117
|
+
raw = surname(person).to_s
|
|
118
|
+
name_form.surname_upcase ? raw.upcase : raw
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def in_text_etal?
|
|
122
|
+
count = name_form.in_text_etal_count
|
|
123
|
+
count.positive? && creators.size >= count
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def etal?
|
|
127
|
+
count = name_form.etal_count
|
|
128
|
+
count.positive? && creators.size >= count
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# The principal creator's given names, as the name form declares
|
|
132
|
+
def principal_given
|
|
133
|
+
principal = creators.first or return ""
|
|
134
|
+
person = principal.person or return ""
|
|
135
|
+
complete = completename(person)
|
|
136
|
+
return "" if complete
|
|
137
|
+
|
|
138
|
+
given_names(person)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
def creators
|
|
144
|
+
@creators ||= begin
|
|
145
|
+
found = contributors("author")
|
|
146
|
+
found = contributors("editor") if found.empty?
|
|
147
|
+
found
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# The declared creator fallback for items with no personal
|
|
152
|
+
# creators: the publishers' abbreviation or full name — all
|
|
153
|
+
# publishers cite, joined per the style's list style ("ISO and
|
|
154
|
+
# IEC")
|
|
155
|
+
def fallback_name
|
|
156
|
+
orgs = contributors("publisher")
|
|
157
|
+
name = case name_form.creator_fallback
|
|
158
|
+
when "publisher_abbrev"
|
|
159
|
+
orgs.map do |c|
|
|
160
|
+
localized(c.organization&.abbreviation)
|
|
161
|
+
end
|
|
162
|
+
when "publisher_name"
|
|
163
|
+
orgs.map do |c|
|
|
164
|
+
localized(Array(c.organization&.name).first)
|
|
165
|
+
end
|
|
166
|
+
else
|
|
167
|
+
[]
|
|
168
|
+
end
|
|
169
|
+
join_names(name.reject(&:empty?))
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def names
|
|
173
|
+
creators.each_with_index
|
|
174
|
+
.map do |contributor, index|
|
|
175
|
+
format(contributor,
|
|
176
|
+
first: index.zero?)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# The style's et-al truncation ("Aluffi, P., D. Anderson,
|
|
181
|
+
# M. Hering <em>et al.</em>"): at etalCount creators, the
|
|
182
|
+
# first etalDisplay names cite, comma-joined without the
|
|
183
|
+
# terminal and-join
|
|
184
|
+
def truncated_creators
|
|
185
|
+
count = name_form.etal_count
|
|
186
|
+
display = name_form.etal_display
|
|
187
|
+
return nil if count <= 0 || display <= 0 ||
|
|
188
|
+
creators.size < count
|
|
189
|
+
|
|
190
|
+
creators.first(display).each_with_index
|
|
191
|
+
.map do |contributor, index|
|
|
192
|
+
format(contributor, first: index.zero?)
|
|
193
|
+
end.join(", ") + " <em>et al.</em>"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def format(contributor, first:)
|
|
197
|
+
person = contributor.person or return org_name(contributor)
|
|
198
|
+
name = completename_name(person, first: first) ||
|
|
199
|
+
personal_name(person, first: first)
|
|
200
|
+
name.empty? ? org_name(contributor) : name
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def completename_name(person, first:)
|
|
204
|
+
complete = completename(person) or return nil
|
|
205
|
+
return complete unless name_form.completename_upcase
|
|
206
|
+
|
|
207
|
+
first ? @style.render_name(surname: complete, given: "") :
|
|
208
|
+
complete.upcase
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def personal_name(person, first:)
|
|
212
|
+
surname = surname(person).to_s
|
|
213
|
+
given = given_names(person)
|
|
214
|
+
if (first || name_form.inverted_all) && !name_form.given_name_first
|
|
215
|
+
@style.render_name(surname: surname, given: given)
|
|
216
|
+
else
|
|
217
|
+
# the direct form initializes per the style's initials
|
|
218
|
+
# knob ("S. Payne" over "Sam Payne")
|
|
219
|
+
shown = name_form.subsequent_surname_upcase ? surname.upcase :
|
|
220
|
+
surname
|
|
221
|
+
[person_given(person), shown].reject(&:empty?).join(" ")
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def name_form
|
|
226
|
+
@style.scheme.name_form
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def join(names)
|
|
230
|
+
join_names(names)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def editors?
|
|
234
|
+
!creators.empty? && creators.all? { |c| has_role?(c, "editor") }
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def completename(person)
|
|
238
|
+
value = person_completename(person)
|
|
239
|
+
value.empty? ? nil : value
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def surname(person)
|
|
243
|
+
value = person_surname(person)
|
|
244
|
+
value.empty? ? nil : value
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def given_names(person)
|
|
248
|
+
person_given(person)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def org_name(contributor)
|
|
252
|
+
super
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|