plurimath 0.8.16 → 0.8.18

Sign up to get free protection for your applications and to get access to all the features.
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