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,
  "monospace": Math::Function::FontStyle::Monospace,
  "script-p": Math::Function::FontStyle::Script,
  "bi": Math::Function::FontStyle::BoldItalic,
  "p": Math::Function::FontStyle::Normal,
  "i": Math::Function::FontStyle::Italic,
  "b": Math::Function::FontStyle::Bold,
}.freeze

Class Method Summary collapse

Class Method Details

.attr_is_accent(attrs, value) ⇒ Object



354
355
356
357
358
359
360
# File 'lib/plurimath/utility.rb', line 354

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

.attr_is_function(attrs, value) ⇒ Object



362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/plurimath/utility.rb', line 362

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



487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/plurimath/utility.rb', line 487

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 == 0
      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

.filter_table_data(table_data) ⇒ Object



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

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



223
224
225
226
227
228
229
230
231
232
# File 'lib/plurimath/utility.rb', line 223

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



258
259
260
261
# File 'lib/plurimath/utility.rb', line 258

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



263
264
265
# File 'lib/plurimath/utility.rb', line 263

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

.frac_values(object) ⇒ Object



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

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



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

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



165
166
167
168
169
# File 'lib/plurimath/utility.rb', line 165

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

.html_entity_to_unicode(string) ⇒ Object



318
319
320
321
# File 'lib/plurimath/utility.rb', line 318

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

.join_attr_value(attrs, value) ⇒ Object



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/plurimath/utility.rb', line 338

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



451
452
453
454
455
456
457
458
# File 'lib/plurimath/utility.rb', line 451

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



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/plurimath/utility.rb', line 290

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



466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/plurimath/utility.rb', line 466

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



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/plurimath/utility.rb', line 384

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



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

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



122
123
124
125
126
127
128
# File 'lib/plurimath/utility.rb', line 122

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



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/plurimath/utility.rb', line 93

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



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

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



184
185
186
187
188
189
190
191
192
# File 'lib/plurimath/utility.rb', line 184

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

.populate_function_classes(mrow = []) ⇒ Object



479
480
481
482
483
484
485
# File 'lib/plurimath/utility.rb', line 479

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



215
216
217
218
219
220
221
# File 'lib/plurimath/utility.rb', line 215

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



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

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



313
314
315
316
# File 'lib/plurimath/utility.rb', line 313

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

.sub_sup_method?(sub_sup) ⇒ Boolean

Returns:

  • (Boolean)


171
172
173
174
175
# File 'lib/plurimath/utility.rb', line 171

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



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

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



278
279
280
# File 'lib/plurimath/utility.rb', line 278

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

.table_options(table_data) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/plurimath/utility.rb', line 130

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



323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/plurimath/utility.rb', line 323

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



422
423
424
425
426
427
428
429
430
# File 'lib/plurimath/utility.rb', line 422

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



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

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



267
268
269
270
271
272
273
274
275
276
# File 'lib/plurimath/utility.rb', line 267

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



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

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



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

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



508
509
510
511
512
513
514
515
516
517
518
519
520
# File 'lib/plurimath/utility.rb', line 508

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)
      next unless object.is_a?(unary_class)
      next if object.is_a?(Math::Function::Text)
      next if object.parameter_one || mrow[ind + 1].nil?

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

.unfenced_value(object) ⇒ Object



402
403
404
405
406
407
408
409
410
411
# File 'lib/plurimath/utility.rb', line 402

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



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

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



460
461
462
463
464
# File 'lib/plurimath/utility.rb', line 460

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



443
444
445
446
447
448
449
# File 'lib/plurimath/utility.rb', line 443

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