Module: Metanorma::Standoc::Utils

Includes:
Core::Boilerplate
Included in:
Cleanup::SpansToBibitem, Converter, Inline, NumberInlineMacro, TermLookupCleanup, Validate::Schema
Defined in:
lib/metanorma/converter/utils.rb,
lib/metanorma/converter/date_utils.rb

Constant Summary collapse

SUBCLAUSE_XPATH =
"//clause[not(parent::sections)]" \
"[not(ancestor::boilerplate)]".freeze
SECTION_CONTAINERS =
%w(foreword introduction acknowledgements executivesummary abstract
clause references terms definitions annex appendix indexsect
executivesummary).freeze

Instance Method Summary collapse

Instance Method Details

#add_id(node) ⇒ Object



43
44
45
# File 'lib/metanorma/converter/utils.rb', line 43

def add_id(node)
  node["id"] = "_#{UUIDTools::UUID.random_create}"
end

#add_id_textObject



47
48
49
# File 'lib/metanorma/converter/utils.rb', line 47

def add_id_text
  %(id = "_#{UUIDTools::UUID.random_create}")
end

#add_noko_elem(node, name, val, attrs = {}) ⇒ Object



187
188
189
190
191
192
# File 'lib/metanorma/converter/utils.rb', line 187

def add_noko_elem(node, name, val, attrs = {})
  (val and !val.empty?) or return
  node.send name, **attr_code(attrs) do |n|
    n << val
  end
end

#adoc2xml(text, flavour, flush_caches: false, localdir: nil) ⇒ Object

Shadow metanorma-core’s adoc2xml so the standoc converter context gets externally-sourced footnotes renumbered automatically (preserving the existing direct-caller behaviour: process_boilerplate_file in cleanup, header conversion in dochistory).



150
151
152
153
# File 'lib/metanorma/converter/utils.rb', line 150

def adoc2xml(text, flavour, flush_caches: false, localdir: nil)
  ret = super
  ret.is_a?(Nokogiri::XML::Node) ? separate_numbering_footnotes(ret) : ret
end

#asciimath_key(sym) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/metanorma/converter/utils.rb', line 164

def asciimath_key(sym)
  key = sym.dup
  key.traverse do |n|
    if n.name == "stem" && a = n.at(".//asciimath")
      n.children = @c.encode(
        @c.decode(grkletters(a.text)), :basic
      )
    end
  end
  key.xpath(".//asciimath").each(&:remove)
  Nokogiri::XML(key.to_xml)
end

#attr_code(attributes) ⇒ Object



39
40
41
# File 'lib/metanorma/converter/utils.rb', line 39

def attr_code(attributes)
  Metanorma::Utils::attr_code(attributes)
end

#complete_and_compare_dates(dates) ⇒ Object

Convert dates to ISO format, complete partial dates, and return the latest



7
8
9
10
11
12
13
# File 'lib/metanorma/converter/date_utils.rb', line 7

def complete_and_compare_dates(dates)
  completed_dates = dates.map do |date_str|
    complete_iso_date(date_str)
  end.compact
  completed_dates.empty? and return nil
  completed_dates.max
end

#complete_iso_date(date_str) ⇒ Object

Complete partial ISO dates (non-inclusive cutoff: adds 1 day) YYYY -> YYYY+1-01-01, YYYY-MM -> YYYY-MM+1-01, YYYY-MM-DD -> unchanged



17
18
19
20
# File 'lib/metanorma/converter/date_utils.rb', line 17

def complete_iso_date(date_str)
  date_str.is_a?(String) or return nil
  parse_partial_date(date_str.strip)
end

#complete_year_month(date_str) ⇒ Object

Complete YYYY-MM format to first day of next month (non-inclusive cutoff)



36
37
38
39
40
41
42
# File 'lib/metanorma/converter/date_utils.rb', line 36

def complete_year_month(date_str)
  date_str =~ /^(\d{4})-(\d{1,2})$/ or return nil
  year = $1.to_i
  month = $2.to_i
  last_day = Date.new(year, month, -1).day
  Date.new(year, month, last_day) + 1
end

#complete_year_only(date_str) ⇒ Object

Complete YYYY format to next year (non-inclusive cutoff)



30
31
32
33
# File 'lib/metanorma/converter/date_utils.rb', line 30

def complete_year_only(date_str)
  /^\d{4}$/.match?(date_str) or return nil
  Date.new(date_str.to_i, 12, 31) + 1
end

#convert(node, transform = nil, opts = {}) ⇒ Object



16
17
18
19
# File 'lib/metanorma/converter/utils.rb', line 16

def convert(node, transform = nil, opts = {})
  transform ||= node.node_name
  opts.empty? ? (send transform, node) : (send transform, node, opts)
end

#csv_split(text, delim = ";", encode: true) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/metanorma/converter/utils.rb', line 51

def csv_split(text, delim = ";", encode: true)
  text ||= ""
  ret = Metanorma::Utils::csv_split(@c.decode(text), delim)
  encode and
    ret.map! { |x| @c.encode(x.strip, :basic, :hexadecimal) }
  ret
end

#dl_to_attrs(elem, dlist, name) ⇒ Object



101
102
103
# File 'lib/metanorma/converter/utils.rb', line 101

def dl_to_attrs(elem, dlist, name)
  Metanorma::Utils::dl_to_attrs(elem, dlist, name)
end

#dl_to_elems(ins, elem, dlist, name) ⇒ Object



105
106
107
# File 'lib/metanorma/converter/utils.rb', line 105

def dl_to_elems(ins, elem, dlist, name)
  Metanorma::Utils::dl_to_elems(ins, elem, dlist, name)
end

#document_ns_attributes(_doc) ⇒ Object



31
32
33
# File 'lib/metanorma/converter/utils.rb', line 31

def document_ns_attributes(_doc)
  nil
end

#grkletters(text) ⇒ Object



177
178
179
180
181
# File 'lib/metanorma/converter/utils.rb', line 177

def grkletters(text)
  text.gsub(/\b(alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|
                lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|
                psi|omega)\b/xi, "&\\1;")
end

#insert_before(xmldoc, xpath) ⇒ Object



121
122
123
124
125
126
127
# File 'lib/metanorma/converter/utils.rb', line 121

def insert_before(xmldoc, xpath)
  unless ins = xmldoc.at(xpath).children.first
    xmldoc.at(xpath) << " "
    ins = xmldoc.at(xpath).children.first
  end
  ins
end

#isodoc(lang, script, locale, i18nyaml = nil) ⇒ Object



94
95
96
97
98
99
# File 'lib/metanorma/converter/utils.rb', line 94

def isodoc(lang, script, locale, i18nyaml = nil)
  conv = presentation_xml_converter(EmptyAttr.new)
  Metanorma::Core::Isodoc.init(conv, lang: lang, script: script,
                                     locale: locale, i18nyaml: i18nyaml,
                                     localdir: @localdir)
end

#kv_parse(text, delim = ",", eql = "=") ⇒ Object



73
74
75
76
77
78
79
80
# File 'lib/metanorma/converter/utils.rb', line 73

def kv_parse(text, delim = ",", eql = "=")
  text or return {}
  c = HTMLEntities.new
  quoted_csv_split(text, delim).each_with_object({}) do |k, m|
    x = k.split(eql, 2)
    m[x[0]] = c.decode(x[1])
  end
end


113
114
115
116
117
118
119
# File 'lib/metanorma/converter/utils.rb', line 113

def link_unwrap(para)
  elems = para.elements
  if elems.size == 1 && elems[0].name == "link"
    para.at("./link").replace(elems[0]["target"].strip)
  end
  para
end

#nokoObject



35
36
37
# File 'lib/metanorma/converter/utils.rb', line 35

def noko(&)
  Metanorma::Utils::noko(@script, &)
end

#parse_complete_date(date_str) ⇒ Object

Parse complete date or return nil



45
46
47
48
49
# File 'lib/metanorma/converter/date_utils.rb', line 45

def parse_complete_date(date_str)
  Date.parse(date_str)
rescue ArgumentError
  nil
end

#parse_partial_date(date_str) ⇒ Object

Parse and complete partial date strings



23
24
25
26
27
# File 'lib/metanorma/converter/date_utils.rb', line 23

def parse_partial_date(date_str)
  complete_year_only(date_str) ||
    complete_year_month(date_str) ||
    parse_complete_date(date_str)
end

#processorObject



21
22
23
24
25
26
27
28
29
# File 'lib/metanorma/converter/utils.rb', line 21

def processor
  parent_type = self.class.name.split("::")[0...-1]
  parent_type << "Processor"
  begin
    Object.const_get(parent_type.join("::"))
  rescue NameError
    nil
  end
end

#quoted_csv_split(text, delim = ",", eql = "=") ⇒ Object

quoted strings: key=“va,lue”,



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/metanorma/converter/utils.rb', line 60

def quoted_csv_split(text, delim = ",", eql = "=")
  c = HTMLEntities.new
  text = c.decode(text).gsub(/([a-zA-Z_]+)#{eql}(["'])(.*?)\2/) do |_|
    key = Regexp.last_match(1)
    value = Regexp.last_match(3).gsub(" ", "&#x20;")
    "\"#{key}#{eql}#{value}\""
  end
  Metanorma::Utils::csv_split(text, delim).map do |x|
    c.encode(x.sub(/^(["'])(.*?)\1$/, "\\2"),
             :basic, :hexadecimal)
  end
end

#refid?(ref) ⇒ Boolean

Returns:

  • (Boolean)


183
184
185
# File 'lib/metanorma/converter/utils.rb', line 183

def refid?(ref)
  @refids.include? ref
end

#section_containersObject



142
143
144
# File 'lib/metanorma/converter/utils.rb', line 142

def section_containers
  SECTION_CONTAINERS
end

#separate_numbering_footnotes(docxml) ⇒ Object

separate numbering of externally sourced footnotes from that of current doc



157
158
159
160
161
162
# File 'lib/metanorma/converter/utils.rb', line 157

def separate_numbering_footnotes(docxml)
  docxml.xpath("//xmlns:fn").each do |f|
    f["reference"] = "_#{UUIDTools::UUID.random_create}_#{f['reference']}"
  end
  docxml
end

#term_expr(elem) ⇒ Object



109
110
111
# File 'lib/metanorma/converter/utils.rb', line 109

def term_expr(elem)
  "<expression><name>#{elem}</name></expression>"
end

#textcleanup(result) ⇒ Object



194
195
196
197
# File 'lib/metanorma/converter/utils.rb', line 194

def textcleanup(result)
  text = result.flatten.map(&:rstrip) * "\n"
  text.gsub(/(?<!\s)\s+<fn /, "<fn ")
end

#to_xml(node) ⇒ Object



86
87
88
89
# File 'lib/metanorma/converter/utils.rb', line 86

def to_xml(node)
  node.to_xml(encoding: "UTF-8", indent: 2,
              save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
end

#wrap_in_para(node, out) ⇒ Object



82
83
84
# File 'lib/metanorma/converter/utils.rb', line 82

def wrap_in_para(node, out)
  Metanorma::Utils::wrap_in_para(node, out)
end

#xml_encode(text) ⇒ Object



129
130
131
132
133
134
135
# File 'lib/metanorma/converter/utils.rb', line 129

def xml_encode(text)
  @c.encode(text, :basic, :hexadecimal)
    .gsub("&amp;gt;", ">").gsub("&amp;lt;", "<").gsub("&amp;amp;", "&")
    .gsub("&gt;", ">").gsub("&lt;", "<").gsub("&amp;", "&")
    .gsub("&quot;", '"').gsub("&#xa;", "\n").gsub("&amp;#", "&#")
    .gsub("&apos;", "'")
end