plurimath 0.11.6 → 0.11.7
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.
- checksums.yaml +4 -4
- data/lib/plurimath/asciimath/utility.rb +50 -0
- data/lib/plurimath/asciimath.rb +1 -0
- data/lib/plurimath/formatter/numbers/mathml_renderer.rb +15 -15
- data/lib/plurimath/formatter/numbers/omml_renderer.rb +19 -19
- data/lib/plurimath/html/utility.rb +18 -0
- data/lib/plurimath/html.rb +1 -0
- data/lib/plurimath/latex/utility.rb +118 -0
- data/lib/plurimath/latex.rb +1 -0
- data/lib/plurimath/math/core.rb +12 -12
- data/lib/plurimath/math/formula.rb +10 -10
- data/lib/plurimath/math/function/abs.rb +3 -3
- data/lib/plurimath/math/function/bar.rb +14 -14
- data/lib/plurimath/math/function/base.rb +15 -7
- data/lib/plurimath/math/function/binary_function.rb +7 -7
- data/lib/plurimath/math/function/cancel.rb +2 -2
- data/lib/plurimath/math/function/ceil.rb +1 -1
- data/lib/plurimath/math/function/color.rb +2 -2
- data/lib/plurimath/math/function/ddot.rb +3 -3
- data/lib/plurimath/math/function/dot.rb +8 -8
- data/lib/plurimath/math/function/fenced.rb +8 -8
- data/lib/plurimath/math/function/floor.rb +1 -1
- data/lib/plurimath/math/function/font_style/bold.rb +2 -2
- data/lib/plurimath/math/function/font_style/double_struck.rb +2 -2
- data/lib/plurimath/math/function/font_style/fraktur.rb +2 -2
- data/lib/plurimath/math/function/font_style/italic.rb +2 -2
- data/lib/plurimath/math/function/font_style/monospace.rb +2 -2
- data/lib/plurimath/math/function/font_style/normal.rb +2 -2
- data/lib/plurimath/math/function/font_style/sans-serif.rb +2 -2
- data/lib/plurimath/math/function/font_style/script.rb +2 -2
- data/lib/plurimath/math/function/font_style.rb +16 -15
- data/lib/plurimath/math/function/frac.rb +7 -7
- data/lib/plurimath/math/function/hat.rb +8 -8
- data/lib/plurimath/math/function/inf.rb +2 -2
- data/lib/plurimath/math/function/int.rb +8 -8
- data/lib/plurimath/math/function/left.rb +5 -5
- data/lib/plurimath/math/function/lim.rb +3 -3
- data/lib/plurimath/math/function/limits.rb +2 -2
- data/lib/plurimath/math/function/linebreak.rb +2 -2
- data/lib/plurimath/math/function/log.rb +10 -10
- data/lib/plurimath/math/function/longdiv.rb +1 -1
- data/lib/plurimath/math/function/menclose.rb +2 -2
- data/lib/plurimath/math/function/merror.rb +2 -2
- data/lib/plurimath/math/function/mod.rb +1 -1
- data/lib/plurimath/math/function/mpadded.rb +2 -2
- data/lib/plurimath/math/function/ms.rb +2 -2
- data/lib/plurimath/math/function/msgroup.rb +2 -2
- data/lib/plurimath/math/function/multiscript.rb +2 -2
- data/lib/plurimath/math/function/nary.rb +15 -15
- data/lib/plurimath/math/function/none.rb +1 -1
- data/lib/plurimath/math/function/norm.rb +1 -1
- data/lib/plurimath/math/function/obrace.rb +8 -8
- data/lib/plurimath/math/function/oint.rb +6 -6
- data/lib/plurimath/math/function/over.rb +5 -5
- data/lib/plurimath/math/function/overleftrightarrow.rb +7 -7
- data/lib/plurimath/math/function/overset.rb +5 -5
- data/lib/plurimath/math/function/phantom.rb +9 -9
- data/lib/plurimath/math/function/power.rb +5 -5
- data/lib/plurimath/math/function/power_base.rb +5 -5
- data/lib/plurimath/math/function/prod.rb +4 -4
- data/lib/plurimath/math/function/right.rb +5 -5
- data/lib/plurimath/math/function/root.rb +7 -7
- data/lib/plurimath/math/function/rule.rb +2 -2
- data/lib/plurimath/math/function/scarries.rb +1 -1
- data/lib/plurimath/math/function/semantics.rb +4 -4
- data/lib/plurimath/math/function/sqrt.rb +7 -7
- data/lib/plurimath/math/function/stackrel.rb +5 -5
- data/lib/plurimath/math/function/substack.rb +1 -1
- data/lib/plurimath/math/function/sum.rb +4 -4
- data/lib/plurimath/math/function/sup.rb +1 -1
- data/lib/plurimath/math/function/table/array.rb +1 -1
- data/lib/plurimath/math/function/table/bmatrix.rb +2 -2
- data/lib/plurimath/math/function/table/matrix.rb +2 -2
- data/lib/plurimath/math/function/table.rb +29 -29
- data/lib/plurimath/math/function/td.rb +3 -3
- data/lib/plurimath/math/function/ternary_function.rb +13 -13
- data/lib/plurimath/math/function/text.rb +4 -4
- data/lib/plurimath/math/function/tilde.rb +6 -6
- data/lib/plurimath/math/function/tr.rb +4 -4
- data/lib/plurimath/math/function/ubrace.rb +1 -1
- data/lib/plurimath/math/function/ul.rb +9 -9
- data/lib/plurimath/math/function/unary_function.rb +14 -14
- data/lib/plurimath/math/function/underover.rb +1 -1
- data/lib/plurimath/math/function/underset.rb +12 -12
- data/lib/plurimath/math/function/unitsml.rb +1 -1
- data/lib/plurimath/math/function/vec.rb +7 -7
- data/lib/plurimath/math/model_helper.rb +103 -0
- data/lib/plurimath/math/number.rb +2 -2
- data/lib/plurimath/math/symbols/symbol.rb +2 -2
- data/lib/plurimath/math/symbols/tilde.rb +1 -1
- data/lib/plurimath/math.rb +1 -0
- data/lib/plurimath/mathml/constants.rb +29 -155
- data/lib/plurimath/mathml/formula_transformation.rb +2 -5
- data/lib/plurimath/mathml/translator.rb +6 -0
- data/lib/plurimath/mathml/utility.rb +53 -0
- data/lib/plurimath/mathml.rb +1 -0
- data/lib/plurimath/omml/formula_transformation.rb +5 -5
- data/lib/plurimath/omml/translator.rb +8 -5
- data/lib/plurimath/omml/utility.rb +109 -0
- data/lib/plurimath/omml.rb +1 -0
- data/lib/plurimath/unicode_math/transform.rb +5 -1
- data/lib/plurimath/unicode_math/utility.rb +256 -0
- data/lib/plurimath/unicode_math.rb +1 -0
- data/lib/plurimath/utility/intent_encoding.rb +4 -4
- data/lib/plurimath/utility.rb +6 -815
- data/lib/plurimath/version.rb +1 -1
- data/lib/plurimath/xml_engine/oga/dumper.rb +8 -1
- data/lib/plurimath/xml_engine/ox_engine.rb +4 -1
- data/lib/plurimath/xml_helper.rb +47 -0
- data/lib/plurimath.rb +1 -0
- metadata +10 -2
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plurimath
|
|
4
|
+
module Math
|
|
5
|
+
# Display/serialization support helpers for the Math node classes,
|
|
6
|
+
# extracted from Plurimath::Utility (macro refactor). Deliberately a
|
|
7
|
+
# standalone class — NOT a Utility subclass — so it does not shadow
|
|
8
|
+
# bareword `Utility` references inside math files.
|
|
9
|
+
class ModelHelper
|
|
10
|
+
TEXT_CLASSES = %w[
|
|
11
|
+
symbol
|
|
12
|
+
number
|
|
13
|
+
text
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
def validate_left_right(fields = [])
|
|
18
|
+
fields.each do |field|
|
|
19
|
+
if field.is_a?(Math::Formula) && field.value.first.is_a?(Math::Function::Left)
|
|
20
|
+
field.left_right_wrapper = true
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def validate_math_zone(object, lang:, intent: false, options: nil)
|
|
26
|
+
return false unless object
|
|
27
|
+
|
|
28
|
+
if object.is_a?(Math::Formula)
|
|
29
|
+
filter_math_zone_values(object.value, lang: lang, intent: intent,
|
|
30
|
+
options: options).find do |value|
|
|
31
|
+
!(value.is_a?(Math::Function::Text) || value.is_a?(Math::Symbols::Symbol))
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
!(TEXT_CLASSES.include?(object.class_name) || object.is_a?(Math::Symbols::Symbol))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def filter_math_zone_values(value, lang:, intent: false, options: nil)
|
|
39
|
+
return [] if value.nil? || value.empty?
|
|
40
|
+
|
|
41
|
+
new_arr = []
|
|
42
|
+
temp_array = []
|
|
43
|
+
skip_index = nil
|
|
44
|
+
value.each_with_index do |obj, index|
|
|
45
|
+
object = obj.dup
|
|
46
|
+
next if index == skip_index
|
|
47
|
+
if TEXT_CLASSES.include?(object.class_name) || math_display_text_objects(object)
|
|
48
|
+
next temp_array << (if object.is_a?(Math::Symbols::Symbol)
|
|
49
|
+
symbol_to_text(
|
|
50
|
+
object, lang: lang, intent: intent, options: options
|
|
51
|
+
)
|
|
52
|
+
else
|
|
53
|
+
object.value
|
|
54
|
+
end)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if temp_array.any?
|
|
58
|
+
new_arr << Math::Function::Text.new(temp_array.join(" "),
|
|
59
|
+
lang: lang)
|
|
60
|
+
end
|
|
61
|
+
temp_array = []
|
|
62
|
+
new_arr << object
|
|
63
|
+
end
|
|
64
|
+
if temp_array.any?
|
|
65
|
+
new_arr << Math::Function::Text.new(temp_array.join(" "),
|
|
66
|
+
lang: lang)
|
|
67
|
+
end
|
|
68
|
+
new_arr
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def notations_to_mask(notations)
|
|
72
|
+
mask = notations.split.map do |notation|
|
|
73
|
+
Utility::MASK_CLASSES.key(notation)
|
|
74
|
+
end
|
|
75
|
+
mask.compact.sum ^ 15
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def symbol_to_text(symbol, lang:, options:, intent: false)
|
|
81
|
+
case lang
|
|
82
|
+
when :asciimath
|
|
83
|
+
symbol.to_asciimath(options: options)
|
|
84
|
+
when :latex
|
|
85
|
+
symbol.to_latex(options: options)
|
|
86
|
+
when :mathml
|
|
87
|
+
symbol.to_mathml_without_math_tag(intent,
|
|
88
|
+
options: options).nodes.first
|
|
89
|
+
when :omml
|
|
90
|
+
symbol.to_omml_without_math_tag(true, options: options)
|
|
91
|
+
when :unicodemath
|
|
92
|
+
symbol.to_unicodemath(options: options)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def math_display_text_objects(object)
|
|
97
|
+
class_names = ["plus", "minus", "circ", "equal", "symbol"].freeze
|
|
98
|
+
class_names.include?(object.class_name)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -60,7 +60,7 @@ module Plurimath
|
|
|
60
60
|
|
|
61
61
|
def insert_t_tag(_, options:)
|
|
62
62
|
[
|
|
63
|
-
|
|
63
|
+
XmlHelper.ox_element("r", namespace: "m") << t_tag(options: options),
|
|
64
64
|
]
|
|
65
65
|
end
|
|
66
66
|
|
|
@@ -69,7 +69,7 @@ module Plurimath
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def t_tag(options:)
|
|
72
|
-
|
|
72
|
+
XmlHelper.ox_element("t",
|
|
73
73
|
namespace: "m") << formatted_value(options)
|
|
74
74
|
end
|
|
75
75
|
|
|
@@ -83,7 +83,7 @@ module Plurimath
|
|
|
83
83
|
# TODO: remove this condition once to word rendering issue is resolved, plurimath/plurimath/pull/328
|
|
84
84
|
return if value == "⁢"
|
|
85
85
|
|
|
86
|
-
[
|
|
86
|
+
[XmlHelper.ox_element("r", namespace: "m") << t_tag(options: options)]
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def tag_name
|
|
@@ -234,7 +234,7 @@ options:)
|
|
|
234
234
|
end
|
|
235
235
|
|
|
236
236
|
def t_element
|
|
237
|
-
|
|
237
|
+
XmlHelper.ox_element("t", namespace: "m")
|
|
238
238
|
end
|
|
239
239
|
|
|
240
240
|
def explicit_checks(unicode)
|
data/lib/plurimath/math.rb
CHANGED
|
@@ -5,6 +5,7 @@ module Plurimath
|
|
|
5
5
|
autoload :Core, "#{__dir__}/math/core"
|
|
6
6
|
autoload :Evaluation, "#{__dir__}/math/evaluation"
|
|
7
7
|
autoload :Formula, "#{__dir__}/math/formula"
|
|
8
|
+
autoload :ModelHelper, "#{__dir__}/math/model_helper"
|
|
8
9
|
autoload :Function, "#{__dir__}/math/function"
|
|
9
10
|
autoload :InvalidTypeError, "#{__dir__}/errors/invalid_type_error"
|
|
10
11
|
autoload :Number, "#{__dir__}/math/number"
|
|
@@ -29,7 +29,7 @@ module Plurimath
|
|
|
29
29
|
"π": "pi",
|
|
30
30
|
"Π": "Pi",
|
|
31
31
|
"ρ": "rho",
|
|
32
|
-
"ς": "
|
|
32
|
+
"ς": "varsigma",
|
|
33
33
|
"σ": "sigma",
|
|
34
34
|
"Σ": "Sigma",
|
|
35
35
|
"τ": "tau",
|
|
@@ -41,7 +41,7 @@ module Plurimath
|
|
|
41
41
|
"ψ": "psi",
|
|
42
42
|
"Ψ": "Psi",
|
|
43
43
|
"ω": "omega",
|
|
44
|
-
"Ω": "
|
|
44
|
+
"Ω": "Omega",
|
|
45
45
|
"⋅": "cdot",
|
|
46
46
|
"∙": "*",
|
|
47
47
|
".": ".",
|
|
@@ -155,6 +155,16 @@ module Plurimath
|
|
|
155
155
|
"¯": "bar",
|
|
156
156
|
_: "ul",
|
|
157
157
|
}.freeze
|
|
158
|
+
|
|
159
|
+
# Accent characters promoted to their function class ONLY in an accent
|
|
160
|
+
# position (MathML <mover>, OMML <m:acc>). Kept separate from
|
|
161
|
+
# UNICODE_SYMBOLS because Text#value= consumes that map as a global
|
|
162
|
+
# substitution table, so an entry there would also rewrite the character
|
|
163
|
+
# inside ordinary text runs and bare tokens.
|
|
164
|
+
CONTEXTUAL_ACCENT_FUNCTIONS = {
|
|
165
|
+
"̃": "tilde",
|
|
166
|
+
}.freeze
|
|
167
|
+
|
|
158
168
|
SYMBOLS = {
|
|
159
169
|
"|": "|",
|
|
160
170
|
"/": "//",
|
|
@@ -174,22 +184,25 @@ module Plurimath
|
|
|
174
184
|
"+": "+",
|
|
175
185
|
"-": "-",
|
|
176
186
|
}.freeze
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
# Named operators that have no dedicated MathML/OMML representation — no
|
|
188
|
+
# unicode character and no structural element — so a bare <mi>/<mo>/<m:t>
|
|
189
|
+
# word (e.g. <mi>sin</mi>, <m:t>min</m:t>) is their only written form and
|
|
190
|
+
# resolves to the function class. Every other CLASSES entry has a proper
|
|
191
|
+
# form — a diacritic character (bar/hat/vec via <mover>), a unicode symbol
|
|
192
|
+
# (sum/prod/int via ∑ etc.), or a structural element (frac via
|
|
193
|
+
# <mfrac>/<m:f>, sqrt via <msqrt>) — so its bare word is a literal
|
|
194
|
+
# identifier, not the function. See PR #450 (which introduced this for accents).
|
|
195
|
+
NAMED_FUNCTION_WORDS = %w[
|
|
196
|
+
arccos arcsin arctan sin cos tan sec csc cot sinh cosh tanh coth sech
|
|
197
|
+
csch log ln exp det dim gcd lcm glb lub max min mod
|
|
184
198
|
].freeze
|
|
185
199
|
|
|
186
|
-
# True when +string+ is a bare word naming an
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
#
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
ACCENT_WORDS.include?(string&.strip)
|
|
200
|
+
# True when +string+ is a bare word naming an operator that has no other
|
|
201
|
+
# MathML/OMML representation, so it legitimately resolves to its function
|
|
202
|
+
# class. Words for constructs that DO have a character/structural form
|
|
203
|
+
# (accents, sum/prod/int, frac/sqrt/...) return false and stay literal.
|
|
204
|
+
def self.named_function_word?(string)
|
|
205
|
+
NAMED_FUNCTION_WORDS.include?(string&.strip)
|
|
193
206
|
end
|
|
194
207
|
|
|
195
208
|
CLASSES = %w[
|
|
@@ -255,145 +268,6 @@ module Plurimath
|
|
|
255
268
|
ul
|
|
256
269
|
ln
|
|
257
270
|
].freeze
|
|
258
|
-
OPERATORS = [
|
|
259
|
-
"    ",
|
|
260
|
-
"  ",
|
|
261
|
-
"*",
|
|
262
|
-
"<",
|
|
263
|
-
">",
|
|
264
|
-
" ",
|
|
265
|
-
"¬",
|
|
266
|
-
"±",
|
|
267
|
-
"×",
|
|
268
|
-
"÷",
|
|
269
|
-
"Γ",
|
|
270
|
-
"Δ",
|
|
271
|
-
"Θ",
|
|
272
|
-
"Λ",
|
|
273
|
-
"Ξ",
|
|
274
|
-
"Π",
|
|
275
|
-
"Σ",
|
|
276
|
-
"Ω",
|
|
277
|
-
"…",
|
|
278
|
-
"′",
|
|
279
|
-
"ℂ",
|
|
280
|
-
"ℕ",
|
|
281
|
-
"ℚ",
|
|
282
|
-
"ℝ",
|
|
283
|
-
"ℤ",
|
|
284
|
-
"ℵ",
|
|
285
|
-
"←",
|
|
286
|
-
"↑",
|
|
287
|
-
"→",
|
|
288
|
-
"→",
|
|
289
|
-
"↓",
|
|
290
|
-
"↔",
|
|
291
|
-
"↠",
|
|
292
|
-
"↣",
|
|
293
|
-
"↦",
|
|
294
|
-
"⇐",
|
|
295
|
-
"⇒",
|
|
296
|
-
"⇒",
|
|
297
|
-
"⇔",
|
|
298
|
-
"⇔",
|
|
299
|
-
"∀",
|
|
300
|
-
"∂",
|
|
301
|
-
"∃",
|
|
302
|
-
"∅",
|
|
303
|
-
"∇",
|
|
304
|
-
"∈",
|
|
305
|
-
"∉",
|
|
306
|
-
"∏",
|
|
307
|
-
"∑",
|
|
308
|
-
"−",
|
|
309
|
-
"∓",
|
|
310
|
-
"∝",
|
|
311
|
-
"∞",
|
|
312
|
-
"∠",
|
|
313
|
-
"∧",
|
|
314
|
-
"∨",
|
|
315
|
-
"∩",
|
|
316
|
-
"∪",
|
|
317
|
-
"∫",
|
|
318
|
-
"∮",
|
|
319
|
-
"∴",
|
|
320
|
-
"∵",
|
|
321
|
-
"∼",
|
|
322
|
-
"≅",
|
|
323
|
-
"≈",
|
|
324
|
-
"≔",
|
|
325
|
-
"≠",
|
|
326
|
-
"≡",
|
|
327
|
-
"≤",
|
|
328
|
-
"≥",
|
|
329
|
-
"≪",
|
|
330
|
-
"≫",
|
|
331
|
-
"≺",
|
|
332
|
-
"≻",
|
|
333
|
-
"⊂",
|
|
334
|
-
"⊃",
|
|
335
|
-
"⊆",
|
|
336
|
-
"⊇",
|
|
337
|
-
"⊕",
|
|
338
|
-
"⊗",
|
|
339
|
-
"⊙",
|
|
340
|
-
"⊢",
|
|
341
|
-
"⊤",
|
|
342
|
-
"⊥",
|
|
343
|
-
"⊨",
|
|
344
|
-
"⋀",
|
|
345
|
-
"⋁",
|
|
346
|
-
"⋂",
|
|
347
|
-
"⋃",
|
|
348
|
-
"⋄",
|
|
349
|
-
"⋅",
|
|
350
|
-
"⋆",
|
|
351
|
-
"⋈",
|
|
352
|
-
"⋉",
|
|
353
|
-
"⋊",
|
|
354
|
-
"⋮",
|
|
355
|
-
"⋯",
|
|
356
|
-
"⋱",
|
|
357
|
-
"⌈",
|
|
358
|
-
"⌉",
|
|
359
|
-
"⌊",
|
|
360
|
-
"⌋",
|
|
361
|
-
"⌢",
|
|
362
|
-
"□",
|
|
363
|
-
"△",
|
|
364
|
-
"⚬",
|
|
365
|
-
"⤖",
|
|
366
|
-
"⪯",
|
|
367
|
-
"⪰",
|
|
368
|
-
"+",
|
|
369
|
-
"=",
|
|
370
|
-
":",
|
|
371
|
-
"<",
|
|
372
|
-
"×",
|
|
373
|
-
"±",
|
|
374
|
-
"&",
|
|
375
|
-
";",
|
|
376
|
-
">",
|
|
377
|
-
"|",
|
|
378
|
-
"lim",
|
|
379
|
-
"max",
|
|
380
|
-
"min",
|
|
381
|
-
"\\",
|
|
382
|
-
"//",
|
|
383
|
-
"/",
|
|
384
|
-
"if",
|
|
385
|
-
"^",
|
|
386
|
-
"_",
|
|
387
|
-
"+",
|
|
388
|
-
"/",
|
|
389
|
-
"=",
|
|
390
|
-
":",
|
|
391
|
-
",",
|
|
392
|
-
")",
|
|
393
|
-
"(",
|
|
394
|
-
"[",
|
|
395
|
-
"]",
|
|
396
|
-
].freeze
|
|
397
271
|
SUPPORTED_FONT_STYLES = {
|
|
398
272
|
"sans-serif-bold-italic": Math::Function::FontStyle::SansSerifBoldItalic,
|
|
399
273
|
"sans-serif-italic": Math::Function::FontStyle::SansSerifItalic,
|
|
@@ -28,7 +28,7 @@ module Plurimath
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def mathml_symbol(value)
|
|
31
|
-
|
|
31
|
+
Utility.resolve_token(value)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Alignment markers affect MathML layout only; the old parser dropped them
|
|
@@ -423,10 +423,7 @@ module Plurimath
|
|
|
423
423
|
end
|
|
424
424
|
|
|
425
425
|
def mathml_symbol_to_class(symbol)
|
|
426
|
-
|
|
427
|
-
Array(symbol),
|
|
428
|
-
lang: :mathml,
|
|
429
|
-
)
|
|
426
|
+
Utility.resolve_token(symbol)
|
|
430
427
|
end
|
|
431
428
|
|
|
432
429
|
def value_is_ternary_or_nary?(value)
|
|
@@ -122,6 +122,12 @@ module Plurimath
|
|
|
122
122
|
children = content_children(mover)
|
|
123
123
|
base = filter_child(mml_to_plurimath(children[0]))
|
|
124
124
|
overscript = filter_child(mml_to_plurimath(children[1]))
|
|
125
|
+
# An accent character that has no function mapping arrives as a plain
|
|
126
|
+
# symbol; promote it here, where it is unambiguously an accent.
|
|
127
|
+
if overscript.instance_of?(Plurimath::Math::Symbols::Symbol)
|
|
128
|
+
overscript =
|
|
129
|
+
Utility.contextual_accent_from_token(overscript.value) || overscript
|
|
130
|
+
end
|
|
125
131
|
options = {}
|
|
126
132
|
options[:accent] = true if truthy_mathml_bool?(mover.accent)
|
|
127
133
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plurimath
|
|
4
|
+
class Mathml
|
|
5
|
+
module FunctionTokenResolver
|
|
6
|
+
# Promotes an accent character to its function class. Callers must only
|
|
7
|
+
# use this from an accent position; elsewhere the character has to stay a
|
|
8
|
+
# plain symbol/text. Decode-then-encode normalizes both call sites: MathML
|
|
9
|
+
# passes an already-encoded "̃", OMML passes the raw U+0303.
|
|
10
|
+
def contextual_accent_from_token(value)
|
|
11
|
+
return nil if value.nil?
|
|
12
|
+
|
|
13
|
+
entity = string_to_html_entity(html_entity_to_unicode(value.to_s))
|
|
14
|
+
function_name =
|
|
15
|
+
Mathml::Constants::CONTEXTUAL_ACCENT_FUNCTIONS[entity.strip.to_sym]
|
|
16
|
+
get_class(function_name).new if function_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def function_from_token(value)
|
|
22
|
+
return nil if value.nil?
|
|
23
|
+
|
|
24
|
+
string = value.to_s
|
|
25
|
+
word = string.strip
|
|
26
|
+
unicode = string_to_html_entity(string)
|
|
27
|
+
symbol = Mathml::Constants::UNICODE_SYMBOLS[unicode.strip.to_sym]&.strip
|
|
28
|
+
function_name =
|
|
29
|
+
if Mathml::Constants::CLASSES.include?(symbol)
|
|
30
|
+
symbol
|
|
31
|
+
elsif Mathml::Constants::CLASSES.include?(word) &&
|
|
32
|
+
Mathml::Constants.named_function_word?(word)
|
|
33
|
+
word
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
get_class(function_name).new if function_name
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Utility < Plurimath::Utility
|
|
41
|
+
extend FunctionTokenResolver
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
def resolve_token(value)
|
|
45
|
+
return nil if value.nil?
|
|
46
|
+
|
|
47
|
+
function_from_token(value) ||
|
|
48
|
+
symbols_class(string_to_html_entity(value.to_s), lang: :mathml)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/plurimath/mathml.rb
CHANGED
|
@@ -6,6 +6,7 @@ module Plurimath
|
|
|
6
6
|
autoload :FormulaTransformation, "#{__dir__}/mathml/formula_transformation"
|
|
7
7
|
autoload :Parser, "#{__dir__}/mathml/parser"
|
|
8
8
|
autoload :Translator, "#{__dir__}/mathml/translator"
|
|
9
|
+
autoload :Utility, "#{__dir__}/mathml/utility"
|
|
9
10
|
|
|
10
11
|
attr_accessor :text
|
|
11
12
|
|
|
@@ -62,7 +62,7 @@ module Plurimath
|
|
|
62
62
|
return Math::Function::Text.new("", lang: :omml) if value == ""
|
|
63
63
|
return nil if value == "\u200B"
|
|
64
64
|
|
|
65
|
-
Utility.
|
|
65
|
+
Utility.resolve_text_token(value)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def omml_argument_value(node)
|
|
@@ -182,7 +182,7 @@ module Plurimath
|
|
|
182
182
|
end
|
|
183
183
|
|
|
184
184
|
def nary_operator(character)
|
|
185
|
-
character && Utility.
|
|
185
|
+
character && Utility.resolve_symbol_token(character)
|
|
186
186
|
end
|
|
187
187
|
|
|
188
188
|
def nary_type(properties)
|
|
@@ -228,13 +228,13 @@ module Plurimath
|
|
|
228
228
|
delimiter_symbol(character.val)
|
|
229
229
|
end
|
|
230
230
|
|
|
231
|
-
def accent_value(
|
|
232
|
-
accent = value.first
|
|
231
|
+
def accent_value(accent, argument)
|
|
233
232
|
unless accent.is_a?(Math::Function::UnaryFunction)
|
|
234
|
-
return Math::Function::Overset.new(accent,
|
|
233
|
+
return Math::Function::Overset.new(accent, argument,
|
|
235
234
|
{ accent: true })
|
|
236
235
|
end
|
|
237
236
|
|
|
237
|
+
accent.parameter_one ||= argument
|
|
238
238
|
accent.attributes = { accent: true }
|
|
239
239
|
accent
|
|
240
240
|
end
|
|
@@ -169,7 +169,6 @@ module Plurimath
|
|
|
169
169
|
omml_argument_value(node.f_name),
|
|
170
170
|
omml_argument_value(node.e),
|
|
171
171
|
],
|
|
172
|
-
lang: :omml,
|
|
173
172
|
),
|
|
174
173
|
)
|
|
175
174
|
end
|
|
@@ -204,10 +203,14 @@ module Plurimath
|
|
|
204
203
|
def accent_to_plurimath(node)
|
|
205
204
|
pr = first_omml_child(node.acc_pr)
|
|
206
205
|
chr = first_omml_child(pr&.chr)&.val
|
|
207
|
-
accent =
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
206
|
+
accent =
|
|
207
|
+
if chr
|
|
208
|
+
Utility.contextual_accent_from_token(chr) ||
|
|
209
|
+
Utility.resolve_symbol_token(chr)
|
|
210
|
+
else
|
|
211
|
+
Math::Function::Hat.new
|
|
212
|
+
end
|
|
213
|
+
accent_value(accent, omml_argument_value(node.e))
|
|
211
214
|
end
|
|
212
215
|
|
|
213
216
|
def bar_to_plurimath(node)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "plurimath/mathml/utility"
|
|
4
|
+
|
|
5
|
+
module Plurimath
|
|
6
|
+
class Omml
|
|
7
|
+
# Omml-specific helper extracted from Plurimath::Utility (code-quality
|
|
8
|
+
# refactor). Subclasses Utility so bareword `Utility.<generic>` calls inside
|
|
9
|
+
# Omml files keep resolving here and inherit the generic helpers.
|
|
10
|
+
class Utility < Plurimath::Utility
|
|
11
|
+
extend Plurimath::Mathml::FunctionTokenResolver
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def valid_class(object)
|
|
15
|
+
text = object.extract_class_name_from_text
|
|
16
|
+
(object.extractable? && Asciimath::Constants::SUB_SUP_CLASSES.include?(text)) ||
|
|
17
|
+
Latex::Constants::SYMBOLS[text&.to_sym] == :power_base
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def resolve_text_token(value)
|
|
21
|
+
return nil if value.nil?
|
|
22
|
+
|
|
23
|
+
function_from_token(value) || text_token(value)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def resolve_symbol_token(value)
|
|
27
|
+
return nil if value.nil?
|
|
28
|
+
|
|
29
|
+
function_from_token(value) ||
|
|
30
|
+
symbols_class(string_to_html_entity(value.to_s), lang: :omml)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def populate_function_classes(mrow = [])
|
|
34
|
+
flatten_mrow = mrow.flatten.compact
|
|
35
|
+
unary_function_classes(flatten_mrow)
|
|
36
|
+
binary_function_classes(flatten_mrow)
|
|
37
|
+
ternary_function_classes(flatten_mrow)
|
|
38
|
+
flatten_mrow
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def binary_function_classes(mrow)
|
|
44
|
+
mrow.each_with_index do |object, ind|
|
|
45
|
+
mrow[ind] = resolve_symbol_token(object) if object.is_a?(String)
|
|
46
|
+
object = mrow[ind]
|
|
47
|
+
next unless object.is_a?(Math::Function::Mod)
|
|
48
|
+
|
|
49
|
+
object.parameter_one = mrow.delete_at(ind - 1) unless ind.zero?
|
|
50
|
+
object.parameter_two = mrow.delete_at(ind)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def unary_function_classes(mrow)
|
|
55
|
+
unary_class = Math::Function::UnaryFunction
|
|
56
|
+
if mrow.any?(String) || mrow.any?(unary_class)
|
|
57
|
+
mrow.each_with_index do |object, ind|
|
|
58
|
+
if object.is_a?(String)
|
|
59
|
+
mrow[ind] = resolve_symbol_token(object)
|
|
60
|
+
object = mrow[ind]
|
|
61
|
+
end
|
|
62
|
+
next unless object.is_a?(unary_class)
|
|
63
|
+
next if object.is_a?(Math::Function::Text)
|
|
64
|
+
next if object.parameter_one || mrow[ind + 1].nil?
|
|
65
|
+
next unless ind.zero?
|
|
66
|
+
|
|
67
|
+
object.parameter_one = mrow.delete_at(ind + 1)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def ternary_function_classes(mrow)
|
|
73
|
+
ternary_class = Math::Function::TernaryFunction
|
|
74
|
+
if mrow.any?(ternary_class) && mrow.length > 1
|
|
75
|
+
mrow.each_with_index do |object, ind|
|
|
76
|
+
if object.is_a?(ternary_class)
|
|
77
|
+
next if [Math::Function::Fenced, Math::Function::Multiscript].include?(object.class)
|
|
78
|
+
next unless object.parameter_one || object.parameter_two
|
|
79
|
+
next if object.parameter_three
|
|
80
|
+
|
|
81
|
+
object.parameter_three = filter_values(mrow.delete_at(ind + 1))
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def text_token(text)
|
|
88
|
+
text = filter_values(text) unless text.is_a?(String)
|
|
89
|
+
return text if text.is_a?(Math::Core)
|
|
90
|
+
|
|
91
|
+
if text.scan(/[[:digit:]]/).length == text.length
|
|
92
|
+
Math::Number.new(text)
|
|
93
|
+
elsif text.match?(/[a-zA-Z]/)
|
|
94
|
+
Math::Function::Text.new(text, lang: :omml)
|
|
95
|
+
else
|
|
96
|
+
text = string_to_html_entity(text)
|
|
97
|
+
.gsub("&", "&")
|
|
98
|
+
.gsub("<", "<")
|
|
99
|
+
.gsub("'", "'")
|
|
100
|
+
.gsub(" ", "\u00A0")
|
|
101
|
+
.gsub(">", ">")
|
|
102
|
+
.gsub("
", "\n")
|
|
103
|
+
symbols_class(text, lang: :omml)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/plurimath/omml.rb
CHANGED
|
@@ -22,6 +22,7 @@ module Plurimath
|
|
|
22
22
|
autoload :FormulaTransformation, "#{__dir__}/omml/formula_transformation"
|
|
23
23
|
autoload :Parser, "#{__dir__}/omml/parser"
|
|
24
24
|
autoload :Translator, "#{__dir__}/omml/translator"
|
|
25
|
+
autoload :Utility, "#{__dir__}/omml/utility"
|
|
25
26
|
autoload :UnsupportedNodeError,
|
|
26
27
|
"#{__dir__}/errors/omml/unsupported_node_error"
|
|
27
28
|
|
|
@@ -116,7 +116,11 @@ module Plurimath
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
rule(prefixed_prime: simple(:prime)) do
|
|
119
|
-
|
|
119
|
+
# Normalize the slash-prefixed name (\prime, \pprime, ...) to its entity
|
|
120
|
+
# so the enclosing prime_accent_symbols handling resolves it like the
|
|
121
|
+
# direct entity forms. Resolving to a node here instead would be dropped
|
|
122
|
+
# by the outer updated_primes re-scan (which only matches entities).
|
|
123
|
+
Constants::PREFIXED_PRIMES[prime.to_s.to_sym] || prime
|
|
120
124
|
end
|
|
121
125
|
|
|
122
126
|
rule(unary_functions: simple(:unary)) do
|