plurimath 0.8.17 → 0.8.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/lib/plurimath/asciimath/parse.rb +1 -0
  4. data/lib/plurimath/asciimath/transform.rb +12 -0
  5. data/lib/plurimath/math/core.rb +63 -4
  6. data/lib/plurimath/math/formula/mrow.rb +193 -0
  7. data/lib/plurimath/math/formula/mstyle.rb +17 -0
  8. data/lib/plurimath/math/formula.rb +307 -4
  9. data/lib/plurimath/math/function/base.rb +4 -0
  10. data/lib/plurimath/math/function/color.rb +17 -4
  11. data/lib/plurimath/math/function/fenced.rb +219 -0
  12. data/lib/plurimath/math/function/frac.rb +4 -0
  13. data/lib/plurimath/math/function/linebreak.rb +2 -2
  14. data/lib/plurimath/math/function/longdiv.rb +3 -0
  15. data/lib/plurimath/math/function/menclose.rb +3 -0
  16. data/lib/plurimath/math/function/merror.rb +5 -2
  17. data/lib/plurimath/math/function/mglyph.rb +27 -0
  18. data/lib/plurimath/math/function/mlabeledtr.rb +19 -0
  19. data/lib/plurimath/math/function/mpadded.rb +28 -1
  20. data/lib/plurimath/math/function/ms.rb +80 -0
  21. data/lib/plurimath/math/function/msgroup.rb +15 -0
  22. data/lib/plurimath/math/function/msline.rb +5 -2
  23. data/lib/plurimath/math/function/multiscript.rb +14 -0
  24. data/lib/plurimath/math/function/over.rb +3 -0
  25. data/lib/plurimath/math/function/overset.rb +11 -0
  26. data/lib/plurimath/math/function/phantom.rb +3 -0
  27. data/lib/plurimath/math/function/power.rb +3 -0
  28. data/lib/plurimath/math/function/power_base.rb +3 -0
  29. data/lib/plurimath/math/function/root.rb +3 -0
  30. data/lib/plurimath/math/function/scarries.rb +3 -0
  31. data/lib/plurimath/math/function/semantics.rb +14 -0
  32. data/lib/plurimath/math/function/sqrt.rb +3 -0
  33. data/lib/plurimath/math/function/stackrel.rb +3 -0
  34. data/lib/plurimath/math/function/table.rb +53 -0
  35. data/lib/plurimath/math/function/td.rb +4 -1
  36. data/lib/plurimath/math/function/text.rb +22 -2
  37. data/lib/plurimath/math/function/tr.rb +13 -0
  38. data/lib/plurimath/math/function/underover.rb +3 -0
  39. data/lib/plurimath/math/function/underset.rb +44 -0
  40. data/lib/plurimath/math/number.rb +10 -1
  41. data/lib/plurimath/math/symbols/gg.rb +4 -4
  42. data/lib/plurimath/math/symbols/ll.rb +4 -4
  43. data/lib/plurimath/math/symbols/minus.rb +1 -1
  44. data/lib/plurimath/math/symbols/symbol.rb +12 -4
  45. data/lib/plurimath/math.rb +2 -0
  46. data/lib/plurimath/mathml/parser.rb +45 -86
  47. data/lib/plurimath/mathml/utility/empty_defined_methods.rb +477 -0
  48. data/lib/plurimath/mathml/utility/formula_transformation.rb +472 -0
  49. data/lib/plurimath/mathml/utility.rb +363 -0
  50. data/lib/plurimath/mathml.rb +1 -0
  51. data/lib/plurimath/unicode_math/transform.rb +2 -2
  52. data/lib/plurimath/utility.rb +5 -23
  53. data/lib/plurimath/version.rb +1 -1
  54. data/lib/plurimath.rb +9 -0
  55. data/plurimath.gemspec +4 -2
  56. metadata +37 -5
  57. data/lib/plurimath/mathml/transform.rb +0 -413
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../mathml/utility"
4
+
3
5
  module Plurimath
4
6
  module Math
5
7
  class Formula < Core
8
+ include Mathml::Utility
9
+
6
10
  attr_accessor :value, :left_right_wrapper, :displaystyle, :input_string, :unitsml, :unitsml_xml
7
11
 
8
12
  MATH_ZONE_TYPES = %i[
@@ -168,7 +172,7 @@ module Plurimath
168
172
 
169
173
  def to_display(type = nil, formatter: nil)
170
174
  options = { formatter: formatter }
171
- return type_error! unless MATH_ZONE_TYPES.include?(type.downcase.to_sym)
175
+ return type_error!(type) unless MATH_ZONE_TYPES.include?(type.downcase.to_sym)
172
176
 
173
177
  math_zone = case type
174
178
  when :asciimath
@@ -246,7 +250,7 @@ module Plurimath
246
250
  end
247
251
 
248
252
  def update(object)
249
- self.value = Array(object)
253
+ @value = Array(object).flatten.compact
250
254
  end
251
255
 
252
256
  def cloned_objects
@@ -292,7 +296,6 @@ module Plurimath
292
296
  update(Array(value) + values)
293
297
  end
294
298
 
295
-
296
299
  def mini_sized?
297
300
  true if value&.first&.mini_sized?
298
301
  end
@@ -304,8 +307,302 @@ module Plurimath
304
307
  }
305
308
  end
306
309
 
310
+ def element_order=(value)
311
+ @value = validated_order(value)
312
+ end
313
+
314
+ # Attributes start
315
+ def mathcolor=(value)
316
+ return if value.nil? || value.empty?
317
+
318
+ update(
319
+ [
320
+ Math::Function::Color.new(
321
+ Math::Function::Text.new(value),
322
+ filter_values(@value, array_to_instance: true),
323
+ )
324
+ ]
325
+ )
326
+ end
327
+
328
+ def mathvariant=(value)
329
+ return if value.nil? || value.empty?
330
+ return unless Plurimath::Utility::FONT_STYLES.key?(value.to_sym)
331
+
332
+ update(
333
+ [
334
+ Plurimath::Utility::FONT_STYLES[value.to_sym].new(
335
+ filter_values(@value, array_to_instance: true),
336
+ value,
337
+ )
338
+ ]
339
+ )
340
+ end
341
+
342
+ def intent=(value)
343
+ return unless value
344
+
345
+ self.content = nil
346
+ update(
347
+ [
348
+ Function::Intent.new(
349
+ filter_values(@value, array_to_instance: true),
350
+ Function::Text.new(value),
351
+ )
352
+ ]
353
+ )
354
+ end
355
+ # Attributes end
356
+
357
+ def ms_value=(value)
358
+ return if value.nil? || value.empty?
359
+
360
+ update(
361
+ replace_order_with_value(
362
+ @value,
363
+ Array(validate_symbols(value)),
364
+ "ms"
365
+ )
366
+ )
367
+ end
368
+
369
+ def mi_value=(value)
370
+ return if value.nil? || value.empty?
371
+
372
+ value = update_temp_mathml_values(value) if value.any? do |val|
373
+ val.is_a?(Math::Core) && val.temp_mathml_order.any?
374
+ end
375
+ update(
376
+ replace_order_with_value(
377
+ @value,
378
+ Array(validate_symbols(value)).flatten,
379
+ "mi"
380
+ )
381
+ )
382
+ end
383
+
384
+ def mn_value=(value)
385
+ return if value.nil? || value.empty?
386
+
387
+ update(
388
+ replace_order_with_value(
389
+ @value,
390
+ Array(validate_symbols(value)),
391
+ "mn"
392
+ )
393
+ )
394
+ end
395
+
396
+ def mtext_value=(value)
397
+ return if value.nil? || value.empty?
398
+
399
+ update(
400
+ replace_order_with_value(
401
+ @value,
402
+ Array(validate_symbols(value)),
403
+ "mtext"
404
+ )
405
+ )
406
+ end
407
+
408
+ def mo_value=(value)
409
+ return if value.nil? || value.empty?
410
+
411
+ value = update_temp_mathml_values(value)
412
+ update(
413
+ replace_order_with_value(
414
+ @value,
415
+ Array(value),
416
+ "mo"
417
+ )
418
+ )
419
+ end
420
+
421
+ def mstyle_value=(value)
422
+ return if value.empty?
423
+
424
+ update(
425
+ filter_values(
426
+ replace_order_with_value(
427
+ @value,
428
+ Array(filter_values(value, array_to_instance: true)),
429
+ "mstyle"
430
+ )
431
+ )
432
+ )
433
+ end
434
+
435
+ def mrow_value=(value)
436
+ return if value.nil? || value.empty?
437
+
438
+ replacing_order = value.length > 1 && value.any?(String)
439
+ update(
440
+ replace_order_with_value(
441
+ @value,
442
+ filter_values(
443
+ value,
444
+ array_to_instance: true,
445
+ replacing_order: replacing_order
446
+ ),
447
+ "mrow"
448
+ )
449
+ )
450
+ end
451
+
452
+ def munderover_value=(value)
453
+ update_temp_order(value, "munderover")
454
+ end
455
+
456
+ def msub_value=(value)
457
+ update_temp_order(value, "msub")
458
+ end
459
+
460
+ def msup_value=(value)
461
+ update_temp_order(value, "msup")
462
+ end
463
+
464
+ def mover_value=(value)
465
+ update_temp_order(value, "mover")
466
+ end
467
+
468
+ def munder_value=(value)
469
+ update_temp_order(value, "munder")
470
+ end
471
+
472
+ def msubsup_value=(value)
473
+ update_temp_order(value, "msubsup")
474
+ end
475
+
476
+ def mfrac_value=(value)
477
+ update_temp_order(value, "mfrac")
478
+ end
479
+
480
+ def msqrt_value=(value)
481
+ update_temp_order(value, "msqrt")
482
+ end
483
+
484
+ def mfenced_value=(value)
485
+ update_temp_order(value, "mfenced")
486
+ end
487
+
488
+ def mroot_value=(value)
489
+ update_temp_order(value, "mroot")
490
+ end
491
+
492
+ def msgroup_value=(value)
493
+ update_temp_order(value, "msgroup")
494
+ end
495
+
496
+ def mscarries_value=(value)
497
+ update_temp_order(value, "mscarries")
498
+ end
499
+
500
+ def msline_value=(value)
501
+ update_temp_order(value, "msline")
502
+ end
503
+
504
+ def msrow_value=(value)
505
+ update_temp_order(value, "msrow")
506
+ end
507
+
508
+ def semantics_value=(value)
509
+ update_temp_order(value, "semantics")
510
+ end
511
+
512
+ def mstack_value=(value)
513
+ update_temp_order(value, "mstack")
514
+ end
515
+
516
+ def merror_value=(value)
517
+ return if value.nil? || value.empty?
518
+
519
+ update(
520
+ replace_order_with_value(
521
+ @value,
522
+ filter_values(update_temp_mathml_values(value)),
523
+ "merror"
524
+ )
525
+ )
526
+ end
527
+
528
+ def mlongdiv_value=(value)
529
+ update_temp_order(value, "mlongdiv")
530
+ end
531
+
532
+ def none_value=(_)
533
+ @value&.delete("none")
534
+ end
535
+
536
+ def maligngroup_value=(value)
537
+ @value&.delete("maligngroup")
538
+ end
539
+
540
+ def menclose_value=(value)
541
+ update_temp_order(value, "menclose")
542
+ end
543
+
544
+ def mspace_value=(value)
545
+ return if value.nil? || value.empty?
546
+
547
+ if value.first.linebreak
548
+ linebreak = Math::Function::Linebreak.new(
549
+ nil,
550
+ { linebreak: value.first.linebreak }
551
+ )
552
+ update(
553
+ replace_order_with_value(
554
+ @value,
555
+ [linebreak],
556
+ "mspace"
557
+ )
558
+ )
559
+ else
560
+ @value&.delete("mspace")
561
+ end
562
+ end
563
+
564
+ def malignmark_value=(value)
565
+ @value&.delete("malignmark")
566
+ end
567
+
568
+ def mpadded_value=(value)
569
+ update_temp_order(value, "mpadded")
570
+ end
571
+
572
+ def mfraction_value=(value)
573
+ update_temp_order(value, "mfraction")
574
+ end
575
+
576
+ def mmultiscripts_value=(value)
577
+ update_temp_order(value, "mmultiscripts")
578
+ end
579
+
580
+ def mphantom_value=(value)
581
+ update_temp_order(value, "mphantom")
582
+ end
583
+
584
+ def mglyph_value=(value)
585
+ update_temp_order(value, "mglyph")
586
+ end
587
+
307
588
  protected
308
589
 
590
+ def update_temp_order(value, order_name)
591
+ return if value.nil? || value.empty?
592
+
593
+ update(
594
+ replace_order_with_value(
595
+ Array(@value),
596
+ Array(update_temp_mathml_values(value)),
597
+ order_name
598
+ )
599
+ )
600
+ end
601
+
602
+ def remove_order(order)
603
+ value.delete_if { |val| val.is_a?(String) && val == order }
604
+ end
605
+
309
606
  def boolean_display_style(display_style = displaystyle)
310
607
  YAML.safe_load(display_style.to_s)
311
608
  end
@@ -561,7 +858,7 @@ module Plurimath
561
858
  mrow_nodes << nodes.delete_at(1)
562
859
  next
563
860
  when "mrow"
564
- second_arg = mrow_nodes.map { |node| encode(node.nodes.first) }.join
861
+ second_arg = mrow_nodes.map { |n| encode(n.nodes.first) }.join
565
862
  third_arg = upcase_dd_intent_name(node.nodes[1..-2])
566
863
  mrow_nodes << nodes.delete_at(1)
567
864
  break
@@ -699,6 +996,12 @@ module Plurimath
699
996
  encode(str)
700
997
  end
701
998
  # Dd derivative nodes end
999
+
1000
+ def type_error!(type)
1001
+ raise Math::InvalidTypeError.new(
1002
+ "Invalid type provided: #{type}. Must be one of #{MATH_ZONE_TYPES.join(', ')}.",
1003
+ )
1004
+ end
702
1005
  end
703
1006
  end
704
1007
  end
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "binary_function"
4
+ require_relative "../../mathml/utility"
4
5
 
5
6
  module Plurimath
6
7
  module Math
7
8
  module Function
8
9
  class Base < BinaryFunction
10
+ include Mathml::Utility
11
+
9
12
  attr_accessor :options
13
+
10
14
  FUNCTION = {
11
15
  name: "subscript",
12
16
  first_value: "base",
@@ -7,6 +7,7 @@ module Plurimath
7
7
  module Function
8
8
  class Color < BinaryFunction
9
9
  attr_accessor :options
10
+
10
11
  FUNCTION = {
11
12
  name: "color",
12
13
  first_value: "mathcolor",
@@ -27,11 +28,10 @@ module Plurimath
27
28
  end
28
29
 
29
30
  def to_mathml_without_math_tag(intent, options:)
30
- color_value = parameter_one&.to_asciimath(options: options)&.gsub(/\s/, "")&.gsub(/"/, "")
31
31
  Utility.update_nodes(
32
32
  Utility.ox_element(
33
33
  "mstyle",
34
- attributes: { attr_key => color_value },
34
+ attributes: mathml_options,
35
35
  ),
36
36
  [parameter_two&.to_mathml_without_math_tag(intent, options: options)],
37
37
  )
@@ -56,13 +56,26 @@ module Plurimath
56
56
  end
57
57
 
58
58
  def to_unicodemath(options:)
59
- "(#{parameter_one.to_unicodemath(options: options)}&#{parameter_two.to_unicodemath(options: options)})"
59
+ "#{color_symbol}(#{parameter_one.to_unicodemath(options: options)}&#{parameter_two.to_unicodemath(options: options)})"
60
60
  end
61
61
 
62
62
  protected
63
63
 
64
+ def color_symbol
65
+ options&.dig(:backgroundcolor) ? "☁" : "✎"
66
+ end
67
+
64
68
  def attr_key
65
- (options && options[:backcolor]) ? :mathbackground : :mathcolor
69
+ options&.dig(:backgroundcolor) ? :mathbackground : :mathcolor
70
+ end
71
+
72
+ def mathml_options
73
+ return unless parameter_one
74
+
75
+ color_options = {}
76
+ color_options[attr_key] =
77
+ parameter_one.to_asciimath(options: options)&.gsub(/\s/, "")&.gsub(/"/, "")
78
+ color_options
66
79
  end
67
80
  end
68
81
  end
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "ternary_function"
4
+ require_relative "../../mathml/utility"
4
5
 
5
6
  module Plurimath
6
7
  module Math
7
8
  module Function
8
9
  class Fenced < TernaryFunction
10
+ include Mathml::Utility
11
+
9
12
  attr_accessor :options
10
13
 
11
14
  def initialize(
@@ -157,8 +160,220 @@ module Plurimath
157
160
  }
158
161
  end
159
162
 
163
+ def separators=(value)
164
+ return if value.nil?
165
+
166
+ @options[:separators] = value
167
+ end
168
+
169
+ def content=(value)
170
+ if parens_nil?
171
+ @parameter_one = Math::Symbols::Paren::Lround.new
172
+ @parameter_three = Math::Symbols::Paren::Rround.new
173
+ end
174
+ end
175
+
176
+ def open=(value)
177
+ return unless value
178
+
179
+ @parameter_one = validate_symbols(value)
180
+ end
181
+
182
+ def close=(value)
183
+ return unless value
184
+
185
+ @parameter_three = validate_symbols(value)
186
+ end
187
+
188
+ def element_order=(value)
189
+ @parameter_two = validated_order(value)
190
+ end
191
+
192
+ def mi_value=(value)
193
+ return if value.nil? || value.empty?
194
+
195
+ update(
196
+ replace_order_with_value(
197
+ @parameter_two,
198
+ Array(validate_symbols(value)),
199
+ "mi"
200
+ )
201
+ )
202
+ end
203
+
204
+ def mn_value=(value)
205
+ return if value.nil? || value.empty?
206
+
207
+ update(
208
+ replace_order_with_value(
209
+ @parameter_two,
210
+ Array(validate_symbols(value)),
211
+ "mn"
212
+ )
213
+ )
214
+ end
215
+
216
+ def mtext_value=(value)
217
+ return if value.nil? || value.empty?
218
+
219
+ update(
220
+ replace_order_with_value(
221
+ @parameter_two,
222
+ Array(validate_symbols(value)),
223
+ "mtext"
224
+ )
225
+ )
226
+ end
227
+
228
+ def mo_value=(value)
229
+ return if value.nil? || value.empty?
230
+
231
+ update(
232
+ replace_order_with_value(
233
+ @parameter_two,
234
+ Array(validate_symbols(value)),
235
+ "mo"
236
+ )
237
+ )
238
+ end
239
+
240
+ def mstyle_value=(value)
241
+ return if value.empty?
242
+
243
+ update(
244
+ replace_order_with_value(
245
+ @parameter_two,
246
+ Array(value),
247
+ "mstyle"
248
+ )
249
+ )
250
+ end
251
+
252
+ def munderover_value=(value)
253
+ update_temp_order(value, "munderover")
254
+ end
255
+
256
+ def msub_value=(value)
257
+ update_temp_order(value, "msub")
258
+ end
259
+
260
+ def msup_value=(value)
261
+ update_temp_order(value, "msup")
262
+ end
263
+
264
+ def mover_value=(value)
265
+ update_temp_order(value, "mover")
266
+ end
267
+
268
+ def munder_value=(value)
269
+ update_temp_order(value, "munder")
270
+ end
271
+
272
+ def msubsup_value=(value)
273
+ update_temp_order(value, "msubsup")
274
+ end
275
+
276
+ def mfrac_value=(value)
277
+ update_temp_order(value, "mfrac")
278
+ end
279
+
280
+ def msqrt_value=(value)
281
+ update_temp_order(value, "msqrt")
282
+ end
283
+
284
+ def mfenced_value=(value)
285
+ update_temp_order(value, "mfenced")
286
+ end
287
+
288
+ def mtable_value=(value)
289
+ return if value.nil? || value.empty?
290
+
291
+ update(
292
+ replace_order_with_value(
293
+ Array(@parameter_two),
294
+ update_temp_mathml_values(value),
295
+ "mtable"
296
+ )
297
+ )
298
+ end
299
+
300
+ def mrow_value=(value)
301
+ return if value.nil? || value.empty?
302
+
303
+ update(
304
+ replace_order_with_value(
305
+ Array(@parameter_two),
306
+ update_temp_mathml_values(
307
+ Array(filter_values(value, array_to_instance: true))
308
+ ),
309
+ "mrow"
310
+ )
311
+ )
312
+ end
313
+
314
+ def mspace_value=(value)
315
+ return if value.nil? || value.empty?
316
+
317
+ if value.first.linebreak
318
+ linebreak = Math::Function::Linebreak.new(
319
+ nil,
320
+ { linebreak: value.first.linebreak }
321
+ )
322
+
323
+ update(
324
+ replace_order_with_value(
325
+ Array(@parameter_two),
326
+ [linebreak],
327
+ "mspace"
328
+ )
329
+ )
330
+ else
331
+ @parameter_two&.delete("mspace")
332
+ end
333
+ end
334
+
335
+ def mpadded_value=(value)
336
+ update_temp_order(value, "mpadded")
337
+ end
338
+
339
+ def mfraction_value=(value)
340
+ update_temp_order(value, "mfraction")
341
+ end
342
+
343
+ def mmultiscripts_value=(value)
344
+ update_temp_order(value, "mmultiscripts")
345
+ end
346
+
347
+ def mphantom_value=(value)
348
+ update_temp_order(value, "mphantom")
349
+ end
350
+
160
351
  protected
161
352
 
353
+ def update_temp_order(value, order_name)
354
+ return if value.nil? || value.empty?
355
+
356
+ update(
357
+ replace_order_with_value(
358
+ Array(@parameter_two),
359
+ update_temp_mathml_values(value),
360
+ order_name
361
+ )
362
+ )
363
+ end
364
+
365
+ def remove_order(order)
366
+ @parameter_two.delete_if { |val| val.is_a?(String) && val == order }
367
+ end
368
+
369
+ def insert(values)
370
+ update(Array(@parameter_two) + values)
371
+ end
372
+
373
+ def update(object)
374
+ @parameter_two = Array(object)
375
+ end
376
+
162
377
  def open_paren(dpr, options:)
163
378
  first_value = symbol_or_paren(parameter_one, lang: :omml, options: options)
164
379
  return dpr if first_value.nil?
@@ -359,6 +574,10 @@ module Plurimath
359
574
  node["intent"]&.start_with?(":partial-derivative") &&
360
575
  !node.locate("*/@arg").include?("f")
361
576
  end
577
+
578
+ def parens_nil?
579
+ @parameter_one.nil? && @parameter_three.nil?
580
+ end
362
581
  end
363
582
  end
364
583
  end
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "binary_function"
4
+ require_relative "../../mathml/utility"
4
5
 
5
6
  module Plurimath
6
7
  module Math
7
8
  module Function
8
9
  class Frac < BinaryFunction
10
+ include Mathml::Utility
11
+
9
12
  attr_accessor :options
13
+
10
14
  FUNCTION = {
11
15
  name: "fraction",
12
16
  first_value: "numerator",
@@ -17,7 +17,7 @@ module Plurimath
17
17
  def ==(object)
18
18
  object.class == self.class &&
19
19
  object.parameter_one == parameter_one &&
20
- object.linebreak == linebreak
20
+ object.linebreak? == linebreak?
21
21
  end
22
22
 
23
23
  def to_asciimath(options:)
@@ -91,7 +91,7 @@ module Plurimath
91
91
  true
92
92
  end
93
93
 
94
- def linebreak
94
+ def linebreak?
95
95
  true
96
96
  end
97
97
  end