Class: Relaton::Render::Parse

Inherits:
Object
  • Object
show all
Defined in:
lib/relaton/render/parse/parse.rb,
lib/relaton/render/parse/parse_id.rb,
lib/relaton/render/parse/parse_extract.rb,
lib/relaton/render/parse/parse_contributors.rb

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Parse

Returns a new instance of Parse.



10
11
12
13
14
# File 'lib/relaton/render/parse/parse.rb', line 10

def initialize(options)
  @lang = options[:lang] || "en"
  @script = options[:script] || "Latn"
  @i18n = options[:i18n]
end

Instance Method Details

#access_location(doc, host) ⇒ Object



108
109
110
111
112
# File 'lib/relaton/render/parse/parse_extract.rb', line 108

def access_location(doc, host)
  x = doc.accesslocation || host&.accesslocation or
    return nil
  x.first
end

#auth_id_allowObject

list of successive filters on individual auth_id instances



38
39
40
41
42
43
# File 'lib/relaton/render/parse/parse_id.rb', line 38

def auth_id_allow
  [->(x) { x.language == @lang && x.primary },
   ->(x) { x.primary },
   ->(x) { x.language == @lang },
   ->(_x) { true }]
end

#auth_id_filter(ids) ⇒ Object

filter applied across full list of auth_id



5
6
7
# File 'lib/relaton/render/parse/parse_id.rb', line 5

def auth_id_filter(ids)
  id_scope_filter(ids)
end

#authoritative_identifier(doc) ⇒ Object



45
46
47
48
49
50
51
52
# File 'lib/relaton/render/parse/parse_id.rb', line 45

def authoritative_identifier(doc)
  out = []
  [auth_id_filter(doc.docidentifier), doc.docidentifier].each do |a|
    out = authoritative_identifier_select(a)
    out.empty? or break
  end
  out.map(&:id)
end

#authoritative_identifier_excludeObject



66
67
68
# File 'lib/relaton/render/parse/parse_id.rb', line 66

def authoritative_identifier_exclude
  %w(METANORMA METANORMA-ORDINAL) + other_identifier_include
end

#authoritative_identifier_select(idents) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/relaton/render/parse/parse_id.rb', line 54

def authoritative_identifier_select(idents)
  out = []
  auth_id_allow.each do |p|
    out = idents.select do |x|
      p.call(x) &&
        !authoritative_identifier_exclude.include?(id_type_norm(x))
    end
    out.empty? or break
  end
  out
end

#authorizer(doc, host) ⇒ Object



155
156
157
158
159
160
161
162
# File 'lib/relaton/render/parse/parse_contributors.rb', line 155

def authorizer(doc, host)
  x = pick_contributor(doc, "authorizer") ||
    pick_contributor(doc, "publisher")
  host and x ||= pick_contributor(host, "authorizer") ||
    pick_contributor(host, "publisher")
  x.nil? and return nil
  x.map { |c| extractname(c) }
end

#content(node) ⇒ Object



4
5
6
7
8
# File 'lib/relaton/render/parse/parse_contributors.rb', line 4

def content(node)
  node.nil? and return node
  node.content.is_a?(Array) and return node.content.map { |x| content(x) }
  node.content.strip
end

#contributor_role(contributors) ⇒ Object



63
64
65
66
67
68
# File 'lib/relaton/render/parse/parse_contributors.rb', line 63

def contributor_role(contributors)
  contributors.length.positive? or return nil
  desc = contributors[0].role.first.description.join("\n")
  type = contributors[0].role.first.type
  desc.empty? ? type : desc
end

#creatornames(doc) ⇒ Object



70
71
72
73
74
# File 'lib/relaton/render/parse/parse_contributors.rb', line 70

def creatornames(doc)
  cr = creatornames1(doc)
  cr.empty? and return [nil, nil]
  [cr.map { |x| extractname(x) }, contributor_role(cr)]
end

#creatornames1(doc) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/relaton/render/parse/parse_contributors.rb', line 80

def creatornames1(doc)
  cr = []
  doc.nil? and return []
  creatornames_roles_allowed.each do |r|
    add = pick_contributor(doc, r)
    add.nil? and next
    cr = add and break
  end
  cr.nil? and cr = doc.contributor
  cr
end

#creatornames_roles_allowedObject



76
77
78
# File 'lib/relaton/render/parse/parse_contributors.rb', line 76

def creatornames_roles_allowed
  %w(author performer adapter translator editor distributor authorizer)
end

#date(doc, host) ⇒ Object

year-only



111
112
113
114
115
116
117
# File 'lib/relaton/render/parse/parse_contributors.rb', line 111

def date(doc, host)
  ret = date1(doc.date)
  host and ret ||= date1(host.date)
  datepick(ret)&.transform_values do |v|
    v&.sub(/-.*$/, "")
  end
end

#date1(date) ⇒ Object



102
103
104
105
106
107
108
# File 'lib/relaton/render/parse/parse_contributors.rb', line 102

def date1(date)
  %w(published issued circulated).each do |t|
    ret = date.detect { |x| x.type == t } and
      return ret
  end
  date.reject { |x| x.type == "accessed" }.first
end

#date_accessed(doc, host) ⇒ Object



125
126
127
128
129
# File 'lib/relaton/render/parse/parse_contributors.rb', line 125

def date_accessed(doc, host)
  ret = doc.date.detect { |x| x.type == "accessed" }
  host and ret ||= host.date.detect { |x| x.type == "accessed" }
  datepick(ret)
end

#date_updated(doc, host) ⇒ Object



119
120
121
122
123
# File 'lib/relaton/render/parse/parse_contributors.rb', line 119

def date_updated(doc, host)
  ret = doc.date.detect { |x| x.type == "updated" }
  host and ret ||= host.date.detect { |x| x.type == "updated" }
  datepick(ret)
end

#datepick(date) ⇒ Object



92
93
94
95
96
97
98
99
100
# File 'lib/relaton/render/parse/parse_contributors.rb', line 92

def datepick(date)
  date.nil? and return nil
  on = date.on
  from = date.from
  to = date.to
  on and return { on: on }
  from and return { from: from, to: to }
  nil
end

#distributor(doc, host) ⇒ Object



148
149
150
151
152
153
# File 'lib/relaton/render/parse/parse_contributors.rb', line 148

def distributor(doc, host)
  x = pick_contributor(doc, "distributor")
  host and x ||= pick_contributor(host, "distributor")
  x.nil? and return nil
  x.map { |c| extractname(c) }
end

#doi(doc) ⇒ Object



82
83
84
85
86
87
88
89
# File 'lib/relaton/render/parse/parse_id.rb', line 82

def doi(doc)
  out = doc.docidentifier.each_with_object([]) do |id, ret|
    type = id.type&.sub(/^(DOI)\..*$/i, "\\1") or next
    type.casecmp("doi").zero? or next
    ret << id.id
  end
  out.empty? ? nil : out
end

#draft(doc, host) ⇒ Object



151
152
153
154
# File 'lib/relaton/render/parse/parse_extract.rb', line 151

def draft(doc, host)
  { iteration: iter_ordinal(doc) || iter_ordinal(host),
    status: status(doc) || status(host) }
end

#edition(doc, host) ⇒ Object



33
34
35
# File 'lib/relaton/render/parse/parse_extract.rb', line 33

def edition(doc, host)
  content(doc.edition || host&.edition)
end

#edition_num(doc, host) ⇒ Object



37
38
39
# File 'lib/relaton/render/parse/parse_extract.rb', line 37

def edition_num(doc, host)
  doc.edition&.number || host&.edition&.number
end

#extent(doc) ⇒ Object



140
141
142
143
144
145
146
147
148
149
# File 'lib/relaton/render/parse/parse_extract.rb', line 140

def extent(doc)
  doc.extent.each_with_object([]) do |e, acc|
    case e
    when RelatonBib::LocalityStack
      acc << extent1(e.locality)
    when RelatonBib::Locality
      acc << extent1(Array(e))
    end
  end
end

#extent1(localities) ⇒ Object



124
125
126
127
128
129
130
131
# File 'lib/relaton/render/parse/parse_extract.rb', line 124

def extent1(localities)
  localities.each_with_object({}) do |l, ret|
    ret[(l.type || "page").to_sym] = {
      from: localized_string_or_text(l.reference_from),
      to: localized_string_or_text(l.reference_to),
    }
  end
end

#extract(doc) ⇒ Object



16
17
18
19
20
21
# File 'lib/relaton/render/parse/parse.rb', line 16

def extract(doc)
  host = host(doc)
  simple_xml2hash(doc).merge(simple_or_host_xml2hash(doc, host))
    .merge(host_xml2hash(host))
    .merge(series_xml2hash(doc, host))
end

#extract_orgname(org) ⇒ Object



10
11
12
# File 'lib/relaton/render/parse/parse_contributors.rb', line 10

def extract_orgname(org)
  content(org.name&.first)
end

#extract_personname(person) ⇒ Object



14
15
16
17
18
19
20
21
# File 'lib/relaton/render/parse/parse_contributors.rb', line 14

def extract_personname(person)
  surname = person.name.surname || person.name.completename
  given, middle, initials = given_and_middle_name(person)
  { surname: content(surname),
    given: given,
    middle: middle,
    initials: initials }
end

#extractname(contributor) ⇒ Object



52
53
54
55
56
57
58
59
60
61
# File 'lib/relaton/render/parse/parse_contributors.rb', line 52

def extractname(contributor)
  org = contributor.entity if contributor.entity
    .is_a?(RelatonBib::Organization)
  person = contributor.entity if contributor.entity
    .is_a?(RelatonBib::Person)
  return { nonpersonal: extract_orgname(org) } if org
  return extract_personname(person) if person

  nil
end

#forenames_parse(person) ⇒ Object



36
37
38
39
40
# File 'lib/relaton/render/parse/parse_contributors.rb', line 36

def forenames_parse(person)
  person.name.forename.map do |x|
    x.content.empty? ? "#{x.initial}." : content(x)
  end
end

#given_and_middle_name(person) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/relaton/render/parse/parse_contributors.rb', line 23

def given_and_middle_name(person)
  forenames = person.name.forename.map do |x|
    x.content.empty? ? "#{x.initial}." : content(x)
  end
  initials = content(person.name.initials)&.sub(/(.)\.?$/, "\\1.")
    &.split /(?<=\.) /
  initials ||= person.name.forename.map(&:initial)
    .compact.map { |x| x.sub(/(.)\.?$/, "\\1.") }
  forenames.empty? and initials.empty? and return [nil, nil, nil]
  initials.empty? and initials = forenames.map { |x| "#{x[0]}." }
  [forenames.first, forenames[1..-1], Array(initials)]
end

#host(doc) ⇒ Object



4
5
6
# File 'lib/relaton/render/parse/parse_extract.rb', line 4

def host(doc)
  doc.relation.detect { |r| r.type == "includedIn" }&.bibitem
end

#host_xml2hash(host) ⇒ Object



44
45
46
47
48
# File 'lib/relaton/render/parse/parse.rb', line 44

def host_xml2hash(host)
  creators, role = creatornames(host)
  { host_creators: creators, host_role_raw: role,
    host_title: title(host) }
end

#id_extract_by_scope(idents, key) ⇒ Object



30
31
32
33
34
35
# File 'lib/relaton/render/parse/parse_id.rb', line 30

def id_extract_by_scope(idents, key)
  if idents.key?(key)
    idents[key]
  else []
  end
end

#id_scope_filter(ids) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/relaton/render/parse/parse_id.rb', line 9

def id_scope_filter(ids)
  ids.detect(&:scope) or return ids
  id_sort_by_scope(ids).each_with_object([]) do |(k, v), m|
    case k
    when "IEEE"
      f = id_extract_by_scope(v, "trademark")
      f.empty? and f = id_extract_by_scope(v, nil)
      m << f
    else m << id_extract_by_scope(v, nil)
    end
  end.flatten
end

#id_sort_by_scope(ids) ⇒ Object



22
23
24
25
26
27
28
# File 'lib/relaton/render/parse/parse_id.rb', line 22

def id_sort_by_scope(ids)
  ids.each_with_object({}) do |i, m|
    m[i.type] ||= {}
    m[i.type][i.scope] ||= []
    m[i.type][i.scope] << i
  end
end

#id_type_norm(id) ⇒ Object



91
92
93
94
95
# File 'lib/relaton/render/parse/parse_id.rb', line 91

def id_type_norm(id)
  id.type or return nil
  m = /^(ISBN|ISSN)\./i.match(id.type) or return id.type.upcase
  m[1].upcase
end

#included(type) ⇒ Object



114
115
116
# File 'lib/relaton/render/parse/parse_extract.rb', line 114

def included(type)
  ["article", "inbook", "incollection", "inproceedings"].include? type
end

#initials_parse(person) ⇒ Object

de S. => one initial, M.-J. => one initial



43
44
45
46
47
48
49
50
# File 'lib/relaton/render/parse/parse_contributors.rb', line 43

def initials_parse(person)
  i = content(person.name.initials) or
    return person.name.forename.map(&:initial)
        .compact.map { |x| x.sub(/(.)\.?$/, "\\1.") }

  i.sub(/(.)\.?$/, "\\1.")
    .scan(/.+?\.(?=(?:$|\s|\p{Alpha}))/).map(&:strip)
end

#iter_ordinal(doc) ⇒ Object



156
157
158
159
# File 'lib/relaton/render/parse/parse_extract.rb', line 156

def iter_ordinal(doc)
  iter = doc&.status&.iteration or return nil
  iter
end

#localized_string_or_text(str) ⇒ Object



133
134
135
136
137
138
# File 'lib/relaton/render/parse/parse_extract.rb', line 133

def localized_string_or_text(str)
  case str
  when RelatonBib::LocalizedString then content(str)
  when String then str
  end
end

#medium(doc, host) ⇒ Object



18
19
20
21
22
23
# File 'lib/relaton/render/parse/parse_extract.rb', line 18

def medium(doc, host)
  x = doc.medium || host&.medium or return nil
  %w(content genre form carrier size scale).each_with_object({}) do |i, m|
    m[i] = x.send i
  end.compact
end

#other_identifier(doc) ⇒ Object



70
71
72
73
74
75
76
# File 'lib/relaton/render/parse/parse_id.rb', line 70

def other_identifier(doc)
  doc.docidentifier.each_with_object([]) do |id, ret|
    type = id_type_norm(id)
    other_identifier_include.include? type or next
    ret << @i18n.l10n("#{type}: #{id.id}")
  end
end

#other_identifier_includeObject



78
79
80
# File 'lib/relaton/render/parse/parse_id.rb', line 78

def other_identifier_include
  %w(ISSN ISBN DOI)
end

#pick_contributor(doc, role) ⇒ Object



164
165
166
167
168
169
# File 'lib/relaton/render/parse/parse_contributors.rb', line 164

def pick_contributor(doc, role)
  ret = doc.contributor.select do |c|
    c.role.any? { |r| r.type == role }
  end
  ret.empty? ? nil : ret
end

#place(doc, host) ⇒ Object



41
42
43
44
45
46
# File 'lib/relaton/render/parse/parse_extract.rb', line 41

def place(doc, host)
  x = doc.place
  x.empty? && host and x = host.place
  x.empty? and return x
  x.map { |p| place1(p) }
end

#place1(place) ⇒ Object



48
49
50
51
52
53
54
55
# File 'lib/relaton/render/parse/parse_extract.rb', line 48

def place1(place)
  c = place.city
  r = place.region
  n = place.country
  c.nil? && r.empty? && n.empty? and return place.name
  ret = [c] + r.map(&:name) + n.map(&:name)
  @i18n.l10n(ret.compact.join(", "))
end

#publisher(doc, host) ⇒ Object



131
132
133
134
135
136
# File 'lib/relaton/render/parse/parse_contributors.rb', line 131

def publisher(doc, host)
  x = pick_contributor(doc, "publisher")
  host and x ||= pick_contributor(host, "publisher")
  x.nil? and return nil
  x.map { |c| extractname(c) }
end

#publisher_abbrev(doc, host) ⇒ Object



138
139
140
141
142
143
144
145
146
# File 'lib/relaton/render/parse/parse_contributors.rb', line 138

def publisher_abbrev(doc, host)
  x = pick_contributor(doc, "publisher")
  host and x ||= pick_contributor(host, "publisher")
  x.nil? and return nil
  x.map do |c|
    content(c.entity.abbreviation) ||
      content(c.entity.name.first)
  end
end

#series(doc) ⇒ Object



57
58
59
60
61
# File 'lib/relaton/render/parse/parse_extract.rb', line 57

def series(doc)
  doc.series.detect { |s| s.type == "main" } ||
    doc.series.detect { |s| s.type.nil? } ||
    doc.series.first
end

#series_abbr(series, _doc) ⇒ Object



77
78
79
# File 'lib/relaton/render/parse/parse_extract.rb', line 77

def series_abbr(series, _doc)
  content(series.abbreviation)
end

#series_dates(series, _doc) ⇒ Object



101
102
103
104
105
106
# File 'lib/relaton/render/parse/parse_extract.rb', line 101

def series_dates(series, _doc)
  f = series.from
  t = series.to
  f || t or return nil
  "#{f}#{t}"
end

#series_formatted(series, _doc) ⇒ Object



73
74
75
# File 'lib/relaton/render/parse/parse_extract.rb', line 73

def series_formatted(series, _doc)
  content(series.formattedref)
end

#series_num(series, _doc) ⇒ Object



81
82
83
# File 'lib/relaton/render/parse/parse_extract.rb', line 81

def series_num(series, _doc)
  series.number
end

#series_org(series, _doc) ⇒ Object



93
94
95
# File 'lib/relaton/render/parse/parse_extract.rb', line 93

def series_org(series, _doc)
  series.organization
end

#series_partnumber(series, _doc) ⇒ Object



85
86
87
# File 'lib/relaton/render/parse/parse_extract.rb', line 85

def series_partnumber(series, _doc)
  series.partnumber
end

#series_place(series, _doc) ⇒ Object



97
98
99
# File 'lib/relaton/render/parse/parse_extract.rb', line 97

def series_place(series, _doc)
  series.place
end

#series_run(series, _doc) ⇒ Object



89
90
91
# File 'lib/relaton/render/parse/parse_extract.rb', line 89

def series_run(series, _doc)
  series.run
end

#series_title(series, _doc) ⇒ Object



63
64
65
66
67
68
69
70
71
# File 'lib/relaton/render/parse/parse_extract.rb', line 63

def series_title(series, _doc)
  series.nil? and return nil
  series.title.respond_to?(:titles) && !series.title.titles.empty? and
    return content(series.title.titles.first.title)
  series.title.respond_to?(:title) and
    return content(series.title.title)
  series.title.respond_to?(:formattedref) and
    content(series.formattedref)
end

#series_xml2hash(doc, host) ⇒ Object



50
51
52
53
54
# File 'lib/relaton/render/parse/parse.rb', line 50

def series_xml2hash(doc, host)
  series = series(doc)
  host and series ||= series(host)
  series_xml2hash1(series, doc)
end

#series_xml2hash1(series, doc) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/relaton/render/parse/parse.rb', line 56

def series_xml2hash1(series, doc)
  return {} unless series

  { series_formatted: series_formatted(series, doc),
    series_title: series_title(series, doc),
    series_abbr: series_abbr(series, doc),
    series_run: series_run(series, doc),
    series_num: series_num(series, doc),
    series_partnumber: series_partnumber(series, doc),
    series_place: series_place(series, doc),
    series_org: series_org(series, doc),
    series_dates: series_dates(series, doc) }
end

#simple_or_host_xml2hash(doc, host) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/relaton/render/parse/parse.rb', line 32

def simple_or_host_xml2hash(doc, host)
  { edition_raw: edition(doc, host), edition_num: edition_num(doc, host),
    medium_raw: medium(doc, host), draft_raw: draft(doc, host),
    place_raw: place(doc, host), publisher_raw: publisher(doc, host),
    publisher_abbrev_raw: publisher_abbrev(doc, host),
    authorizer_raw: authorizer(doc, host),
    distributor_raw: distributor(doc, host),
    access_location: access_location(doc, host),
    date: date(doc, host), date_updated: date_updated(doc, host),
    date_accessed: date_accessed(doc, host) }
end

#simple_xml2hash(doc) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/relaton/render/parse/parse.rb', line 23

def simple_xml2hash(doc)
  creators, role = creatornames(doc)
  { type: type(doc), title: title(doc), extent_raw: extent(doc),
    size_raw: size(doc), uri_raw: uri(doc), doi: doi(doc),
    authoritative_identifier: authoritative_identifier(doc),
    other_identifier: other_identifier(doc),
    status: status(doc), creators: creators, role_raw: role }
end

#size(doc) ⇒ Object



25
26
27
28
29
30
31
# File 'lib/relaton/render/parse/parse_extract.rb', line 25

def size(doc)
  x = doc.size or return nil
  x.size.each_with_object({}) do |v, m|
    m[v.type] ||= []
    m[v.type] << v.value
  end
end

#status(doc) ⇒ Object



161
162
163
164
# File 'lib/relaton/render/parse/parse_extract.rb', line 161

def status(doc)
  v = doc&.status&.stage&.value
  @i18n.get.dig("stage", v) || v
end

#title(doc) ⇒ Object

TODO : first is naive choice



9
10
11
12
13
14
15
16
# File 'lib/relaton/render/parse/parse_extract.rb', line 9

def title(doc)
  doc.nil? || doc.title.empty? and return nil
  t = doc.title.select { |x| x.title.language&.include? @lang }
  t.empty? and t = doc.title
  t1 = t.select { |x| x.type == "main" }
  t1.empty? and t1 = t
  content(t1.first&.title)
end

#type(doc) ⇒ Object



118
119
120
121
122
# File 'lib/relaton/render/parse/parse_extract.rb', line 118

def type(doc)
  type = doc.type and return type
  doc.relation.any? { |r| r.type == "includedIn" } and return "inbook"
  "book"
end

#uri(doc) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/relaton/render/parse/parse_id.rb', line 97

def uri(doc)
  uri = nil
  %w(citation uri src).each do |t|
    uri = uri_type_select(doc, t) and break
  end
  uri ||= doc.link.detect do |u|
    u.language == @lang && !u.type&.casecmp("doi")&.zero?
  end
  uri ||= doc.link.detect { |u| !u.type&.casecmp("doi")&.zero? }
  uri or return nil
  uri.content.to_s.strip
end

#uri_type_select(doc, type) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/relaton/render/parse/parse_id.rb', line 110

def uri_type_select(doc, type)
  uri = doc.link.detect do |u|
    u.type&.downcase == type && u.language == @lang
  end and return uri
  uri = doc.link.detect { |u| u.type&.downcase == type } and return uri
  nil
end