plurimath 0.10.0 → 0.10.2

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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec-opal +1 -1
  3. data/.rubocop.yml +9 -5
  4. data/.rubocop_todo.yml +0 -0
  5. data/Gemfile +7 -5
  6. data/README.adoc +57 -1
  7. data/Rakefile +11 -0
  8. data/lib/plurimath/asciimath/parse.rb +0 -1
  9. data/lib/plurimath/asciimath/parser.rb +0 -3
  10. data/lib/plurimath/asciimath.rb +5 -0
  11. data/lib/plurimath/cli.rb +28 -1
  12. data/lib/plurimath/errors.rb +0 -4
  13. data/lib/plurimath/formatter/numbers.rb +12 -0
  14. data/lib/plurimath/formatter/numeric_formatter.rb +4 -1
  15. data/lib/plurimath/formatter/standard.rb +0 -1
  16. data/lib/plurimath/formatter.rb +6 -9
  17. data/lib/plurimath/html/parse.rb +0 -1
  18. data/lib/plurimath/html/parser.rb +0 -3
  19. data/lib/plurimath/html.rb +5 -0
  20. data/lib/plurimath/latex/parse.rb +0 -1
  21. data/lib/plurimath/latex/parser.rb +2 -5
  22. data/lib/plurimath/latex.rb +5 -0
  23. data/lib/plurimath/math/core.rb +6 -2
  24. data/lib/plurimath/math/formula/mrow.rb +2 -41
  25. data/lib/plurimath/math/formula/mstyle.rb +6 -0
  26. data/lib/plurimath/math/formula.rb +59 -301
  27. data/lib/plurimath/math/function/abs.rb +0 -1
  28. data/lib/plurimath/math/function/arccos.rb +0 -1
  29. data/lib/plurimath/math/function/arcsin.rb +0 -1
  30. data/lib/plurimath/math/function/arctan.rb +0 -1
  31. data/lib/plurimath/math/function/arg.rb +0 -1
  32. data/lib/plurimath/math/function/bar.rb +0 -1
  33. data/lib/plurimath/math/function/base.rb +0 -3
  34. data/lib/plurimath/math/function/binary_function.rb +5 -3
  35. data/lib/plurimath/math/function/cancel.rb +0 -1
  36. data/lib/plurimath/math/function/ceil.rb +0 -1
  37. data/lib/plurimath/math/function/color.rb +0 -1
  38. data/lib/plurimath/math/function/cos.rb +0 -1
  39. data/lib/plurimath/math/function/cosh.rb +0 -1
  40. data/lib/plurimath/math/function/cot.rb +0 -1
  41. data/lib/plurimath/math/function/coth.rb +0 -1
  42. data/lib/plurimath/math/function/csc.rb +0 -1
  43. data/lib/plurimath/math/function/csch.rb +0 -1
  44. data/lib/plurimath/math/function/ddot.rb +0 -1
  45. data/lib/plurimath/math/function/deg.rb +0 -1
  46. data/lib/plurimath/math/function/det.rb +0 -1
  47. data/lib/plurimath/math/function/dim.rb +0 -1
  48. data/lib/plurimath/math/function/dot.rb +0 -1
  49. data/lib/plurimath/math/function/exp.rb +0 -1
  50. data/lib/plurimath/math/function/fenced.rb +1 -197
  51. data/lib/plurimath/math/function/floor.rb +0 -1
  52. data/lib/plurimath/math/function/font_style/bold-fraktur.rb +0 -1
  53. data/lib/plurimath/math/function/font_style/bold-italic.rb +0 -1
  54. data/lib/plurimath/math/function/font_style/bold-sans-serif.rb +0 -1
  55. data/lib/plurimath/math/function/font_style/bold-script.rb +0 -1
  56. data/lib/plurimath/math/function/font_style/bold.rb +0 -1
  57. data/lib/plurimath/math/function/font_style/double_struck.rb +0 -1
  58. data/lib/plurimath/math/function/font_style/fraktur.rb +0 -1
  59. data/lib/plurimath/math/function/font_style/italic.rb +0 -1
  60. data/lib/plurimath/math/function/font_style/monospace.rb +0 -1
  61. data/lib/plurimath/math/function/font_style/normal.rb +0 -1
  62. data/lib/plurimath/math/function/font_style/sans-serif-bold-italic.rb +0 -1
  63. data/lib/plurimath/math/function/font_style/sans-serif-italic.rb +0 -1
  64. data/lib/plurimath/math/function/font_style/sans-serif.rb +0 -1
  65. data/lib/plurimath/math/function/font_style/script.rb +0 -1
  66. data/lib/plurimath/math/function/font_style.rb +29 -2
  67. data/lib/plurimath/math/function/frac.rb +0 -3
  68. data/lib/plurimath/math/function/gcd.rb +0 -1
  69. data/lib/plurimath/math/function/glb.rb +0 -1
  70. data/lib/plurimath/math/function/hat.rb +0 -1
  71. data/lib/plurimath/math/function/hom.rb +0 -1
  72. data/lib/plurimath/math/function/inf.rb +1 -2
  73. data/lib/plurimath/math/function/int.rb +2 -3
  74. data/lib/plurimath/math/function/intent.rb +0 -1
  75. data/lib/plurimath/math/function/ker.rb +0 -1
  76. data/lib/plurimath/math/function/lcm.rb +0 -1
  77. data/lib/plurimath/math/function/left.rb +0 -1
  78. data/lib/plurimath/math/function/lg.rb +0 -1
  79. data/lib/plurimath/math/function/lim.rb +1 -2
  80. data/lib/plurimath/math/function/liminf.rb +0 -1
  81. data/lib/plurimath/math/function/limits.rb +0 -1
  82. data/lib/plurimath/math/function/limsup.rb +0 -1
  83. data/lib/plurimath/math/function/linebreak.rb +0 -1
  84. data/lib/plurimath/math/function/ln.rb +0 -1
  85. data/lib/plurimath/math/function/log.rb +1 -2
  86. data/lib/plurimath/math/function/longdiv.rb +0 -3
  87. data/lib/plurimath/math/function/lub.rb +0 -1
  88. data/lib/plurimath/math/function/max.rb +0 -1
  89. data/lib/plurimath/math/function/mbox.rb +0 -1
  90. data/lib/plurimath/math/function/menclose.rb +0 -3
  91. data/lib/plurimath/math/function/merror.rb +0 -3
  92. data/lib/plurimath/math/function/mglyph.rb +0 -3
  93. data/lib/plurimath/math/function/min.rb +0 -1
  94. data/lib/plurimath/math/function/mlabeledtr.rb +0 -20
  95. data/lib/plurimath/math/function/mod.rb +0 -1
  96. data/lib/plurimath/math/function/mpadded.rb +0 -3
  97. data/lib/plurimath/math/function/ms.rb +1 -77
  98. data/lib/plurimath/math/function/msgroup.rb +0 -27
  99. data/lib/plurimath/math/function/msline.rb +0 -3
  100. data/lib/plurimath/math/function/multiscript.rb +0 -14
  101. data/lib/plurimath/math/function/nary.rb +4 -0
  102. data/lib/plurimath/math/function/none.rb +1 -4
  103. data/lib/plurimath/math/function/norm.rb +0 -1
  104. data/lib/plurimath/math/function/obrace.rb +0 -1
  105. data/lib/plurimath/math/function/oint.rb +2 -3
  106. data/lib/plurimath/math/function/over.rb +0 -3
  107. data/lib/plurimath/math/function/overset.rb +3 -3
  108. data/lib/plurimath/math/function/phantom.rb +0 -3
  109. data/lib/plurimath/math/function/power.rb +0 -3
  110. data/lib/plurimath/math/function/power_base.rb +0 -3
  111. data/lib/plurimath/math/function/prod.rb +2 -3
  112. data/lib/plurimath/math/function/right.rb +0 -1
  113. data/lib/plurimath/math/function/root.rb +0 -3
  114. data/lib/plurimath/math/function/rule.rb +0 -1
  115. data/lib/plurimath/math/function/scarries.rb +0 -3
  116. data/lib/plurimath/math/function/scarry.rb +22 -0
  117. data/lib/plurimath/math/function/sec.rb +0 -1
  118. data/lib/plurimath/math/function/sech.rb +0 -1
  119. data/lib/plurimath/math/function/semantics.rb +0 -15
  120. data/lib/plurimath/math/function/sin.rb +0 -1
  121. data/lib/plurimath/math/function/sinh.rb +0 -1
  122. data/lib/plurimath/math/function/sqrt.rb +0 -3
  123. data/lib/plurimath/math/function/stackrel.rb +0 -3
  124. data/lib/plurimath/math/function/substack.rb +0 -1
  125. data/lib/plurimath/math/function/sum.rb +2 -3
  126. data/lib/plurimath/math/function/sup.rb +0 -1
  127. data/lib/plurimath/math/function/table/align.rb +0 -1
  128. data/lib/plurimath/math/function/table/array.rb +0 -1
  129. data/lib/plurimath/math/function/table/bmatrix.rb +0 -1
  130. data/lib/plurimath/math/function/table/cases.rb +0 -1
  131. data/lib/plurimath/math/function/table/eqarray.rb +0 -1
  132. data/lib/plurimath/math/function/table/matrix.rb +0 -1
  133. data/lib/plurimath/math/function/table/multline.rb +0 -1
  134. data/lib/plurimath/math/function/table/pmatrix.rb +0 -1
  135. data/lib/plurimath/math/function/table/split.rb +0 -1
  136. data/lib/plurimath/math/function/table/vmatrix.rb +0 -1
  137. data/lib/plurimath/math/function/table.rb +10 -23
  138. data/lib/plurimath/math/function/tan.rb +0 -1
  139. data/lib/plurimath/math/function/tanh.rb +0 -1
  140. data/lib/plurimath/math/function/td.rb +0 -4
  141. data/lib/plurimath/math/function/ternary_function.rb +6 -2
  142. data/lib/plurimath/math/function/text.rb +1 -6
  143. data/lib/plurimath/math/function/tilde.rb +4 -1
  144. data/lib/plurimath/math/function/tr.rb +0 -13
  145. data/lib/plurimath/math/function/ubrace.rb +0 -1
  146. data/lib/plurimath/math/function/ul.rb +4 -1
  147. data/lib/plurimath/math/function/underover.rb +0 -3
  148. data/lib/plurimath/math/function/underset.rb +22 -45
  149. data/lib/plurimath/math/function/unitsml.rb +2 -1
  150. data/lib/plurimath/math/function/vec.rb +4 -1
  151. data/lib/plurimath/math/function.rb +107 -10
  152. data/lib/plurimath/math/number.rb +9 -7
  153. data/lib/plurimath/math/symbols/comma.rb +1 -1
  154. data/lib/plurimath/math/symbols/plus.rb +1 -1
  155. data/lib/plurimath/math/symbols/symbol.rb +17 -4
  156. data/lib/plurimath/math.rb +8 -26
  157. data/lib/plurimath/mathml/constants.rb +1 -0
  158. data/lib/plurimath/mathml/formula_transformation.rb +442 -0
  159. data/lib/plurimath/mathml/parser.rb +11 -50
  160. data/lib/plurimath/mathml/translator.rb +584 -0
  161. data/lib/plurimath/mathml/utility/formula_transformation.rb +2 -341
  162. data/lib/plurimath/mathml.rb +5 -0
  163. data/lib/plurimath/number_formatter.rb +2 -1
  164. data/lib/plurimath/omml/parser.rb +10 -7
  165. data/lib/plurimath/omml/transform.rb +17 -5
  166. data/lib/plurimath/omml.rb +3 -0
  167. data/lib/plurimath/setup/opal.rb.erb +3 -4
  168. data/lib/plurimath/unicode_math/parse.rb +0 -5
  169. data/lib/plurimath/unicode_math/parser.rb +1 -6
  170. data/lib/plurimath/unicode_math/parsing_rules/absence_rules.rb +0 -1
  171. data/lib/plurimath/unicode_math/parsing_rules/common_rules.rb +0 -1
  172. data/lib/plurimath/unicode_math/parsing_rules/constants_rules.rb +0 -1
  173. data/lib/plurimath/unicode_math/parsing_rules/masked.rb +0 -1
  174. data/lib/plurimath/unicode_math/parsing_rules/sub_sup.rb +0 -1
  175. data/lib/plurimath/unicode_math/parsing_rules.rb +14 -0
  176. data/lib/plurimath/unicode_math.rb +6 -0
  177. data/lib/plurimath/utility.rb +1 -1
  178. data/lib/plurimath/version.rb +1 -1
  179. data/lib/plurimath/xml_engine/oga.rb +6 -6
  180. data/lib/plurimath/xml_engine/ox_engine.rb +2 -2
  181. data/lib/plurimath/xml_engine.rb +2 -0
  182. data/lib/plurimath.rb +43 -18
  183. data/plurimath.gemspec +5 -4
  184. metadata +33 -15
  185. data/lib/plurimath/mathml/utility/empty_defined_methods.rb +0 -483
  186. data/lib/plurimath/mathml/utility.rb +0 -369
@@ -1,33 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "errors"
4
- require_relative "asciimath"
5
- require_relative "omml"
6
- require_relative "unicode_math"
7
- require_relative "mathml"
8
- require_relative "html"
9
- require_relative "latex"
10
- require_relative "unitsml"
11
- require_relative "number_formatter"
12
- require_relative "formatter/standard"
13
- require_relative "math/core"
14
- require_relative "math/number"
15
- require_relative "math/symbols"
16
- require_relative "math/formula"
17
- require_relative "math/formula/mrow"
18
- require_relative "math/formula/mstyle"
19
- require_relative "math/function"
20
- require_relative "asciimath/parser"
21
- require_relative "unicode_math/parser"
22
- require_relative "mathml/parser"
23
- require_relative "latex/parser"
24
- require_relative "html/parser"
25
- require_relative "omml/parser"
26
- require_relative "utility"
27
- require "yaml"
28
-
29
3
  module Plurimath
30
4
  module Math
5
+ autoload :Core, "#{__dir__}/math/core"
6
+ autoload :Formula, "#{__dir__}/math/formula"
7
+ autoload :Function, "#{__dir__}/math/function"
8
+ autoload :InvalidTypeError, "#{__dir__}/errors/invalid_type_error"
9
+ autoload :Number, "#{__dir__}/math/number"
10
+ autoload :ParseError, "#{__dir__}/errors/parse_error"
11
+ autoload :Symbols, "#{__dir__}/math/symbols"
12
+
31
13
  VALID_TYPES = {
32
14
  omml: Omml,
33
15
  html: Html,
@@ -141,6 +141,7 @@ module Plurimath
141
141
  "⏟": "ubrace",
142
142
  "→": "vec",
143
143
  "̂": "hat",
144
+ "̅": "bar",
144
145
  "̲": "ul",
145
146
  "¯": "bar",
146
147
  "&": "&",
@@ -0,0 +1,442 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plurimath
4
+ class Mathml
5
+ module FormulaTransformation
6
+ private
7
+
8
+ # Use each_mixed_content to get children in document order.
9
+ def ordered_children(node)
10
+ children = []
11
+ node.each_mixed_content { |child| children << child }
12
+ children
13
+ end
14
+
15
+ def text_value(value)
16
+ return if value.nil?
17
+ return value if value.is_a?(String)
18
+
19
+ Array(value).join
20
+ end
21
+
22
+ def mathml_symbol(value)
23
+ Plurimath::Utility.mathml_unary_classes([value], lang: :mathml)
24
+ end
25
+
26
+ # Alignment markers affect MathML layout only; the old parser dropped them
27
+ # before building the Plurimath AST.
28
+ def content_children(node)
29
+ ordered_children(node).reject do |child|
30
+ child.is_a?(Mml::V4::Malignmark) || child.is_a?(Mml::V4::Maligngroup)
31
+ end
32
+ end
33
+
34
+ def default_fenced_open(fenced)
35
+ "(" unless fenced.close
36
+ end
37
+
38
+ def default_fenced_close(fenced)
39
+ ")" unless fenced.open
40
+ end
41
+
42
+ def resolve_paren(value)
43
+ return nil unless value
44
+
45
+ mathml_symbol(value)
46
+ end
47
+
48
+ def extract_ms_text(node)
49
+ return (node.empty? ? nil : node) if node.is_a?(String)
50
+
51
+ if ms_token_element?(node)
52
+ return Array(node.value).join
53
+ end
54
+
55
+ if node.respond_to?(:each_mixed_content)
56
+ return ordered_children(node).filter_map { |child| extract_ms_text(child) }.join(" ")
57
+ end
58
+
59
+ Array(node.value).join if node.respond_to?(:value)
60
+ end
61
+
62
+ def ms_token_element?(node)
63
+ node.is_a?(Mml::V4::Mi) ||
64
+ node.is_a?(Mml::V4::Mn) ||
65
+ node.is_a?(Mml::V4::Mo) ||
66
+ node.is_a?(Mml::V4::Ms) ||
67
+ node.is_a?(Mml::V4::Mtext)
68
+ end
69
+
70
+ def normalize_phantom_child(child)
71
+ return child unless child.respond_to?(:value=) && child.respond_to?(:value)
72
+ return child if child.instance_of?(Math::Symbols::Symbol)
73
+ return child unless child.value.is_a?(String)
74
+ return child unless child.value.match?(/\A[[:space:]]|[[:space:]]\z/)
75
+
76
+ child.value = nil
77
+ child
78
+ end
79
+
80
+ def boolean_to_displaystyle(value)
81
+ case value
82
+ when "true", true then true
83
+ when "false", false then false
84
+ else true
85
+ end
86
+ end
87
+
88
+ def truthy_mathml_bool?(value)
89
+ [true, "true"].include?(value)
90
+ end
91
+
92
+ def filter_child(value)
93
+ return nil if value.nil?
94
+ return value unless value.is_a?(Math::Formula)
95
+ return value if value.value.nil? || value.value.empty?
96
+
97
+ value.value.length == 1 ? value.value.first : value
98
+ end
99
+
100
+ def wrap_children(children)
101
+ case children.length
102
+ when 0 then nil
103
+ when 1 then children.first
104
+ else Math::Formula.new(children)
105
+ end
106
+ end
107
+
108
+ def nary_check(children)
109
+ return children unless children.length == 2
110
+
111
+ first = children.first
112
+ second = children.last
113
+
114
+ if first.is_a?(Math::Function::PowerBase) && first.parameter_one&.is_nary_symbol?
115
+ [Math::Function::Nary.new(
116
+ first.parameter_one,
117
+ first.parameter_two,
118
+ first.parameter_three,
119
+ second,
120
+ )]
121
+ elsif first.is_a?(Math::Function::Overset) && first.parameter_two&.is_nary_symbol?
122
+ [Math::Function::Nary.new(
123
+ first.parameter_two,
124
+ nil,
125
+ first.parameter_one,
126
+ second,
127
+ { type: "undOvr" },
128
+ )]
129
+ elsif first.is_a?(Math::Function::Power) && first.parameter_one&.is_nary_symbol?
130
+ [Math::Function::Nary.new(
131
+ first.parameter_one,
132
+ nil,
133
+ first.parameter_two,
134
+ second,
135
+ { type: "subSup" },
136
+ )]
137
+ else
138
+ children
139
+ end
140
+ end
141
+
142
+ def fill_ternary_third_values(values)
143
+ return unless values.is_a?(Array) && values.length > 1
144
+
145
+ first = values.first
146
+ return if preserve_separate_nary_body?(first, values[1])
147
+
148
+ if first.is_a?(Math::Function::Nary)
149
+ first.parameter_four ||= values.delete_at(1)
150
+ elsif first.respond_to?(:is_nary_function?) && first.is_nary_function? && !first.all_values_exist?
151
+ if first.respond_to?(:new_nary_function) && !first.any_value_exist?
152
+ values[0] = first.new_nary_function(values.delete_at(1))
153
+ elsif first.any_value_exist?
154
+ first.parameter_three = values.delete_at(1)
155
+ end
156
+ elsif value_is_ternary_or_nary?(values)
157
+ first.parameter_three = values.delete_at(1)
158
+ end
159
+ end
160
+
161
+ def unwrap_single(value)
162
+ return nil if value.nil? || (value.is_a?(Array) && value.empty?)
163
+ return value unless value.is_a?(Array)
164
+
165
+ value.length == 1 ? value.first : Math::Formula.new(value)
166
+ end
167
+
168
+ def preserve_separate_nary_body?(first, second)
169
+ return false unless first.respond_to?(:is_nary_function?) && first.is_nary_function?
170
+
171
+ normalized_second = filter_child(second)
172
+
173
+ normalized_second.is_a?(Math::Function::Base) ||
174
+ normalized_second.is_a?(Math::Function::PowerBase)
175
+ end
176
+
177
+ def preserve_explicit_nary_body!(values)
178
+ return unless values.is_a?(Array) && values.any?
179
+
180
+ first = values.first
181
+ return unless first.is_a?(Math::Function::Nary)
182
+ return unless first.options&.[](:type) == "undOvr"
183
+
184
+ body = filter_child(first.parameter_four)
185
+ return unless body.is_a?(Math::Function::Base) ||
186
+ body.is_a?(Math::Function::PowerBase)
187
+
188
+ replacement =
189
+ if first.parameter_three.nil?
190
+ Math::Function::Underset.new(first.parameter_two, first.parameter_one)
191
+ else
192
+ Math::Function::Underover.new(
193
+ first.parameter_one,
194
+ first.parameter_two,
195
+ first.parameter_three,
196
+ )
197
+ end
198
+
199
+ values[0] = replacement
200
+ values.insert(1, body)
201
+ end
202
+
203
+ def convert_multiscript_child(child)
204
+ return Math::Function::None.new if child.is_a?(Mml::V4::None) || child.is_a?(Mml::V3::None)
205
+ return Math::Function::None.new if child.respond_to?(:value) && Array(child.value).join.empty?
206
+
207
+ mml_to_plurimath(child) || Math::Function::None.new
208
+ end
209
+
210
+ def convert_multiscript_children(children)
211
+ Array(children).map { |child| convert_multiscript_child(child) }
212
+ end
213
+
214
+ def multiscript_post_element_count(element_order, prescript_index)
215
+ post_names = element_order[0...prescript_index]
216
+ .select { |element| element.node_type == :element }
217
+ .map(&:name)
218
+ post_names.size - 1
219
+ end
220
+
221
+ def split_multiscript_children(children, post_element_count)
222
+ [
223
+ convert_multiscript_children(children[1..post_element_count]),
224
+ convert_multiscript_children(children[(post_element_count + 1)..-1]),
225
+ ]
226
+ end
227
+
228
+ def split_script_pairs(children, compact: false)
229
+ pairs = children.each_slice(2).to_a
230
+ subscripts = pairs.map { |pair| pair[0] if pair[0] }
231
+ superscripts = pairs.map { |pair| pair[1] if pair[1] }
232
+
233
+ if compact
234
+ [subscripts.compact, superscripts.compact]
235
+ else
236
+ [subscripts, superscripts]
237
+ end
238
+ end
239
+
240
+ def attach_postscripts(base, subscripts, superscripts)
241
+ normalized_base = filter_child(base)
242
+ return normalized_base unless subscripts.any? || superscripts.any?
243
+
244
+ Math::Function::PowerBase.new(
245
+ normalized_base,
246
+ unwrap_single(subscripts),
247
+ unwrap_single(superscripts),
248
+ )
249
+ end
250
+
251
+ def build_annotation_entries(entries, tag_name)
252
+ return [] unless entries&.any?
253
+
254
+ entries.map do |annotation|
255
+ value = annotation.respond_to?(:value) ? annotation.value : annotation.to_s
256
+ { tag_name => [Math::Symbols::Symbol.new(value)] }
257
+ end
258
+ end
259
+
260
+ # Heuristic: combine function name with following opening parenthesis.
261
+ def combine_function_with_parens(values)
262
+ return values if values.size < 2
263
+
264
+ result = []
265
+ i = 0
266
+ while i < values.size
267
+ current = values[i]
268
+ if i + 1 < values.size && can_combine_with_paren?(current)
269
+ next_elem = values[i + 1]
270
+ if opening_paren?(next_elem)
271
+ paren = if next_elem.respond_to?(:paren?) && next_elem.paren?
272
+ next_elem
273
+ else
274
+ Math::Symbols::Paren::Lround.new
275
+ end
276
+ result << current.class.new(paren)
277
+ i += 2
278
+ next
279
+ end
280
+ end
281
+ result << current
282
+ i += 1
283
+ end
284
+ result
285
+ end
286
+
287
+ def opening_paren?(obj)
288
+ return true if obj.is_a?(Math::Symbols::Symbol) && obj.value == "("
289
+ return true if obj.class_name == "lround"
290
+ return true if obj.respond_to?(:paren?) && obj.paren? && obj.respond_to?(:to_asciimath) && obj.to_asciimath(options: {}) == "("
291
+
292
+ false
293
+ end
294
+
295
+ def can_combine_with_paren?(obj)
296
+ return false unless obj.respond_to?(:class)
297
+
298
+ obj.class < Math::Function::UnaryFunction
299
+ end
300
+
301
+ def apply_font_style(element, result)
302
+ return result unless element.respond_to?(:mathvariant)
303
+
304
+ variant = element.mathvariant
305
+ return result if variant.nil? || variant.empty?
306
+
307
+ font_class = Plurimath::Utility::FONT_STYLES[variant.to_sym]
308
+ return result unless font_class
309
+
310
+ font_class.new(result, variant)
311
+ end
312
+
313
+ def filter_values(value, array_to_instance: false, replacing_order: true)
314
+ return value unless value.is_a?(Array)
315
+ return array_to_instance ? nil : value if value.empty?
316
+
317
+ if is_a?(Math::Formula) && value.length == 1 && value.first.is_mstyle?
318
+ @displaystyle = value.first.displaystyle
319
+ end
320
+
321
+ if value.length == 1 && value.all? { |val| val.is_a?(Math::Formula) }
322
+ if array_to_instance
323
+ filter_values(value.first.value, array_to_instance: true)
324
+ else
325
+ value.first.value
326
+ end
327
+ elsif value.is_a?(Array) && value.any?(Math::Formula::Mrow)
328
+ value.each_with_index do |element, index|
329
+ next unless element.is_a?(Math::Formula::Mrow)
330
+
331
+ value[index] = filter_values(
332
+ Array(element),
333
+ array_to_instance: true,
334
+ replacing_order: replacing_order,
335
+ )
336
+ end
337
+ value
338
+ elsif value_is_ternary_or_nary?(value)
339
+ value.first.parameter_three = value.delete_at(1)
340
+ filter_values(
341
+ Array(value),
342
+ array_to_instance: array_to_instance,
343
+ replacing_order: replacing_order,
344
+ )
345
+ elsif ternary_naryable?(value)
346
+ [
347
+ Math::Function::Nary.new(
348
+ value.first.parameter_one,
349
+ value.first.parameter_two,
350
+ value.first.parameter_three,
351
+ value.last,
352
+ ),
353
+ ]
354
+ elsif overset_naryable?(value)
355
+ [
356
+ Math::Function::Nary.new(
357
+ value.first.parameter_two,
358
+ nil,
359
+ value.first.parameter_one,
360
+ value.last,
361
+ { type: "undOvr" },
362
+ ),
363
+ ]
364
+ elsif power_naryable?(value)
365
+ [
366
+ Math::Function::Nary.new(
367
+ value.first.parameter_one,
368
+ nil,
369
+ value.first.parameter_two,
370
+ value.last,
371
+ { type: "subSup" },
372
+ ),
373
+ ]
374
+ elsif array_to_instance && replacing_order
375
+ value.length > 1 ? Math::Formula.new(value) : value.first
376
+ else
377
+ value
378
+ end
379
+ end
380
+
381
+ def validate_symbols(value)
382
+ case value
383
+ when Array
384
+ array_validations(value)
385
+ when Math::Symbols::Symbol
386
+ return value if value.value.nil?
387
+
388
+ instance = mathml_symbol_to_class(value.value)
389
+ if value&.options&.any? && instance.is_a?(Math::Symbols::Symbol)
390
+ instance.options = value.options
391
+ end
392
+ instance
393
+ when String
394
+ mathml_symbol_to_class(value)
395
+ end
396
+ end
397
+
398
+ def array_validations(value)
399
+ value.each_with_index do |val, index|
400
+ next unless val.is_a?(Math::Symbols::Symbol)
401
+
402
+ value[index] = mathml_symbol_to_class(val.value) unless val.value.nil?
403
+ end
404
+ value
405
+ end
406
+
407
+ def mathml_symbol_to_class(symbol)
408
+ Plurimath::Utility.mathml_unary_classes(
409
+ Array(symbol),
410
+ lang: :mathml,
411
+ )
412
+ end
413
+
414
+ def value_is_ternary_or_nary?(value)
415
+ return if value.any?(String)
416
+
417
+ value.length >= 2 &&
418
+ value.first.is_ternary_function? &&
419
+ value.first.parameter_three.nil? &&
420
+ (!value.first.parameter_one.nil? || !value.first.parameter_two.nil?)
421
+ end
422
+
423
+ def ternary_naryable?(value)
424
+ value.length == 2 &&
425
+ value.first.is_a?(Math::Function::PowerBase) &&
426
+ value.first.parameter_one.is_nary_symbol?
427
+ end
428
+
429
+ def overset_naryable?(value)
430
+ value.length == 2 &&
431
+ value.first.is_a?(Math::Function::Overset) &&
432
+ value.first.parameter_two.is_nary_symbol?
433
+ end
434
+
435
+ def power_naryable?(value)
436
+ value.length == 2 &&
437
+ value.first.is_a?(Math::Function::Power) &&
438
+ value.first.parameter_one.is_nary_symbol?
439
+ end
440
+ end
441
+ end
442
+ end
@@ -1,67 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "constants"
4
- require "mml"
5
-
6
3
  module Plurimath
7
4
  class Mathml
8
5
  class Parser
9
- CONFIGURATION = {
10
- Mml::MathWithNilNamespace => Plurimath::Math::Formula,
11
- Mml::MathWithNamespace => Plurimath::Math::Formula,
12
- Mml::Mmultiscripts => Plurimath::Math::Function::Multiscript,
13
- Mml::Mlabeledtr => Plurimath::Math::Function::Mlabeledtr,
14
- Mml::Munderover => Plurimath::Math::Function::Underover,
15
- Mml::Semantics => Plurimath::Math::Function::Semantics,
16
- Mml::Mscarries => Plurimath::Math::Function::Scarries,
17
- Mml::Mfraction => Plurimath::Math::Function::Frac,
18
- Mml::Menclose => Plurimath::Math::Function::Menclose,
19
- Mml::Mlongdiv => Plurimath::Math::Function::Longdiv,
20
- Mml::Mphantom => Plurimath::Math::Function::Phantom,
21
- Mml::Msubsup => Plurimath::Math::Function::PowerBase,
22
- Mml::Msgroup => Plurimath::Math::Function::Msgroup,
23
- Mml::Mpadded => Plurimath::Math::Function::Mpadded,
24
- Mml::Mfenced => Plurimath::Math::Function::Fenced,
25
- Mml::Mstack => Plurimath::Math::Function::Stackrel,
26
- Mml::Munder => Plurimath::Math::Function::Underset,
27
- Mml::Msline => Plurimath::Math::Function::Msline,
28
- Mml::Merror => Plurimath::Math::Function::Merror,
29
- Mml::Mtable => Plurimath::Math::Function::Table,
30
- Mml::Mstyle => Plurimath::Math::Formula::Mstyle,
31
- Mml::Mglyph => Plurimath::Math::Function::Mglyph,
32
- Mml::Mover => Plurimath::Math::Function::Overset,
33
- Mml::Msqrt => Plurimath::Math::Function::Sqrt,
34
- Mml::Mroot => Plurimath::Math::Function::Root,
35
- Mml::Mtext => Plurimath::Math::Function::Text,
36
- Mml::Mfrac => Plurimath::Math::Function::Frac,
37
- Mml::Msrow => Plurimath::Math::Formula,
38
- Mml::Msup => Plurimath::Math::Function::Power,
39
- Mml::Msub => Plurimath::Math::Function::Base,
40
- Mml::None => Plurimath::Math::Function::None,
41
- Mml::Mrow => Plurimath::Math::Formula::Mrow,
42
- Mml::Mtd => Plurimath::Math::Function::Td,
43
- Mml::Mtr => Plurimath::Math::Function::Tr,
44
- Mml::Mi => Plurimath::Math::Symbols::Symbol,
45
- Mml::Mo => Plurimath::Math::Symbols::Symbol,
46
- Mml::Ms => Plurimath::Math::Function::Ms,
47
- Mml::Mn => Plurimath::Math::Number,
48
- }
49
6
  attr_accessor :text
50
- @@models_set = false
51
7
 
52
8
  def initialize(text)
53
- mml_config unless @@models_set
54
9
  @text = text
55
10
  end
56
11
 
57
12
  def parse
58
- namespace_exist = text.split(">").first.include?(" xmlns=")
59
- Mml.parse(text, namespace_exist: namespace_exist)
13
+ mml_tree = Mml.parse(
14
+ text,
15
+ version: 4,
16
+ namespace_exist: namespace_exist?,
17
+ )
18
+
19
+ Mathml::Translator.new.mml_to_plurimath(mml_tree)
60
20
  end
61
21
 
62
- def mml_config
63
- Mml::Configuration.custom_models = CONFIGURATION
64
- @@models_set = true
22
+ private
23
+
24
+ def namespace_exist?
25
+ text.split(">").first.include?(" xmlns=")
65
26
  end
66
27
  end
67
28
  end