Class: Plurimath::Utility

Inherits:
Object
  • Object
show all
Defined in:
lib/plurimath/utility.rb

Constant Summary collapse

FONT_STYLES =
{
  "double-struck": Math::Function::FontStyle::DoubleStruck,
  "sans-serif": Math::Function::FontStyle::SansSerif,
  monospace: Math::Function::FontStyle::Monospace,
  fraktur: Math::Function::FontStyle::Fraktur,
  script: Math::Function::FontStyle::Script,
  normal: Math::Function::FontStyle::Normal,
  bold: Math::Function::FontStyle::Bold,
  mathfrak: Math::Function::FontStyle::Fraktur,
  mathcal: Math::Function::FontStyle::Script,
  mathbb: Math::Function::FontStyle::DoubleStruck,
  mathtt: Math::Function::FontStyle::Monospace,
  mathsf: Math::Function::FontStyle::SansSerif,
  mathrm: Math::Function::FontStyle::Normal,
  textrm: Math::Function::FontStyle::Normal,
  mathbf: Math::Function::FontStyle::Bold,
  textbf: Math::Function::FontStyle::Bold,
  bbb: Math::Function::FontStyle::DoubleStruck,
  cal: Math::Function::FontStyle::Script,
  bf: Math::Function::FontStyle::Bold,
  sf: Math::Function::FontStyle::SansSerif,
  tt: Math::Function::FontStyle::Monospace,
  fr: Math::Function::FontStyle::Fraktur,
  rm: Math::Function::FontStyle::Normal,
  cc: Math::Function::FontStyle::Script,
  ii: Math::Function::FontStyle::Italic,
  bb: Math::Function::FontStyle::Bold,
}.freeze
ALIGNMENT_LETTERS =
{
  c: "center",
  r: "right",
  l: "left",
}.freeze
UNARY_CLASSES =
%w[
  arccos
  arcsin
  arctan
  right
  sech
  sinh
  tanh
  cosh
  coth
  csch
  left
  max
  min
  sec
  sin
  deg
  det
  dim
  exp
  gcd
  glb
  lub
  tan
  cos
  cot
  csc
  ln
  lg
].freeze
MUNDER_CLASSES =
%w[
  ubrace
  obrace
  right
  max
  min
].freeze
OMML_FONTS =
{
  "sans-serif-bi": Math::Function::FontStyle::SansSerifBoldItalic,
  "sans-serif-i": Math::Function::FontStyle::SansSerifItalic,
  "sans-serif-b": Math::Function::FontStyle::BoldSansSerif,
  "double-struck": Math::Function::FontStyle::DoubleStruck,
  "sans-serif-p": Math::Function::FontStyle::SansSerif,
  "fraktur-p": Math::Function::FontStyle::Fraktur,
  "fraktur-b": Math::Function::FontStyle::BoldFraktur,
  "script-b": Math::Function::FontStyle::BoldScript,
  "script-p": Math::Function::FontStyle::Script,
  monospace: Math::Function::FontStyle::Monospace,
  bi: Math::Function::FontStyle::BoldItalic,
  p: Math::Function::FontStyle::Normal,
  i: Math::Function::FontStyle::Italic,
  b: Math::Function::FontStyle::Bold,
}.freeze
PARENTHESIS =
{
  "〈": "〉",
  "⌊": "⌋",
  "⌈": "⌉",
  "‖": "‖",
  "{": "}",
  "[": "]",
  "|": "|",
  "(": ")",
  "{": "}",
  "[": "]",
}.freeze

Class Method Summary collapse

Class Method Details

.attr_is_accent(attrs, value) ⇒ Object



366
367
368
369
370
371
372
# File 'lib/plurimath/utility.rb', line 366

def attr_is_accent(attrs, value)
  if value.last.is_a?(Math::Function::UnaryFunction)
    value.last.parameter_one = value.shift if value.length > 1
    value.last.attributes = attrs.transform_values { |v| YAML.safe_load(v) }
  end
  value
end

.attr_is_function(attrs, value) ⇒ Object



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/plurimath/utility.rb', line 374

def attr_is_function(attrs, value)
  case attrs
  when Math::Function::Menclose
    attrs.parameter_two = filter_values(value)
    attrs
  when Math::Function::Fenced
    attrs.parameter_two = value.compact
    attrs
  when Math::Function::FontStyle
    attrs.parameter_one = filter_values(value)
    attrs
  when Math::Function::Color
    color_value = filter_values(value)
    if attrs.parameter_two
      attrs.parameter_two.parameter_one = color_value
    else
      attrs.parameter_two = color_value
    end
    attrs
  end
end

.binary_function_classes(mrow, under: false) ⇒ Object



499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'lib/plurimath/utility.rb', line 499

def binary_function_classes(mrow, under: false)
  binary_class = Math::Function::BinaryFunction
  mrow.each_with_index do |object, ind|
    mrow[ind] = mathml_unary_classes([object]) if object.is_a?(String)
    object = mrow[ind]
    next unless object.is_a?(binary_class)

    if object.is_a?(Math::Function::Mod)
      next unless mrow.length >= 1

      object.parameter_one = mrow.delete_at(ind - 1) unless ind.zero?
      object.parameter_two = mrow.delete_at(ind)
    elsif Mathml::Constants::UNICODE_SYMBOLS.invert[object.class_name] && mrow.length > 1
      next if object.parameter_one || mrow.length > 2
      next object.parameter_one = mrow.delete_at(ind - 1) if under && ind <= 1

      object.parameter_one = mrow.delete_at(ind + 1)
    end
  end
end

.fenceable_classes(mrow = []) ⇒ Object



557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
# File 'lib/plurimath/utility.rb', line 557

def fenceable_classes(mrow = [])
  return false unless mrow.length > 1

  if paren_able?(PARENTHESIS, mrow)
    open_paren = mrow.shift
    close_paren = mrow.pop
    if mrow.length == 1 && mrow.first.is_a?(Math::Function::Table)
      table = mrow.first
      table.open_paren = open_paren
      table.close_paren = close_paren
    else
      mrow.replace(
        [
          Math::Function::Fenced.new(open_paren, mrow.dup, close_paren),
        ],
      )
    end
  end
end

.filter_table_data(table_data) ⇒ Object



166
167
168
169
170
171
172
173
174
175
# File 'lib/plurimath/utility.rb', line 166

def filter_table_data(table_data)
  table_data.each_with_index do |object, ind|
    if symbol_value(object, "-")
      table_data[ind] = Math::Formula.new(
        [object, table_data.delete_at(ind.next)],
      )
    end
  end
  table_data
end

.filter_values(array) ⇒ Object



235
236
237
238
239
240
241
242
243
244
# File 'lib/plurimath/utility.rb', line 235

def filter_values(array)
  return array unless array.is_a?(Array)

  array = array.flatten.compact
  if array.length > 1
    return Math::Formula.new(array)
  end

  array.first
end

.find_class_name(object) ⇒ Object



270
271
272
273
# File 'lib/plurimath/utility.rb', line 270

def find_class_name(object)
  new_object = object.value.first.parameter_one if object.is_a?(Math::Formula)
  get_class(new_object) unless new_object.nil?
end

.find_pos_chr(fonts_array, key) ⇒ Object



275
276
277
# File 'lib/plurimath/utility.rb', line 275

def find_pos_chr(fonts_array, key)
  fonts_array.find { |d| d.is_a?(Hash) && d[key] }
end

.frac_values(object) ⇒ Object



425
426
427
428
429
430
431
432
# File 'lib/plurimath/utility.rb', line 425

def frac_values(object)
  case object
  when Math::Formula
    object.value.any? { |d| symbol_value(d, ",") }
  when Array
    object.any? { |d| symbol_value(d, ",") }
  end
end

.get_class(text) ⇒ Object



189
190
191
192
193
194
# File 'lib/plurimath/utility.rb', line 189

def get_class(text)
  text = text.to_s.split("_").map(&:capitalize).join
  Object.const_get(
    "Plurimath::Math::Function::#{text}",
  )
end

.get_table_class(text) ⇒ Object



177
178
179
180
181
# File 'lib/plurimath/utility.rb', line 177

def get_table_class(text)
  Object.const_get(
    "Plurimath::Math::Function::Table::#{text.to_s.capitalize}",
  )
end

.html_entity_to_unicode(string) ⇒ Object



330
331
332
333
# File 'lib/plurimath/utility.rb', line 330

def html_entity_to_unicode(string)
  entities = HTMLEntities.new
  entities.decode(string)
end

.join_attr_value(attrs, value) ⇒ Object



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/plurimath/utility.rb', line 350

def join_attr_value(attrs, value)
  if value.any?(String)
    new_value = mathml_unary_classes(value)
    array_value = Array(new_value)
    attrs.nil? ? array_value : join_attr_value(attrs, array_value)
  elsif attrs.nil?
    value
  elsif attrs.is_a?(String) && ["solid", "none"].include?(attrs.split.first.downcase)
    table_separator(attrs.split, value)
  elsif attrs.is_a?(Hash) && (attrs.key?(:accent) || attrs.key?(:accentunder))
    attr_is_accent(attrs, value)
  elsif attrs.is_a?(Math::Core)
    attr_is_function(attrs, value)
  end
end

.left_right_objects(paren, function) ⇒ Object



463
464
465
466
467
468
469
470
# File 'lib/plurimath/utility.rb', line 463

def left_right_objects(paren, function)
  paren = if paren.to_s.match?(/\\{|\\}/)
            paren.to_s.gsub(/\\/, "")
          else
            Latex::Constants::LEFT_RIGHT_PARENTHESIS[paren.to_sym]
          end
  get_class(function).new(paren)
end

.mathml_unary_classes(text_array, omml: false) ⇒ Object



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/plurimath/utility.rb', line 302

def mathml_unary_classes(text_array, omml: false)
  return [] if text_array.empty?

  compacted = text_array.compact
  string = if compacted.count == 1
             compacted.first
           else
             compacted.join
           end
  return string unless string.is_a?(String)

  classes = Mathml::Constants::CLASSES
  unicode = string_to_html_entity(string)
  symbol  = Mathml::Constants::UNICODE_SYMBOLS[unicode.strip.to_sym]
  if classes.include?(symbol&.strip)
    get_class(symbol.strip).new
  elsif classes.any?(string&.strip)
    get_class(string.strip).new
  else
    omml ? text_classes(string) : Math::Symbol.new(unicode)
  end
end

.mrow_left_right(mrow = []) ⇒ Object



478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/plurimath/utility.rb', line 478

def mrow_left_right(mrow = [])
  object = mrow.first
  !(
    (
      (
        object.is_a?(Math::Function::TernaryFunction) && object.any_value_exist?
      ) &&
      (mrow.length <= 2)
    ) ||
    (object.is_a?(Math::Function::UnaryFunction) && mrow.length == 1)
  )
end

.multiscript(values) ⇒ Object



396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/plurimath/utility.rb', line 396

def multiscript(values)
  values.slice_before("mprescripts").map do |value|
    base_value   = value.shift
    part_val     = value.partition.with_index { |_, i| i.even? }
    first_value  = part_val[0].empty? ? nil : filter_values(part_val[0])
    second_value = part_val[1].empty? ? nil : filter_values(part_val[1])
    if base_value.to_s.include?("mprescripts")
      [first_value, second_value]
    else
      Math::Function::PowerBase.new(
        base_value,
        first_value,
        second_value,
      )
    end
  end
end

.nary_fonts(nary) ⇒ Object



259
260
261
262
263
264
265
266
267
268
# File 'lib/plurimath/utility.rb', line 259

def nary_fonts(nary)
  narypr  = nary.first.flatten.compact
  subsup  = narypr.any?("undOvr") ? "underover" : "power_base"
  unicode = narypr.any?(Hash) ? narypr.first[:chr] : ""
  get_class(subsup).new(
    Math::Symbol.new(string_to_html_entity(unicode)),
    nary[1],
    nary[2],
  )
end

.organize_options(table_data, column_align) ⇒ Object



134
135
136
137
138
139
140
# File 'lib/plurimath/utility.rb', line 134

def organize_options(table_data, column_align)
  return column_align if column_align.length <= 1

  align = [column_align&.shift]
  table_data.insert(0, *column_align)
  align
end

.organize_table(array, column_align: nil, options: nil) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/plurimath/utility.rb', line 105

def organize_table(array, column_align: nil, options: nil)
  table = []
  table_data = []
  table_row = []
  table_separators = ["&", "\\\\"].freeze
  organize_options(array, column_align) if options
  string_columns = column_align&.map(&:value)
  array.each do |data|
    if data.is_a?(Math::Symbol) && table_separators.include?(data.value)
      table_row << Math::Function::Td.new(filter_table_data(table_data).compact)
      table_data = []
      if data.value == "\\\\"
        organize_tds(table_row.flatten, string_columns.dup, options)
        table << Math::Function::Tr.new(table_row)
        table_row = []
      end
      next
    end
    table_data << data
  end
  table_row << Math::Function::Td.new(table_data.compact) if table_data
  unless table_row.nil? || table_row.empty?
    organize_tds(table_row.flatten, string_columns.dup, options)
    table << Math::Function::Tr.new(table_row)
  end
  table_separator(string_columns, table, symbol: "|") unless column_align.nil? || column_align.empty?
  table
end

.organize_tds(tr_array, column_align, options) ⇒ Object



155
156
157
158
159
160
161
162
163
164
# File 'lib/plurimath/utility.rb', line 155

def organize_tds(tr_array, column_align, options)
  return tr_array if column_align.nil? || column_align.empty?

  column_align.reject! { |string| string == "|" }
  column_align = column_align * tr_array.length if options
  tr_array.map.with_index do |td, ind|
    columnalign = ALIGNMENT_LETTERS[column_align[ind]&.to_sym]
    td.parameter_two = { columnalign: columnalign } if columnalign
  end
end

.ox_element(node, attributes: [], namespace: "") ⇒ Object



196
197
198
199
200
201
202
203
204
# File 'lib/plurimath/utility.rb', line 196

def ox_element(node, attributes: [], namespace: "")
  namespace = "#{namespace}:" unless namespace.empty?

  element = Ox::Element.new("#{namespace}#{node}")
  attributes&.each do |attr_key, attr_value|
    element[attr_key] = attr_value
  end
  element
end

.paren_able?(arr = [], mrow = []) ⇒ Boolean

Returns:

  • (Boolean)


551
552
553
554
555
# File 'lib/plurimath/utility.rb', line 551

def paren_able?(arr = [], mrow = [])
  arr.any? do |opening, closing|
    symbol_value(mrow.first, opening.to_s) && symbol_value(mrow.last, closing.to_s)
  end
end

.populate_function_classes(mrow = []) ⇒ Object



491
492
493
494
495
496
497
# File 'lib/plurimath/utility.rb', line 491

def populate_function_classes(mrow = [])
  flatten_mrow = mrow.flatten.compact
  unary_function_classes(flatten_mrow)
  binary_function_classes(flatten_mrow)
  ternary_function_classes(flatten_mrow)
  flatten_mrow
end

.pr_element(main_tag, wi_tag = false, namespace: "") ⇒ Object



227
228
229
230
231
232
233
# File 'lib/plurimath/utility.rb', line 227

def pr_element(main_tag, wi_tag = false, namespace: "")
  tag_name = "#{main_tag}Pr"
  ox_element(
    tag_name,
    namespace: namespace,
  ) << rpr_element(wi_tag: wi_tag)
end

.rpr_element(wi_tag: false) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
# File 'lib/plurimath/utility.rb', line 206

def rpr_element(wi_tag: false)
  rpr_element = ox_element("rPr", namespace: "w")
  attributes = { "w:ascii": "Cambria Math", "w:hAnsi": "Cambria Math" }
  rpr_element << ox_element(
    "rFonts",
    namespace: "w",
    attributes: attributes,
  )
  rpr_element << ox_element("i", namespace: "w") if wi_tag
  rpr_element
end

.string_to_html_entity(string) ⇒ Object



325
326
327
328
# File 'lib/plurimath/utility.rb', line 325

def string_to_html_entity(string)
  entities = HTMLEntities.new
  entities.encode(string, :hexadecimal)
end

.sub_sup_method?(sub_sup) ⇒ Boolean

Returns:

  • (Boolean)


183
184
185
186
187
# File 'lib/plurimath/utility.rb', line 183

def sub_sup_method?(sub_sup)
  if sub_sup.methods.include?(:class_name)
    Html::Constants::SUB_SUP_CLASSES.value?(sub_sup.class_name.to_sym)
  end
end

.symbol_object(value) ⇒ Object



444
445
446
447
448
449
450
451
452
453
# File 'lib/plurimath/utility.rb', line 444

def symbol_object(value)
  value = case value
          when "" then "{:"
          when "" then ":}"
          when "" then "&#x2329;"
          when "" then "&#x232a;"
          else value
          end
  Math::Symbol.new(value)
end

.symbol_value(object, value) ⇒ Object



290
291
292
# File 'lib/plurimath/utility.rb', line 290

def symbol_value(object, value)
  object.is_a?(Math::Symbol) && object.value.include?(value)
end

.table_options(table_data) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/plurimath/utility.rb', line 142

def table_options(table_data)
  rowline = ""
  table_data.map do |tr|
    if symbol_value(tr&.parameter_one&.first&.parameter_one&.first, "&#x23af;")
      rowline += "solid "
    else
      rowline += "none "
    end
  end
  options = { rowline: rowline.strip } if rowline.include?("solid")
  options || {}
end

.table_separator(separator, value, symbol: "solid") ⇒ Object



335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/plurimath/utility.rb', line 335

def table_separator(separator, value, symbol: "solid")
  sep_symbol = Math::Function::Td.new([Math::Symbol.new("|")])
  separator&.each_with_index do |sep, ind|
    next unless sep == symbol

    value.map do |val|
      val.parameter_one.insert((ind + 1), sep_symbol) if symbol == "solid"
      val.parameter_one.insert(ind, sep_symbol) if symbol == "|"
      (val.parameter_one[val.parameter_one.index(nil)] = Math::Function::Td.new([])) rescue nil
      val
    end
  end
  value
end

.table_td(object) ⇒ Object



434
435
436
437
438
439
440
441
442
# File 'lib/plurimath/utility.rb', line 434

def table_td(object)
  new_object = case object
               when Math::Function::Td
                 object
               else
                 Math::Function::Td.new([object])
               end
  Array(new_object)
end

.td_value(td_object) ⇒ Object



294
295
296
297
298
299
300
# File 'lib/plurimath/utility.rb', line 294

def td_value(td_object)
  if td_object.is_a?(String) && td_object.empty?
    return Math::Function::Text.new(nil)
  end

  td_object
end

.td_values(objects, slicer) ⇒ Object



279
280
281
282
283
284
285
286
287
288
# File 'lib/plurimath/utility.rb', line 279

def td_values(objects, slicer)
  sliced = objects.slice_when { |object, _| symbol_value(object, slicer) }
  tds = sliced.map do |slice|
    Math::Function::Td.new(
      slice.delete_if { |d| symbol_value(d, slicer) }.compact,
    )
  end
  tds << Math::Function::Td.new([]) if symbol_value(objects.last, slicer)
  tds
end

.ternary_function_classes(mrow) ⇒ Object



536
537
538
539
540
541
542
543
544
545
546
547
548
549
# File 'lib/plurimath/utility.rb', line 536

def ternary_function_classes(mrow)
  ternary_class = Math::Function::TernaryFunction
  if mrow.any?(ternary_class) && mrow.length > 1
    mrow.each_with_index do |object, ind|
      if object.is_a?(ternary_class)
        next if [Math::Function::Fenced, Math::Function::Multiscript].include?(object.class)
        next unless object.parameter_one || object.parameter_two
        next if object.parameter_three

        object.parameter_three = filter_values(mrow.delete_at(ind + 1))
      end
    end
  end
end

.text_classes(text) ⇒ Object



246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/plurimath/utility.rb', line 246

def text_classes(text)
  return nil if text&.empty?

  text = filter_values(text) unless text.is_a?(String)
  if text&.scan(/[[:digit:]]/)&.length == text&.length
    Math::Number.new(text)
  elsif text&.match?(/[a-zA-Z]/)
    Math::Function::Text.new(text)
  else
    Math::Symbol.new(text)
  end
end

.unary_function_classes(mrow) ⇒ Object



520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
# File 'lib/plurimath/utility.rb', line 520

def unary_function_classes(mrow)
  unary_class = Math::Function::UnaryFunction
  if mrow.any?(String) || mrow.any?(unary_class)
    mrow.each_with_index do |object, ind|
      mrow[ind] = mathml_unary_classes([object]) if object.is_a?(String)
      object = mrow[ind] if object.is_a?(String)
      next unless object.is_a?(unary_class)
      next if object.is_a?(Math::Function::Text)
      next if object.parameter_one || mrow[ind + 1].nil?
      next unless ind.zero?

      object.parameter_one = mrow.delete_at(ind + 1)
    end
  end
end

.unfenced_value(object) ⇒ Object



414
415
416
417
418
419
420
421
422
423
# File 'lib/plurimath/utility.rb', line 414

def unfenced_value(object)
  case object
  when Math::Function::Fenced
    filter_values(object.parameter_two)
  when Array
    filter_values(object)
  else
    object
  end
end

.update_nodes(element, nodes) ⇒ Object



218
219
220
221
222
223
224
225
# File 'lib/plurimath/utility.rb', line 218

def update_nodes(element, nodes)
  nodes&.each do |node|
    next update_nodes(element, node) if node.is_a?(Array)

    element << node unless node.nil?
  end
  element
end

.valid_class(object) ⇒ Object



472
473
474
475
476
# File 'lib/plurimath/utility.rb', line 472

def valid_class(object)
  text = object.extract_class_from_text
  (object.extractable? && Asciimath::Constants::SUB_SUP_CLASSES.include?(text)) ||
    Latex::Constants::SYMBOLS[text.to_sym] == :power_base
end

.validate_left_right(fields = []) ⇒ Object



455
456
457
458
459
460
461
# File 'lib/plurimath/utility.rb', line 455

def validate_left_right(fields = [])
  fields.each do |field|
    if field.is_a?(Math::Formula) && field.value.first.is_a?(Math::Function::Left)
      field.left_right_wrapper = true
    end
  end
end