Class: Metanorma::Standoc::NumberInlineMacro

Inherits:
Asciidoctor::Extensions::InlineMacroProcessor
  • Object
show all
Includes:
Utils
Defined in:
lib/metanorma/converter/macros_number.rb

Constant Summary collapse

MATHML_NS =
"http://www.w3.org/1998/Math/MathML".freeze

Constants included from Utils

Utils::SECTION_CONTAINERS, Utils::SUBCLAUSE_XPATH

Instance Method Summary collapse

Methods included from Utils

#add_id, #add_id_text, #add_noko_elem, adoc2xml, #asciimath_key, #attr_code, #complete_and_compare_dates, #complete_iso_date, #complete_year_month, #complete_year_only, #convert, #csv_split, #dl_to_attrs, #dl_to_elems, #document_ns_attributes, #grkletters, #insert_before, #isodoc, #isolated_asciidoctor_convert, #kv_parse, #link_unwrap, #noko, #parse_complete_date, #parse_partial_date, #processor, #quoted_csv_split, #refid?, #section_containers, #separate_numbering_footnotes, #term_expr, #textcleanup, #to_xml, #wrap_in_para, #xml_encode

Instance Method Details

#format(attrs, number) ⇒ Object



16
17
18
19
20
21
22
23
24
# File 'lib/metanorma/converter/macros_number.rb', line 16

def format(attrs, number)
  # a="," => "a=,"
  out = quoted_csv_split(attrs || "", ",").map do |x|
    m = /^(.+?)=(.+)?$/.match(HTMLEntities.new.decode(x)) or next
    "#{m[1]}='#{m[2]}'"
  end
  /^\+/.match?(number.strip) and out << "number_sign='plus'"
  out.join(",")
end

#number(text) ⇒ Object

Detect prefix and convert to decimal



47
48
49
50
51
52
# File 'lib/metanorma/converter/macros_number.rb', line 47

def number(text)
  n = BigDecimal(number_base(text))
  trailing_zeroes = 0
  m = /\.[1-9]*(0+)/.match(text) and trailing_zeroes += m[1].size
  n.to_s("E").sub("e", "0" * trailing_zeroes + "e") # rubocop:disable Style/StringConcatenation
end

#number_base(text) ⇒ Object

Detect prefix and convert to decimal



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/metanorma/converter/macros_number.rb', line 55

def number_base(text)
  case text.strip
  when /^0[xX]([0-9A-Fa-f.]+)$/
    parse_number_with_base(Regexp.last_match(1), 16)
  when /^0[bB]([01.]+)$/
    parse_number_with_base(Regexp.last_match(1), 2)
  when /^0[oO]([0-7.]+)$/
    parse_number_with_base(Regexp.last_match(1), 8)
  else
    text # Regular decimal - pass through
  end
end

#parse_number_with_base(num_str, base) ⇒ Object

Handle numbers with fractional parts in different bases Split on decimal point



28
29
30
31
32
33
34
35
36
37
# File 'lib/metanorma/converter/macros_number.rb', line 28

def parse_number_with_base(num_str, base)
  integer_part, fractional_part = split_number(num_str)
  int_value = integer_part.to_i(base)
  frac_value = 0.0
  fractional_part.chars.each_with_index do |digit, index|
    digit_val = digit.to_i(base)
    frac_value += digit_val * (base**-(index + 1))
  end
  (int_value + frac_value).to_s
end

#process(parent, target, attrs) ⇒ Object



68
69
70
71
72
73
74
# File 'lib/metanorma/converter/macros_number.rb', line 68

def process(parent, target, attrs)
  out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
  fmt = format(out, target)
  fmt.empty? and fmt = "default"
  fmt = %( number-format="#{fmt}")
  "<mathml-number#{fmt}>#{number(target)}</mathml-number>"
end

#split_number(num_str) ⇒ Object



39
40
41
42
43
44
# File 'lib/metanorma/converter/macros_number.rb', line 39

def split_number(num_str)
  parts = num_str.split(".")
  integer_part = parts[0] || "0"
  fractional_part = parts[1] || ""
  [integer_part, fractional_part]
end

#unquote(str) ⇒ Object



12
13
14
# File 'lib/metanorma/converter/macros_number.rb', line 12

def unquote(str)
  str.sub(/^(["'])(.+)\1$/, "\\2")
end