relaton-render 3.0.0.pre.alpha.22 → 3.0.0.pre.alpha.24
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/lib/relaton/render/general.rb +19 -12
- data/lib/relaton/render/iso690/elements/creator.rb +1 -2
- data/lib/relaton/render/iso690/elements/extent.rb +25 -5
- data/lib/relaton/render/iso690/elements/production.rb +2 -1
- data/lib/relaton/render/iso690/elements/series.rb +5 -1
- data/lib/relaton/render/iso690/i18n/en.yml +5 -4
- data/lib/relaton/render/iso690/i18n/ja.yml +5 -5
- data/lib/relaton/render/iso690/renderer.rb +10 -5
- data/lib/relaton/render/iso690/style/scheme.rb +7 -1
- data/lib/relaton/render/iso690/style.rb +11 -0
- data/lib/relaton/render/iso690/template.rb +76 -6
- data/lib/relaton/render/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1f8e1bb4347d4eab41a00189b7040c378c6eaa59631eb52fa0e62de36cce9861
|
|
4
|
+
data.tar.gz: b6c530258baf6fdf30c70c1f56d17a5c4333fc6f68b6c466e72a18e7cbd7c06d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45ef9145e49a975775ded3f52bdea26bd429f669adf3a1130524d9b84c60555114f4301a0aac4cb4944bf1126f81b36aa622d2268958e9a6fec357c8b82d4882
|
|
7
|
+
data.tar.gz: 7d34cfe2fc402a565bb07d530db022cd9e700a6081a96a8bf271fa19193755e8b1f1eaa5deef5767514ffb8c501b801a7da5c7cd128f005ca3e659a5ca7d7ce8
|
|
@@ -79,13 +79,15 @@ module Relaton
|
|
|
79
79
|
next
|
|
80
80
|
end
|
|
81
81
|
m[item.id] = {
|
|
82
|
-
id: item.id, ord: i,
|
|
83
82
|
author: renderer.in_text_author(item),
|
|
84
|
-
|
|
83
|
+
date: renderer.disambiguated_date(item,
|
|
84
|
+
disambiguator:
|
|
85
|
+
disambiguators[item.id]),
|
|
85
86
|
citation: citation_renderings(item, ref, renderer,
|
|
86
87
|
type: type,
|
|
87
88
|
disambiguator:
|
|
88
89
|
disambiguators[item.id]),
|
|
90
|
+
formattedref: terminate_reference(ref, item),
|
|
89
91
|
}
|
|
90
92
|
end
|
|
91
93
|
end
|
|
@@ -93,7 +95,7 @@ module Relaton
|
|
|
93
95
|
# isodoc's styled citations consume these keys: the default is the
|
|
94
96
|
# authoritative identifier; the short cite is the style's citation,
|
|
95
97
|
# falling back to the reference rendering (the 1.x short-cite)
|
|
96
|
-
FIRST_DELIM =
|
|
98
|
+
FIRST_DELIM = '<span class="fmt-first-biblio-delim"/>'
|
|
97
99
|
|
|
98
100
|
# A creator list alone (flavors' document-history name forms)
|
|
99
101
|
def creator_names(item)
|
|
@@ -141,11 +143,14 @@ module Relaton
|
|
|
141
143
|
# names the key)
|
|
142
144
|
def citation_renderings(item, ref, renderer, type: "author-date",
|
|
143
145
|
disambiguator: nil)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
# A style declaring shortFromReference takes the reference form
|
|
147
|
+
# with the first-biblio marker (the 1.x citetemplate short)
|
|
148
|
+
short = if renderer.short_from_reference?
|
|
146
149
|
renderer.render_short(item, FIRST_DELIM)
|
|
147
150
|
else
|
|
148
|
-
short
|
|
151
|
+
short = renderer.citation(item)
|
|
152
|
+
short.empty? ? renderer.render_short(item, FIRST_DELIM) :
|
|
153
|
+
short
|
|
149
154
|
end
|
|
150
155
|
|
|
151
156
|
title = renderer.title_citation(item)
|
|
@@ -154,15 +159,15 @@ module Relaton
|
|
|
154
159
|
full: ref,
|
|
155
160
|
default: item.docidentifier.first&.content.to_s,
|
|
156
161
|
short: short,
|
|
157
|
-
author_date: renderer.
|
|
158
|
-
|
|
159
|
-
),
|
|
162
|
+
author_date: renderer.citation(item,
|
|
163
|
+
disambiguator: disambiguator),
|
|
160
164
|
author_date_br: renderer.bracketed_date_citation(
|
|
161
165
|
item, disambiguator: disambiguator,
|
|
162
166
|
),
|
|
163
167
|
author: renderer.in_text_author(item),
|
|
164
|
-
date: renderer.disambiguated_date(item
|
|
165
|
-
reference_tag:
|
|
168
|
+
date: renderer.disambiguated_date(item),
|
|
169
|
+
# reference_tag: no rendering — isodoc falls back to the
|
|
170
|
+
# biblio-tag anchor (the 1.x nil)
|
|
166
171
|
title: title,
|
|
167
172
|
title_reference_tag: title,
|
|
168
173
|
}
|
|
@@ -240,7 +245,9 @@ module Relaton
|
|
|
240
245
|
end
|
|
241
246
|
out.empty? or break
|
|
242
247
|
end
|
|
243
|
-
|
|
248
|
+
# esc-wrapped: isodoc's l10n skips the tags, leaving a standard
|
|
249
|
+
# identifier's punctuation verbatim (the 1.x Parse behaviour)
|
|
250
|
+
out.map { |x| "<esc>#{x.text.strip}</esc>" }
|
|
244
251
|
end
|
|
245
252
|
|
|
246
253
|
def facade_id_type(id)
|
|
@@ -48,8 +48,7 @@ module Relaton
|
|
|
48
48
|
# plain join, without the wrap and sentence period (1.x
|
|
49
49
|
# short-cite templates carried no wrap)
|
|
50
50
|
def plain_render
|
|
51
|
-
marker = editors? &&
|
|
52
|
-
"#{role_space}#{role_parenthesis}" : ''
|
|
51
|
+
marker = editors? && marked? ? "#{role_space}#{role_parenthesis}" : ''
|
|
53
52
|
"#{join(names)}#{marker}"
|
|
54
53
|
end
|
|
55
54
|
|
|
@@ -12,17 +12,37 @@ module Relaton
|
|
|
12
12
|
|
|
13
13
|
def render
|
|
14
14
|
groups = [numeration, page_range].reject { |g| g.empty? }
|
|
15
|
-
groups.join(
|
|
15
|
+
groups.join(group_sep)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
private
|
|
19
19
|
|
|
20
|
+
# An extent label is a template over its value: "vol. %" in
|
|
21
|
+
# the Latin pack, "巻%" / "%頁" in the CJK packs
|
|
22
|
+
def unit(type, value)
|
|
23
|
+
label = @i18n.label(type)
|
|
24
|
+
return "#{label} #{value}" unless label.include?("%")
|
|
25
|
+
|
|
26
|
+
label.sub("%", value)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def cjk?(label)
|
|
30
|
+
label.match?(/\p{Han}|\p{Hiragana}|\p{Katakana}/)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def group_sep
|
|
34
|
+
sep = @i18n.label("extent_group_separator")
|
|
35
|
+
return sep unless sep == "extent_group_separator"
|
|
36
|
+
|
|
37
|
+
cjk?(@i18n.label("page")) ? "、 " : ", "
|
|
38
|
+
end
|
|
39
|
+
|
|
20
40
|
def numeration
|
|
21
41
|
%w[volume issue].filter_map do |type|
|
|
22
42
|
loc = localities.find { |l| l.type == type }
|
|
23
43
|
next if loc.nil? || loc.reference_from.to_s.empty?
|
|
24
44
|
|
|
25
|
-
|
|
45
|
+
unit(type, loc.reference_from)
|
|
26
46
|
end.join(" ")
|
|
27
47
|
end
|
|
28
48
|
|
|
@@ -31,10 +51,10 @@ module Relaton
|
|
|
31
51
|
from = loc.reference_from.to_s
|
|
32
52
|
to = loc.reference_to.to_s
|
|
33
53
|
if to.empty? || to == from
|
|
34
|
-
"
|
|
54
|
+
unit("page", from)
|
|
35
55
|
else
|
|
36
|
-
"#{@i18n.label('
|
|
37
|
-
|
|
56
|
+
range = "#{from}#{@i18n.label('date_range')}#{to}"
|
|
57
|
+
unit("pages", range)
|
|
38
58
|
end
|
|
39
59
|
end
|
|
40
60
|
|
|
@@ -57,7 +57,8 @@ module Relaton
|
|
|
57
57
|
return "" if label.empty? || label == "no_place"
|
|
58
58
|
|
|
59
59
|
pubs = publishers.join("; ")
|
|
60
|
-
pubs.empty? ? "#{label}
|
|
60
|
+
pubs.empty? ? "#{label}#{production_sep}".rstrip :
|
|
61
|
+
"#{label}#{production_sep}#{pubs}"
|
|
61
62
|
end
|
|
62
63
|
|
|
63
64
|
def no_place_declared?
|
|
@@ -25,7 +25,11 @@ module Relaton
|
|
|
25
25
|
if number.empty?
|
|
26
26
|
base
|
|
27
27
|
else
|
|
28
|
-
|
|
28
|
+
# an empty series_no label joins on the space alone (the
|
|
29
|
+
# CJK form: "Series 472")
|
|
30
|
+
label = @i18n.label("series_no")
|
|
31
|
+
label.empty? ? "#{base} #{number}" :
|
|
32
|
+
"#{base}, #{label} #{number}"
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
@@ -13,10 +13,11 @@ labels:
|
|
|
13
13
|
ordinal_word_10: "Tenth"
|
|
14
14
|
size_volume: "vol."
|
|
15
15
|
size_page: "pp."
|
|
16
|
-
page: "p."
|
|
17
|
-
pages: "pp."
|
|
18
|
-
volume: "vol."
|
|
19
|
-
issue: "no."
|
|
16
|
+
page: "p. %"
|
|
17
|
+
pages: "pp. %"
|
|
18
|
+
volume: "vol. %"
|
|
19
|
+
issue: "no. %"
|
|
20
|
+
no_place: "n.p."
|
|
20
21
|
version: "Version"
|
|
21
22
|
medium_website: "[website]"
|
|
22
23
|
viewed: "viewed"
|
|
@@ -3,10 +3,10 @@ labels:
|
|
|
3
3
|
edition: "版"
|
|
4
4
|
size_volume: "巻"
|
|
5
5
|
size_page: "頁"
|
|
6
|
-
page: "
|
|
7
|
-
pages: "
|
|
8
|
-
volume: "
|
|
9
|
-
issue: "
|
|
6
|
+
page: "%頁"
|
|
7
|
+
pages: "%頁"
|
|
8
|
+
volume: "巻%"
|
|
9
|
+
issue: "%号"
|
|
10
10
|
version: "版"
|
|
11
11
|
viewed: "閲覧"
|
|
12
12
|
series_no: "番号"
|
|
@@ -25,7 +25,7 @@ labels:
|
|
|
25
25
|
list_separator: "、 "
|
|
26
26
|
and: ""
|
|
27
27
|
oxford_comma: ""
|
|
28
|
-
date_range: "
|
|
28
|
+
date_range: "〜"
|
|
29
29
|
punct:
|
|
30
30
|
size-join: ""
|
|
31
31
|
marker-space: ""
|
|
@@ -64,7 +64,8 @@ module Relaton
|
|
|
64
64
|
# The short cite: the reference with the first-biblio marker
|
|
65
65
|
def render_short(model, delim)
|
|
66
66
|
kind = @style.kind_for(model.type)
|
|
67
|
-
template = @style.
|
|
67
|
+
template = @style.short_template_for(kind,
|
|
68
|
+
home: home_docid?(model)) ||
|
|
68
69
|
@style.template_for(kind, home: home_docid?(model))
|
|
69
70
|
Template.new(template).evaluate_short(
|
|
70
71
|
Fields.new(model, style: @style, i18n: @i18n, short: true,
|
|
@@ -93,12 +94,12 @@ module Relaton
|
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
# The bracketed author-date in-text capsule ("Aluffi (2022)"):
|
|
96
|
-
# the author and the date
|
|
97
|
-
|
|
97
|
+
# the author and the PLAIN date (un-disambiguated, the 1.x
|
|
98
|
+
# citetemplate's {{ date }}) in the locale's parentheses
|
|
99
|
+
def bracketed_date_citation(model, **)
|
|
98
100
|
f = Fields.new(model, style: @style, i18n: @i18n,
|
|
99
|
-
disambiguator: disambiguator,
|
|
100
101
|
elements: @elements).to_h
|
|
101
|
-
date = f["
|
|
102
|
+
date = f["date"].text
|
|
102
103
|
return "" if date.empty?
|
|
103
104
|
|
|
104
105
|
open = @i18n.punct_fetch("open-paren", "(")
|
|
@@ -114,6 +115,10 @@ module Relaton
|
|
|
114
115
|
elements: @elements).to_h["disambiguateddate"].text
|
|
115
116
|
end
|
|
116
117
|
|
|
118
|
+
def short_from_reference?
|
|
119
|
+
@style.scheme.short_from_reference
|
|
120
|
+
end
|
|
121
|
+
|
|
117
122
|
# The title citation ("{{ title }}" in the 1.x citetemplate):
|
|
118
123
|
# the title element's plain form, no style markers
|
|
119
124
|
def title_citation(model)
|
|
@@ -13,12 +13,18 @@ module Relaton
|
|
|
13
13
|
attribute :home_docid_type, :string, collection: true
|
|
14
14
|
attribute :default_kind, :string, default: ""
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
# The renderings' short cite takes the reference form with the
|
|
17
|
+
# first-biblio marker (the 1.x citetemplate short), not the
|
|
18
|
+
# citation template
|
|
19
|
+
attribute :short_from_reference, :boolean, default: -> { false }
|
|
20
|
+
|
|
21
|
+
key_value do
|
|
17
22
|
map "system", to: :system
|
|
18
23
|
map "nameForm", to: :name_form
|
|
19
24
|
map "locale", to: :locale
|
|
20
25
|
map "homeDocidType", to: :home_docid_type
|
|
21
26
|
map "defaultKind", to: :default_kind
|
|
27
|
+
map "shortFromReference", to: :short_from_reference
|
|
22
28
|
end
|
|
23
29
|
end
|
|
24
30
|
end
|
|
@@ -66,6 +66,17 @@ module Relaton
|
|
|
66
66
|
per_type.find { |t| t.type == type.to_s }
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# The home split applies to the short cite as it does to the
|
|
70
|
+
# reference template (a home standard's short cite is not an
|
|
71
|
+
# external standard's)
|
|
72
|
+
def short_template_for(type, home: nil)
|
|
73
|
+
candidates = per_type.select { |t| t.type == type.to_s }
|
|
74
|
+
if candidates.size > 1 && !home.nil?
|
|
75
|
+
candidates = candidates.select { |t| (t.home || false) == home }
|
|
76
|
+
end
|
|
77
|
+
candidates.filter_map(&:short).first
|
|
78
|
+
end
|
|
79
|
+
|
|
69
80
|
# The absent-slot replacement text declared for a type, when any
|
|
70
81
|
def fallback_for(type, slot)
|
|
71
82
|
type_template_for(type)&.fallbacks&.[](slot.to_s)
|
|
@@ -30,8 +30,18 @@ module Relaton
|
|
|
30
30
|
present = present_indices(fields)
|
|
31
31
|
return "" if present.empty?
|
|
32
32
|
|
|
33
|
+
# The split marker follows the leading run of present slots
|
|
34
|
+
# (the 1.x first SEGMENT: "{{creator}}{{role}}" splits after
|
|
35
|
+
# the role), before the first literal that follows it
|
|
36
|
+
lead_slots = []
|
|
37
|
+
@chunks.each_with_index do |(kind, _value), i|
|
|
38
|
+
break if kind != :slot || !present.include?(i)
|
|
39
|
+
|
|
40
|
+
lead_slots << i
|
|
41
|
+
end
|
|
42
|
+
split_at = lead_slots.last ? lead_slots.last + 1 : nil
|
|
43
|
+
|
|
33
44
|
out = +""
|
|
34
|
-
first_seen = false
|
|
35
45
|
@chunks.each_with_index do |(kind, value), i|
|
|
36
46
|
text =
|
|
37
47
|
case kind
|
|
@@ -39,18 +49,20 @@ module Relaton
|
|
|
39
49
|
field = fields[normalise(value)]
|
|
40
50
|
next unless field&.present?
|
|
41
51
|
|
|
42
|
-
|
|
52
|
+
field.text
|
|
43
53
|
else
|
|
44
|
-
# the split marker precedes the component's trailing
|
|
45
|
-
# punctuation (1.x ret[0] += delim, then join), with
|
|
46
|
-
# the join's separating space
|
|
47
54
|
next unless bridged?(i, present)
|
|
48
55
|
|
|
49
56
|
value
|
|
50
57
|
end
|
|
51
|
-
|
|
58
|
+
if split_at == i
|
|
59
|
+
out << fieldless(lead_slots, fields) if false
|
|
60
|
+
out << delim.to_s
|
|
61
|
+
split_at = nil
|
|
62
|
+
end
|
|
52
63
|
out << text unless text.nil?
|
|
53
64
|
end
|
|
65
|
+
out << delim.to_s if split_at == @chunks.length
|
|
54
66
|
terminate(out).rstrip
|
|
55
67
|
end
|
|
56
68
|
|
|
@@ -64,10 +76,44 @@ module Relaton
|
|
|
64
76
|
return "" if present.empty?
|
|
65
77
|
|
|
66
78
|
out = +"".dup
|
|
79
|
+
# Parenthetical groups balance on the template's literal
|
|
80
|
+
# parens alone: data text (a series run "(N.S.)", a host
|
|
81
|
+
# creator's closing paren) carries parens of its own that
|
|
82
|
+
# are no part of the template's group structure
|
|
83
|
+
paren_balance = 0
|
|
67
84
|
@chunks.each_with_index do |(kind, value), i|
|
|
68
85
|
if kind == :slot
|
|
69
86
|
field = fields[normalise(value)]
|
|
70
87
|
out << field.text if field&.present?
|
|
88
|
+
elsif value.to_s.match?(/\A[))]/)
|
|
89
|
+
# Symmetric close: with no pending open the close-paren
|
|
90
|
+
# drops, and any trailing punctuation bridges normally
|
|
91
|
+
closes = value.to_s[/\A[))]+/]
|
|
92
|
+
emitted = [paren_balance, closes.size].min
|
|
93
|
+
if emitted.positive?
|
|
94
|
+
out << closes[0, emitted] +
|
|
95
|
+
value.to_s[closes.size..].to_s
|
|
96
|
+
paren_balance -= emitted
|
|
97
|
+
else
|
|
98
|
+
rest = value.to_s.sub(/\A[))]+/, "")
|
|
99
|
+
# the trailing separator of a dropped group bridges as
|
|
100
|
+
# though the group were never there
|
|
101
|
+
if !rest.empty? && present.any? { |j| j > i } &&
|
|
102
|
+
group_gap?(i, present)
|
|
103
|
+
out << rest
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
elsif value.to_s.match?(/[((]\z/)
|
|
107
|
+
# A literal opening a parenthetical group ("({{series}})",
|
|
108
|
+
# "。({{series}})") attaches its paren to the slot it
|
|
109
|
+
# opens — the pair drops with an absent element, while
|
|
110
|
+
# any leading punctuation bridges normally
|
|
111
|
+
lead, paren = value.to_s.match(/\A(.*)([((])\z/).captures
|
|
112
|
+
out << lead if bridged_text?(i, lead, present)
|
|
113
|
+
if present.include?(i + 1)
|
|
114
|
+
out << paren
|
|
115
|
+
paren_balance += 1
|
|
116
|
+
end
|
|
71
117
|
elsif bridged?(i, present) ||
|
|
72
118
|
(value.include?("<") && present.any? { |j| j < i })
|
|
73
119
|
# markup attaches to the element it closes
|
|
@@ -102,6 +148,30 @@ module Relaton
|
|
|
102
148
|
end
|
|
103
149
|
end
|
|
104
150
|
|
|
151
|
+
# The texts between this close and the last present slot are
|
|
152
|
+
# all parenthetical-group parts (each dropped or partial)
|
|
153
|
+
def group_gap?(index, present)
|
|
154
|
+
left = present.select { |i| i < index }.max
|
|
155
|
+
@chunks[(left + 1)...index].all? do |(_, text)|
|
|
156
|
+
text.to_s.match?(/\A[))]|[((]\z/)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# The leading punctuation of a paren-opening literal bridges
|
|
161
|
+
# per the segment-join rule (a bare paren has no lead)
|
|
162
|
+
def bridged_text?(index, lead, present)
|
|
163
|
+
return true if lead.empty?
|
|
164
|
+
|
|
165
|
+
first_slot = @chunks.index { |(kind, _)| kind == :slot }
|
|
166
|
+
return present.include?(first_slot) if index < first_slot
|
|
167
|
+
|
|
168
|
+
left = present.select { |i| i < index }.max
|
|
169
|
+
left && present.any? { |i| i > index } &&
|
|
170
|
+
!@chunks[(left + 1)...index].any? do |(kind, _)|
|
|
171
|
+
kind == :text
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
105
175
|
# A literal is the trailing separator of the element that
|
|
106
176
|
# precedes it: it renders when that element renders and a
|
|
107
177
|
# later element renders, and it is the FIRST literal of its
|