relaton-render 0.7.0 → 0.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51ae7431472a2a411d6fbb2e0d68e7a8b32c647cf839886c347e34000576a11c
4
- data.tar.gz: 5ede0d93ad108c2add767f4b9a5cec9b483ee9a1b6dd2db60ef51ee2959e65ab
3
+ metadata.gz: a61037d7e9fc1193d54cb03fd7155a09431a30710990c50366112558b86d8210
4
+ data.tar.gz: 7fe54372399bb332f686af101b9f6e36140497e89073cdf02f5e2bb0afec3183
5
5
  SHA512:
6
- metadata.gz: 0a2c1ff06584f6dddaedd7fab2d58467f3f4e54330107ff300529f26094f67331d09a19838743185af859c9d1deadbe4219ecec1e562f23bd320d87d4359bc1d
7
- data.tar.gz: 2da0c615b6cb5a610d9d4d14c892d22131eb3317595b5b2e131baf7d8f985cb0a8fc76a66f22ab550fc83b37005d9b29c6817ded7bc0b0b50ef3519a1c6ea769
6
+ metadata.gz: 9f39ff4adacad120c2b2661d89ff59593b7fb41b4cbee209171ebbb92bf188bb52f36f0e8a8f7c62323cfb834bd2d296a7ce2b94bc8217e86838927c189c2794
7
+ data.tar.gz: 655a9918e4559a77dbcb94bcef62037b1e13ae81aea2472e1d8fd62941ff312abdf2394b9a7dec3528faf083e0079b3111d4aec21e4e935a688807a3b348cedd
data/README.adoc CHANGED
@@ -90,6 +90,11 @@ if called with `type: "author-date"`.
90
90
  The author and date are differentiated so that consumers can separate them in citations -- e.g. "Jones (1996) claims",
91
91
  "(Jones 1996, 1997)".
92
92
 
93
+ === Parsing single reference
94
+
95
+ Given an Relaton bibitem object (or equivalent Relaton XML), `parse(input)` will output the hash of fields that is passed into the
96
+ Liquid templates described below for rendering: it is the hash of bibliographic fields extracted by the gem.
97
+
93
98
  == Configuration
94
99
 
95
100
  === Templates
@@ -14,6 +14,7 @@ date_formats:
14
14
  date_time: to_long_s
15
15
  ordinal_keys: []
16
16
  OrdinalRules: digits-ordinal
17
+ SpelloutRules: spellout-ordinal
17
18
  edition_ordinal: "第{{ var1 | ordinal_num: '', '' }}版"
18
19
  edition: 版
19
20
  draft: "草案%"
@@ -108,22 +108,23 @@ module Relaton
108
108
  end
109
109
 
110
110
  def render(bib, embedded: false)
111
- if bib.is_a?(String) && Nokogiri::XML(bib).errors.empty?
112
- bib = RelatonBib::XMLParser.from_xml bib
113
- end
114
- parse(bib, embedded: embedded)
111
+ bib = xml2relaton(bib)
112
+ f = bib.formattedref and
113
+ return embedded ? f.content : fmtref(f.content)
114
+ ret = render1(bib) or return nil
115
+ embedded and return ret
116
+ fmtref(ret)
115
117
  end
116
118
 
117
- def fmtref(doc)
118
- "<formattedref>#{doc}</formattedref>"
119
+ def xml2relaton(bib)
120
+ bib.is_a?(Nokogiri::XML::Element) and
121
+ bib = bib.to_xml
122
+ bib.is_a?(String) && Nokogiri::XML(bib).errors.empty? and
123
+ bib = RelatonBib::XMLParser.from_xml(bib) or bib
119
124
  end
120
125
 
121
- def parse(doc, embedded: false)
122
- f = doc.formattedref and
123
- return embedded ? f.content : fmtref(f.content)
124
- ret = parse1(doc) or return nil
125
- embedded and return ret
126
- fmtref(ret)
126
+ def fmtref(doc)
127
+ "<formattedref>#{doc}</formattedref>"
127
128
  end
128
129
 
129
130
  def renderer(type)
@@ -135,20 +136,30 @@ module Relaton
135
136
  ret
136
137
  end
137
138
 
138
- def parse1(doc)
139
+ def render1(doc)
139
140
  r = doc.relation.select { |x| x.type == "hasRepresentation" }
140
- .map { |x| @i18n.also_pub_as + parse_single_bibitem(x.bibitem) }
141
- out = [parse_single_bibitem(doc)] + r
141
+ .map { |x| @i18n.also_pub_as + render_single_bibitem(x.bibitem) }
142
+ out = [render_single_bibitem(doc)] + r
142
143
  @i18n.l10n(out.join(". ").gsub(".. ", ". "))
143
144
  end
144
145
 
145
- def parse_single_bibitem(doc)
146
+ def render_single_bibitem(doc)
147
+ data_liquid, r = parse(doc)
148
+ liquid(data_liquid, r)
149
+ end
150
+
151
+ def liquid(data_liquid, renderer)
152
+ valid_parse(@i18n.l10n(renderer.render(data_liquid)))
153
+ end
154
+
155
+ def parse(doc)
156
+ doc = xml2relaton(doc)
146
157
  r = renderer(doc.type || "misc")
147
158
  data = @parse.extract(doc)
148
159
  enhance_data(data, r.template_raw)
149
160
  data_liquid = @fieldsklass.new(renderer: self)
150
161
  .compound_fields_format(data)
151
- valid_parse(@i18n.l10n(r.render(data_liquid)))
162
+ [data_liquid, r]
152
163
  end
153
164
 
154
165
  def valid_parse(ret)
@@ -214,15 +225,16 @@ module Relaton
214
225
  end
215
226
 
216
227
  def url_exist?(url_string)
217
- res = access_url(url_string)
228
+ url = URI.parse(url_string)
229
+ url.host or return true # allow file URLs
230
+ res = access_url(url)
218
231
  res.is_a?(Net::HTTPRedirection) and return url_exist?(res["location"])
219
232
  res.code[0] != "4"
220
233
  rescue Errno::ENOENT, SocketError
221
234
  false # false if can't find the server
222
235
  end
223
236
 
224
- def access_url(url_string)
225
- url = URI.parse(url_string)
237
+ def access_url(url)
226
238
  req = Net::HTTP.new(url.host, url.port)
227
239
  req.use_ssl = (url.scheme == "https")
228
240
  path = url.path or return false
@@ -2,6 +2,7 @@ require "nokogiri"
2
2
  require "twitter_cldr"
3
3
  require_relative "parse_contributors"
4
4
  require_relative "parse_extract"
5
+ require_relative "parse_id"
5
6
 
6
7
  module Relaton
7
8
  module Render
@@ -65,6 +66,12 @@ module Relaton
65
66
  series_org: series_org(series, doc),
66
67
  series_dates: series_dates(series, doc) }
67
68
  end
69
+
70
+ private
71
+
72
+ def blank?(text)
73
+ text.nil? || text.empty?
74
+ end
68
75
  end
69
76
  end
70
77
  end
@@ -61,8 +61,7 @@ module Relaton
61
61
  end
62
62
 
63
63
  def contributor_role(contributors)
64
- return nil unless contributors.length.positive?
65
-
64
+ contributors.length.positive? or return nil
66
65
  desc = contributors[0].role.first.description.join("\n")
67
66
  type = contributors[0].role.first.type
68
67
  desc.empty? ? type : desc
@@ -80,12 +79,10 @@ module Relaton
80
79
 
81
80
  def creatornames1(doc)
82
81
  cr = []
83
- return [] if doc.nil?
84
-
82
+ doc.nil? and return []
85
83
  creatornames_roles_allowed.each do |r|
86
84
  add = pick_contributor(doc, r)
87
- next if add.nil?
88
-
85
+ add.nil? and next
89
86
  cr = add and break
90
87
  end
91
88
  cr.nil? and cr = doc.contributor
@@ -93,14 +90,12 @@ module Relaton
93
90
  end
94
91
 
95
92
  def datepick(date)
96
- return nil if date.nil?
97
-
93
+ date.nil? and return nil
98
94
  on = date.on
99
95
  from = date.from
100
96
  to = date.to
101
- return { on: on } if on
102
- return { from: from, to: to } if from
103
-
97
+ on and return { on: on }
98
+ from and return { from: from, to: to }
104
99
  nil
105
100
  end
106
101
 
@@ -165,6 +160,13 @@ module Relaton
165
160
  x.nil? and return nil
166
161
  x.map { |c| extractname(c) }
167
162
  end
163
+
164
+ def pick_contributor(doc, role)
165
+ ret = doc.contributor.select do |c|
166
+ c.role.any? { |r| r.type == role }
167
+ end
168
+ ret.empty? ? nil : ret
169
+ end
168
170
  end
169
171
  end
170
172
  end
@@ -17,7 +17,6 @@ module Relaton
17
17
 
18
18
  def medium(doc, host)
19
19
  x = doc.medium || host&.medium or return nil
20
-
21
20
  %w(content genre form carrier size scale).each_with_object({}) do |i, m|
22
21
  m[i] = x.send i
23
22
  end.compact
@@ -47,10 +46,11 @@ module Relaton
47
46
  end
48
47
 
49
48
  def place1(place)
50
- place.city.nil? && place.region.empty? && place.country.empty? and
51
- return place.name
52
- ret = [place.city] + place.region.map(&:name) +
53
- place.country.map(&:name)
49
+ c = place.city
50
+ r = place.region
51
+ n = place.country
52
+ c.nil? && r.empty? && n.empty? and return place.name
53
+ ret = [c] + r.map(&:name) + n.map(&:name)
54
54
  @i18n.l10n(ret.compact.join(", "))
55
55
  end
56
56
 
@@ -105,68 +105,6 @@ module Relaton
105
105
  "#{f}–#{t}"
106
106
  end
107
107
 
108
- def authoritative_identifier(doc)
109
- out = doc.docidentifier.each_with_object([]) do |id, ret|
110
- id.primary && !authoritative_identifier_exclude.include?(id.type) and
111
- ret << id.id
112
- end
113
- out.empty? and out = doc.docidentifier.each_with_object([]) do |id, ret|
114
- authoritative_identifier_exclude.include?(id_type_norm(id)) or
115
- ret << id.id
116
- end
117
- out
118
- end
119
-
120
- def authoritative_identifier_exclude
121
- %w(metanorma metanorma-ordinal) + other_identifier_include
122
- end
123
-
124
- def other_identifier(doc)
125
- doc.docidentifier.each_with_object([]) do |id, ret|
126
- type = id_type_norm(id)
127
- other_identifier_include.include? type or next
128
- ret << @i18n.l10n("#{type}: #{id.id}")
129
- end
130
- end
131
-
132
- def other_identifier_include
133
- %w(ISSN ISBN DOI)
134
- end
135
-
136
- def doi(doc)
137
- out = doc.docidentifier.each_with_object([]) do |id, ret|
138
- type = id.type&.sub(/^(DOI)\..*$/i, "\\1") or next
139
- type.casecmp("doi").zero? or next
140
- ret << id.id
141
- end
142
- out.empty? ? nil : out
143
- end
144
-
145
- def id_type_norm(id)
146
- id.type&.sub(/^(ISBN|ISSN)\..*$/i) { $1.upcase }
147
- end
148
-
149
- def uri(doc)
150
- uri = nil
151
- %w(citation uri src).each do |t|
152
- uri = uri_type_select(doc, t) and break
153
- end
154
- uri ||= doc.link.detect do |u|
155
- u.language == @lang && !u.type&.casecmp("doi")&.zero?
156
- end
157
- uri ||= doc.link.detect { |u| !u.type&.casecmp("doi")&.zero? }
158
- uri or return nil
159
- uri.content.to_s.strip
160
- end
161
-
162
- def uri_type_select(doc, type)
163
- uri = doc.link.detect do |u|
164
- u.type&.downcase == type && u.language == @lang
165
- end and return uri
166
- uri = doc.link.detect { |u| u.type&.downcase == type } and return uri
167
- nil
168
- end
169
-
170
108
  def access_location(doc, host)
171
109
  x = doc.accesslocation || host&.accesslocation or
172
110
  return nil
@@ -192,6 +130,13 @@ module Relaton
192
130
  end
193
131
  end
194
132
 
133
+ def localized_string_or_text(str)
134
+ case str
135
+ when RelatonBib::LocalizedString then content(str)
136
+ when String then str
137
+ end
138
+ end
139
+
195
140
  def extent(doc)
196
141
  doc.extent.each_with_object([]) do |e, acc|
197
142
  case e
@@ -209,34 +154,13 @@ module Relaton
209
154
  end
210
155
 
211
156
  def iter_ordinal(doc)
212
- return nil unless iter = doc&.status&.iteration
213
-
157
+ iter = doc&.status&.iteration or return nil
214
158
  iter
215
159
  end
216
160
 
217
161
  def status(doc)
218
162
  doc&.status&.stage&.value
219
163
  end
220
-
221
- private
222
-
223
- def blank?(text)
224
- text.nil? || text.empty?
225
- end
226
-
227
- def pick_contributor(doc, role)
228
- ret = doc.contributor.select do |c|
229
- c.role.any? { |r| r.type == role }
230
- end
231
- ret.empty? ? nil : ret
232
- end
233
-
234
- def localized_string_or_text(str)
235
- case str
236
- when RelatonBib::LocalizedString then content(str)
237
- when String then str
238
- end
239
- end
240
164
  end
241
165
  end
242
166
  end
@@ -0,0 +1,119 @@
1
+ module Relaton
2
+ module Render
3
+ class Parse
4
+ # filter applied across full list of auth_id
5
+ def auth_id_filter(ids)
6
+ id_scope_filter(ids)
7
+ end
8
+
9
+ def id_scope_filter(ids)
10
+ ids.detect(&:scope) or return ids
11
+ id_sort_by_scope(ids).each_with_object([]) do |(k, v), m|
12
+ case k
13
+ when "IEEE"
14
+ m << id_extract_by_scope(v, "trademark")
15
+ else
16
+ m << id_extract_by_scope(v, nil)
17
+ end
18
+ end.flatten
19
+ end
20
+
21
+ def id_sort_by_scope(ids)
22
+ ids.each_with_object({}) do |i, m|
23
+ m[i.type] ||= {}
24
+ m[i.type][i.scope] ||= []
25
+ m[i.type][i.scope] << i
26
+ end
27
+ end
28
+
29
+ def id_extract_by_scope(idents, key)
30
+ if idents.key?(key) && idents.keys.size > 1
31
+ idents[key]
32
+ else
33
+ idents.each_with_object([]) { |(_, v), m| m << v }.flatten
34
+ end
35
+ end
36
+
37
+ # list of successive filters on individual auth_id instances
38
+ def auth_id_allow
39
+ [->(x) { x.language == @lang && x.primary },
40
+ ->(x) { x.primary },
41
+ ->(x) { x.language == @lang },
42
+ ->(_x) { true }]
43
+ end
44
+
45
+ def authoritative_identifier(doc)
46
+ out = []
47
+ [auth_id_filter(doc.docidentifier), doc.docidentifier].each do |a|
48
+ out = authoritative_identifier_select(a)
49
+ out.empty? or break
50
+ end
51
+ out.map(&:id)
52
+ end
53
+
54
+ def authoritative_identifier_select(idents)
55
+ out = []
56
+ auth_id_allow.each do |p|
57
+ out = idents.select do |x|
58
+ p.call(x) &&
59
+ !authoritative_identifier_exclude.include?(id_type_norm(x))
60
+ end
61
+ out.empty? or break
62
+ end
63
+ out
64
+ end
65
+
66
+ def authoritative_identifier_exclude
67
+ %w(METANORMA METANORMA-ORDINAL) + other_identifier_include
68
+ end
69
+
70
+ def other_identifier(doc)
71
+ doc.docidentifier.each_with_object([]) do |id, ret|
72
+ type = id_type_norm(id)
73
+ other_identifier_include.include? type or next
74
+ ret << @i18n.l10n("#{type}: #{id.id}")
75
+ end
76
+ end
77
+
78
+ def other_identifier_include
79
+ %w(ISSN ISBN DOI)
80
+ end
81
+
82
+ def doi(doc)
83
+ out = doc.docidentifier.each_with_object([]) do |id, ret|
84
+ type = id.type&.sub(/^(DOI)\..*$/i, "\\1") or next
85
+ type.casecmp("doi").zero? or next
86
+ ret << id.id
87
+ end
88
+ out.empty? ? nil : out
89
+ end
90
+
91
+ def id_type_norm(id)
92
+ id.type or return nil
93
+ m = /^(ISBN|ISSN)\./i.match(id.type) or return id.type.upcase
94
+ m[1].upcase
95
+ end
96
+
97
+ def uri(doc)
98
+ uri = nil
99
+ %w(citation uri src).each do |t|
100
+ uri = uri_type_select(doc, t) and break
101
+ end
102
+ uri ||= doc.link.detect do |u|
103
+ u.language == @lang && !u.type&.casecmp("doi")&.zero?
104
+ end
105
+ uri ||= doc.link.detect { |u| !u.type&.casecmp("doi")&.zero? }
106
+ uri or return nil
107
+ uri.content.to_s.strip
108
+ end
109
+
110
+ def uri_type_select(doc, type)
111
+ uri = doc.link.detect do |u|
112
+ u.type&.downcase == type && u.language == @lang
113
+ end and return uri
114
+ uri = doc.link.detect { |u| u.type&.downcase == type } and return uri
115
+ nil
116
+ end
117
+ end
118
+ end
119
+ end
@@ -1,5 +1,5 @@
1
1
  module Relaton
2
2
  module Render
3
- VERSION = "0.7.0".freeze
3
+ VERSION = "0.7.1".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relaton-render
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-19 00:00:00.000000000 Z
11
+ date: 2024-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -216,6 +216,7 @@ files:
216
216
  - lib/relaton/render/parse/parse.rb
217
217
  - lib/relaton/render/parse/parse_contributors.rb
218
218
  - lib/relaton/render/parse/parse_extract.rb
219
+ - lib/relaton/render/parse/parse_id.rb
219
220
  - lib/relaton/render/template/liquid.rb
220
221
  - lib/relaton/render/template/template.rb
221
222
  - lib/relaton/render/utils/utils.rb