relaton-render 0.1.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,96 +0,0 @@
1
- class Iso690Parse
2
- def extract_orgname(org)
3
- name = org.at("./name")
4
- name&.text
5
- end
6
-
7
- def extract_personname(person)
8
- surname = person.at("./name/surname") || person.at("./name/completename")
9
- given, middle, initials = given_and_middle_name(person)
10
- { surname: surname&.text,
11
- given: given,
12
- middle: middle,
13
- initials: initials }
14
- end
15
-
16
- def given_and_middle_name(person)
17
- forenames = person.xpath("./name/forename")&.map(&:text)
18
- initials = person.xpath("./name/initial")&.map(&:text)
19
- forenames.empty? and initials.empty? and return [nil, nil, nil]
20
- forenames.empty? and forenames = initials.dup
21
- initials.empty? and initials = forenames.map { |x| x[0] }
22
- [forenames.first, forenames[1..-1], initials]
23
- end
24
-
25
- def extractname(contributor)
26
- org = contributor.at("./organization")
27
- person = contributor.at("./person")
28
- return { surname: extract_orgname(org) } if org
29
- return extract_personname(person) if person
30
-
31
- nil
32
- end
33
-
34
- def contributor_role(contributors)
35
- return nil unless contributors.length.positive?
36
-
37
- desc = contributors[0].at("role/description")&.text
38
- type = contributors[0].at("role/@type")&.text
39
- return nil if %w(author publisher).include?(type) && desc.nil?
40
-
41
- type
42
- end
43
-
44
- def creatornames(doc)
45
- cr = creatornames1(doc)
46
- cr.empty? and return [nil, nil]
47
- [cr.map { |x| extractname(x) }, contributor_role(cr)]
48
- end
49
-
50
- def creatornames1(doc)
51
- cr = []
52
- return cr if doc.nil?
53
-
54
- %w(author performer adapter translator editor publisher distributor)
55
- .each do |r|
56
- add = doc.xpath("./contributor[role/@type = '#{r}']")
57
- next if add.empty?
58
-
59
- cr = add and break
60
- end
61
- cr.empty? and cr = doc.xpath("./contributor")
62
- cr
63
- end
64
-
65
- def date1(date)
66
- on = date.at("./on")
67
- from = date.at("./from")
68
- to = date.at("./to")
69
- return { on: on.text } if on
70
- return { from: from.text, to: to&.text } if from
71
-
72
- nil
73
- end
74
-
75
- def date(doc, host)
76
- x = doc.at("./date[@type = 'issued']") ||
77
- doc.at("./date[@type = 'circulated']") ||
78
- doc.at("./date") ||
79
- host&.at("./date[@type = 'issued']") ||
80
- host&.at("./date[@type = 'circulated']") ||
81
- host&.at("./date") or return nil
82
- date1(x)
83
- end
84
-
85
- def date_updated(doc, host)
86
- x = doc.at("./date[@type = 'updated']") ||
87
- host&.at("./date[@type = 'updated']") or return nil
88
- date1(x)
89
- end
90
-
91
- def date_accessed(doc, host)
92
- x = doc.at("./date[@type = 'accessed']") ||
93
- host&.at("./date[@type = 'accessed']") or return nil
94
- date1(x)
95
- end
96
- end
@@ -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]}&#x2013;#{hash[:to]}" : hash[:from]
93
- else hash
94
- end
95
- end
96
-
97
- def date_range(hash)
98
- if hash[:from]
99
- "#{hash[:from]}&#x2013;#{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
@@ -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