plurimath 0.2.0 → 0.2.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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +13 -0
  3. data/.github/workflows/release.yml +22 -0
  4. data/.gitignore +1 -0
  5. data/.hound.yml +5 -0
  6. data/.rubocop.yml +8 -0
  7. data/AsciiMath-Supported-Data.adoc +2000 -0
  8. data/Gemfile +3 -0
  9. data/Latex-Supported-Data.adoc +1879 -0
  10. data/MathML-Supported-Data.adoc +287 -0
  11. data/README.adoc +96 -0
  12. data/lib/plurimath/asciimath/constants.rb +267 -229
  13. data/lib/plurimath/asciimath/parse.rb +125 -26
  14. data/lib/plurimath/asciimath/parser.rb +6 -3
  15. data/lib/plurimath/asciimath/transform.rb +1135 -208
  16. data/lib/plurimath/asciimath.rb +1 -1
  17. data/lib/plurimath/html/constants.rb +50 -0
  18. data/lib/plurimath/html/parse.rb +149 -0
  19. data/lib/plurimath/html/parser.rb +26 -0
  20. data/lib/plurimath/html/transform.rb +363 -0
  21. data/lib/plurimath/html.rb +1 -1
  22. data/lib/plurimath/latex/constants.rb +3729 -1906
  23. data/lib/plurimath/latex/parse.rb +167 -51
  24. data/lib/plurimath/latex/parser.rb +12 -4
  25. data/lib/plurimath/latex/transform.rb +598 -183
  26. data/lib/plurimath/math/base.rb +15 -0
  27. data/lib/plurimath/math/formula.rb +96 -11
  28. data/lib/plurimath/math/function/bar.rb +34 -0
  29. data/lib/plurimath/math/function/base.rb +32 -5
  30. data/lib/plurimath/math/function/binary_function.rb +104 -17
  31. data/lib/plurimath/math/function/cancel.rb +8 -0
  32. data/lib/plurimath/math/function/ceil.rb +3 -0
  33. data/lib/plurimath/math/function/color.rb +16 -6
  34. data/lib/plurimath/math/function/f.rb +8 -0
  35. data/lib/plurimath/math/function/fenced.rb +95 -3
  36. data/lib/plurimath/math/function/floor.rb +15 -0
  37. data/lib/plurimath/math/function/font_style/bold.rb +37 -0
  38. data/lib/plurimath/math/function/font_style/double_struck.rb +37 -0
  39. data/lib/plurimath/math/function/font_style/fraktur.rb +37 -0
  40. data/lib/plurimath/math/function/font_style/italic.rb +37 -0
  41. data/lib/plurimath/math/function/font_style/monospace.rb +37 -0
  42. data/lib/plurimath/math/function/font_style/normal.rb +37 -0
  43. data/lib/plurimath/math/function/font_style/sans-serif.rb +37 -0
  44. data/lib/plurimath/math/function/font_style/script.rb +37 -0
  45. data/lib/plurimath/math/function/font_style.rb +18 -25
  46. data/lib/plurimath/math/function/frac.rb +35 -5
  47. data/lib/plurimath/math/function/g.rb +7 -0
  48. data/lib/plurimath/math/function/hat.rb +12 -0
  49. data/lib/plurimath/math/function/inf.rb +21 -1
  50. data/lib/plurimath/math/function/int.rb +23 -2
  51. data/lib/plurimath/math/function/left.rb +25 -4
  52. data/lib/plurimath/math/function/lim.rb +40 -2
  53. data/lib/plurimath/math/function/limits.rb +8 -0
  54. data/lib/plurimath/math/function/log.rb +61 -4
  55. data/lib/plurimath/math/function/longdiv.rb +12 -0
  56. data/lib/plurimath/math/function/mbox.rb +31 -0
  57. data/lib/plurimath/math/function/menclose.rb +46 -0
  58. data/lib/plurimath/math/function/merror.rb +12 -0
  59. data/lib/plurimath/math/function/mod.rb +25 -4
  60. data/lib/plurimath/math/function/msgroup.rb +37 -0
  61. data/lib/plurimath/math/function/msline.rb +12 -0
  62. data/lib/plurimath/math/function/multiscript.rb +30 -0
  63. data/lib/plurimath/math/function/norm.rb +18 -1
  64. data/lib/plurimath/math/function/obrace.rb +17 -0
  65. data/lib/plurimath/math/function/oint.rb +2 -2
  66. data/lib/plurimath/math/function/over.rb +36 -0
  67. data/lib/plurimath/math/function/overset.rb +36 -7
  68. data/lib/plurimath/math/function/phantom.rb +28 -0
  69. data/lib/plurimath/math/function/power.rb +33 -9
  70. data/lib/plurimath/math/function/power_base.rb +110 -5
  71. data/lib/plurimath/math/function/prod.rb +29 -2
  72. data/lib/plurimath/math/function/right.rb +44 -0
  73. data/lib/plurimath/math/function/root.rb +27 -4
  74. data/lib/plurimath/math/function/rule.rb +33 -0
  75. data/lib/plurimath/math/function/scarries.rb +12 -0
  76. data/lib/plurimath/math/function/scarry.rb +12 -0
  77. data/lib/plurimath/math/function/sqrt.rb +24 -2
  78. data/lib/plurimath/math/function/stackrel.rb +27 -0
  79. data/lib/plurimath/math/function/substack.rb +7 -1
  80. data/lib/plurimath/math/function/sum.rb +56 -2
  81. data/lib/plurimath/math/function/sup.rb +3 -0
  82. data/lib/plurimath/math/function/table/align.rb +24 -0
  83. data/lib/plurimath/math/function/table/array.rb +44 -0
  84. data/lib/plurimath/math/function/table/bmatrix.rb +37 -0
  85. data/lib/plurimath/math/function/table/matrix.rb +32 -0
  86. data/lib/plurimath/math/function/table/multline.rb +24 -0
  87. data/lib/plurimath/math/function/table/pmatrix.rb +24 -0
  88. data/lib/plurimath/math/function/table/split.rb +24 -0
  89. data/lib/plurimath/math/function/table/vmatrix.rb +24 -0
  90. data/lib/plurimath/math/function/table.rb +190 -20
  91. data/lib/plurimath/math/function/td.rb +27 -9
  92. data/lib/plurimath/math/function/ternary_function.rb +83 -8
  93. data/lib/plurimath/math/function/text.rb +45 -8
  94. data/lib/plurimath/math/function/tr.rb +28 -4
  95. data/lib/plurimath/math/function/ubrace.rb +17 -0
  96. data/lib/plurimath/math/function/ul.rb +29 -0
  97. data/lib/plurimath/math/function/unary_function.rb +85 -7
  98. data/lib/plurimath/math/function/underline.rb +12 -0
  99. data/lib/plurimath/math/function/underover.rb +107 -0
  100. data/lib/plurimath/math/function/underset.rb +39 -0
  101. data/lib/plurimath/math/function/vec.rb +10 -0
  102. data/lib/plurimath/math/function.rb +13 -2
  103. data/lib/plurimath/math/number.rb +11 -3
  104. data/lib/plurimath/math/symbol.rb +57 -9
  105. data/lib/plurimath/math/unicode.rb +11 -0
  106. data/lib/plurimath/math.rb +15 -6
  107. data/lib/plurimath/mathml/constants.rb +224 -179
  108. data/lib/plurimath/mathml/parser.rb +24 -7
  109. data/lib/plurimath/mathml/transform.rb +249 -148
  110. data/lib/plurimath/mathml.rb +1 -1
  111. data/lib/plurimath/omml/parser.rb +42 -0
  112. data/lib/plurimath/omml/transform.rb +278 -0
  113. data/lib/plurimath/omml.rb +1 -1
  114. data/lib/plurimath/unitsml.rb +4 -0
  115. data/lib/plurimath/utility.rb +395 -0
  116. data/lib/plurimath/version.rb +1 -1
  117. data/plurimath.gemspec +1 -0
  118. metadata +66 -9
  119. data/.github/workflows/test.yml +0 -36
  120. data/README.md +0 -40
  121. data/lib/plurimath/mathml/parse.rb +0 -63
@@ -0,0 +1,278 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+ module Plurimath
5
+ class Omml
6
+ class Transform < Parslet::Transform
7
+ rule(t: simple(:t)) { Utility.text_classes(t) }
8
+ rule(e: subtree(:e)) { e.flatten.compact }
9
+ rule(i: sequence(:i)) { i }
10
+ rule(e: sequence(:e)) { e.flatten.compact }
11
+
12
+ rule(val: simple(:val)) { val }
13
+ rule(dPr: subtree(:dpr)) { dpr }
14
+ rule(num: subtree(:num)) { num }
15
+ rule(den: subtree(:den)) { den }
16
+ rule(rPr: subtree(:rPr)) { nil }
17
+ rule(fPr: subtree(:fPr)) { nil }
18
+ rule(mpr: subtree(:mpr)) { nil }
19
+ rule(mPr: subtree(:mPr)) { nil }
20
+ rule(box: subtree(:box)) { box.flatten.compact }
21
+ rule(deg: sequence(:deg)) { Utility.filter_values(deg) }
22
+ rule(sub: sequence(:sub)) { Utility.filter_values(sub) }
23
+ rule(sup: sequence(:sup)) { Utility.filter_values(sup) }
24
+ rule(boxPr: subtree(:box)) { nil }
25
+ rule(argPr: subtree(:arg)) { nil }
26
+ rule(accPr: subtree(:acc)) { acc.flatten.compact }
27
+
28
+ rule(sSubPr: subtree(:arg)) { nil }
29
+ rule(space: simple(:space)) { space }
30
+ rule(radPr: subtree(:radpr)) { nil }
31
+ rule(barPr: subtree(:barpr)) { barpr }
32
+ rule(oMath: subtree(:omath)) { omath.flatten.compact }
33
+ rule(fName: subtree(:fname)) { fname }
34
+ rule(oMath: sequence(:omath)) { omath }
35
+ rule(limLoc: simple(:limLoc)) { limLoc }
36
+ rule(begChr: simple(:begChr)) { Math::Symbol.new(begChr) }
37
+ rule(endChr: simple(:endChr)) { Math::Symbol.new(endChr) }
38
+
39
+ rule(rFonts: subtree(:rFonts)) { nil }
40
+ rule(sSupPr: subtree(:ssuppr)) { nil }
41
+ rule(sPrePr: subtree(:sprepr)) { nil }
42
+ rule(funcPr: subtree(:funcpr)) { nil }
43
+ rule(naryPr: subtree(:narypr)) { narypr }
44
+ rule(subHide: simple(:subHide)) { nil }
45
+ rule(supHide: simple(:supHide)) { nil }
46
+ rule(degHide: simple(:degHide)) { nil }
47
+ rule(ctrlPr: sequence(:ctrlpr)) { ctrlpr }
48
+ rule(eqArrPr: subtree(:eqarrpr)) { eqarrpr.flatten.compact }
49
+
50
+ rule(sequence: subtree(:sequence)) { sequence.flatten.compact }
51
+ rule(limUppPr: subtree(:limUppPr)) { nil }
52
+ rule(limLowPr: subtree(:limLowpr)) { nil }
53
+ rule(sequence: sequence(:sequence)) { sequence }
54
+ rule(sSubSupPr: subtree(:sSubSuppr)) { nil }
55
+
56
+ rule(groupChrPr: subtree(:groupchrpr)) { groupchrpr }
57
+ rule(borderBoxPr: subtree(:borderBoxpr)) { nil }
58
+ rule(lastRenderedPageBreak: sequence(:break)) { nil }
59
+
60
+ rule(f: subtree(:f)) do
61
+ Math::Function::Frac.new(
62
+ Utility.filter_values(f[1]),
63
+ Utility.filter_values(f[2]),
64
+ )
65
+ end
66
+
67
+ rule(r: sequence(:r)) do
68
+ Math::Formula.new(
69
+ r.flatten.compact,
70
+ )
71
+ end
72
+
73
+ rule(m: sequence(:m)) do
74
+ Math::Function::Table.new(
75
+ m.flatten.compact,
76
+ )
77
+ end
78
+
79
+ rule(t: sequence(:t)) do
80
+ if t.empty?
81
+ Math::Function::Text.new
82
+ else
83
+ Utility.text_classes(t)
84
+ end
85
+ end
86
+
87
+ rule(d: subtree(:data)) do
88
+ fenced = data.flatten.compact
89
+ open_paren = fenced.shift if fenced.first.class_name == "symbol"
90
+ close_paren = fenced.shift if fenced.first.class_name == "symbol"
91
+ fenced_value = fenced
92
+ Math::Function::Fenced.new(
93
+ open_paren,
94
+ fenced_value,
95
+ close_paren,
96
+ )
97
+ end
98
+
99
+ rule(mr: subtree(:mr)) do
100
+ row = []
101
+ mr.each do |td|
102
+ row << Math::Function::Td.new(
103
+ td.is_a?(Array) ? td : [td],
104
+ )
105
+ end
106
+ Math::Function::Tr.new(row)
107
+ end
108
+
109
+ rule(lim: sequence(:lim)) do
110
+ if lim.any?(String)
111
+ Utility.text_classes(lim)
112
+ else
113
+ Utility.filter_values(lim)
114
+ end
115
+ end
116
+
117
+ rule(acc: subtree(:acc)) do
118
+ acc_value = acc.flatten.compact
119
+ chr = Utility.find_pos_chr(acc_value, :chr)
120
+ chr_value = chr ? chr[:chr] : "^"
121
+ Math::Function::Overset.new(
122
+ Math::Symbol.new(chr_value),
123
+ Utility.filter_values(acc.last),
124
+ )
125
+ end
126
+
127
+ rule(func: subtree(:func)) do
128
+ func_name = func.flatten.compact
129
+ class_object = Utility.find_class_name(func_name.first)
130
+ if class_object
131
+ class_object.new(func_name.last)
132
+ else
133
+ Math::Formula.new(
134
+ func_name,
135
+ )
136
+ end
137
+ end
138
+
139
+ rule(nary: subtree(:nary)) do
140
+ Math::Formula.new(
141
+ [
142
+ Utility.nary_fonts(nary),
143
+ Utility.filter_values(nary[3]),
144
+ ],
145
+ )
146
+ end
147
+
148
+ rule(groupChr: subtree(:groupchr)) do
149
+ chr_pos = groupchr.first
150
+ pos = Utility.find_pos_chr(chr_pos, :pos)
151
+ chr = Utility.find_pos_chr(chr_pos, :chr)
152
+ if pos&.value?("top")
153
+ Math::Function::Overset.new(
154
+ Math::Symbol.new(chr ? chr[:chr] : ""),
155
+ Utility.filter_values(groupchr[1]),
156
+ )
157
+ else
158
+ Math::Function::Underset.new(
159
+ Math::Symbol.new(chr ? chr[:chr] : "⏟"),
160
+ Utility.filter_values(groupchr[1]),
161
+ )
162
+ end
163
+ end
164
+
165
+ rule(sSubSup: subtree(:sSubSup)) do
166
+ subsup = sSubSup.flatten.compact
167
+ subsup.each_with_index do |object, ind|
168
+ subsup[ind] = Utility.mathml_unary_classes([object]) if object.is_a?(String)
169
+ end
170
+ Math::Function::PowerBase.new(
171
+ subsup[0],
172
+ subsup[1],
173
+ subsup[2],
174
+ )
175
+ end
176
+
177
+ rule(sSup: subtree(:ssup)) do
178
+ sup = ssup.flatten.compact
179
+ Math::Function::Power.new(
180
+ sup[0],
181
+ sup[1],
182
+ )
183
+ end
184
+
185
+ rule(rad: subtree(:rad)) do
186
+ if rad[1].nil?
187
+ Math::Function::Sqrt.new(
188
+ Utility.filter_values(rad[2]),
189
+ )
190
+ else
191
+ Math::Function::Root.new(
192
+ Utility.filter_values(rad[2]),
193
+ rad[1],
194
+ )
195
+ end
196
+ end
197
+
198
+ rule(sSub: subtree(:ssub)) do
199
+ sub = ssub.flatten.compact
200
+ Plurimath::Math::Function::Base.new(
201
+ sub[0],
202
+ sub[1],
203
+ )
204
+ end
205
+
206
+ rule(limUpp: subtree(:limUpp)) do
207
+ lim_values = limUpp.flatten.compact
208
+ first_value = lim_values[0]
209
+ Math::Function::Overset.new(
210
+ first_value,
211
+ lim_values[1],
212
+ )
213
+ end
214
+
215
+ rule(limLow: subtree(:lim)) do
216
+ Math::Function::Underset.new(
217
+ Utility.filter_values(lim[1]),
218
+ Utility.filter_values(lim[2]),
219
+ )
220
+ end
221
+
222
+ rule(borderBox: subtree(:box)) do
223
+ Math::Function::Menclose.new(
224
+ "longdiv",
225
+ Utility.filter_values(box[1]),
226
+ )
227
+ end
228
+
229
+ rule(bar: subtree(:bar)) do
230
+ barpr = bar&.flatten&.compact
231
+ pospr = Utility.find_pos_chr(bar.first, :pos)
232
+ class_name = if pospr&.value?("top")
233
+ Math::Function::Bar
234
+ else
235
+ Math::Function::Ul
236
+ end
237
+ class_name.new(barpr.last)
238
+ end
239
+
240
+ rule(sPre: subtree(:spre)) do
241
+ pre = spre.flatten.compact
242
+ Math::Function::Multiscript.new(
243
+ pre[2],
244
+ pre[0],
245
+ pre[1],
246
+ )
247
+ end
248
+
249
+ rule(eqArr: subtree(:eqArr)) do
250
+ table_value = []
251
+ eqArr.delete_at(0)
252
+ eqArr.each do |value|
253
+ table_value << Math::Function::Tr.new(
254
+ [
255
+ Math::Function::Td.new(
256
+ value.is_a?(Array) ? value : [value],
257
+ ),
258
+ ],
259
+ )
260
+ end
261
+ Math::Function::Table.new(table_value)
262
+ end
263
+
264
+ rule(ascii: simple(:ascii),
265
+ hAnsi: simple(:hansi)) do
266
+ nil
267
+ end
268
+
269
+ rule(attributes: simple(:attributes), value: sequence(:value)) do
270
+ if value.any? || attributes == "preserve"
271
+ value.any? ? value : [" "]
272
+ else
273
+ attributes
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end
@@ -9,7 +9,7 @@ module Plurimath
9
9
  end
10
10
 
11
11
  def to_formula
12
- # TODO: Will be implemented soon
12
+ Parser.new(text).parse
13
13
  end
14
14
  end
15
15
  end
@@ -7,5 +7,9 @@ module Plurimath
7
7
  def initialize(text)
8
8
  @text = text
9
9
  end
10
+
11
+ def to_formula
12
+ # TODO: Will be implemented soon
13
+ end
10
14
  end
11
15
  end
@@ -0,0 +1,395 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plurimath
4
+ class Utility
5
+ FONT_STYLES = {
6
+ "double-struck": Math::Function::FontStyle::DoubleStruck,
7
+ "sans-serif": Math::Function::FontStyle::SansSerif,
8
+ monospace: Math::Function::FontStyle::Monospace,
9
+ fraktur: Math::Function::FontStyle::Fraktur,
10
+ script: Math::Function::FontStyle::Script,
11
+ normal: Math::Function::FontStyle::Normal,
12
+ bold: Math::Function::FontStyle::Bold,
13
+ mathfrak: Math::Function::FontStyle::Fraktur,
14
+ mathcal: Math::Function::FontStyle::Script,
15
+ mathbb: Math::Function::FontStyle::DoubleStruck,
16
+ mathtt: Math::Function::FontStyle::Monospace,
17
+ mathsf: Math::Function::FontStyle::SansSerif,
18
+ mathrm: Math::Function::FontStyle::Normal,
19
+ textrm: Math::Function::FontStyle::Normal,
20
+ mathbf: Math::Function::FontStyle::Bold,
21
+ textbf: Math::Function::FontStyle::Bold,
22
+ bbb: Math::Function::FontStyle::DoubleStruck,
23
+ cal: Math::Function::FontStyle::Script,
24
+ bf: Math::Function::FontStyle::Bold,
25
+ sf: Math::Function::FontStyle::SansSerif,
26
+ tt: Math::Function::FontStyle::Monospace,
27
+ fr: Math::Function::FontStyle::Fraktur,
28
+ rm: Math::Function::FontStyle::Normal,
29
+ cc: Math::Function::FontStyle::Script,
30
+ ii: Math::Function::FontStyle::Italic,
31
+ bb: Math::Function::FontStyle::Bold,
32
+ }.freeze
33
+ ALIGNMENT_LETTERS = {
34
+ c: "center",
35
+ r: "right",
36
+ l: "left",
37
+ }.freeze
38
+ UNARY_CLASSES = %w[
39
+ arccos
40
+ arcsin
41
+ arctan
42
+ right
43
+ sech
44
+ sinh
45
+ tanh
46
+ cosh
47
+ coth
48
+ csch
49
+ left
50
+ max
51
+ min
52
+ sec
53
+ sin
54
+ deg
55
+ det
56
+ dim
57
+ exp
58
+ gcd
59
+ glb
60
+ lub
61
+ tan
62
+ cos
63
+ cot
64
+ csc
65
+ ln
66
+ lg
67
+ f
68
+ g
69
+ ].freeze
70
+
71
+ class << self
72
+ def organize_table(array, column_align: nil, options: nil)
73
+ table = []
74
+ table_data = []
75
+ table_row = []
76
+ table_separators = ["&", "\\\\"].freeze
77
+ organize_options(array, column_align) if options
78
+ string_columns = column_align&.map(&:value)
79
+ array.each do |data|
80
+ if data.is_a?(Math::Symbol) && table_separators.include?(data.value)
81
+ table_row << Math::Function::Td.new(filter_table_data(table_data).compact)
82
+ table_data = []
83
+ if data.value == "\\\\"
84
+ organize_tds(table_row.flatten, string_columns.dup, options)
85
+ table << Math::Function::Tr.new(table_row)
86
+ table_row = []
87
+ end
88
+ next
89
+ end
90
+ table_data << data
91
+ end
92
+ table_row << Math::Function::Td.new(table_data.compact) if table_data
93
+ unless table_row.nil? || table_row.empty?
94
+ organize_tds(table_row.flatten, string_columns.dup, options)
95
+ table << Math::Function::Tr.new(table_row)
96
+ end
97
+ table_separator(string_columns, table, symbol: "|") unless column_align.nil? || column_align.empty?
98
+ table
99
+ end
100
+
101
+ def organize_options(table_data, column_align)
102
+ return column_align if column_align.length <= 1
103
+
104
+ align = [column_align&.shift]
105
+ table_data.insert(0, *column_align)
106
+ align
107
+ end
108
+
109
+ def table_options(table_data)
110
+ rowline = ""
111
+ table_data.map do |tr|
112
+ if symbol_value(tr&.parameter_one&.first&.parameter_one&.first, "&#x23af;")
113
+ rowline += "solid "
114
+ else
115
+ rowline += "none "
116
+ end
117
+ end
118
+ options = { rowline: rowline.strip } if rowline.include?("solid")
119
+ options || {}
120
+ end
121
+
122
+ def organize_tds(tr_array, column_align, options)
123
+ return tr_array if column_align.nil? || column_align.empty?
124
+
125
+ column_align.reject! { |string| string == "|" }
126
+ column_align = column_align * tr_array.length if options
127
+ tr_array.map.with_index do |td, ind|
128
+ columnalign = ALIGNMENT_LETTERS[column_align[ind]&.to_sym]
129
+ td.parameter_two = { columnalign: columnalign } if columnalign
130
+ end
131
+ end
132
+
133
+ def filter_table_data(table_data)
134
+ table_data.each_with_index do |object, ind|
135
+ if symbol_value(object, "-")
136
+ table_data[ind] = Math::Formula.new(
137
+ [object, table_data.delete_at(ind.next)],
138
+ )
139
+ end
140
+ end
141
+ table_data
142
+ end
143
+
144
+ def get_table_class(text)
145
+ Object.const_get(
146
+ "Plurimath::Math::Function::Table::#{text.to_s.capitalize}",
147
+ )
148
+ end
149
+
150
+ def sub_sup_method?(sub_sup)
151
+ if sub_sup.methods.include?(:class_name)
152
+ Html::Constants::SUB_SUP_CLASSES.value?(sub_sup.class_name.to_sym)
153
+ end
154
+ end
155
+
156
+ def get_class(text)
157
+ text = text.to_s.split("_").map(&:capitalize).join
158
+ Object.const_get(
159
+ "Plurimath::Math::Function::#{text}",
160
+ )
161
+ end
162
+
163
+ def ox_element(node, attributes: [], namespace: "")
164
+ namespace = "#{namespace}:" unless namespace.empty?
165
+
166
+ element = Ox::Element.new("#{namespace}#{node}")
167
+ attributes&.each do |attr_key, attr_value|
168
+ element[attr_key] = attr_value
169
+ end
170
+ element
171
+ end
172
+
173
+ def rpr_element(wi_tag: false)
174
+ rpr_element = ox_element("rPr", namespace: "w")
175
+ attributes = { "w:ascii": "Cambria Math", "w:hAnsi": "Cambria Math" }
176
+ rpr_element << ox_element(
177
+ "rFonts",
178
+ namespace: "w",
179
+ attributes: attributes,
180
+ )
181
+ rpr_element << ox_element("i", namespace: "w") if wi_tag
182
+ rpr_element
183
+ end
184
+
185
+ def update_nodes(element, nodes)
186
+ nodes&.each { |node| element << node unless node.nil? }
187
+ element
188
+ end
189
+
190
+ def pr_element(main_tag, wi_tag, namespace: "")
191
+ tag_name = "#{main_tag}Pr"
192
+ ox_element(
193
+ tag_name,
194
+ namespace: namespace,
195
+ ) << rpr_element(wi_tag: wi_tag)
196
+ end
197
+
198
+ def filter_values(array)
199
+ return array unless array.is_a?(Array)
200
+
201
+ array = array.flatten.compact
202
+ if array.length > 1
203
+ return Math::Formula.new(array)
204
+ end
205
+
206
+ array.first
207
+ end
208
+
209
+ def text_classes(text)
210
+ return nil if text.empty?
211
+
212
+ text = filter_values(text) unless text.is_a?(String)
213
+ if text.scan(/[[:digit:]]/).length == text.length
214
+ Math::Number.new(text)
215
+ elsif text.match?(/[a-zA-Z]/)
216
+ Math::Function::Text.new(text)
217
+ else
218
+ Math::Symbol.new(text)
219
+ end
220
+ end
221
+
222
+ def nary_fonts(nary)
223
+ narypr = nary.first.flatten.compact
224
+ subsup = narypr.any?("undOvr") ? "underover" : "power_base"
225
+ get_class(subsup).new(
226
+ Math::Symbol.new(narypr.any?(Hash) ? narypr.first[:chr] : "∫"),
227
+ nary[1],
228
+ nary[2],
229
+ )
230
+ end
231
+
232
+ def find_class_name(object)
233
+ new_object = object.value.first.parameter_one if object.is_a?(Math::Formula)
234
+ get_class(new_object) unless new_object.nil?
235
+ end
236
+
237
+ def find_pos_chr(fonts_array, key)
238
+ fonts_array.find { |d| d.is_a?(Hash) && d[key] }
239
+ end
240
+
241
+ def td_values(objects, slicer)
242
+ sliced = objects.slice_when { |object, _| symbol_value(object, slicer) }
243
+ tds = sliced.map do |slice|
244
+ Math::Function::Td.new(
245
+ slice.delete_if { |d| symbol_value(d, slicer) }.compact,
246
+ )
247
+ end
248
+ tds << Math::Function::Td.new([]) if symbol_value(objects.last, slicer)
249
+ tds
250
+ end
251
+
252
+ def symbol_value(object, value)
253
+ object.is_a?(Math::Symbol) && object.value.include?(value)
254
+ end
255
+
256
+ def td_value(td_object)
257
+ if td_object.is_a?(String) && td_object.empty?
258
+ return Math::Function::Text.new(nil)
259
+ end
260
+
261
+ td_object
262
+ end
263
+
264
+ def mathml_unary_classes(text_array)
265
+ return [] if text_array.empty?
266
+
267
+ compacted = text_array.compact
268
+ string = if compacted.count == 1
269
+ compacted.first
270
+ else
271
+ compacted.join
272
+ end
273
+ return string unless string.is_a?(String)
274
+
275
+ classes = Mathml::Constants::CLASSES
276
+ unicode = string_to_html_entity(string)
277
+ symbol = Mathml::Constants::UNICODE_SYMBOLS[unicode.strip.to_sym]
278
+ if classes.include?(symbol&.strip)
279
+ get_class(symbol.strip).new
280
+ elsif classes.any?(string&.strip)
281
+ get_class(string.strip).new
282
+ else
283
+ Math::Symbol.new(unicode)
284
+ end
285
+ end
286
+
287
+ def string_to_html_entity(string)
288
+ entities = HTMLEntities.new
289
+ entities.encode(string, :hexadecimal)
290
+ end
291
+
292
+ def table_separator(separator, value, symbol: "solid")
293
+ sep_symbol = Math::Function::Td.new([Math::Symbol.new("|")])
294
+ separator&.each_with_index do |sep, ind|
295
+ next unless sep == symbol
296
+
297
+ value.map do |val|
298
+ val.parameter_one.insert((ind + 1), sep_symbol) if symbol == "solid"
299
+ val.parameter_one.insert(ind, sep_symbol) if symbol == "|"
300
+ (val.parameter_one[val.parameter_one.index(nil)] = Math::Function::Td.new([])) rescue nil
301
+ val
302
+ end
303
+ end
304
+ value
305
+ end
306
+
307
+ def join_attr_value(attrs, value)
308
+ if value.any?(String)
309
+ new_value = mathml_unary_classes(value)
310
+ array_value = Array(new_value)
311
+ attrs.nil? ? array_value : join_attr_value(attrs, array_value)
312
+ elsif attrs.nil?
313
+ value
314
+ elsif attrs.is_a?(Math::Function::Menclose)
315
+ attrs.parameter_two = filter_values(value)
316
+ attrs
317
+ elsif attrs.is_a?(Math::Function::Fenced)
318
+ attrs.parameter_two = value
319
+ attrs
320
+ elsif attrs.is_a?(Math::Function::FontStyle)
321
+ attrs.parameter_one = filter_values(value)
322
+ attrs
323
+ elsif attrs.is_a?(Math::Function::Color)
324
+ color_value = filter_values(value)
325
+ if attrs.parameter_two
326
+ attrs.parameter_two.parameter_one = color_value
327
+ else
328
+ attrs.parameter_two = color_value
329
+ end
330
+ attrs
331
+ elsif ["solid", "none"].include?(attrs.split.first.downcase)
332
+ table_separator(attrs.split, value)
333
+ end
334
+ end
335
+
336
+ def multiscript(values)
337
+ values.slice_before("mprescripts").map do |value|
338
+ base_value = value.shift
339
+ part_val = value.partition.with_index { |_, i| i.even? }
340
+ first_value = part_val[0].empty? ? nil : filter_values(part_val[0])
341
+ second_value = part_val[1].empty? ? nil : filter_values(part_val[1])
342
+ if base_value.to_s.include?("mprescripts")
343
+ [first_value, second_value]
344
+ else
345
+ Math::Function::PowerBase.new(
346
+ base_value,
347
+ first_value,
348
+ second_value,
349
+ )
350
+ end
351
+ end
352
+ end
353
+
354
+ def unfenced_value(object)
355
+ case object
356
+ when Math::Function::Fenced
357
+ value = filter_values(object.parameter_two)
358
+ unfenced_value(value)
359
+ when Array
360
+ filter_values(object)
361
+ else
362
+ object
363
+ end
364
+ end
365
+
366
+ def frac_values(object)
367
+ case object
368
+ when Math::Formula
369
+ object.value.any? { |d| symbol_value(d, ",") }
370
+ when Array
371
+ object.any? { |d| symbol_value(d, ",") }
372
+ end
373
+ end
374
+
375
+ def table_td(object)
376
+ new_object = case object
377
+ when Math::Function::Td
378
+ object
379
+ else
380
+ Math::Function::Td.new([object])
381
+ end
382
+ Array(new_object)
383
+ end
384
+
385
+ def symbol_object(value)
386
+ value = case value
387
+ when "ℒ" then "{:"
388
+ when "ℛ" then ":}"
389
+ else value
390
+ end
391
+ Math::Symbol.new(value)
392
+ end
393
+ end
394
+ end
395
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plurimath
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
data/plurimath.gemspec CHANGED
@@ -25,4 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
  spec.add_dependency 'parslet'
28
+ spec.add_dependency 'ox'
28
29
  end