plurimath 0.2.0 → 0.2.2

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