relaton-render 1.3.0 → 1.4.0.pre.alpha.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 +4 -4
- data/Gemfile +15 -2
- data/lib/relaton/render/iso690/element.rb +43 -0
- data/lib/relaton/render/iso690/elements/component_part.rb +50 -0
- data/lib/relaton/render/iso690/elements/creator.rb +129 -0
- data/lib/relaton/render/iso690/elements/edition.rb +47 -0
- data/lib/relaton/render/iso690/elements/identifier.rb +32 -0
- data/lib/relaton/render/iso690/elements/location.rb +27 -0
- data/lib/relaton/render/iso690/elements/medium.rb +27 -0
- data/lib/relaton/render/iso690/elements/numeration.rb +26 -0
- data/lib/relaton/render/iso690/elements/production.rb +36 -0
- data/lib/relaton/render/iso690/elements/pub_date.rb +51 -0
- data/lib/relaton/render/iso690/elements/series.rb +40 -0
- data/lib/relaton/render/iso690/elements/title.rb +30 -0
- data/lib/relaton/render/iso690/elements.rb +40 -0
- data/lib/relaton/render/iso690/fields.rb +53 -0
- data/lib/relaton/render/iso690/i18n/en.yml +13 -0
- data/lib/relaton/render/iso690/i18n/fr.yml +14 -0
- data/lib/relaton/render/iso690/i18n.rb +53 -0
- data/lib/relaton/render/iso690/identifier_kinds.rb +34 -0
- data/lib/relaton/render/iso690/index_renderer.rb +57 -0
- data/lib/relaton/render/iso690/kinds.rb +43 -0
- data/lib/relaton/render/iso690/renderer.rb +52 -0
- data/lib/relaton/render/iso690/style/locale.rb +44 -0
- data/lib/relaton/render/iso690/style/name_form.rb +21 -0
- data/lib/relaton/render/iso690/style/scheme.rb +23 -0
- data/lib/relaton/render/iso690/style/sort_rule.rb +25 -0
- data/lib/relaton/render/iso690/style/template_map.rb +28 -0
- data/lib/relaton/render/iso690/style/type_template.rb +21 -0
- data/lib/relaton/render/iso690/style.rb +76 -0
- data/lib/relaton/render/iso690/styles/author-date.yml +28 -0
- data/lib/relaton/render/iso690/template.rb +72 -0
- data/lib/relaton/render/iso690.rb +22 -0
- data/lib/relaton/render/version.rb +1 -1
- data/lib/relaton-render.rb +3 -7
- data/relaton-render.gemspec +2 -19
- metadata +35 -249
- data/lib/relaton/render/fields/date.rb +0 -48
- data/lib/relaton/render/fields/fields.rb +0 -266
- data/lib/relaton/render/general/citations.rb +0 -178
- data/lib/relaton/render/general/config.yml +0 -129
- data/lib/relaton/render/general/render.rb +0 -316
- data/lib/relaton/render/general/render_classes.rb +0 -132
- data/lib/relaton/render/general/uri.rb +0 -57
- data/lib/relaton/render/i18n/i18n.rb +0 -40
- data/lib/relaton/render/parse/parse.rb +0 -152
- data/lib/relaton/render/parse/parse_contributors.rb +0 -184
- data/lib/relaton/render/parse/parse_extract.rb +0 -200
- data/lib/relaton/render/parse/parse_id.rb +0 -128
- data/lib/relaton/render/template/liquid.rb +0 -48
- data/lib/relaton/render/template/subclasses.rb +0 -123
- data/lib/relaton/render/template/template.rb +0 -228
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
module Relaton
|
|
2
|
-
module Render
|
|
3
|
-
BIBTYPE =
|
|
4
|
-
%w(article book booklet manual proceedings presentation thesis techreport
|
|
5
|
-
standard unpublished map electronic_resource audiovisual film video
|
|
6
|
-
broadcast software graphic_work music patent inbook incollection
|
|
7
|
-
inproceedings journal website webresource dataset archival social_media
|
|
8
|
-
alert message conversation misc internal).freeze
|
|
9
|
-
|
|
10
|
-
class General
|
|
11
|
-
singleton_class.send(:attr_reader, :descendants)
|
|
12
|
-
@descendants = {}
|
|
13
|
-
|
|
14
|
-
def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
|
|
15
|
-
type = subclass.name.downcase.sub(/relaton::render::/, "")
|
|
16
|
-
General.descendants[type] = subclass
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.subclass(type)
|
|
20
|
-
# Always look up from the root General class, not from subclasses
|
|
21
|
-
base = self
|
|
22
|
-
base = base.superclass while base.superclass != Object && base.superclass.name =~ /Relaton::Render/
|
|
23
|
-
base.instance_variable_get(:@descendants)&.[](type)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class Book < General
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
class Journal < General
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
class Booklet < General
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
class Manual < General
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
class Proceedings < General
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
class Presentation < General
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
class Thesis < General
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
class Techreport < General
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
class Standard < General
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
class Unpublished < General
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
class Map < General
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
class Electronic_resource < General
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
class Software < Electronic_resource
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
class Webresource < Electronic_resource
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
class Website < Webresource
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
class Dataset < Electronic_resource
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
class Social_media < Electronic_resource
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
class Alert < Social_media
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
class Message < Social_media
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
class Audiovisual < General
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
class Film < Audiovisual
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
class Video < Audiovisual
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
class Broadcast < Audiovisual
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
class Graphic_work < General
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
class Music < General
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
class Patent < General
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
class Hosted < General
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
class Article < Hosted
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
class InBook < Hosted
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
class InCollection < Hosted
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
class InProceedings < Hosted
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
class Archival < General
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
class Conversation < General
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
class Misc < General
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
class Internal < General
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
require "concurrent"
|
|
2
|
-
require "net/http"
|
|
3
|
-
require "uri"
|
|
4
|
-
|
|
5
|
-
module Relaton
|
|
6
|
-
module Render
|
|
7
|
-
class General
|
|
8
|
-
def url_exist?(url_string)
|
|
9
|
-
return true # temporarily disabling validation of URIs
|
|
10
|
-
url = URI.parse(url_string)
|
|
11
|
-
url.host or return true # allow file URLs
|
|
12
|
-
res = access_url(url) or return false
|
|
13
|
-
res.is_a?(Net::HTTPRedirection) and return url_exist?(res["location"])
|
|
14
|
-
res.code[0] != "4"
|
|
15
|
-
rescue Errno::ENOENT, SocketError
|
|
16
|
-
false # false if can't find the server
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def access_url(url)
|
|
20
|
-
path = url.path or return false
|
|
21
|
-
path.empty? and path = "/"
|
|
22
|
-
url_head(url, path)
|
|
23
|
-
rescue StandardError => e
|
|
24
|
-
warn e
|
|
25
|
-
false
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def url_head(url, path)
|
|
29
|
-
ret = nil
|
|
30
|
-
@semaphore.synchronize { ret = @urlcache[url.to_s] }
|
|
31
|
-
ret and return ret
|
|
32
|
-
ret = Net::HTTP.start(url.host, url.port,
|
|
33
|
-
read_timeout: 2, open_timeout: 2,
|
|
34
|
-
use_ssl: url.scheme == "https") do |http|
|
|
35
|
-
http.request_head(path)
|
|
36
|
-
end
|
|
37
|
-
@semaphore.synchronize { @urlcache[url.to_s] = ret }
|
|
38
|
-
ret
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def urls_exist_concurrent(urls)
|
|
42
|
-
responses = Concurrent::Array.new
|
|
43
|
-
thread_pool = Concurrent::FixedThreadPool.new(5)
|
|
44
|
-
urls.each do |u|
|
|
45
|
-
thread_pool.post { responses << url_exist_async?(u) }
|
|
46
|
-
end
|
|
47
|
-
thread_pool.shutdown
|
|
48
|
-
thread_pool.wait_for_termination
|
|
49
|
-
responses.each_with_object({}) { |n, m| m[n[:url]] = n[:status] }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def url_exist_async?(url_string)
|
|
53
|
-
{ url: url_string, status: url_exist?(url_string) }
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
module Relaton
|
|
2
|
-
module Render
|
|
3
|
-
class I18n
|
|
4
|
-
# @i18n is a hash of IsoDoc::I18n objects, selected from according to
|
|
5
|
-
# attributes of the parsed Relaton object
|
|
6
|
-
def initialize(opt)
|
|
7
|
-
if opt["i18n_multi"]
|
|
8
|
-
@i18n = opt["i18n_multi"]
|
|
9
|
-
elsif opt["i18n"]
|
|
10
|
-
@i18n = { "" => opt["i18n"] }
|
|
11
|
-
else
|
|
12
|
-
raise error "Bad configuration, Relaton::Render::I18n"
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# obj is the biblio hash, extracted by Relaton::Render::Fields
|
|
17
|
-
# There must always be a default selection, for obj = nil,
|
|
18
|
-
# being the document language setting. If select is applied on obj,
|
|
19
|
-
# the i18n selected is appropriate to the citation specifically,
|
|
20
|
-
# and potentially to the field specificaly
|
|
21
|
-
def select(obj)
|
|
22
|
-
if obj.nil? then select_default
|
|
23
|
-
else select_obj(obj)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def select_default
|
|
28
|
-
@i18n[""]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def select_obj(_obj)
|
|
32
|
-
@i18n[""]
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def config
|
|
36
|
-
@i18n
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
require "nokogiri"
|
|
2
|
-
require "twitter_cldr"
|
|
3
|
-
require_relative "parse_contributors"
|
|
4
|
-
require_relative "parse_extract"
|
|
5
|
-
require_relative "parse_id"
|
|
6
|
-
|
|
7
|
-
module Relaton
|
|
8
|
-
module Render
|
|
9
|
-
class Parse
|
|
10
|
-
def initialize(options)
|
|
11
|
-
@lang = options[:lang] || "en"
|
|
12
|
-
@script = options[:script] || "Latn"
|
|
13
|
-
@i18n = options[:i18n]
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def extract(doc)
|
|
17
|
-
host = host(doc)
|
|
18
|
-
ret = simple_xml2hash(doc).merge(simple_or_host_xml2hash(doc, host))
|
|
19
|
-
.merge(host_xml2hash(host))
|
|
20
|
-
.merge(series_xml2hash(doc, host))
|
|
21
|
-
ret
|
|
22
|
-
#i18n(ret)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def simple_xml2hash(doc)
|
|
26
|
-
creators, role = creatornames(doc)
|
|
27
|
-
{ type: type(doc), title: title(doc), extent_raw: extent(doc),
|
|
28
|
-
size_raw: size(doc), uri_raw: uri(doc), doi: doi(doc),
|
|
29
|
-
authoritative_identifier: authoritative_identifier(doc),
|
|
30
|
-
other_identifier_raw: other_identifier(doc), biblio_tag: biblio_tag(doc),
|
|
31
|
-
status_raw: status(doc), creators: creators, role_raw: role,
|
|
32
|
-
language: language(doc), script: script(doc), locale: locale(doc) }
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def simple_or_host_xml2hash(doc, host)
|
|
36
|
-
{ edition_raw: edition(doc, host), edition_num: edition_num(doc, host),
|
|
37
|
-
medium_raw: medium(doc, host), draft_raw: draft(doc, host),
|
|
38
|
-
place_raw: place(doc, host), publisher_raw: publisher(doc, host),
|
|
39
|
-
publisher_abbrev_raw: publisher_abbrev(doc, host),
|
|
40
|
-
authorizer_raw: authorizer(doc, host),
|
|
41
|
-
distributor_raw: distributor(doc, host),
|
|
42
|
-
access_location: access_location(doc, host),
|
|
43
|
-
date: date(doc, host), date_updated: date_updated(doc, host),
|
|
44
|
-
date_accessed: date_accessed(doc, host) }
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def host_xml2hash(host)
|
|
48
|
-
creators, role = creatornames(host)
|
|
49
|
-
{ host_creators: creators, host_role_raw: role,
|
|
50
|
-
host_title: title(host) }
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def series_xml2hash(doc, host)
|
|
54
|
-
series = series(doc)
|
|
55
|
-
host and series ||= series(host)
|
|
56
|
-
series_xml2hash1(series, doc)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def series_xml2hash1(series, doc)
|
|
60
|
-
series or return {}
|
|
61
|
-
ret = { series_formatted: series_formatted(series, doc),
|
|
62
|
-
series_title: series_title(series, doc),
|
|
63
|
-
series_abbr: series_abbr(series, doc),
|
|
64
|
-
series_run: series_run(series, doc),
|
|
65
|
-
series_num: series_num(series, doc),
|
|
66
|
-
series_partnumber: series_partnumber(series, doc),
|
|
67
|
-
series_place: series_place(series, doc),
|
|
68
|
-
series_org: series_org(series, doc),
|
|
69
|
-
series_dates: series_dates(series, doc) }
|
|
70
|
-
ret.each do |k, v|
|
|
71
|
-
%i(series_num series_dates).include?(k) and next
|
|
72
|
-
ret[k] = esc(v)
|
|
73
|
-
end
|
|
74
|
-
ret
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
#KILL
|
|
78
|
-
def other_identifier_i18n(hash)
|
|
79
|
-
#ret << "#{type}: #{esc id.id}"
|
|
80
|
-
hash[:other_identifier]&.map! do |i|
|
|
81
|
-
i.include?("<esc>") ? @i18n.select(hash).l10n(i) : i
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
ALLOWED_INLINE_TAGS = %w[
|
|
86
|
-
em eref strong stem sub sup tt underline keyword ruby
|
|
87
|
-
strike smallcap xref br link hr pagebreak bookmark
|
|
88
|
-
image index index-xref concept add del span erefstack
|
|
89
|
-
date fn
|
|
90
|
-
].freeze
|
|
91
|
-
|
|
92
|
-
private
|
|
93
|
-
|
|
94
|
-
def blank?(text)
|
|
95
|
-
text.nil? || text.empty?
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def esc(text)
|
|
99
|
-
blank?(text) and return text
|
|
100
|
-
"<esc>#{text}</esc>"
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Strip any tag not in ALLOWED_INLINE_TAGS, in both literal (<tag>) and
|
|
104
|
-
# entity-encoded (<tag>) forms. Used to defend Liquid template
|
|
105
|
-
# output against embedded structural markup (most commonly <title>) in
|
|
106
|
-
# bibliographic text fields, where relaton-bib may surface either form
|
|
107
|
-
# depending on lutaml-model serialisation behaviour.
|
|
108
|
-
#
|
|
109
|
-
# Authors embed inline markup either literally (<em>foo</em>) or
|
|
110
|
-
# entity-encoded (<em>foo</em>); both are intended as
|
|
111
|
-
# markup, and downstream template rendering decodes entities anyway
|
|
112
|
-
# (see HTMLEntities.decode in template.rb), so we normalise the
|
|
113
|
-
# encoded form to literal up front and let a single Nokogiri-fragment
|
|
114
|
-
# walk handle both. Elements whose name is in the allow-list are
|
|
115
|
-
# preserved verbatim with their entire subtree, so wrappers that
|
|
116
|
-
# legitimately carry block content (notably <fn><p>…</p></fn>)
|
|
117
|
-
# round-trip intact rather than being shredded one tag at a time.
|
|
118
|
-
# Disallowed elements are unwrapped (tag dropped, children kept),
|
|
119
|
-
# recursing first so allowed wrappers nested inside disallowed
|
|
120
|
-
# wrappers still survive. Nokogiri re-escapes any genuine `<` left in
|
|
121
|
-
# text positions on serialisation, so plain prose like "5 < 10" is
|
|
122
|
-
# preserved correctly.
|
|
123
|
-
def sanitise_inline_markup(str)
|
|
124
|
-
blank?(str) and return str
|
|
125
|
-
normalised = str.gsub("<", "<").gsub(">", ">")
|
|
126
|
-
frag = Nokogiri::XML.fragment(normalised)
|
|
127
|
-
unwrap_disallowed(frag)
|
|
128
|
-
save_opts = Nokogiri::XML::Node::SaveOptions::AS_XML |
|
|
129
|
-
Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
|
130
|
-
frag.to_xml(encoding: "UTF-8", save_with: save_opts)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def unwrap_disallowed(node)
|
|
134
|
-
node.children.to_a.each do |child|
|
|
135
|
-
next unless child.element?
|
|
136
|
-
next if ALLOWED_INLINE_TAGS.include?(child.name)
|
|
137
|
-
|
|
138
|
-
unwrap_disallowed(child)
|
|
139
|
-
child.replace(child.children)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def wrap_in_esc(obj)
|
|
144
|
-
case obj
|
|
145
|
-
when String then esc(obj)
|
|
146
|
-
when Array then obj.map { |e| wrap_in_esc(e) }
|
|
147
|
-
else obj
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
module Relaton
|
|
2
|
-
module Render
|
|
3
|
-
class Parse
|
|
4
|
-
def content(node)
|
|
5
|
-
node.nil? and return node
|
|
6
|
-
node.is_a?(String) and
|
|
7
|
-
return sanitise_inline_markup(node.strip)
|
|
8
|
-
.gsub(/>\n\s*</, "><").gsub(/\n\s*/, " ")
|
|
9
|
-
node.content.is_a?(Array) and return node.content.map { |x| content(x) }
|
|
10
|
-
ret = sanitise_inline_markup(node.content.strip)
|
|
11
|
-
# safeguard against indented XML
|
|
12
|
-
ret.gsub(/>\n\s*</, "><").gsub(/\n\s*/, " ")
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def extract_orgname(org)
|
|
16
|
-
content(org.name&.first)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def extract_personname(person)
|
|
20
|
-
surname = person.name.surname || person.name.completename
|
|
21
|
-
given, middle, initials = given_and_middle_name(person)
|
|
22
|
-
{ surname: wrap_in_esc(content(surname)),
|
|
23
|
-
given: given,
|
|
24
|
-
middle: middle,
|
|
25
|
-
initials: initials }
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def given_and_middle_name(person)
|
|
29
|
-
forenames = forenames_parse(person)
|
|
30
|
-
initials = extract_initials(person)
|
|
31
|
-
forenames.empty? and initials.empty? and return [nil, nil, nil]
|
|
32
|
-
initials.empty? and initials = initials_from_forenames(forenames)
|
|
33
|
-
[forenames.first, forenames[1..-1],
|
|
34
|
-
wrap_in_esc(Array(initials))]
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def extract_initials(person)
|
|
38
|
-
initials = content(person.name.formatted_initials)&.sub(/(.)\.?$/, "\\1.")
|
|
39
|
-
&.split /(?<=\.) /
|
|
40
|
-
initials ||= person.name.forename.map(&:initial)
|
|
41
|
-
.compact.map { |x| x.sub(/(.)\.?$/, "\\1.") }
|
|
42
|
-
initials
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def forenames_parse(person)
|
|
46
|
-
person.name.forename.map do |x|
|
|
47
|
-
x.content.nil? || x.content.empty? ? esc("#{x.initial}.") : content(x)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# de S. => one initial, M.-J. => one initial
|
|
52
|
-
def initials_parse(person)
|
|
53
|
-
i = content(person.name.formatted_initials) or
|
|
54
|
-
return person.name.forename.map(&:initial)
|
|
55
|
-
.compact.map { |x| x.sub(/(.)\.?$/, "\\1.") }
|
|
56
|
-
|
|
57
|
-
i.sub(/(.)\.?$/, "\\1.")
|
|
58
|
-
.scan(/.+?\.(?=(?:$|\s|\p{Alpha}))/).map(&:strip)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def initials_from_forenames(forenames)
|
|
62
|
-
forenames.map(&:split).flatten.map { |x| "#{x[0]}." }
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def extractname(contributor)
|
|
66
|
-
org = contributor.organization
|
|
67
|
-
person = contributor.person
|
|
68
|
-
return { nonpersonal: extract_orgname(org) } if org
|
|
69
|
-
return extract_personname(person) if person
|
|
70
|
-
|
|
71
|
-
nil
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def contributor_role(contributors)
|
|
75
|
-
contributors.length.positive? or return nil
|
|
76
|
-
role = contributors[0].role.first
|
|
77
|
-
desc = Array(role&.description).map(&:content).join("\n")
|
|
78
|
-
type = role&.type
|
|
79
|
-
desc.empty? ? type : desc
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def creatornames(doc)
|
|
83
|
-
cr = creatornames1(doc)
|
|
84
|
-
cr.empty? and return [nil, nil]
|
|
85
|
-
[cr.map { |x| extractname(x) }, contributor_role(cr)]
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def creatornames_roles_allowed
|
|
89
|
-
%w(author performer adapter translator editor distributor authorizer)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def creatornames1(doc)
|
|
93
|
-
cr = []
|
|
94
|
-
doc.nil? and return []
|
|
95
|
-
creatornames_roles_allowed.each do |r|
|
|
96
|
-
add = pick_contributor(doc, r)
|
|
97
|
-
add.nil? and next
|
|
98
|
-
cr = add and break
|
|
99
|
-
end
|
|
100
|
-
cr.nil? and cr = Array(doc.contributor)
|
|
101
|
-
cr
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def datepick(date)
|
|
105
|
-
date.nil? and return nil
|
|
106
|
-
at = date.at
|
|
107
|
-
from = date.from
|
|
108
|
-
to = date.to
|
|
109
|
-
at and return { on: at.to_s }
|
|
110
|
-
from and return { from: from.to_s, to: to&.to_s }
|
|
111
|
-
nil
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def date1(date)
|
|
115
|
-
%w(published issued circulated).each do |t|
|
|
116
|
-
ret = date.detect { |x| x.type == t } and
|
|
117
|
-
return ret
|
|
118
|
-
end
|
|
119
|
-
date.reject { |x| x.type == "accessed" }.first
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# year-only
|
|
123
|
-
def date(doc, host)
|
|
124
|
-
ret = date1(Array(doc.date))
|
|
125
|
-
host and ret ||= date1(Array(host.date))
|
|
126
|
-
datepick(ret)&.transform_values do |v|
|
|
127
|
-
v&.sub(/-.*$/, "")
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def date_updated(doc, host)
|
|
132
|
-
ret = Array(doc.date).detect { |x| x.type == "updated" }
|
|
133
|
-
host and ret ||= Array(host.date).detect { |x| x.type == "updated" }
|
|
134
|
-
datepick(ret)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def date_accessed(doc, host)
|
|
138
|
-
ret = Array(doc.date).detect { |x| x.type == "accessed" }
|
|
139
|
-
host and ret ||= Array(host.date).detect { |x| x.type == "accessed" }
|
|
140
|
-
datepick(ret)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def publisher(doc, host)
|
|
144
|
-
x = pick_contributor(doc, "publisher")
|
|
145
|
-
host and x ||= pick_contributor(host, "publisher")
|
|
146
|
-
x.nil? and return nil
|
|
147
|
-
x.map { |c| extractname(c) }
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def publisher_abbrev(doc, host)
|
|
151
|
-
x = pick_contributor(doc, "publisher")
|
|
152
|
-
host and x ||= pick_contributor(host, "publisher")
|
|
153
|
-
x.nil? and return nil
|
|
154
|
-
x.map do |c|
|
|
155
|
-
content(c.organization.abbreviation) ||
|
|
156
|
-
content(c.organization.name.first)
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def distributor(doc, host)
|
|
161
|
-
x = pick_contributor(doc, "distributor")
|
|
162
|
-
host and x ||= pick_contributor(host, "distributor")
|
|
163
|
-
x.nil? and return nil
|
|
164
|
-
x.map { |c| extractname(c) }
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
def authorizer(doc, host)
|
|
168
|
-
x = pick_contributor(doc, "authorizer") ||
|
|
169
|
-
pick_contributor(doc, "publisher")
|
|
170
|
-
host and x ||= pick_contributor(host, "authorizer") ||
|
|
171
|
-
pick_contributor(host, "publisher")
|
|
172
|
-
x.nil? and return nil
|
|
173
|
-
x.map { |c| extractname(c) }
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def pick_contributor(doc, role)
|
|
177
|
-
ret = Array(doc.contributor).select do |c|
|
|
178
|
-
Array(c.role).any? { |r| r.type == role }
|
|
179
|
-
end
|
|
180
|
-
ret.empty? ? nil : ret
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
end
|