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,45 @@
|
|
|
1
|
+
# American Psychological Association (7th ed.) reference forms: all
|
|
2
|
+
# author names invert with initials ("Author, A. B."), the date
|
|
3
|
+
# follows the authors in parentheses, article titles take no marks
|
|
4
|
+
# (sentence case is the author's), and only book titles and journal
|
|
5
|
+
# names carry italics. The reference list joins with a comma and ampersand.
|
|
6
|
+
name: "APA (7th edition) references"
|
|
7
|
+
family: apa
|
|
8
|
+
scheme:
|
|
9
|
+
system: name-date
|
|
10
|
+
nameForm:
|
|
11
|
+
initials: true
|
|
12
|
+
initialsSeparator: " "
|
|
13
|
+
initialsPeriod: true
|
|
14
|
+
invertedAll: true
|
|
15
|
+
givenNameFirst: false
|
|
16
|
+
editorsMarked: false
|
|
17
|
+
surnameUpcase: false
|
|
18
|
+
subsequentSurnameUpcase: false
|
|
19
|
+
locale:
|
|
20
|
+
"in": "In"
|
|
21
|
+
labels:
|
|
22
|
+
"and": "&"
|
|
23
|
+
oxford_comma: ","
|
|
24
|
+
oxford_comma: ","
|
|
25
|
+
templates:
|
|
26
|
+
titleOpen: ""
|
|
27
|
+
titleClose: ""
|
|
28
|
+
citation: "{{surname}}, {{date}}"
|
|
29
|
+
reference: "{{creator}} ({{date}}). {{title}}. {{series}}. {{production}}. {{extent}}"
|
|
30
|
+
name: "{{surname}}, {{givenNames}}"
|
|
31
|
+
identifierMode: all
|
|
32
|
+
perType:
|
|
33
|
+
- type: report
|
|
34
|
+
home: true
|
|
35
|
+
template: "{{title}}"
|
|
36
|
+
- type: report
|
|
37
|
+
template: "{{identifier}}. {{title}}. {{production}}."
|
|
38
|
+
- type: monograph
|
|
39
|
+
title: "<em>{{title}}</em>"
|
|
40
|
+
template: "{{creator}} ({{date}}). {{title}}. {{production}}."
|
|
41
|
+
- type: component_part
|
|
42
|
+
template: "{{creator}} ({{date}}). {{title}}. {{componentpart}} ({{extent}}). {{production}}."
|
|
43
|
+
- type: continuing
|
|
44
|
+
series: "<em>{{seriestitle}}, {{serienumber}}</em>"
|
|
45
|
+
template: "{{creator}} ({{date}}). {{title}}. {{series}} {{extent}}. {{location}}"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# ISO 690 name-and-date citation style, an instance of the relaton-models
|
|
2
|
+
# CitationStyle model. Templates place the ISO 690 clause 7 data elements
|
|
3
|
+
# ({{creator}}, {{title}}, ...) in each resource kind's clause 8 order; an
|
|
4
|
+
# absent element takes its trailing punctuation with it. A new style is a
|
|
5
|
+
# YAML instance — the engine holds no styles.
|
|
6
|
+
name: "ISO 690 (name and date)"
|
|
7
|
+
scheme:
|
|
8
|
+
system: name-date
|
|
9
|
+
nameForm:
|
|
10
|
+
initials: false
|
|
11
|
+
givenNameFirst: false
|
|
12
|
+
# ISO 690 marks an editor list's role ("(éd.)") also when the list
|
|
13
|
+
# holds a single editor; flavors opt out per their own style
|
|
14
|
+
loneEditorMarked: true
|
|
15
|
+
templates:
|
|
16
|
+
titleOpen: "_"
|
|
17
|
+
titleClose: "_"
|
|
18
|
+
citation: "{{surname}}, {{date}}{{disambiguator}}"
|
|
19
|
+
reference: "{{creator}}. {{title}}. {{medium}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{identifier}}. {{location}}."
|
|
20
|
+
name: "{{surname}}, {{givenNames}}"
|
|
21
|
+
perType:
|
|
22
|
+
- type: monograph
|
|
23
|
+
template: "{{creator}}. {{title}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{identifier}}. {{location}}."
|
|
24
|
+
- type: report
|
|
25
|
+
template: "{{creator}}. {{title}}. {{numeration}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{identifier}}. {{location}}."
|
|
26
|
+
- type: patent
|
|
27
|
+
template: "{{creator}}. {{title}}. {{identifier}}. {{date}}."
|
|
28
|
+
- type: continuing
|
|
29
|
+
template: "{{creator}}. {{title}}. {{componentPart}}. {{medium}}. {{edition}}. {{production}}, {{date}}. {{numeration}}. {{identifier}}. {{location}}."
|
|
30
|
+
- type: online
|
|
31
|
+
template: "{{creator}}. {{title}}. {{date}}. {{identifier}}. {{location}}."
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Chicago Manual of Style (17th ed.), bibliography forms: the notes
|
|
2
|
+
# system's reference list. Only the first author name inverts ("Peck,
|
|
3
|
+
# R. B., W. E. Hanson, and T. H. Thornburn"), article titles carry
|
|
4
|
+
# quotation marks, book titles are set in italics, and production runs
|
|
5
|
+
# "Place: Publisher".
|
|
6
|
+
name: "Chicago Manual of Style (bibliography)"
|
|
7
|
+
family: chicago
|
|
8
|
+
requires:
|
|
9
|
+
- extent_units
|
|
10
|
+
scheme:
|
|
11
|
+
system: name-date
|
|
12
|
+
nameForm:
|
|
13
|
+
initials: false
|
|
14
|
+
initialsSeparator: " "
|
|
15
|
+
initialsPeriod: true
|
|
16
|
+
invertedAll: false
|
|
17
|
+
givenNameFirst: false
|
|
18
|
+
editorsMarked: true
|
|
19
|
+
loneEditorMarked: true
|
|
20
|
+
surnameUpcase: false
|
|
21
|
+
subsequentSurnameUpcase: false
|
|
22
|
+
locale:
|
|
23
|
+
"in": "in"
|
|
24
|
+
labels:
|
|
25
|
+
"and": "and"
|
|
26
|
+
oxford_comma: ","
|
|
27
|
+
series_no: "no."
|
|
28
|
+
templates:
|
|
29
|
+
titleOpen: "\""
|
|
30
|
+
titleClose: "\""
|
|
31
|
+
citation: "{{surname}}, {{date}}"
|
|
32
|
+
reference: "{{creator}}. {{title}}. {{edition}}. {{series}}. {{production}}, {{date}}. {{extent}}."
|
|
33
|
+
name: "{{surname}}, {{givenNames}}"
|
|
34
|
+
identifierMode: all
|
|
35
|
+
perType:
|
|
36
|
+
- type: report
|
|
37
|
+
home: true
|
|
38
|
+
template: "{{title}}"
|
|
39
|
+
- type: report
|
|
40
|
+
template: "{{creator}}. {{title}}. {{edition}}. {{production}}, {{date}}."
|
|
41
|
+
- type: monograph
|
|
42
|
+
title: "<em>{{title}}</em>"
|
|
43
|
+
template: "{{creator}}. {{title}}. {{edition}}. {{production}}, {{date}}. {{extent}}."
|
|
44
|
+
- type: component_part
|
|
45
|
+
template: "{{creator}}. \"{{title}}.\" {{componentpart}}. {{production}}, {{date}}. {{extent}}."
|
|
46
|
+
- type: continuing
|
|
47
|
+
series: "<em>{{seriestitle}}</em>"
|
|
48
|
+
template: "{{creator}}. \"{{title}}.\" {{series}} {{extent}} ({{date}}). {{location}}"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# IEEE-SA Standards Style Manual bibliography forms (clause 17): a
|
|
2
|
+
# standard's entry is its designation and title, nothing else - no
|
|
3
|
+
# authors, no publisher, no place; articles and books follow the
|
|
4
|
+
# Chicago-derived forms, with only the first author name inverting and
|
|
5
|
+
# the in-text citation carrying the designation and the [B#] number.
|
|
6
|
+
name: "IEEE-SA standards bibliography"
|
|
7
|
+
family: ieee-sa
|
|
8
|
+
scheme:
|
|
9
|
+
system: designation
|
|
10
|
+
nameForm:
|
|
11
|
+
initials: true
|
|
12
|
+
initialsSeparator: " "
|
|
13
|
+
initialsPeriod: true
|
|
14
|
+
invertedAll: false
|
|
15
|
+
givenNameFirst: false
|
|
16
|
+
editorsMarked: false
|
|
17
|
+
surnameUpcase: false
|
|
18
|
+
subsequentSurnameUpcase: false
|
|
19
|
+
locale:
|
|
20
|
+
labels:
|
|
21
|
+
"and": "and"
|
|
22
|
+
oxford_comma: ","
|
|
23
|
+
templates:
|
|
24
|
+
titleOpen: ""
|
|
25
|
+
titleClose: ""
|
|
26
|
+
citation: "{{identifier}}"
|
|
27
|
+
reference: "{{creator}}, {{title}}. {{series}}. {{extent}}. {{date}}."
|
|
28
|
+
name: "{{surname}}, {{givenNames}}"
|
|
29
|
+
identifierMode: first
|
|
30
|
+
perType:
|
|
31
|
+
- type: report
|
|
32
|
+
home: true
|
|
33
|
+
template: "{{title}}"
|
|
34
|
+
- type: report
|
|
35
|
+
template: "{{identifier}}, {{title}}"
|
|
36
|
+
- type: monograph
|
|
37
|
+
title: "<em>{{title}}</em>"
|
|
38
|
+
template: "{{creator}}, {{title}}, {{edition}}. {{production}}, {{date}}, {{extent}}."
|
|
39
|
+
- type: component_part
|
|
40
|
+
title: "\"{{title}},\""
|
|
41
|
+
template: "{{creator}}, {{title}} {{componentpart}}, {{extent}}, {{date}}."
|
|
42
|
+
- type: continuing
|
|
43
|
+
title: "\"{{title}},\""
|
|
44
|
+
series: "<em>{{seriestitle}}</em>"
|
|
45
|
+
template: "{{creator}}, {{title}} {{series}}, {{extent}}, {{date}}."
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Springer LNCS citation style, an instance of the relaton-models
|
|
2
|
+
# CitationStyle model. The LNCS shape: "Author, A.B.: Title. In:
|
|
3
|
+
# Editor, E. (ed.), Proceedings. LNCS 1234, pp. 10-20. Springer,
|
|
4
|
+
# Heidelberg (2010)" - the creator list closes on a colon, the year
|
|
5
|
+
# closes the entry in parentheses, publishers precede places, and a
|
|
6
|
+
# standard with no personal authors leads with the publisher's
|
|
7
|
+
# abbreviation.
|
|
8
|
+
name: "Springer LNCS"
|
|
9
|
+
family: lncs
|
|
10
|
+
requires:
|
|
11
|
+
- production_order
|
|
12
|
+
- extent_units
|
|
13
|
+
scheme:
|
|
14
|
+
system: name-date
|
|
15
|
+
nameForm:
|
|
16
|
+
initials: true
|
|
17
|
+
initialsSeparator: ""
|
|
18
|
+
initialsPeriod: true
|
|
19
|
+
invertedAll: true
|
|
20
|
+
givenNameFirst: false
|
|
21
|
+
editorsMarked: true
|
|
22
|
+
loneEditorMarked: true
|
|
23
|
+
creatorFallback: publisher_abbrev
|
|
24
|
+
surnameUpcase: false
|
|
25
|
+
subsequentSurnameUpcase: false
|
|
26
|
+
locale:
|
|
27
|
+
"in": "In"
|
|
28
|
+
availableAt: ""
|
|
29
|
+
labels:
|
|
30
|
+
"and": ""
|
|
31
|
+
oxford_comma: ""
|
|
32
|
+
series_no: ""
|
|
33
|
+
punct:
|
|
34
|
+
production_order: publisher_first
|
|
35
|
+
production_sep: ", "
|
|
36
|
+
templates:
|
|
37
|
+
titleOpen: ""
|
|
38
|
+
titleClose: ""
|
|
39
|
+
citation: "{{surname}}, {{date}}"
|
|
40
|
+
reference: "{{creator}}: {{title}}. {{series}}. {{production}} {{dategroup}}. {{location}}"
|
|
41
|
+
name: "{{surname}}, {{givenNames}}"
|
|
42
|
+
identifierMode: first
|
|
43
|
+
perType:
|
|
44
|
+
- type: report
|
|
45
|
+
home: true
|
|
46
|
+
template: "{{title}}"
|
|
47
|
+
- type: report
|
|
48
|
+
template: "{{creator}}: {{identifier}}, {{title}}. {{production}} {{dategroup}}."
|
|
49
|
+
- type: monograph
|
|
50
|
+
template: "{{creator}}: {{title}}. {{series}} {{production}} {{dategroup}}"
|
|
51
|
+
- type: component_part
|
|
52
|
+
template: "{{creator}}: {{title}}. {{componentpart}} {{extent}} {{production}} {{dategroup}}"
|
|
53
|
+
- type: continuing
|
|
54
|
+
template: "{{creator}}: {{title}}. {{series}} {{extent}} {{dategroup}}"
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
module Iso690
|
|
6
|
+
# A citation template as declared in a style instance: literal text
|
|
7
|
+
# interleaved with {{slot}} placeholders resolved against the ISO 690
|
|
8
|
+
# data element inventory. A leading literal attaches to the first
|
|
9
|
+
# slot, and a literal between two slots to the preceding one, so an
|
|
10
|
+
# absent field never orphans punctuation around it. The last rendered
|
|
11
|
+
# slot gives up its trailing literal in favour of the template
|
|
12
|
+
# terminator, appended once when any field rendered and the output
|
|
13
|
+
# does not already end with it.
|
|
14
|
+
class Template
|
|
15
|
+
SLOT = /\{\{\s*([\w-]+)\s*\}\}/.freeze
|
|
16
|
+
|
|
17
|
+
Field = Struct.new(:present?, :text)
|
|
18
|
+
|
|
19
|
+
def initialize(source)
|
|
20
|
+
@chunks = []
|
|
21
|
+
@terminator = ""
|
|
22
|
+
scan(source.to_s)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The short cite renders the reference with the first-biblio
|
|
26
|
+
# marker appended to its first component: isodoc's styled
|
|
27
|
+
# references (eref2linkshort) split there (the 1.x
|
|
28
|
+
# fmt-first-biblio-delim)
|
|
29
|
+
def evaluate_short(fields, delim)
|
|
30
|
+
present = present_indices(fields)
|
|
31
|
+
return "" if present.empty?
|
|
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
|
+
|
|
44
|
+
out = +""
|
|
45
|
+
@chunks.each_with_index do |(kind, value), i|
|
|
46
|
+
text =
|
|
47
|
+
case kind
|
|
48
|
+
when :slot
|
|
49
|
+
field = fields[normalise(value)]
|
|
50
|
+
next unless field&.present?
|
|
51
|
+
|
|
52
|
+
field.text
|
|
53
|
+
else
|
|
54
|
+
next unless bridged?(i, present)
|
|
55
|
+
|
|
56
|
+
value
|
|
57
|
+
end
|
|
58
|
+
if split_at == i
|
|
59
|
+
out << fieldless(lead_slots, fields) if false
|
|
60
|
+
out << delim.to_s
|
|
61
|
+
split_at = nil
|
|
62
|
+
end
|
|
63
|
+
out << text unless text.nil?
|
|
64
|
+
end
|
|
65
|
+
out << delim.to_s if split_at == @chunks.length
|
|
66
|
+
terminate(out).rstrip
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# 1.x segment-join semantics: present elements joined with the
|
|
70
|
+
# template's separators — a literal renders only when it
|
|
71
|
+
# separates (a run of absent elements between) two present
|
|
72
|
+
# elements; leading and trailing literals drop with the
|
|
73
|
+
# elements they would have attached to
|
|
74
|
+
def evaluate(fields)
|
|
75
|
+
present = present_indices(fields)
|
|
76
|
+
return "" if present.empty?
|
|
77
|
+
|
|
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
|
|
84
|
+
@chunks.each_with_index do |(kind, value), i|
|
|
85
|
+
if kind == :slot
|
|
86
|
+
field = fields[normalise(value)]
|
|
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
|
|
117
|
+
elsif bridged?(i, present) ||
|
|
118
|
+
(value.include?("<") && present.any? { |j| j < i })
|
|
119
|
+
# markup attaches to the element it closes
|
|
120
|
+
out << value
|
|
121
|
+
elsif close_pending_paren?(out, value)
|
|
122
|
+
out << value
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
terminate(out).rstrip
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
def scan(source)
|
|
131
|
+
rest = source
|
|
132
|
+
while (slot = SLOT.match(rest))
|
|
133
|
+
@chunks << [:text, rest[0...slot.begin(0)]] if
|
|
134
|
+
slot.begin(0).positive?
|
|
135
|
+
@chunks << [:slot, slot[1]]
|
|
136
|
+
rest = rest[slot.end(0)..]
|
|
137
|
+
end
|
|
138
|
+
@terminator = rest
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def present_indices(fields)
|
|
142
|
+
@chunks.each_index.select do |i|
|
|
143
|
+
kind, value = @chunks[i]
|
|
144
|
+
next false unless kind == :slot
|
|
145
|
+
|
|
146
|
+
field = fields[normalise(value)]
|
|
147
|
+
!field.nil? && field.present?
|
|
148
|
+
end
|
|
149
|
+
end
|
|
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
|
+
|
|
175
|
+
# A literal is the trailing separator of the element that
|
|
176
|
+
# precedes it: it renders when that element renders and a
|
|
177
|
+
# later element renders, and it is the FIRST literal of its
|
|
178
|
+
# gap (the 1.x segment join — absent elements between two
|
|
179
|
+
# present ones leave the single separator that follows the
|
|
180
|
+
# earlier present element; an absent slot directly before a
|
|
181
|
+
# present one, as "{{date}}{{disambiguator}}, {{access}}",
|
|
182
|
+
# does not swallow it). A leading literal (no slot precedes
|
|
183
|
+
# it) attaches to the first slot, emitting only when that
|
|
184
|
+
# slot is present.
|
|
185
|
+
def bridged?(index, present)
|
|
186
|
+
first_slot = @chunks.index { |(kind, _)| kind == :slot }
|
|
187
|
+
return present.include?(first_slot) if index < first_slot
|
|
188
|
+
|
|
189
|
+
left = present.select { |i| i < index }.max
|
|
190
|
+
left && present.any? { |i| i > index } &&
|
|
191
|
+
!@chunks[(left + 1)...index].any? do |(kind, _)|
|
|
192
|
+
kind == :text
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# A template's paired literal ("({{production}})") closes even
|
|
197
|
+
# when nothing follows the present element it wraps. Fullwidth
|
|
198
|
+
# parens (CJK) pair the same way
|
|
199
|
+
def close_pending_paren?(out, value)
|
|
200
|
+
return false unless value.start_with?(")", "\uFF09")
|
|
201
|
+
|
|
202
|
+
opens = out.count("(") + out.count("\uFF08")
|
|
203
|
+
closes = out.count(")") + out.count("\uFF09")
|
|
204
|
+
opens > closes
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def terminate(body)
|
|
208
|
+
# 1.x punctuation cleanup: a sentence period before a spaced
|
|
209
|
+
# comma yields to the comma (", 2013" over ". , 2013"; an
|
|
210
|
+
# initials period before a comma ("P.,") stands, being
|
|
211
|
+
# unspaced), and stacked separators around absent elements
|
|
212
|
+
# collapse into one (". : ." into ". "); an empty pair left
|
|
213
|
+
# by an absent element drops
|
|
214
|
+
body = body.gsub(/:\s*\.\s*/, ": ")
|
|
215
|
+
body = body.gsub(/\.\s+,/, ",")
|
|
216
|
+
body = body.gsub(/(?:[.,:;]\s+)+[.,:;]/, ". ")
|
|
217
|
+
body = body.gsub(/\.\s*\./, ". ")
|
|
218
|
+
body = body.gsub(/:\s*\.\s*/, ": ")
|
|
219
|
+
body = body.gsub(/\(\s*\)/, "")
|
|
220
|
+
body = body.gsub(/ +/, " ").gsub(" ,", ",")
|
|
221
|
+
terminator = unbalanced_close(body, @terminator)
|
|
222
|
+
return body if terminator.strip.empty?
|
|
223
|
+
if terminator !~ /[<\w]/ && body.rstrip.end_with?(terminator.strip)
|
|
224
|
+
return body
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
"#{body}#{terminator}"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# The terminator's closing parens stand only when the body
|
|
231
|
+
# opened them (their "(" died with an absent element)
|
|
232
|
+
def unbalanced_close(body, terminator)
|
|
233
|
+
return terminator unless terminator.start_with?(")")
|
|
234
|
+
|
|
235
|
+
open = body.count("(") - body.count(")")
|
|
236
|
+
return terminator.sub(/\A\)+/) { |closes| closes[0, open] } if
|
|
237
|
+
open.positive?
|
|
238
|
+
|
|
239
|
+
terminator.sub(/\A\)+/, "")
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def normalise(slot)
|
|
243
|
+
slot.to_s.delete("_").downcase
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Render
|
|
5
|
+
# Citation rendering per the ISO 690 architecture: a style instance
|
|
6
|
+
# places the inventory's data elements (clause 7) in each resource
|
|
7
|
+
# kind's order (clause 8); the engine is a template evaluator over a
|
|
8
|
+
# field resolver and holds no styles, no vocabularies, no i18n.
|
|
9
|
+
# The v1 compatibility facade (relaton-render#90): isodoc's
|
|
10
|
+
# render-isodoc subclasses Relaton::Render::General.
|
|
11
|
+
autoload :General, "relaton/render/general"
|
|
12
|
+
|
|
13
|
+
module Iso690
|
|
14
|
+
autoload :Element, "relaton/render/iso690/element"
|
|
15
|
+
autoload :Elements, "relaton/render/iso690/elements"
|
|
16
|
+
autoload :Fields, "relaton/render/iso690/fields"
|
|
17
|
+
autoload :I18n, "relaton/render/iso690/i18n"
|
|
18
|
+
autoload :IndexRenderer, "relaton/render/iso690/index_renderer"
|
|
19
|
+
autoload :IdentifierKinds, "relaton/render/iso690/identifier_kinds"
|
|
20
|
+
autoload :Kinds, "relaton/render/iso690/kinds"
|
|
21
|
+
autoload :Renderer, "relaton/render/iso690/renderer"
|
|
22
|
+
autoload :Rules, "relaton/render/iso690/rules"
|
|
23
|
+
autoload :Style, "relaton/render/iso690/style"
|
|
24
|
+
autoload :Template, "relaton/render/iso690/template"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/relaton-render.rb
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "relaton/render/version"
|
|
2
|
-
require "relaton/render/
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
require "relaton/render/iso690"
|
|
5
|
+
|
|
6
|
+
module Relaton
|
|
7
|
+
module Render
|
|
8
|
+
# A bibliographic item whose style template resolves to nothing: the
|
|
9
|
+
# single-item API raises, the batch API skips
|
|
10
|
+
class Unrenderable < StandardError; end
|
|
7
11
|
|
|
12
|
+
end
|
|
13
|
+
end
|
data/relaton-render.gemspec
CHANGED
|
@@ -19,20 +19,13 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
spec.bindir = "exe"
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
21
|
spec.require_paths = ["lib"]
|
|
22
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
|
22
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.3.0")
|
|
23
23
|
|
|
24
|
-
spec.
|
|
25
|
-
spec.add_development_dependency "
|
|
26
|
-
spec.
|
|
27
|
-
spec.
|
|
28
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
|
29
|
-
spec.add_development_dependency "simplecov"
|
|
30
|
-
|
|
31
|
-
spec.add_dependency "isodoc-i18n"
|
|
32
|
-
spec.add_dependency "liquid", "~> 4"
|
|
24
|
+
spec.add_dependency "htmlentities"
|
|
25
|
+
spec.add_development_dependency "relaton-bib"
|
|
26
|
+
spec.add_dependency "liquid", "~> 5"
|
|
27
|
+
spec.add_dependency "lutaml-model"
|
|
33
28
|
spec.add_dependency "nokogiri"
|
|
34
|
-
spec.add_dependency "relaton-bib", ">= 1.12.0"
|
|
35
29
|
spec.add_dependency "twitter_cldr"
|
|
36
|
-
spec.
|
|
37
|
-
#spec.metadata["rubygems_mfa_required"] = "true"
|
|
30
|
+
# spec.metadata["rubygems_mfa_required"] = "true"
|
|
38
31
|
end
|