Class: Relaton::Render::General

Inherits:
Object
  • Object
show all
Defined in:
lib/relaton/render/general/uri.rb,
lib/relaton/render/general/render.rb,
lib/relaton/render/general/render_classes.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opt = {}) ⇒ General

Returns a new instance of General.



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

def initialize(opt = {})
  options = init_options(opt)
  @type = self.class.name.downcase.split("::").last
  klass_initialize(options)
  root_initalize(options)
  render_initialize(options)
  @parse ||= options["parse"]
  init_misc
end

Instance Attribute Details

#authorcitetemplateObject (readonly)

Returns the value of attribute authorcitetemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def authorcitetemplate
  @authorcitetemplate
end

#citeshorttemplateObject (readonly)

Returns the value of attribute citeshorttemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def citeshorttemplate
  @citeshorttemplate
end

#citetemplateObject (readonly)

Returns the value of attribute citetemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def citetemplate
  @citetemplate
end

#configObject (readonly)

Returns the value of attribute config.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def config
  @config
end

#dateObject (readonly)

Returns the value of attribute date.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def date
  @date
end

#dateklassObject (readonly)

Returns the value of attribute dateklass.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def dateklass
  @dateklass
end

#editionObject (readonly)

Returns the value of attribute edition.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def edition
  @edition
end

#extenttemplateObject (readonly)

Returns the value of attribute extenttemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def extenttemplate
  @extenttemplate
end

#fieldsklassObject (readonly)

Returns the value of attribute fieldsklass.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def fieldsklass
  @fieldsklass
end

#i18nObject (readonly)

Returns the value of attribute i18n.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def i18n
  @i18n
end

#journaltemplateObject (readonly)

Returns the value of attribute journaltemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def journaltemplate
  @journaltemplate
end

#langObject (readonly)

Returns the value of attribute lang.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def lang
  @lang
end

#nametemplateObject (readonly)

Returns the value of attribute nametemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def nametemplate
  @nametemplate
end

#scriptObject (readonly)

Returns the value of attribute script.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def script
  @script
end

#seriestemplateObject (readonly)

Returns the value of attribute seriestemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def seriestemplate
  @seriestemplate
end

#sizetemplateObject (readonly)

Returns the value of attribute sizetemplate.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def sizetemplate
  @sizetemplate
end

#templateObject (readonly)

Returns the value of attribute template.



18
19
20
# File 'lib/relaton/render/general/render.rb', line 18

def template
  @template
end

Class Method Details

.inherited(subclass) ⇒ Object

rubocop:disable Lint/MissingSuper



14
15
16
17
# File 'lib/relaton/render/general/render_classes.rb', line 14

def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
  type = subclass.name.downcase.sub(/relaton::render::/, "")
  General.descendants[type] = subclass
end

.subclass(type) ⇒ Object



19
20
21
22
23
24
# File 'lib/relaton/render/general/render_classes.rb', line 19

def self.subclass(type)
  # Always look up from the root General class, not from subclasses
  base = self
  base = base.superclass while base.superclass != Object && base.superclass.name =~ /Relaton::Render/
  base.instance_variable_get(:@descendants)&.[](type)
end

Instance Method Details

#access_url(url) ⇒ Object



19
20
21
22
23
24
25
26
# File 'lib/relaton/render/general/uri.rb', line 19

def access_url(url)
  path = url.path or return false
  path.empty? and path = "/"
  url_head(url, path)
rescue StandardError => e
  warn e
  false
end

#add_date_accessed(data, template) ⇒ Object

functionality removed: date needs to be given explicitly



275
276
277
278
279
280
281
282
283
# File 'lib/relaton/render/general/render.rb', line 275

def add_date_accessed(data, template)
  (/\{\{\s*date_accessed\s*\}\}/.match?(template) &&
    /\{\{\s*uri\s*\}\}/.match?(template) &&
    data[:uri_raw] && !data[:date_accessed]) or return
  if url_exist?(data[:uri_raw])
    data[:date_accessed] = { on: ::Date.today.to_s }
  else url_warn(data[:uri_raw])
  end
end

#also_pub_as(doc) ⇒ Object



200
201
202
203
204
205
206
# File 'lib/relaton/render/general/render.rb', line 200

def also_pub_as(doc)
  r = doc.relation.select { |x| x.type == "hasRepresentation" }
  r.map do |x|
    _, out = render_single_bibitem(x.bibitem)
    @i18n.select(nil).also_pub_as + out
  end
end

#citation_renderersObject



242
243
244
# File 'lib/relaton/render/general/render.rb', line 242

def citation_renderers
  { default: self }
end

#citations1(bib) ⇒ Object



259
260
261
262
263
264
265
266
# File 'lib/relaton/render/general/render.rb', line 259

def citations1(bib)
  bib.each_with_object([]).with_index do |(b, m), i|
    data_liquid = @fieldsklass.new(renderer: self)
      .compound_fields_format(@parse.extract(b))
    m << { author: data_liquid[:authorcite], date: data_liquid[:date],
           ord: i, id: b.id, data: data_liquid, type: b.type }
  end
end

#citerenderers(opt) ⇒ Object



136
137
138
139
140
141
142
143
144
# File 'lib/relaton/render/general/render.rb', line 136

def citerenderers(opt)
  s = opt["citetemplate"]["short"]
  r = opt["citetemplate"].reject { |k, _| k == "short" }
  short = @citetemplateklass
    &.new(template: template_hash_fill(s), i18n: @i18n)
  ret = @citetemplateklass
    &.new(template: r, i18n: @i18n)
  [ret, short]
end

#config_override(ret) ⇒ Object



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

def config_override(ret)
  new = {}
  @override_file and new = YAML.load_file(@override_file)
  ret.deep_merge(new)
end

#default_templateObject



146
147
148
# File 'lib/relaton/render/general/render.rb', line 146

def default_template
  "{{creatornames}}. {{title}}. {{date}}."
end

#enhance_data(_data, template) ⇒ Object

add to liquid data based on template



269
270
271
272
# File 'lib/relaton/render/general/render.rb', line 269

def enhance_data(_data, template)
  template.is_a?(String) or return
  # add_date_accessed(data, template)
end

#esc_cleanup(text) ⇒ Object

<esc> in field can get capitalised in filters



185
186
187
# File 'lib/relaton/render/general/render.rb', line 185

def esc_cleanup(text)
  text.gsub(/<esc>/i, "<esc>").gsub(/<\/esc>/i, "</esc>")
end

#extentrenderers(opt) ⇒ Object



126
127
128
129
# File 'lib/relaton/render/general/render.rb', line 126

def extentrenderers(opt)
  @extenttemplateklass
    .new(template: template_hash_fill(opt["extenttemplate"]), i18n: @i18n)
end

#fmtref(doc) ⇒ Object



172
173
174
# File 'lib/relaton/render/general/render.rb', line 172

def fmtref(doc)
  "<formattedref>#{doc}</formattedref>"
end

#i18n_default_strs(opt) ⇒ Object

avoid using these, they are document-set not citation-specific



100
101
102
103
104
105
# File 'lib/relaton/render/general/render.rb', line 100

def i18n_default_strs(opt)
  @edition = opt["edition"] || @i18n.select(nil).edition
  @date = opt["date"] || @i18n.select(nil).get["date_formats"] ||
    { "month_year" => "yMMMM", "day_month_year" => "to_long_s",
      "date_time" => "to_long_s" }
end

#i18n_initialize(opt) ⇒ Object



88
89
90
91
92
93
94
95
96
97
# File 'lib/relaton/render/general/render.rb', line 88

def i18n_initialize(opt)
  @lang = opt["language"]
  @script = opt["script"]
  @locale = opt["locale"]
  default_i18n = opt["i18n"] ||
    i18n_klass(language: @lang, script: @script, locale: @locale,
               i18nhash: opt["i18nhash"])
  @i18n = @i18nklass.new(opt.merge({ "i18n" => default_i18n }))
  i18n_default_strs(opt)
end

#i18n_klass(language: "en", script: "Latn", locale: nil, i18nhash: nil) ⇒ Object



150
151
152
153
# File 'lib/relaton/render/general/render.rb', line 150

def i18n_klass(language: "en", script: "Latn", locale: nil, i18nhash: nil)
  ::IsoDoc::RelatonRenderI18n.new(language, script, locale: locale,
                                                    i18nhash: i18nhash)
end

#init_miscObject



40
41
42
43
44
# File 'lib/relaton/render/general/render.rb', line 40

def init_misc
  @semaphore = Mutex.new
  @urlcache = {}
  @url_warned = {}
end

#init_options(opt) ⇒ Object



33
34
35
36
37
38
# File 'lib/relaton/render/general/render.rb', line 33

def init_options(opt)
  opt = opt.stringify_all_keys
  @override_file ||= opt["config"]
  @config = config_override(read_config)
  @config.merge(opt)
end

#klass_initialize(options) ⇒ Object



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

def klass_initialize(options)
  @nametemplateklass = Relaton::Render::Template::Name
  @authorcitetemplateklass = Relaton::Render::Template::AuthorCite
  @citetemplateklass = Relaton::Render::Template::Cite
  @citeshorttemplateklass = Relaton::Render::Template::Cite
  @seriestemplateklass = Relaton::Render::Template::Series
  @extenttemplateklass = Relaton::Render::Template::Extent
  @sizetemplateklass = Relaton::Render::Template::Size
  @generaltemplateklass = Relaton::Render::Template::General
  @fieldsklass = Relaton::Render::Fields
  @dateklass = Relaton::Render::Date
  @parseklass = Relaton::Render::Parse
  @i18nklass = options["i18nklass"] || Relaton::Render::I18n
  @citeklass = Relaton::Render::Citations
end

#liquid(data_liquid, renderer) ⇒ Object



214
215
216
# File 'lib/relaton/render/general/render.rb', line 214

def liquid(data_liquid, renderer)
  valid_parse(renderer.render(data_liquid, data_liquid))
end

#parse(doc) ⇒ Object



218
219
220
221
222
223
224
225
226
# File 'lib/relaton/render/general/render.rb', line 218

def parse(doc)
  doc = xml2relaton(doc)
  r = renderer(doc.type || "misc")
  data = @parse.extract(doc)
  enhance_data(data, r.template_raw)
  data_liquid = @fieldsklass.new(renderer: self)
    .compound_fields_format(data)
  [data_liquid, r]
end

#read_configObject



46
47
48
# File 'lib/relaton/render/general/render.rb', line 46

def read_config
  YAML.load_file(File.join(File.dirname(__FILE__), "config.yml"))
end

#render(bib, embedded: false, terminator: true) ⇒ Object



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

def render(bib, embedded: false, terminator: true)
  bib = xml2relaton(bib)
  f = bib.formattedref and
    return embedded ? f.content : fmtref(f.content)
  ret = render1(bib, terminator) or return nil
  embedded and return ret
  fmtref(ret)
end

#render1(doc, terminator) ⇒ Object



189
190
191
192
193
194
195
196
197
198
# File 'lib/relaton/render/general/render.rb', line 189

def render1(doc, terminator)
  obj, str = render_single_bibitem(doc)
  out = [str] + also_pub_as(doc)
  ret1 = out.join(@i18n.select(obj).get["punct"]["biblio-field-delimiter"] || ". ")
  ret = @i18n.select(obj).l10n(esc_cleanup(ret1)
    .gsub(".</esc>.", ".</esc>").gsub(".. ", ". "))
  final = @i18n.select(obj).get["punct"]["biblio-terminator"] || "."
  terminator && !ret.end_with?(final) && !ret.empty? and ret += final
  ret
end

#render_all(bib, type: "author-date") ⇒ Object

expect array of Relaton objects, in sorted order enhance_data is skipped here, and is done in batch inside Citations



235
236
237
238
239
240
# File 'lib/relaton/render/general/render.rb', line 235

def render_all(bib, type: "author-date")
  bib = sanitise_citations_input(bib) or return
  @citeklass.new(type: type, renderer: citation_renderers,
                 i18n: @i18n, lang: @lang, script: @script)
    .render(citations1(bib))
end

#render_initialize(opt) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/relaton/render/general/render.rb', line 107

def render_initialize(opt)
  case opt["template"]
  when String
    @template = @generaltemplateklass
      .new(template: opt["template"], i18n: @i18n)
  when Hash
    @render = renderers(opt)
  end
end

#render_single_bibitem(doc) ⇒ Object



208
209
210
211
212
# File 'lib/relaton/render/general/render.rb', line 208

def render_single_bibitem(doc)
  data_liquid, r = parse(doc)
  out = liquid(data_liquid, r)
  [data_liquid, out]
end

#renderer(type) ⇒ Object



176
177
178
179
180
181
182
# File 'lib/relaton/render/general/render.rb', line 176

def renderer(type)
  ret = @template || @render[type]&.template or
    raise "No renderer defined for #{type}"
  @type == "general" || @type == type or
    raise "No renderer defined for #{type}"
  ret
end

#renderers(opt) ⇒ Object



117
118
119
120
121
122
123
124
# File 'lib/relaton/render/general/render.rb', line 117

def renderers(opt)
  template_hash_fill(opt["template"]).each_with_object({}) do |(k, v), m|
    @type == "general" || @type == k or next
    m[k] = self.class.subclass(k)
      .new(template: v, parse: @parse, i18n_multi: @i18n.config,
           language: @lang, script: @script, i18nklass: @i18nklass)
  end
end

#root_initalize(opt) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/relaton/render/general/render.rb', line 72

def root_initalize(opt)
  i18n_initialize(opt)
  @parse = @parseklass.new(lang: @lang, script: @script, i18n: @i18n)
  @nametemplate = @nametemplateklass
    .new(template: opt["nametemplate"], i18n: @i18n)
  @citetemplate,  @citeshorttemplate = citerenderers(opt)
  @authorcitetemplate = @authorcitetemplateklass
    &.new(template: opt["authorcitetemplate"], i18n: @i18n)
  @seriestemplate = @seriestemplateklass
    .new(template: opt["seriestemplate"], i18n: @i18n)
  @journaltemplate = @seriestemplateklass
    .new(template: opt["journaltemplate"], i18n: @i18n)
  @extenttemplate = extentrenderers(opt)
  @sizetemplate = sizerenderers(opt)
end

#sanitise_citations_input(bib) ⇒ Object



246
247
248
249
# File 'lib/relaton/render/general/render.rb', line 246

def sanitise_citations_input(bib)
  bib.is_a?(Array) and return bib
  bib.is_a?(String) and return sanitise_citations_input_string(bib)
end

#sanitise_citations_input_string(bib) ⇒ Object



251
252
253
254
255
256
257
# File 'lib/relaton/render/general/render.rb', line 251

def sanitise_citations_input_string(bib)
  p = Nokogiri::XML(bib) or return
  (p.errors.empty? && p.root.at("./bibitem")) or return nil
  p.root.xpath("./bibitem").each_with_object([]) do |b, m|
    m << RelatonBib::XMLParser.from_xml(b.to_xml)
  end
end

#sizerenderers(opt) ⇒ Object



131
132
133
134
# File 'lib/relaton/render/general/render.rb', line 131

def sizerenderers(opt)
  @sizetemplateklass
    .new(template: template_hash_fill(opt["sizetemplate"]), i18n: @i18n)
end

#url_exist?(url_string) ⇒ Boolean

Returns:

  • (Boolean)


8
9
10
11
12
13
14
15
16
17
# File 'lib/relaton/render/general/uri.rb', line 8

def url_exist?(url_string)
  return true # temporarily disabling validation of URIs
  url = URI.parse(url_string)
  url.host or return true # allow file URLs
  res = access_url(url) or return false
  res.is_a?(Net::HTTPRedirection) and return url_exist?(res["location"])
  res.code[0] != "4"
rescue Errno::ENOENT, SocketError
  false # false if can't find the server
end

#url_exist_async?(url_string) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/relaton/render/general/uri.rb', line 52

def url_exist_async?(url_string)
  { url: url_string, status: url_exist?(url_string) }
end

#url_head(url, path) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/relaton/render/general/uri.rb', line 28

def url_head(url, path)
  ret = nil
  @semaphore.synchronize { ret = @urlcache[url.to_s] }
  ret and return ret
  ret = Net::HTTP.start(url.host, url.port,
                        read_timeout: 2, open_timeout: 2,
                        use_ssl: url.scheme == "https") do |http|
    http.request_head(path)
  end
  @semaphore.synchronize { @urlcache[url.to_s] = ret }
  ret
end

#url_warn(uri) ⇒ Object



285
286
287
288
289
# File 'lib/relaton/render/general/render.rb', line 285

def url_warn(uri)
  @url_warned[uri] and return
  warn "BIBLIOGRAPHY WARNING: cannot access #{uri}"
  @url_warned[uri] = true
end

#urls_exist_concurrent(urls) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/relaton/render/general/uri.rb', line 41

def urls_exist_concurrent(urls)
  responses = Concurrent::Array.new
  thread_pool = Concurrent::FixedThreadPool.new(5)
  urls.each do |u|
    thread_pool.post { responses << url_exist_async?(u) }
  end
  thread_pool.shutdown
  thread_pool.wait_for_termination
  responses.each_with_object({}) { |n, m| m[n[:url]] = n[:status] }
end

#valid_parse(ret) ⇒ Object



228
229
230
231
# File 'lib/relaton/render/general/render.rb', line 228

def valid_parse(ret)
  @i18n.select(nil).get["no_date"] == ret and return nil
  ret
end

#xml2relaton(bib) ⇒ Object



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

def xml2relaton(bib)
  bib.is_a?(Nokogiri::XML::Element) and
    bib = bib.to_xml(encoding: "UTF-8", indent: 0,
                     save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
  bib.is_a?(String) && Nokogiri::XML(bib).errors.empty? and
    bib = RelatonBib::XMLParser.from_xml(bib) or bib
end