plurimath 0.8.16 → 0.8.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/gen_docs.yml +10 -8
  3. data/Gemfile +1 -1
  4. data/README.adoc +4 -0
  5. data/Rakefile +55 -8
  6. data/intent_supported_classes.adoc +82 -0
  7. data/lib/plurimath/asciimath/parse.rb +1 -0
  8. data/lib/plurimath/asciimath/transform.rb +12 -0
  9. data/lib/plurimath/formatter/number_formatter.rb +6 -6
  10. data/lib/plurimath/formatter/numeric_formatter.rb +5 -2
  11. data/lib/plurimath/formatter/standard.rb +2 -0
  12. data/lib/plurimath/math/core.rb +65 -6
  13. data/lib/plurimath/math/formula/mrow.rb +193 -0
  14. data/lib/plurimath/math/formula/mstyle.rb +17 -0
  15. data/lib/plurimath/math/formula.rb +317 -7
  16. data/lib/plurimath/math/function/abs.rb +5 -1
  17. data/lib/plurimath/math/function/base.rb +4 -0
  18. data/lib/plurimath/math/function/color.rb +17 -4
  19. data/lib/plurimath/math/function/fenced.rb +238 -7
  20. data/lib/plurimath/math/function/frac.rb +12 -1
  21. data/lib/plurimath/math/function/inf.rb +5 -1
  22. data/lib/plurimath/math/function/int.rb +5 -1
  23. data/lib/plurimath/math/function/intent.rb +6 -2
  24. data/lib/plurimath/math/function/lim.rb +5 -1
  25. data/lib/plurimath/math/function/linebreak.rb +2 -2
  26. data/lib/plurimath/math/function/longdiv.rb +3 -0
  27. data/lib/plurimath/math/function/menclose.rb +3 -0
  28. data/lib/plurimath/math/function/merror.rb +5 -2
  29. data/lib/plurimath/math/function/mglyph.rb +27 -0
  30. data/lib/plurimath/math/function/mlabeledtr.rb +19 -0
  31. data/lib/plurimath/math/function/mpadded.rb +28 -1
  32. data/lib/plurimath/math/function/ms.rb +80 -0
  33. data/lib/plurimath/math/function/msgroup.rb +15 -0
  34. data/lib/plurimath/math/function/msline.rb +5 -2
  35. data/lib/plurimath/math/function/multiscript.rb +14 -0
  36. data/lib/plurimath/math/function/nary.rb +13 -1
  37. data/lib/plurimath/math/function/oint.rb +5 -1
  38. data/lib/plurimath/math/function/over.rb +3 -0
  39. data/lib/plurimath/math/function/overset.rb +11 -0
  40. data/lib/plurimath/math/function/phantom.rb +3 -0
  41. data/lib/plurimath/math/function/power.rb +3 -0
  42. data/lib/plurimath/math/function/power_base.rb +3 -0
  43. data/lib/plurimath/math/function/prod.rb +5 -1
  44. data/lib/plurimath/math/function/root.rb +3 -0
  45. data/lib/plurimath/math/function/scarries.rb +3 -0
  46. data/lib/plurimath/math/function/semantics.rb +14 -0
  47. data/lib/plurimath/math/function/sqrt.rb +3 -0
  48. data/lib/plurimath/math/function/stackrel.rb +3 -0
  49. data/lib/plurimath/math/function/sum.rb +5 -1
  50. data/lib/plurimath/math/function/table/array.rb +1 -1
  51. data/lib/plurimath/math/function/table/bmatrix.rb +1 -1
  52. data/lib/plurimath/math/function/table/cases.rb +2 -2
  53. data/lib/plurimath/math/function/table/eqarray.rb +2 -2
  54. data/lib/plurimath/math/function/table/pmatrix.rb +1 -1
  55. data/lib/plurimath/math/function/table/vmatrix.rb +1 -1
  56. data/lib/plurimath/math/function/table.rb +65 -0
  57. data/lib/plurimath/math/function/td.rb +4 -1
  58. data/lib/plurimath/math/function/text.rb +22 -2
  59. data/lib/plurimath/math/function/tr.rb +13 -0
  60. data/lib/plurimath/math/function/unary_function.rb +5 -1
  61. data/lib/plurimath/math/function/underover.rb +3 -0
  62. data/lib/plurimath/math/function/underset.rb +44 -0
  63. data/lib/plurimath/math/number.rb +10 -1
  64. data/lib/plurimath/math/symbols/bigwedge.rb +4 -0
  65. data/lib/plurimath/math/symbols/cap.rb +0 -4
  66. data/lib/plurimath/math/symbols/clockoint.rb +1 -1
  67. data/lib/plurimath/math/symbols/cntclockoint.rb +1 -1
  68. data/lib/plurimath/math/symbols/coprod.rb +1 -1
  69. data/lib/plurimath/math/symbols/dd.rb +4 -0
  70. data/lib/plurimath/math/symbols/dint.rb +4 -0
  71. data/lib/plurimath/math/symbols/duni.rb +4 -0
  72. data/lib/plurimath/math/symbols/gg.rb +4 -4
  73. data/lib/plurimath/math/symbols/ii.rb +4 -0
  74. data/lib/plurimath/math/symbols/iiiint.rb +1 -1
  75. data/lib/plurimath/math/symbols/iiint.rb +4 -0
  76. data/lib/plurimath/math/symbols/iint.rb +1 -1
  77. data/lib/plurimath/math/symbols/intclockwise.rb +1 -1
  78. data/lib/plurimath/math/symbols/intercal.rb +4 -0
  79. data/lib/plurimath/math/symbols/jj.rb +4 -0
  80. data/lib/plurimath/math/symbols/ll.rb +4 -4
  81. data/lib/plurimath/math/symbols/minus.rb +1 -1
  82. data/lib/plurimath/math/symbols/oiiint.rb +1 -1
  83. data/lib/plurimath/math/symbols/oiint.rb +1 -1
  84. data/lib/plurimath/math/symbols/oint.rb +1 -1
  85. data/lib/plurimath/math/symbols/symbol.rb +12 -4
  86. data/lib/plurimath/math/symbols/upcase_dd.rb +4 -0
  87. data/lib/plurimath/math.rb +2 -0
  88. data/lib/plurimath/mathml/parser.rb +45 -86
  89. data/lib/plurimath/mathml/utility/empty_defined_methods.rb +477 -0
  90. data/lib/plurimath/mathml/utility/formula_transformation.rb +472 -0
  91. data/lib/plurimath/mathml/utility.rb +363 -0
  92. data/lib/plurimath/mathml.rb +1 -0
  93. data/lib/plurimath/unicode_math/transform.rb +2 -2
  94. data/lib/plurimath/utility/intent_encoding.rb +21 -21
  95. data/lib/plurimath/utility.rb +5 -23
  96. data/lib/plurimath/version.rb +1 -1
  97. data/lib/plurimath.rb +9 -0
  98. data/plurimath.gemspec +4 -2
  99. metadata +38 -5
  100. data/lib/plurimath/mathml/transform.rb +0 -411
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../mathml/utility"
4
+
3
5
  module Plurimath
4
6
  module Math
5
7
  class Formula < Core
8
+ include Mathml::Utility
9
+
6
10
  attr_accessor :value, :left_right_wrapper, :displaystyle, :input_string, :unitsml, :unitsml_xml
7
11
 
8
12
  MATH_ZONE_TYPES = %i[
@@ -168,7 +172,7 @@ module Plurimath
168
172
 
169
173
  def to_display(type = nil, formatter: nil)
170
174
  options = { formatter: formatter }
171
- return type_error! unless MATH_ZONE_TYPES.include?(type.downcase.to_sym)
175
+ return type_error!(type) unless MATH_ZONE_TYPES.include?(type.downcase.to_sym)
172
176
 
173
177
  math_zone = case type
174
178
  when :asciimath
@@ -246,7 +250,7 @@ module Plurimath
246
250
  end
247
251
 
248
252
  def update(object)
249
- self.value = Array(object)
253
+ @value = Array(object).flatten.compact
250
254
  end
251
255
 
252
256
  def cloned_objects
@@ -292,13 +296,313 @@ module Plurimath
292
296
  update(Array(value) + values)
293
297
  end
294
298
 
295
-
296
299
  def mini_sized?
297
300
  true if value&.first&.mini_sized?
298
301
  end
299
302
 
303
+ def intent_names
304
+ {
305
+ partial_derivative: ":partial-derivative",
306
+ derivative: ":derivative",
307
+ }
308
+ end
309
+
310
+ def element_order=(value)
311
+ @value = validated_order(value)
312
+ end
313
+
314
+ # Attributes start
315
+ def mathcolor=(value)
316
+ return if value.nil? || value.empty?
317
+
318
+ update(
319
+ [
320
+ Math::Function::Color.new(
321
+ Math::Function::Text.new(value),
322
+ filter_values(@value, array_to_instance: true),
323
+ )
324
+ ]
325
+ )
326
+ end
327
+
328
+ def mathvariant=(value)
329
+ return if value.nil? || value.empty?
330
+ return unless Plurimath::Utility::FONT_STYLES.key?(value.to_sym)
331
+
332
+ update(
333
+ [
334
+ Plurimath::Utility::FONT_STYLES[value.to_sym].new(
335
+ filter_values(@value, array_to_instance: true),
336
+ value,
337
+ )
338
+ ]
339
+ )
340
+ end
341
+
342
+ def intent=(value)
343
+ return unless value
344
+
345
+ self.content = nil
346
+ update(
347
+ [
348
+ Function::Intent.new(
349
+ filter_values(@value, array_to_instance: true),
350
+ Function::Text.new(value),
351
+ )
352
+ ]
353
+ )
354
+ end
355
+ # Attributes end
356
+
357
+ def ms_value=(value)
358
+ return if value.nil? || value.empty?
359
+
360
+ update(
361
+ replace_order_with_value(
362
+ @value,
363
+ Array(validate_symbols(value)),
364
+ "ms"
365
+ )
366
+ )
367
+ end
368
+
369
+ def mi_value=(value)
370
+ return if value.nil? || value.empty?
371
+
372
+ value = update_temp_mathml_values(value) if value.any? do |val|
373
+ val.is_a?(Math::Core) && val.temp_mathml_order.any?
374
+ end
375
+ update(
376
+ replace_order_with_value(
377
+ @value,
378
+ Array(validate_symbols(value)).flatten,
379
+ "mi"
380
+ )
381
+ )
382
+ end
383
+
384
+ def mn_value=(value)
385
+ return if value.nil? || value.empty?
386
+
387
+ update(
388
+ replace_order_with_value(
389
+ @value,
390
+ Array(validate_symbols(value)),
391
+ "mn"
392
+ )
393
+ )
394
+ end
395
+
396
+ def mtext_value=(value)
397
+ return if value.nil? || value.empty?
398
+
399
+ update(
400
+ replace_order_with_value(
401
+ @value,
402
+ Array(validate_symbols(value)),
403
+ "mtext"
404
+ )
405
+ )
406
+ end
407
+
408
+ def mo_value=(value)
409
+ return if value.nil? || value.empty?
410
+
411
+ value = update_temp_mathml_values(value)
412
+ update(
413
+ replace_order_with_value(
414
+ @value,
415
+ Array(value),
416
+ "mo"
417
+ )
418
+ )
419
+ end
420
+
421
+ def mstyle_value=(value)
422
+ return if value.empty?
423
+
424
+ update(
425
+ filter_values(
426
+ replace_order_with_value(
427
+ @value,
428
+ Array(filter_values(value, array_to_instance: true)),
429
+ "mstyle"
430
+ )
431
+ )
432
+ )
433
+ end
434
+
435
+ def mrow_value=(value)
436
+ return if value.nil? || value.empty?
437
+
438
+ replacing_order = value.length > 1 && value.any?(String)
439
+ update(
440
+ replace_order_with_value(
441
+ @value,
442
+ filter_values(
443
+ value,
444
+ array_to_instance: true,
445
+ replacing_order: replacing_order
446
+ ),
447
+ "mrow"
448
+ )
449
+ )
450
+ end
451
+
452
+ def munderover_value=(value)
453
+ update_temp_order(value, "munderover")
454
+ end
455
+
456
+ def msub_value=(value)
457
+ update_temp_order(value, "msub")
458
+ end
459
+
460
+ def msup_value=(value)
461
+ update_temp_order(value, "msup")
462
+ end
463
+
464
+ def mover_value=(value)
465
+ update_temp_order(value, "mover")
466
+ end
467
+
468
+ def munder_value=(value)
469
+ update_temp_order(value, "munder")
470
+ end
471
+
472
+ def msubsup_value=(value)
473
+ update_temp_order(value, "msubsup")
474
+ end
475
+
476
+ def mfrac_value=(value)
477
+ update_temp_order(value, "mfrac")
478
+ end
479
+
480
+ def msqrt_value=(value)
481
+ update_temp_order(value, "msqrt")
482
+ end
483
+
484
+ def mfenced_value=(value)
485
+ update_temp_order(value, "mfenced")
486
+ end
487
+
488
+ def mroot_value=(value)
489
+ update_temp_order(value, "mroot")
490
+ end
491
+
492
+ def msgroup_value=(value)
493
+ update_temp_order(value, "msgroup")
494
+ end
495
+
496
+ def mscarries_value=(value)
497
+ update_temp_order(value, "mscarries")
498
+ end
499
+
500
+ def msline_value=(value)
501
+ update_temp_order(value, "msline")
502
+ end
503
+
504
+ def msrow_value=(value)
505
+ update_temp_order(value, "msrow")
506
+ end
507
+
508
+ def semantics_value=(value)
509
+ update_temp_order(value, "semantics")
510
+ end
511
+
512
+ def mstack_value=(value)
513
+ update_temp_order(value, "mstack")
514
+ end
515
+
516
+ def merror_value=(value)
517
+ return if value.nil? || value.empty?
518
+
519
+ update(
520
+ replace_order_with_value(
521
+ @value,
522
+ filter_values(update_temp_mathml_values(value)),
523
+ "merror"
524
+ )
525
+ )
526
+ end
527
+
528
+ def mlongdiv_value=(value)
529
+ update_temp_order(value, "mlongdiv")
530
+ end
531
+
532
+ def none_value=(_)
533
+ @value&.delete("none")
534
+ end
535
+
536
+ def maligngroup_value=(value)
537
+ @value&.delete("maligngroup")
538
+ end
539
+
540
+ def menclose_value=(value)
541
+ update_temp_order(value, "menclose")
542
+ end
543
+
544
+ def mspace_value=(value)
545
+ return if value.nil? || value.empty?
546
+
547
+ if value.first.linebreak
548
+ linebreak = Math::Function::Linebreak.new(
549
+ nil,
550
+ { linebreak: value.first.linebreak }
551
+ )
552
+ update(
553
+ replace_order_with_value(
554
+ @value,
555
+ [linebreak],
556
+ "mspace"
557
+ )
558
+ )
559
+ else
560
+ @value&.delete("mspace")
561
+ end
562
+ end
563
+
564
+ def malignmark_value=(value)
565
+ @value&.delete("malignmark")
566
+ end
567
+
568
+ def mpadded_value=(value)
569
+ update_temp_order(value, "mpadded")
570
+ end
571
+
572
+ def mfraction_value=(value)
573
+ update_temp_order(value, "mfraction")
574
+ end
575
+
576
+ def mmultiscripts_value=(value)
577
+ update_temp_order(value, "mmultiscripts")
578
+ end
579
+
580
+ def mphantom_value=(value)
581
+ update_temp_order(value, "mphantom")
582
+ end
583
+
584
+ def mglyph_value=(value)
585
+ update_temp_order(value, "mglyph")
586
+ end
587
+
300
588
  protected
301
589
 
590
+ def update_temp_order(value, order_name)
591
+ return if value.nil? || value.empty?
592
+
593
+ update(
594
+ replace_order_with_value(
595
+ Array(@value),
596
+ Array(update_temp_mathml_values(value)),
597
+ order_name
598
+ )
599
+ )
600
+ end
601
+
602
+ def remove_order(order)
603
+ value.delete_if { |val| val.is_a?(String) && val == order }
604
+ end
605
+
302
606
  def boolean_display_style(display_style = displaystyle)
303
607
  YAML.safe_load(display_style.to_s)
304
608
  end
@@ -489,7 +793,7 @@ module Plurimath
489
793
  prime_str = encode(nodes.last.nodes.first) if valid_prime?(nodes.last)
490
794
  second_arg.insert(-1, prime_str) unless second_arg.match?(/[0-9]$/)
491
795
  end
492
- ":partial-derivative(#{first_arg},$f,#{second_arg})"
796
+ "#{intent_names[:partial_derivative]}(#{first_arg},$f,#{second_arg})"
493
797
  end
494
798
 
495
799
  def f_arg(tag_nodes, index)
@@ -554,14 +858,14 @@ module Plurimath
554
858
  mrow_nodes << nodes.delete_at(1)
555
859
  next
556
860
  when "mrow"
557
- second_arg = mrow_nodes.map { |node| encode(node.nodes.first) }.join
861
+ second_arg = mrow_nodes.map { |n| encode(n.nodes.first) }.join
558
862
  third_arg = upcase_dd_intent_name(node.nodes[1..-2])
559
863
  mrow_nodes << nodes.delete_at(1)
560
864
  break
561
865
  end
562
866
  break
563
867
  end
564
- intent_name = ":derivative(1,#{second_arg},#{third_arg})"
868
+ intent_name = "#{intent_names[:derivative]}(1,#{second_arg},#{third_arg})"
565
869
  mrow = ox_element("mrow", attributes: { intent: intent_name })
566
870
  nodes.insert(0, Utility.update_nodes(mrow, mrow_nodes))
567
871
  end
@@ -576,7 +880,7 @@ module Plurimath
576
880
 
577
881
  if DERIVATIVE_CONSTS.include?(node.nodes[0]&.nodes&.first)
578
882
  iteration += 1
579
- node["intent"] = ":derivative#{derivative_intent_name(node.nodes[1], nodes[iteration..-1], type: node.name)}"
883
+ node["intent"] = "#{intent_names[:derivative]}#{derivative_intent_name(node.nodes[1], nodes[iteration..-1], type: node.name)}"
580
884
  next_node = nodes[iteration]
581
885
  case next_node.name
582
886
  when "mi", "mrow"
@@ -692,6 +996,12 @@ module Plurimath
692
996
  encode(str)
693
997
  end
694
998
  # Dd derivative nodes end
999
+
1000
+ def type_error!(type)
1001
+ raise Math::InvalidTypeError.new(
1002
+ "Invalid type provided: #{type}. Must be one of #{MATH_ZONE_TYPES.join(', ')}.",
1003
+ )
1004
+ end
695
1005
  end
696
1006
  end
697
1007
  end
@@ -14,7 +14,7 @@ module Plurimath
14
14
  first_value = first_value&.insert(0, symbol) unless open_paren
15
15
  first_value << symbol unless close_paren
16
16
  mrow = Utility.update_nodes(ox_element("mrow"), first_value)
17
- intentify(mrow, intent, func_name: :abs, intent_name: :"absolute-value")
17
+ intentify(mrow, intent, func_name: :abs, intent_name: intent_names[:name])
18
18
  end
19
19
 
20
20
  def to_omml_without_math_tag(display_style, options:)
@@ -39,6 +39,10 @@ module Plurimath
39
39
  "⒜#{unicodemath_parens(parameter_one, options: options)}"
40
40
  end
41
41
 
42
+ def intent_names
43
+ { name: "absolute-value" }
44
+ end
45
+
42
46
  protected
43
47
 
44
48
  def md_tag
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "binary_function"
4
+ require_relative "../../mathml/utility"
4
5
 
5
6
  module Plurimath
6
7
  module Math
7
8
  module Function
8
9
  class Base < BinaryFunction
10
+ include Mathml::Utility
11
+
9
12
  attr_accessor :options
13
+
10
14
  FUNCTION = {
11
15
  name: "subscript",
12
16
  first_value: "base",
@@ -7,6 +7,7 @@ module Plurimath
7
7
  module Function
8
8
  class Color < BinaryFunction
9
9
  attr_accessor :options
10
+
10
11
  FUNCTION = {
11
12
  name: "color",
12
13
  first_value: "mathcolor",
@@ -27,11 +28,10 @@ module Plurimath
27
28
  end
28
29
 
29
30
  def to_mathml_without_math_tag(intent, options:)
30
- color_value = parameter_one&.to_asciimath(options: options)&.gsub(/\s/, "")&.gsub(/"/, "")
31
31
  Utility.update_nodes(
32
32
  Utility.ox_element(
33
33
  "mstyle",
34
- attributes: { attr_key => color_value },
34
+ attributes: mathml_options,
35
35
  ),
36
36
  [parameter_two&.to_mathml_without_math_tag(intent, options: options)],
37
37
  )
@@ -56,13 +56,26 @@ module Plurimath
56
56
  end
57
57
 
58
58
  def to_unicodemath(options:)
59
- "(#{parameter_one.to_unicodemath(options: options)}&#{parameter_two.to_unicodemath(options: options)})"
59
+ "#{color_symbol}(#{parameter_one.to_unicodemath(options: options)}&#{parameter_two.to_unicodemath(options: options)})"
60
60
  end
61
61
 
62
62
  protected
63
63
 
64
+ def color_symbol
65
+ options&.dig(:backgroundcolor) ? "☁" : "✎"
66
+ end
67
+
64
68
  def attr_key
65
- (options && options[:backcolor]) ? :mathbackground : :mathcolor
69
+ options&.dig(:backgroundcolor) ? :mathbackground : :mathcolor
70
+ end
71
+
72
+ def mathml_options
73
+ return unless parameter_one
74
+
75
+ color_options = {}
76
+ color_options[attr_key] =
77
+ parameter_one.to_asciimath(options: options)&.gsub(/\s/, "")&.gsub(/"/, "")
78
+ color_options
66
79
  end
67
80
  end
68
81
  end