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.



204
205
206
207
208
209
210
211
212
213
214
# File 'lib/relaton/render/template/template.rb', line 204

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



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

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
# 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).get
  ret = template_clean(t.render(liquid_hash(hash.merge("labels" => i))))
  template_components(ret,
                      i.dig("punct", "biblio-field-delimiter") || ". ")
end

#strip_empty_variables(str) ⇒ Object

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

{}

$$$ => “ $$$”



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

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

#template_clean(str) ⇒ Object



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

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



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

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) ⇒ 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.)



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

def template_components(str, delim)
  str or return str
  delimrstrip, delimre, delimrstripre = template_components_prep(delim)
  ret = str.gsub(NON_SPACING_DELIM, "|").split(/#{COMPONENT_DELIM}/o)
    .map(&:strip).reject(&:empty?)
  ret = ret[0...-1].map do |s|
    s.sub(/#{delimre}$/, "").sub(%r[#{delimre}(</[^>]+>)$], "\\1")
  end + [ret.last]
  delim != delimrstrip and # "." in field followed by ". " in delim
    ret = remove_double_period(ret, delimrstripre)
  ret.join(delim).gsub(/#{delim}\|/, delimrstrip)
end

#template_components_prep(delim) ⇒ Object



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

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_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



124
125
126
# File 'lib/relaton/render/template/template.rb', line 124

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