relaton-render 0.1.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.adoc +64 -19
- data/lib/isodoc/i18n.rb +12 -3
- data/lib/isodoc-yaml/i18n-ar.yaml +29 -0
- data/lib/isodoc-yaml/i18n-de.yaml +27 -0
- data/lib/isodoc-yaml/i18n-en.yaml +14 -5
- data/lib/isodoc-yaml/i18n-es.yaml +28 -0
- data/lib/isodoc-yaml/i18n-fr.yaml +28 -0
- data/lib/isodoc-yaml/i18n-ru.yaml +13 -5
- data/lib/isodoc-yaml/i18n-zh-Hans.yaml +28 -0
- data/lib/relaton/render/fields/date.rb +45 -0
- data/lib/relaton/render/fields/fields.rb +212 -0
- data/lib/relaton/{config.yml → render/general/config.yml} +36 -31
- data/lib/relaton/{render.rb → render/general/render.rb} +52 -33
- data/lib/relaton/{render_classes.rb → render/general/render_classes.rb} +4 -1
- data/lib/relaton/render/parse/parse.rb +62 -0
- data/lib/relaton/render/parse/parse_contributors.rb +105 -0
- data/lib/relaton/render/parse/parse_extract.rb +188 -0
- data/lib/relaton/render/template/liquid.rb +15 -0
- data/lib/relaton/render/template/template.rb +183 -0
- data/lib/{utils → relaton/render/utils}/utils.rb +0 -0
- data/lib/relaton/{version.rb → render/version.rb} +1 -1
- data/lib/relaton-render.rb +5 -4
- data/relaton-render.gemspec +4 -1
- metadata +42 -12
- data/lib/parse/parse.rb +0 -54
- data/lib/parse/parse_contributors.rb +0 -96
- data/lib/parse/parse_extract.rb +0 -155
- data/lib/relaton/render_fields.rb +0 -151
- data/lib/template/template.rb +0 -152
data/lib/parse/parse_extract.rb
DELETED
@@ -1,155 +0,0 @@
|
|
1
|
-
class Iso690Parse
|
2
|
-
def title(doc)
|
3
|
-
doc&.at("./title")&.text
|
4
|
-
end
|
5
|
-
|
6
|
-
def medium(doc, host)
|
7
|
-
x = doc.at("./medium") || host&.at("./medium") or return nil
|
8
|
-
|
9
|
-
%w(content genre form carrier size scale).each_with_object([]) do |i, m|
|
10
|
-
m << x.at("./#{i}")&.text
|
11
|
-
end.compact.join(", ")
|
12
|
-
end
|
13
|
-
|
14
|
-
def blank?(text)
|
15
|
-
text.nil? || text.empty?
|
16
|
-
end
|
17
|
-
|
18
|
-
def edition(doc, host)
|
19
|
-
x = doc.at("./edition") || host&.at("./edition") or return nil
|
20
|
-
|
21
|
-
x.text
|
22
|
-
end
|
23
|
-
|
24
|
-
def place(doc, host)
|
25
|
-
x = doc.at("./place") || host&.at("./place") or return nil
|
26
|
-
|
27
|
-
x.text
|
28
|
-
end
|
29
|
-
|
30
|
-
def publisher(doc, host)
|
31
|
-
x = doc.at("./contributor[role/@type = 'publisher']/organization/name") ||
|
32
|
-
host&.at("./contributor[role/@type = 'publisher']/organization/name") or
|
33
|
-
return nil
|
34
|
-
x.text
|
35
|
-
end
|
36
|
-
|
37
|
-
def distributor(doc, host)
|
38
|
-
x = doc.at("./contributor[role/@type = 'distributor']/organization/name") ||
|
39
|
-
host&.at("./contributor[role/@type = 'distributor']/organization/name") or
|
40
|
-
return nil
|
41
|
-
x.text
|
42
|
-
end
|
43
|
-
|
44
|
-
def series_title(doc)
|
45
|
-
doc&.at("./title")&.text || doc&.at("./formattedref")&.text
|
46
|
-
end
|
47
|
-
|
48
|
-
def series_abbr(doc)
|
49
|
-
doc&.at("./abbreviation")&.text
|
50
|
-
end
|
51
|
-
|
52
|
-
def series_num(doc)
|
53
|
-
doc&.at("./number")&.text
|
54
|
-
end
|
55
|
-
|
56
|
-
def series_partnumber(doc)
|
57
|
-
doc&.at("./partnumber")&.text
|
58
|
-
end
|
59
|
-
|
60
|
-
def series_run(doc)
|
61
|
-
doc&.at("./run")&.text
|
62
|
-
end
|
63
|
-
|
64
|
-
def standardidentifier(doc)
|
65
|
-
doc.xpath("./docidentifier").each_with_object([]) do |id, ret|
|
66
|
-
ret << id.text unless %w(metanorma metanorma-ordinal).include? id["type"]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def uri(doc)
|
71
|
-
uri = doc.at("./uri[@type = 'doi']") || doc.at("./uri[@type = 'uri']") ||
|
72
|
-
doc.at("./uri[@type = 'src']") || doc.at("./uri")
|
73
|
-
uri&.text
|
74
|
-
end
|
75
|
-
|
76
|
-
def access_location(doc, host)
|
77
|
-
x = doc.at("./accessLocation") || host&.at("./accessLocation") or
|
78
|
-
return nil
|
79
|
-
x.text
|
80
|
-
end
|
81
|
-
|
82
|
-
def included(type)
|
83
|
-
["article", "inbook", "incollection", "inproceedings"].include? type
|
84
|
-
end
|
85
|
-
|
86
|
-
def wrap(text, startdelim = " ", enddelim = ".")
|
87
|
-
return "" if blank?(text)
|
88
|
-
|
89
|
-
"#{startdelim}#{text}#{enddelim}"
|
90
|
-
end
|
91
|
-
|
92
|
-
def type(doc)
|
93
|
-
type = doc.at("./@type") and return type&.text
|
94
|
-
doc.at("./relation[@type = 'includedIn']") and return "inbook"
|
95
|
-
"book"
|
96
|
-
end
|
97
|
-
|
98
|
-
def extent1(localities)
|
99
|
-
localities.each_with_object({}) do |l, ret|
|
100
|
-
ret[(l["type"] || "page").to_sym] = {
|
101
|
-
from: l.at("./referenceFrom")&.text,
|
102
|
-
to: l.at("./referenceTo")&.text,
|
103
|
-
}
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def extent0(elem, acc, ret1)
|
108
|
-
case elem.name
|
109
|
-
when "localityStack"
|
110
|
-
acc << ret1
|
111
|
-
ret1 = {}
|
112
|
-
acc << extent1(elem.elements)
|
113
|
-
when "locality" then ret1.merge!(extent1([elem]))
|
114
|
-
when "referenceFrom" then ret1.merge!(extent1([elem.parent]))
|
115
|
-
end
|
116
|
-
[acc, ret1]
|
117
|
-
end
|
118
|
-
|
119
|
-
def extent(doc)
|
120
|
-
ret1 = {}
|
121
|
-
ret = doc.xpath("./extent").each_with_object([]) do |e, acc|
|
122
|
-
e.elements.each do |l|
|
123
|
-
acc, ret1 = extent0(l, acc, ret1)
|
124
|
-
break if l.name == "referenceFrom"
|
125
|
-
end
|
126
|
-
end
|
127
|
-
ret << ret1
|
128
|
-
ret.reject(&:empty?)
|
129
|
-
end
|
130
|
-
|
131
|
-
def draft(doc)
|
132
|
-
dr = doc&.at("./status/stage")&.text
|
133
|
-
|
134
|
-
iterord = iter_ordinal(doc)
|
135
|
-
status = status_print(dr)
|
136
|
-
status = "#{iterord} #{status}" if iterord
|
137
|
-
status
|
138
|
-
end
|
139
|
-
|
140
|
-
def iter_ordinal(isoxml)
|
141
|
-
return nil unless isoxml.at(("./status/iteration"))
|
142
|
-
|
143
|
-
iter = isoxml.at(("./status/iteration"))&.text || "1"
|
144
|
-
iter.to_i.localize.to_rbnf_s("SpelloutRules",
|
145
|
-
"spellout-ordinal").capitalize
|
146
|
-
end
|
147
|
-
|
148
|
-
def status_print(status)
|
149
|
-
status
|
150
|
-
end
|
151
|
-
|
152
|
-
def status(doc)
|
153
|
-
doc&.at("./status/stage")&.text
|
154
|
-
end
|
155
|
-
end
|
@@ -1,151 +0,0 @@
|
|
1
|
-
module Relaton
|
2
|
-
module Render
|
3
|
-
class Fields
|
4
|
-
def initialize(options)
|
5
|
-
@r = options[:renderer]
|
6
|
-
end
|
7
|
-
|
8
|
-
def compound_fields_format(hash)
|
9
|
-
name_fields_format(hash)
|
10
|
-
role_fields_format(hash)
|
11
|
-
date_fields_format(hash)
|
12
|
-
misc_fields_format(hash)
|
13
|
-
end
|
14
|
-
|
15
|
-
def name_fields_format(hash)
|
16
|
-
hash[:creatornames] = nameformat(hash[:creators])
|
17
|
-
hash[:host_creatornames] = nameformat(hash[:host_creators])
|
18
|
-
end
|
19
|
-
|
20
|
-
def role_fields_format(hash)
|
21
|
-
hash[:role] = role_inflect(hash[:creators], hash[:role_raw])
|
22
|
-
hash[:host_role] =
|
23
|
-
role_inflect(hash[:host_creators], hash[:host_role_raw])
|
24
|
-
end
|
25
|
-
|
26
|
-
def misc_fields_format(hash)
|
27
|
-
hash[:series] = seriesformat(hash)
|
28
|
-
hash[:edition] = editionformat(hash[:edition_raw])
|
29
|
-
hash[:extent] = extentformat(hash[:extent_raw], hash)
|
30
|
-
hash
|
31
|
-
end
|
32
|
-
|
33
|
-
def date_fields_format(hash)
|
34
|
-
hash[:date] = dateformat(hash[:date], hash)
|
35
|
-
hash[:date_updated] = dateformat(hash[:date_updated], hash)
|
36
|
-
hash[:date_accessed] = dateformat(hash[:date_accessed], hash)
|
37
|
-
end
|
38
|
-
|
39
|
-
def seriesformat(hash)
|
40
|
-
parts = %i(series_title series_abbr series_num series_partnumber
|
41
|
-
series_run)
|
42
|
-
series_out = parts.each_with_object({}) do |i, m|
|
43
|
-
m[i] = hash[i]
|
44
|
-
end
|
45
|
-
t = hash[:type] == "article" ? @r.journaltemplate : @r.seriestemplate
|
46
|
-
t.render(series_out)
|
47
|
-
end
|
48
|
-
|
49
|
-
def nameformat(names)
|
50
|
-
return names if names.nil?
|
51
|
-
|
52
|
-
parts = %i(surname initials given middle)
|
53
|
-
names_out = names.each_with_object({}) do |n, m|
|
54
|
-
parts.each do |i|
|
55
|
-
m[i] ||= []
|
56
|
-
m[i] << n[i]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
@r.nametemplate.render(names_out)
|
60
|
-
end
|
61
|
-
|
62
|
-
def role_inflect(contribs, role)
|
63
|
-
return nil if role.nil? || contribs.size.zero?
|
64
|
-
|
65
|
-
number = contribs.size > 1 ? "pl" : "sg"
|
66
|
-
@r.i18n.get[role][number] || role
|
67
|
-
end
|
68
|
-
|
69
|
-
def editionformat(edn)
|
70
|
-
return edn unless /^\d+$/.match?(edn)
|
71
|
-
|
72
|
-
num = edn.to_i.localize(@r.lang.to_sym)
|
73
|
-
.to_rbnf_s(*@r.edition_number)
|
74
|
-
@r.edition.sub(/%/, num)
|
75
|
-
end
|
76
|
-
|
77
|
-
def extentformat(extent, hash)
|
78
|
-
extent.map do |e|
|
79
|
-
extent_out = e.merge(type: hash[:type],
|
80
|
-
host_title: hash[:host_title])
|
81
|
-
.transform_values do |v|
|
82
|
-
v.is_a?(Hash) ? range(v) : v
|
83
|
-
end
|
84
|
-
@r.extenttemplate.render(extent_out.merge(orig: e))
|
85
|
-
end.join("; ")
|
86
|
-
end
|
87
|
-
|
88
|
-
def range(hash)
|
89
|
-
if hash[:on] then hash[:on]
|
90
|
-
elsif hash.has_key?(:from) && hash[:from].nil? then nil
|
91
|
-
elsif hash[:from]
|
92
|
-
hash[:to] ? "#{hash[:from]}–#{hash[:to]}" : hash[:from]
|
93
|
-
else hash
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def date_range(hash)
|
98
|
-
if hash[:from]
|
99
|
-
"#{hash[:from]}–#{hash[:to]}"
|
100
|
-
else range(hash)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def dateformat(date, hash)
|
105
|
-
return nil if date.nil?
|
106
|
-
|
107
|
-
%i(from to on).each do |k|
|
108
|
-
date[k] = daterender(date[k], hash)
|
109
|
-
end
|
110
|
-
date_range(date)
|
111
|
-
end
|
112
|
-
|
113
|
-
def daterender(date, _hash)
|
114
|
-
return date if date.nil? || /^\d+$/.match?(date)
|
115
|
-
|
116
|
-
daterender1(date, dategranularity(date), hash)
|
117
|
-
end
|
118
|
-
|
119
|
-
def daterender1(date, format, _hash)
|
120
|
-
datef = dateparse(date, format, @r.lang.to_sym)
|
121
|
-
case @r.date[format]
|
122
|
-
when "to_full_s", "to_long_s", "to_medium_s", "to_short_s"
|
123
|
-
datef.send @r.date[format]
|
124
|
-
else
|
125
|
-
datef.to_additional_s(@r.date[format])
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def dategranularity(date)
|
132
|
-
case date
|
133
|
-
when /^\d+-\d+$/ then "month_year"
|
134
|
-
when /^\d+-\d+-\d+$/ then "day_month_year"
|
135
|
-
else "date_time"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def dateparse(date, format, lang)
|
140
|
-
case format
|
141
|
-
when "date_time" then DateTime.parse(date)
|
142
|
-
.localize(lang, timezone: "Zulu")
|
143
|
-
when "day_month_year" then DateTime.parse(date)
|
144
|
-
.localize(lang, timezone: "Zulu").to_date
|
145
|
-
when "month_year" then Date.parse(date)
|
146
|
-
.localize(lang, timezone: "Zulu").to_date
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
data/lib/template/template.rb
DELETED
@@ -1,152 +0,0 @@
|
|
1
|
-
require_relative "../utils/utils"
|
2
|
-
|
3
|
-
module Relaton
|
4
|
-
module Render
|
5
|
-
class Iso690Template
|
6
|
-
def initialize(opt = {})
|
7
|
-
opt = Utils::sym_keys(opt)
|
8
|
-
@i18n = opt[:i18n]
|
9
|
-
@template_raw = opt[:template].dup
|
10
|
-
@template =
|
11
|
-
case opt[:template]
|
12
|
-
when Hash
|
13
|
-
opt[:template].transform_values { |x| template_process(x) }
|
14
|
-
when Array then opt[:template].map { |x| template_process(x) }
|
15
|
-
else { default: template_process(opt[:template]) }
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# denote start and end of field,
|
20
|
-
# so that we can detect empty fields in postprocessing
|
21
|
-
FIELD_DELIM = "\u0018".freeze
|
22
|
-
|
23
|
-
# use tab internally for non-spacing delimiter
|
24
|
-
NON_SPACING_DELIM = "\t".freeze
|
25
|
-
|
26
|
-
def template_process(template)
|
27
|
-
t = template.gsub(/\{\{/, "#{FIELD_DELIM}{{")
|
28
|
-
.gsub(/\}\}/, "}}#{FIELD_DELIM}")
|
29
|
-
.gsub(/\t/, " ")
|
30
|
-
t1 = t.split(/(\{\{.+?\}\})/).map do |n|
|
31
|
-
n.include?("{{") ? n : n.gsub(/(?<!\\)\|/, "\t")
|
32
|
-
end.join
|
33
|
-
Liquid::Template.parse(t1)
|
34
|
-
end
|
35
|
-
|
36
|
-
def render(hash)
|
37
|
-
template_clean(template_select(hash)
|
38
|
-
.render(liquid_hash(hash.merge("labels" => @i18n.get))))
|
39
|
-
end
|
40
|
-
|
41
|
-
def template_select(_hash)
|
42
|
-
@template[:default]
|
43
|
-
end
|
44
|
-
|
45
|
-
# use tab internally for non-spacing delimiter
|
46
|
-
def template_clean(str)
|
47
|
-
str = str.gsub(/\S*#{FIELD_DELIM}#{FIELD_DELIM}\S*/o, "")
|
48
|
-
.gsub(/#{FIELD_DELIM}/o, "")
|
49
|
-
.gsub(/_/, " ")
|
50
|
-
.gsub(/([,:;]\s*)+([,:;](\s|$))/, "\\2")
|
51
|
-
.gsub(/([,.:;]\s*)+([.](\s|$))/, "\\2")
|
52
|
-
.gsub(/(:\s+)(&\s)/, "\\2")
|
53
|
-
.gsub(/\s+([,.:;])/, "\\1")
|
54
|
-
.gsub(/#{NON_SPACING_DELIM}/o, "").gsub(/\s+/, " ")
|
55
|
-
str.strip
|
56
|
-
end
|
57
|
-
|
58
|
-
def liquid_hash(hash)
|
59
|
-
case hash
|
60
|
-
when Hash
|
61
|
-
hash.map { |k, v| [k.to_s, liquid_hash(v)] }.to_h
|
62
|
-
when Array
|
63
|
-
hash.map { |v| liquid_hash(v) }
|
64
|
-
when String
|
65
|
-
hash.empty? ? nil : hash
|
66
|
-
else hash
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class Iso690SeriesTemplate < Iso690Template
|
72
|
-
end
|
73
|
-
|
74
|
-
class Iso690ExtentTemplate < Iso690Template
|
75
|
-
def template_select(hash)
|
76
|
-
t = @template_raw[hash[:type].to_sym]
|
77
|
-
hash.each do |k, _v|
|
78
|
-
next unless hash[:orig][k].is_a?(Hash)
|
79
|
-
|
80
|
-
num = number(hash[:type], hash[:orig][k])
|
81
|
-
t = t.gsub(/labels\[['"]extent['"]\]\[['"]#{k}['"]\]/,
|
82
|
-
"\\0['#{num}']")
|
83
|
-
end
|
84
|
-
t = t.gsub(/labels\[['"]extent['"]\]\[['"][^\]'"]+['"]\](?!\[)/,
|
85
|
-
"\\0['sg']")
|
86
|
-
template_process(t)
|
87
|
-
end
|
88
|
-
|
89
|
-
def number(type, value)
|
90
|
-
return "pl" if value[:to]
|
91
|
-
return "sg" if %w(article incollection inproceedings inbook)
|
92
|
-
.include?(type) || value[:host_title]
|
93
|
-
|
94
|
-
value[:from] == "1" ? "sg" : "pl"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
class Iso690NameTemplate < Iso690Template
|
99
|
-
def initialize(opt = {})
|
100
|
-
@etal_count = opt[:template]["etal_count"]
|
101
|
-
opt[:template].delete("etal_count")
|
102
|
-
super
|
103
|
-
end
|
104
|
-
|
105
|
-
def template_select(names)
|
106
|
-
case names[:surname].size
|
107
|
-
when 1 then @template[:one]
|
108
|
-
when 2 then @template[:two]
|
109
|
-
when 3 then @template[:more]
|
110
|
-
else
|
111
|
-
if @etal_count && names.size >= @etal_count
|
112
|
-
@template[:etal]
|
113
|
-
else expand_nametemplate(@template_raw[:more], names.size)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# assumes that template contains, consecutively and not interleaved,
|
119
|
-
# ...[0], ...[1], ...[2]
|
120
|
-
def expand_nametemplate(template, size)
|
121
|
-
t = nametemplate_split(template)
|
122
|
-
mid = (1..size - 1).each_with_object([]) do |i, m|
|
123
|
-
m << t[1].gsub(/\[1\]/, "[#{i}]")
|
124
|
-
end
|
125
|
-
template_process(t[0] + mid.join + t[2].gsub(/\[2\]/, "[#{size}]"))
|
126
|
-
end
|
127
|
-
|
128
|
-
def nametemplate_split(template)
|
129
|
-
curr = 0
|
130
|
-
prec = ""
|
131
|
-
t = template.split(/(\{\{.+?\}\})/)
|
132
|
-
.each_with_object(["", "", ""]) do |n, m|
|
133
|
-
m, curr, prec = nametemplate_split1(n, m, curr, prec)
|
134
|
-
m
|
135
|
-
end
|
136
|
-
t[-1] += prec
|
137
|
-
t
|
138
|
-
end
|
139
|
-
|
140
|
-
def nametemplate_split1(elem, acc, curr, prec)
|
141
|
-
if match = /\{\{.+?\[(\d)\]/.match(elem)
|
142
|
-
curr += 1 if match[1].to_i > curr
|
143
|
-
acc[curr] += prec
|
144
|
-
prec = ""
|
145
|
-
acc[curr] += elem
|
146
|
-
else prec += elem
|
147
|
-
end
|
148
|
-
[acc, curr, prec]
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|