Class: Relaton::Render::Template::General

Inherits:
Object
  • Object
show all
Defined in:
lib/relaton/render/template/template.rb

Constant Summary collapse

VARIABLE_DELIM =

denote start and end of variable, so that we can detect empty variables in postprocessing

"%%".freeze
COMPONENT_DELIM =

denote citation components which get delimited by period conventionally

Regexp.quote("$$$").freeze
LT_DELIM =

escape < >

"\u0019".freeze
GT_DELIM =
"\u001a".freeze
NON_SPACING_DELIM =

use tab internally for non-spacing delimiter

"\t".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opt = {}) ⇒ General

Returns a new instance of General.



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

def initialize(opt = {})
  @htmlentities = HTMLEntities.new
  @templatecache = CacheManager.instance
  @liquid_env = create_liquid_environment
  parse_options(opt)
end

Instance Attribute Details

#template_rawObject (readonly)

Returns the value of attribute template_raw.



36
37
38
# File 'lib/relaton/render/template/template.rb', line 36

def template_raw
  @template_raw
end

Instance Method Details

#add_field_delim_to_template(template) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/relaton/render/template/template.rb', line 100

def add_field_delim_to_template(template)
  t = template.split(/(\{\{|\}\})/).each_slice(4).map do |a|
    unless !a[2] || punct_field?(a[2]&.strip)
      a[1] = "#{VARIABLE_DELIM}{{"
      a[3] = "}}#{VARIABLE_DELIM}"
    end
    a.join
  end.join.tr("\t", " ")
  t.gsub(/\}\}#{VARIABLE_DELIM}\|/o, "}}#{VARIABLE_DELIM}#{NON_SPACING_DELIM}")
    .gsub(/\|#{VARIABLE_DELIM}\{\{/o, "#{NON_SPACING_DELIM}#{VARIABLE_DELIM}{{")
end

#create_liquid_environmentObject



59
60
61
62
63
# File 'lib/relaton/render/template/template.rb', line 59

def create_liquid_environment
  env = ::Liquid::Environment.new
  env.register_filter(::Relaton::Render::Template::CustomFilters)
  env
end

#liquid_hash(hash) ⇒ Object

need non-breaking spaces in fields: “Updated:_nil” — we want the “Updated:” deleted, even if it’s multiple words, as in French Mise_à_jour.



212
213
214
215
216
217
218
219
220
221
222
# File 'lib/relaton/render/template/template.rb', line 212

def liquid_hash(hash)
  case hash
  when Hash
    hash.map { |k, v| [k.to_s, liquid_hash(v)] }.to_h
  when Array
    hash.map { |v| liquid_hash(v) }
  when String
    hash.empty? ? nil : hash.gsub("_", "\\_").tr(" ", "_")
  else hash
  end
end

#parse_options(opt) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/relaton/render/template/template.rb', line 45

def parse_options(opt)
  # opt = Utils::sym_keys(opt)
  opt = opt.symbolize_all_keys
  @i18n = opt[:i18n]
  @template_raw = opt[:template].dup
  @template =
    case opt[:template]
    when Hash
      opt[:template].transform_values { |x| template_process(x) }
    when Array then opt[:template].map { |x| template_process(x) }
    else { default: template_process(opt[:template]) }
    end
end

#punct_field?(name) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
85
# File 'lib/relaton/render/template/template.rb', line 79

def punct_field?(name)
  name or return false
  name = name.tr("'", '"')
  %w(labels["punct"]["open-title"] labels["punct"]["close-title"]
     labels["punct"]["open-secondary-title"]
     labels["punct"]["close-secondary-title"]).include?(name)
end

#remove_double_period(ret, delimrstripre) ⇒ Object



196
197
198
199
200
201
# File 'lib/relaton/render/template/template.rb', line 196

def remove_double_period(ret, delimrstripre)
  ret[0...-1].map do |s|
    s.sub(/#{delimrstripre}$/, "")
      .sub(%r[#{delimrstripre}(</[^>]+>)$], "\\1")
  end + [ret.last]
end

#render(hash, context) ⇒ Object

hash is what to render, which can be entire bib entry, or a subset of it like names context is information for selecting i18n, which is entire bib entry, potentially enhanced



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

def render(hash, context)
  t = template_select(hash) or return nil # TODO select on context?
  i = @i18n.select(context)
  i18nsettings = { "labels" => i.get, "lang" => i.lang,
                   "script" => i.script, "locale" => i.locale }
  ret = template_clean(t.render(liquid_hash(hash.merge(i18nsettings))))
  bib_delim = i.get.dig("punct", "biblio-field-delimiter") || ". "
  template_components(ret, bib_delim, context)
end

#strip_empty_variables(str) ⇒ Object

get rid of all empty variables, and any text around them, including component delimiters: [{}]$$$ => “”

{}

$$$ => “ $$$”



163
164
165
166
# File 'lib/relaton/render/template/template.rb', line 163

def strip_empty_variables(str)
  str.gsub(/\S*#{VARIABLE_DELIM}#{VARIABLE_DELIM}\S*/o, "")
    .gsub(/#{VARIABLE_DELIM}/o, "")
end

#template_clean(str) ⇒ Object



130
131
132
133
134
135
136
137
# File 'lib/relaton/render/template/template.rb', line 130

def template_clean(str)
  str = str.gsub(/&#x3c;/i, LT_DELIM).gsub(/&#x3e;/i, GT_DELIM)
  str = template_clean1(@htmlentities.decode(str))
  /[[:alnum:]]/.match?(str) or return nil
  str.strip.gsub(/#{LT_DELIM}/o, "&#x3c;")
    .gsub(/#{GT_DELIM}/o, "&#x3e;")
    .gsub(/&(?!#\S+?;)/, "&#x26;")
end

#template_clean1(str) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/relaton/render/template/template.rb', line 139

def template_clean1(str)
  str = strip_empty_variables(str)
  str.gsub(/([,:;]\s*)+<\/esc>([,:;])(\s|_|$)/, "\\2</esc>\\3")
    .gsub(/([,:;]\s*)+([,:;](\s|_|$))/, "\\2")
    .gsub(/([,.:;]\s*)+<\/esc>([.])(\s|_|$)/, "\\2</esc>\\3") # move outside
    .gsub(/([,.:;]\s*)+([.](\s|_|$))/, "\\2") # move outside
    .gsub(/([,:;]\s*)+<\/esc>(,)(\s|_|$)/, "\\2</esc>\\3")
    .gsub(/([,:;]\s*)+(,(\s|_|$))/, "\\2")
    .gsub(/([,:;]\s*)+(#{COMPONENT_DELIM})/o, "\\2")
    .gsub(/(:\s+)(&\s)/, "\\2")
    .gsub(/\s+([,.:;)])/, "\\1") # trim around $$$
    .sub(/^\s*[,.:;]\s*/, "") # no init $$$
    .sub(/[,:;]\s*$/, "")
    .gsub(/(?<!\\)_/, " ")
    .gsub("\\_", "_")
    .gsub(/(?<!#{COMPONENT_DELIM})#{NON_SPACING_DELIM}(?!#{COMPONENT_DELIM})/o, "") # preserve NON_SPACING_DELIM near $$$
    .gsub(/[\n\r ]+/, " ")
    .gsub(/<(\/)?esc>/i, "<\\1esc>")
end

#template_components(str, delim, context) ⇒ Object

delim = punct.biblio-field-terminator must not be i18n’ised: .</esc>. deletes first . .</esc>。does not delete first . So we do not want to pass delim in as ., and then have it i18n to 。after we are done parsing

Do not strip any delimiters from final field in string

if delim = “. ” , then: (series }$$$|) => (series1.)



177
178
179
180
181
182
183
184
185
186
# File 'lib/relaton/render/template/template.rb', line 177

def template_components(str, delim, context)
  str or return str
  delimrstrip, delimre, delimrstripre = template_components_prep(delim)
  ret = template_components_split(str, delimre)
  delim != delimrstrip and # "." in field followed by ". " in delim
    ret = remove_double_period(ret, delimrstripre)
  context[:citestyle] == "short" and
    ret[0] += "<span class='fmt-first-biblio-delim'/>"
  ret.join(delim).gsub(/#{delim}\|/, delimrstrip)
end

#template_components_prep(delim) ⇒ Object



203
204
205
206
207
# File 'lib/relaton/render/template/template.rb', line 203

def template_components_prep(delim)
  [delim.rstrip, Regexp.quote(delim),
   # if delim is esc'd, ignore the escs in the preceding span
   Regexp.quote(delim.rstrip.gsub(%r{</?esc>}, ""))]
end

#template_components_split(str, delimre) ⇒ Object



188
189
190
191
192
193
194
# File 'lib/relaton/render/template/template.rb', line 188

def template_components_split(str, delimre)
  ret = str.gsub(NON_SPACING_DELIM, "|").split(/#{COMPONENT_DELIM}/o)
    .map(&:strip).reject(&:empty?)
  ret[0...-1].map do |s|
    s.sub(/#{delimre}$/, "").sub(%r[#{delimre}(</[^>]+>)$], "\\1")
  end + [ret.last]
end

#template_process(template) ⇒ Object



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

def template_process(template)
  template.is_a?(String) or return template
  t = nil
  @templatecache.mutex.synchronize do
    unless t = @templatecache.retrieve(template)
      t = ::Liquid::Template
        .parse(add_field_delim_to_template(template), environment: @liquid_env)
      @templatecache.store(template, t)
    end
  end
  t
end

#template_select(_hash) ⇒ Object



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

def template_select(_hash)
  @template[:default]
end