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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9de48dbb937f65122d95415947e417692fc0d5a11d48e7a1caa1b54f3c4465bf
4
- data.tar.gz: 2f1e748929a2569b2e7b291381624648fc11a3fc2b93d44406a9a92c2fa21068
3
+ metadata.gz: 766097c1faa26dc82f8664fca18a302b52920df2fce4ec8395cf2f65d8a7d687
4
+ data.tar.gz: 35cf1a6b6a0e87fa5404b3eea87927cd69da535deeebfcd49f8db5ce1aaba8e6
5
5
  SHA512:
6
- metadata.gz: c8054b884f09d830a6b7a1e98d1c5679434540f6ad018c4135654f3ea4495336aa4971e43be842def4ad0fc139664ffa477c12407cef5553c55c46f9d0f2037d
7
- data.tar.gz: 852c85f6edab822fc8e880ceded6913283be3e65300069be0fd7a898b6d057bb1143fee9f1e5b182a9dee36213c564e11038cb38040b58586c5acbd16b0d063d
6
+ metadata.gz: 7307ab95dc0d60e6fe65c939665e08ec59902527a454427956ee17e6d2c7bc207921e529ae107d51ec0f2a2a0909cd7da260943d277a03755efc34aa01edd2d0
7
+ data.tar.gz: 6f050eb9cae6730e911ccae66afe0a4384ab0fade68810fa4fa176e15d5f37eef225f0b11c1409fcd10ed05e75cbf7aa6fdd10a4e18d85ab335dbb947c22d350
@@ -9,6 +9,13 @@ on:
9
9
  jobs:
10
10
  generate_docs:
11
11
  runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ filename:
15
+ - supported_parens_list.adoc
16
+ - supported_symbols_list.adoc
17
+ - intent_supported_classes.adoc
18
+
12
19
  steps:
13
20
  - uses: actions/checkout@v4
14
21
 
@@ -17,12 +24,7 @@ jobs:
17
24
  ruby-version: '3.3'
18
25
  bundler-cache: true
19
26
 
20
- - name: Generate supported_parens_list.adoc
21
- run: |
22
- rm -f supported_parens_list.adoc
23
- bundle exec rake supported_parens_list.adoc
24
-
25
- - name: Generate supported_symbols_list.adoc
27
+ - name: Generate documentation
26
28
  run: |
27
- rm -f supported_symbols_list.adoc
28
- bundle exec rake supported_symbols_list.adoc
29
+ rm -f ${{ matrix.filename }}
30
+ bundle exec rake ${{ matrix.filename }}
data/Gemfile CHANGED
@@ -11,5 +11,5 @@ gem 'equivalent-xml'
11
11
  gem 'opal-rspec', "~> 1.1.0a"
12
12
  gem 'oga'
13
13
  gem 'ox'
14
- gem "unitsml"
14
+ gem "unitsml", "0.2.9"
15
15
  gem "debug"
data/README.adoc CHANGED
@@ -583,6 +583,10 @@ Consult the following tables for details on supported symbols and parentheses:
583
583
  * link:supported_symbols_list.adoc[Symbols]
584
584
  * link:supported_parens_list.adoc[Parentheses]
585
585
 
586
+ The following table shows the classes that support MathML "intent" encoding:
587
+
588
+ * link:intent_supported_classes.adoc[Classes that support MathML Intent]
589
+
586
590
  NOTE: To regenerate these files, delete them and run:
587
591
  `bundle exec rake supported_symbols_list.adoc`.
588
592
 
data/Rakefile CHANGED
@@ -18,6 +18,7 @@ end
18
18
  DOC_FILES = {
19
19
  "supported_parens_list.adoc" => :paren,
20
20
  "supported_symbols_list.adoc" => :symbols,
21
+ "intent_supported_classes.adoc" => :intent,
21
22
  }.freeze
22
23
 
23
24
  DOC_FILES.each do |file_name, type|
@@ -28,17 +29,26 @@ end
28
29
 
29
30
  def write_doc_file(doc_file, type:)
30
31
  File.open(doc_file, "a") do |file|
31
- file.write(file_header)
32
-
33
- Plurimath::Utility.send(:"#{type}_files").each do |klass|
34
- next if klass::INPUT.empty?
35
-
36
- file_name = File.basename(klass.const_source_location(:INPUT).first, ".rb")
37
- file.write(documentation_content(file_name, klass))
32
+ case type
33
+ when :intent
34
+ write_intent_doc_file(file)
35
+ else
36
+ paren_symbols_doc(file, type)
38
37
  end
38
+ end
39
+ end
40
+
41
+ def paren_symbols_doc(file, type)
42
+ file.write(file_header)
39
43
 
40
- file.write("|===")
44
+ Plurimath::Utility.send(:"#{type}_files").each do |klass|
45
+ next if klass::INPUT.empty?
46
+
47
+ file_name = File.basename(klass.const_source_location(:INPUT).first, ".rb")
48
+ file.write(documentation_content(file_name, klass))
41
49
  end
50
+
51
+ file.write("|===")
42
52
  end
43
53
 
44
54
  def documentation_content(file_name, klass)
@@ -75,4 +85,41 @@ def format_input(format, klass)
75
85
  end.join(", ").gsub(/\|/, "\\|")
76
86
  end
77
87
 
88
+ def write_intent_doc_file(file)
89
+ file.write("= List of classes supporting `intent` encoding with relevant values\n")
90
+
91
+ intent_classes.each do |klass|
92
+ intents = klass.new.intent_names.values.map do |intent|
93
+ "`#{intent}`"
94
+ end
95
+
96
+ file.write(
97
+ <<~INTENT
98
+
99
+ * `#{klass.name.gsub("Plurimath::Math::", "")}`
100
+ ** #{intents.join("\n** ")}
101
+ INTENT
102
+ )
103
+ end
104
+
105
+ file.write("\nIntent for unary classes like, sin, cos, tan, etc. will be `Function`.\n")
106
+ end
107
+
108
+ def intent_classes
109
+ intent_classes = [
110
+ Plurimath::Math::Function::TernaryFunction.descendants,
111
+ Plurimath::Math::Function::BinaryFunction.descendants,
112
+ Plurimath::Math::Function::UnaryFunction.descendants,
113
+ Plurimath::Math::Function::Table.descendants,
114
+ Plurimath::Math::Symbols::Symbol.descendants,
115
+ Plurimath::Math::Function::UnaryFunction,
116
+ Plurimath::Math::Function::Table,
117
+ Plurimath::Math::Function::Nary,
118
+ Plurimath::Math::Formula,
119
+ ].flatten
120
+ intent_classes.select do |klass|
121
+ klass.instance_methods(false).include?(:intent_names)
122
+ end
123
+ end
124
+
78
125
  task :default => :spec
@@ -0,0 +1,82 @@
1
+ = List of classes supporting `intent` encoding with relevant values
2
+
3
+ * `Function::Fenced`
4
+ ** `open-closed-interval`
5
+ ** `closed-open-interval`
6
+ ** `binomial-coefficient`
7
+ ** `closed-interval`
8
+ ** `open-interval`
9
+ ** `:fenced`
10
+
11
+ * `Function::Int`
12
+ ** `:integral`
13
+
14
+ * `Function::Oint`
15
+ ** `:contour integral`
16
+
17
+ * `Function::Prod`
18
+ ** `:product`
19
+
20
+ * `Function::Sum`
21
+ ** `:sum`
22
+
23
+ * `Function::Frac`
24
+ ** `:derivative`
25
+ ** `:partial-derivative`
26
+
27
+ * `Function::Inf`
28
+ ** `:function`
29
+
30
+ * `Function::Intent`
31
+ ** `:derivative`
32
+
33
+ * `Function::Lim`
34
+ ** `:function`
35
+
36
+ * `Function::Abs`
37
+ ** `absolute-value`
38
+
39
+ * `Symbols::Dd`
40
+ ** `ⅆ`
41
+
42
+ * `Symbols::Ii`
43
+ ** `ⅈ`
44
+
45
+ * `Symbols::Intercal`
46
+ ** `transpose`
47
+
48
+ * `Symbols::Jj`
49
+ ** `ⅉ`
50
+
51
+ * `Symbols::UpcaseDd`
52
+ ** `ⅅ`
53
+
54
+ * `Function::UnaryFunction`
55
+ ** `:function`
56
+
57
+ * `Function::Table`
58
+ ** `:curly-braced-matrix`
59
+ ** `:parenthesized-matrix`
60
+ ** `:bracketed-matrix`
61
+ ** `:normed-matrix`
62
+ ** `:determinant`
63
+ ** `:equations`
64
+ ** `:cases`
65
+
66
+ * `Function::Nary`
67
+ ** `:n-ary`
68
+ ** `:anticlockwise contour integral`
69
+ ** `:coproduct`
70
+ ** `:quadruple integral`
71
+ ** `:triple integral`
72
+ ** `:double integral`
73
+ ** `:clockwise contour integral`
74
+ ** `:volume integral`
75
+ ** `:surface integral`
76
+ ** `:contour integral`
77
+
78
+ * `Formula`
79
+ ** `:partial-derivative`
80
+ ** `:derivative`
81
+
82
+ Intent for unary classes like, sin, cos, tan, etc. will be `Function`.
@@ -158,6 +158,7 @@ module Plurimath
158
158
  str("") |
159
159
  (rparen.as(:rparen) >> space? >> controversial_symbols >> comma.as(:comma).maybe >> expression).repeat(1).as(:expr) |
160
160
  (power.as(:symbol) >> space? >> expression).as(:expr) |
161
+ table.as(:table) >> space? >> rparen.as(:rparen) >> space? >> expression.as(:expr).maybe |
161
162
  comma.as(:comma).maybe
162
163
  end
163
164
 
@@ -900,6 +900,18 @@ module Plurimath
900
900
  Math::Formula.new(formula_array)
901
901
  end
902
902
 
903
+ rule(table: simple(:table),
904
+ rparen: simple(:rparen),
905
+ expr: sequence(:expr)) do
906
+ [
907
+ Math::Function::Fenced.new(
908
+ Math::Symbols::Paren::OpenParen.new,
909
+ [table],
910
+ Utility.asciimath_symbol_object(rparen),
911
+ ),
912
+ ] + expr.flatten.compact
913
+ end
914
+
903
915
  rule(left: simple(:left),
904
916
  left_right_value: simple(:left_right),
905
917
  right: simple(:right)) do
@@ -3,7 +3,7 @@
3
3
  module Plurimath
4
4
  module Formatter
5
5
  class NumberFormatter
6
- attr_reader :number, :data_reader
6
+ attr_reader :number, :data_reader, :prefix
7
7
 
8
8
  STRING_SYMBOLS = {
9
9
  dot: ".".freeze,
@@ -13,6 +13,7 @@ module Plurimath
13
13
  def initialize(number, data_reader = {})
14
14
  @number = number
15
15
  @data_reader = data_reader
16
+ @prefix = "-" if number.negative?
16
17
  end
17
18
 
18
19
  def format(precision: nil)
@@ -20,16 +21,15 @@ module Plurimath
20
21
  int, frac, integer_format, fraction_format, signif_format = *partition_tokens(number)
21
22
  result = integer_format.apply(int, data_reader)
22
23
  result << fraction_format.apply(frac, data_reader, int) if frac
23
-
24
24
  result = signif_format.apply(result, integer_format, fraction_format)
25
-
26
- result
25
+ result = "+#{result}" if number.positive? && data_reader[:number_sign] == :plus
26
+ "#{prefix}#{result}"
27
27
  end
28
28
 
29
29
  private
30
30
 
31
31
  def partition_tokens(number)
32
- int, fraction = parse_number(number, data_reader)
32
+ int, fraction = parse_number(number)
33
33
  [
34
34
  int,
35
35
  fraction,
@@ -46,7 +46,7 @@ module Plurimath
46
46
  parts.size == 2 ? parts[1].size : 0
47
47
  end
48
48
 
49
- def parse_number(number, options = {})
49
+ def parse_number(number, options = data_reader)
50
50
  precision = options[:precision] || precision_from(number)
51
51
 
52
52
  num = if precision == 0
@@ -72,7 +72,9 @@ module Plurimath
72
72
 
73
73
  def update_exponent_value(number_str)
74
74
  exponent_number = BigDecimal(number_str) - 1
75
- "#{"+" if @exponent_sign == :plus}#{exponent_number.to_i}"
75
+ return exponent_number.to_i if exponent_number.negative? || @exponent_sign != :plus
76
+
77
+ "+#{exponent_number.to_i}"
76
78
  end
77
79
 
78
80
  def notation_chars(num_str)
@@ -112,7 +114,8 @@ module Plurimath
112
114
 
113
115
  chars.first.delete!(".")
114
116
  chars.first.insert(index + 1, ".") unless chars.first[index + 2].nil?
115
- chars[-1] = (chars[-1].to_i - index).to_s
117
+ exponent = chars[-1]
118
+ chars[-1] = "#{"+" if exponent.to_s.start_with?("+")}#{exponent.to_i - index}"
116
119
  end
117
120
  end
118
121
  end
@@ -10,6 +10,7 @@ module Plurimath
10
10
  fraction_group_digits: 3,
11
11
  exponent_sign: "plus",
12
12
  fraction_group: "'",
13
+ number_sign: "plus",
13
14
  notation: :basic,
14
15
  group_digits: 3,
15
16
  significant: 0,
@@ -38,6 +39,7 @@ module Plurimath
38
39
  options[:fraction_group] ||= default_options[:fraction_group]
39
40
  options[:exponent_sign] ||= default_options[:exponent_sign]
40
41
  options[:group_digits] ||= default_options[:group_digits]
42
+ options[:number_sign] ||= default_options[:number_sign]
41
43
  options[:significant] ||= default_options[:significant]
42
44
  options[:notation] ||= default_options[:notation]
43
45
  options[:decimal] ||= default_options[:decimal]
@@ -8,6 +8,13 @@ module Plurimath
8
8
  /^\n/ => "",
9
9
  }.freeze
10
10
 
11
+ ALL_PARAMETERS = %i[
12
+ parameter_one
13
+ parameter_two
14
+ parameter_three
15
+ parameter_four
16
+ ].freeze
17
+
11
18
  def self.inherited(subclass)
12
19
  @descendants ||= []
13
20
  @descendants << subclass
@@ -201,7 +208,7 @@ module Plurimath
201
208
  false
202
209
  end
203
210
 
204
- def linebreak
211
+ def linebreak?
205
212
  false
206
213
  end
207
214
 
@@ -291,11 +298,15 @@ module Plurimath
291
298
  is_a?(Math::Function::UnaryFunction)
292
299
  end
293
300
 
294
- def is_nary_function?;end
301
+ def is_nary_function?; end
302
+
303
+ def is_nary_symbol?; end
295
304
 
296
- def is_nary_symbol?;end
305
+ def nary_intent_name; end
297
306
 
298
- def nary_intent_name;end
307
+ def symbol?
308
+ is_a?(Math::Symbols::Symbol)
309
+ end
299
310
 
300
311
  def is_binary_function?
301
312
  is_a?(Function::BinaryFunction)
@@ -323,8 +334,56 @@ module Plurimath
323
334
  Utility.primes_constants.any? { |prefix, prime| unicodemath_field_value(field).include?(prime) }
324
335
  end
325
336
 
337
+ def paren?
338
+ false
339
+ end
340
+
341
+ def pretty_print_instance_variables
342
+ excluded_vars = [
343
+ :@left_right_wrapper,
344
+ :@temp_mathml_order,
345
+ :@using_default,
346
+ :@displaystyle,
347
+ :@__ordered,
348
+ :@__mixed,
349
+ :@is_mrow,
350
+ :@values,
351
+ ]
352
+ instance_variables.sort - excluded_vars
353
+ end
354
+
355
+ def to_ms_value
356
+ new_arr = []
357
+ case self
358
+ when Math::Symbols::Symbol
359
+ new_arr << (value ? value.to_s : to_unicodemath(options: {}))
360
+ when Math::Number, Math::Function::Text
361
+ new_arr << value
362
+ else
363
+ parameters_to_ms_value(new_arr)
364
+ if respond_to?(:value) && value.is_a?(Array)
365
+ new_arr << value&.map { |element| element.to_ms_value }.join(" ")
366
+ end
367
+ end
368
+ new_arr
369
+ end
370
+
371
+ def is_mstyle?
372
+ false
373
+ end
374
+
375
+ def is_mrow?
376
+ false
377
+ end
378
+
326
379
  private
327
380
 
381
+ def parameters_to_ms_value(array)
382
+ ALL_PARAMETERS.each do |field|
383
+ array << get("@#{field}")&.to_ms_value if respond_to?(field)
384
+ end
385
+ end
386
+
328
387
  def array_line_break_field(field, variable, obj)
329
388
  if result(field).length > 1
330
389
  updated_object_values(variable, obj: obj)
@@ -344,10 +403,10 @@ module Plurimath
344
403
  ox_element("mrow") << xml_engine_node
345
404
  end
346
405
 
347
- def intentify(tag, intent, func_name:, intent_name: nil)
406
+ def intentify(tag, intent, func_name:, intent_name: nil, options: {})
348
407
  return tag unless intent
349
408
 
350
- Utility::IntentEncoding.send("#{func_name}_intent", tag, intent_name)
409
+ Utility::IntentEncoding.send("#{func_name}_intent", tag, intent_name, options)
351
410
  end
352
411
 
353
412
  def masked_tag(tag)
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plurimath
4
+ module Math
5
+ class Formula
6
+ class Mrow < Formula
7
+ attr_accessor :is_mrow
8
+
9
+ def initialize(
10
+ value = [],
11
+ left_right_wrapper = true,
12
+ display_style: true,
13
+ input_string: nil,
14
+ unitsml: false
15
+ )
16
+ super
17
+ @is_mrow = true
18
+ end
19
+
20
+ def element_order=(value)
21
+ @value = validated_order(value, rejectable_array: ["comment"])
22
+ end
23
+
24
+ def content; end
25
+
26
+ def content=(value)
27
+ arr_value = Array(value)
28
+ if no_content_in?(arr_value)
29
+ delete_all_text
30
+ else
31
+ validate_text_order(
32
+ arr_value.map { |val| validate_symbols(val) unless val.strip.empty? }
33
+ )
34
+ end
35
+ organize_value
36
+ end
37
+
38
+ def is_mrow?
39
+ @is_mrow
40
+ end
41
+
42
+ private
43
+
44
+ def organize_value
45
+ return if value.any?(String)
46
+ return unless is_mrow
47
+
48
+ value.each_with_index do |element, index|
49
+ update_current_element(element, value, index)
50
+ if value[index + 1].is_a?(Math::Function::Mod)
51
+ update_mod_function(value, index)
52
+ elsif unary_function_updatable?(value, element, index)
53
+ unary_function_update(value, index)
54
+ elsif value.first.paren? && value.last.paren?
55
+ organize_fencing(value)
56
+ elsif valid_underset_function?(element)
57
+ value[index] = new_nary_element(element, value)
58
+ elsif valid_underover_function?(element)
59
+ replace_with_nary_function(element, value, index)
60
+ elsif ternary_function_third_value_present?(element)
61
+ element.parameter_three = value.delete_at(index + 1)
62
+ end
63
+ end
64
+ end
65
+
66
+ def update_current_element(element, value, index)
67
+ if first_and_last_values_nil?(value)
68
+ replace_symbols_with_parens(value)
69
+ elsif element.class_name == "symbol" && element.value.nil?
70
+ element.value = ""
71
+ end
72
+ end
73
+
74
+ def validate_text_order(value)
75
+ @value.each_with_index do |item, index|
76
+ next unless item == "text"
77
+
78
+ if value.first
79
+ @value[index] = value.shift
80
+ else
81
+ value.shift
82
+ @value.delete_at(index)
83
+ end
84
+ end
85
+ end
86
+
87
+ def delete_all_text
88
+ @value.delete("text")
89
+ end
90
+
91
+ def no_content_in?(value)
92
+ value.nil? || value.empty? || value&.all? { |val| val.strip.empty? }
93
+ end
94
+
95
+ def first_and_last_values_nil?(value)
96
+ value.first.class_name == "symbol" &&
97
+ value.first.value.nil? &&
98
+ value.last.class_name == "symbol" &&
99
+ value.last.value.nil?
100
+ end
101
+
102
+ def replace_symbols_with_parens(value)
103
+ value[0] = Math::Symbols::Paren::OpenParen.new
104
+ value[-1] = Math::Symbols::Paren::CloseParen.new
105
+ end
106
+
107
+ def nary_function_or_symbol?(element)
108
+ element.is_nary_function? || element.is_nary_symbol?
109
+ end
110
+
111
+ def valid_underover_function?(element)
112
+ element.is_a?(Math::Function::Underover) &&
113
+ nary_function_or_symbol?(element.parameter_one)
114
+ end
115
+
116
+ def valid_underset_function?(element)
117
+ element.is_a?(Math::Function::Underset) &&
118
+ nary_function_or_symbol?(element.parameter_two)
119
+ end
120
+
121
+ def unary_function_updatable?(value, element, index)
122
+ value.length > 1 &&
123
+ element.is_unary? &&
124
+ value[index + 1] &&
125
+ Plurimath::Utility::UNARY_CLASSES.include?(element.class_name)
126
+ end
127
+
128
+ def ternary_function_third_value_present?(element)
129
+ element.is_ternary_function? &&
130
+ element.any_value_exist? &&
131
+ element.parameter_three.nil?
132
+ end
133
+
134
+ def update_mod_function(value, index)
135
+ mod_obj = value[index + 1]
136
+ mod_obj.parameter_one = filter_values(
137
+ value.delete_at(index),
138
+ array_to_instance: true
139
+ )
140
+ mod_obj.parameter_two = filter_values(
141
+ value.delete_at(index + 1),
142
+ array_to_instance: true
143
+ )
144
+ end
145
+
146
+ def unary_function_update(value, index)
147
+ element = value.delete_at(index)
148
+ element.parameter_one = filter_values(
149
+ value.delete_at(index),
150
+ array_to_instance: true
151
+ )
152
+ value.insert(index, element)
153
+ end
154
+
155
+ def organize_fencing(value)
156
+ if value[1].is_a?(Math::Function::Table) && value.length == 3
157
+ table = value[1]
158
+ table.open_paren = value.shift
159
+ table.close_paren = value.pop
160
+ else
161
+ @value = [
162
+ Function::Fenced.new(value.shift, value, value.pop)
163
+ ]
164
+ end
165
+ end
166
+
167
+ def new_nary_element(element, value)
168
+ value.shift
169
+ nary = Plurimath::Math::Function::Nary.new(
170
+ element.parameter_two,
171
+ element.parameter_one,
172
+ nil,
173
+ filter_values(value.shift(value.length), array_to_instance: true),
174
+ { type: "undOvr" }
175
+ )
176
+ nary
177
+ end
178
+
179
+ def replace_with_nary_function(element, value, index)
180
+ fourth_value = value.delete_at(index + 1)
181
+ organize_value(fourth_value) if fourth_value.is_mrow?
182
+ value[index] = Math::Function::Nary.new(
183
+ element.parameter_one,
184
+ element.parameter_two,
185
+ element.parameter_three,
186
+ filter_values(fourth_value, array_to_instance: true),
187
+ { type: "undOvr" }
188
+ )
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plurimath
4
+ module Math
5
+ class Formula
6
+ class Mstyle < Formula
7
+ def displaystyle=(value)
8
+ @displaystyle = boolean_display_style(value)
9
+ end
10
+
11
+ def is_mstyle?
12
+ true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end