mml 2.1.0 → 2.2.0
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/.rubocop_todo.yml +14 -22
- data/README.adoc +205 -153
- data/lib/mml/v3/common_attributes.rb +22 -0
- data/lib/mml/v3/configuration.rb +105 -0
- data/lib/mml/v3/maction.rb +22 -0
- data/lib/mml/v3/maligngroup.rb +20 -0
- data/lib/mml/v3/malignmark.rb +20 -0
- data/lib/mml/v3/math.rb +20 -0
- data/lib/mml/v3/menclose.rb +21 -0
- data/lib/mml/v3/merror.rb +19 -0
- data/lib/mml/v3/mfenced.rb +28 -0
- data/lib/mml/v3/mfrac.rb +27 -0
- data/lib/mml/v3/mfraction.rb +27 -0
- data/lib/mml/v3/mglyph.rb +46 -0
- data/lib/mml/v3/mi.rb +38 -0
- data/lib/mml/v3/mlabeledtr.rb +31 -0
- data/lib/mml/v3/mlongdiv.rb +25 -0
- data/lib/mml/v3/mmultiscripts.rb +27 -0
- data/lib/mml/v3/mn.rb +38 -0
- data/lib/mml/v3/mo.rb +86 -0
- data/lib/mml/v3/mover.rb +23 -0
- data/lib/mml/v3/mpadded.rb +29 -0
- data/lib/mml/v3/mphantom.rb +19 -0
- data/lib/mml/v3/mprescripts.rb +18 -0
- data/lib/mml/v3/mroot.rb +19 -0
- data/lib/mml/v3/mrow.rb +25 -0
- data/lib/mml/v3/ms.rb +43 -0
- data/lib/mml/v3/mscarries.rb +27 -0
- data/lib/mml/v3/mscarry.rb +23 -0
- data/lib/mml/v3/msgroup.rb +25 -0
- data/lib/mml/v3/msline.rb +28 -0
- data/lib/mml/v3/mspace.rb +58 -0
- data/lib/mml/v3/msqrt.rb +19 -0
- data/lib/mml/v3/msrow.rb +21 -0
- data/lib/mml/v3/mstack.rb +27 -0
- data/lib/mml/v3/mstyle.rb +211 -0
- data/lib/mml/v3/msub.rb +21 -0
- data/lib/mml/v3/msubsup.rb +23 -0
- data/lib/mml/v3/msup.rb +21 -0
- data/lib/mml/v3/mtable.rb +61 -0
- data/lib/mml/v3/mtd.rb +23 -0
- data/lib/mml/v3/mtext.rb +38 -0
- data/lib/mml/v3/mtr.rb +29 -0
- data/lib/mml/v3/munder.rb +25 -0
- data/lib/mml/v3/munderover.rb +25 -0
- data/lib/mml/v3/namespace.rb +10 -0
- data/lib/mml/v3/none.rb +18 -0
- data/lib/mml/v3/semantics.rb +19 -0
- data/lib/mml/v3/version.rb +7 -0
- data/lib/mml/v3.rb +85 -0
- data/lib/mml/v4/a.rb +31 -0
- data/lib/mml/v4/common_attributes.rb +26 -0
- data/lib/mml/v4/configuration.rb +106 -0
- data/lib/mml/v4/maction.rb +30 -0
- data/lib/mml/v4/maligngroup.rb +28 -0
- data/lib/mml/v4/malignmark.rb +28 -0
- data/lib/mml/v4/math.rb +27 -0
- data/lib/mml/v4/menclose.rb +29 -0
- data/lib/mml/v4/merror.rb +27 -0
- data/lib/mml/v4/mfenced.rb +36 -0
- data/lib/mml/v4/mfrac.rb +35 -0
- data/lib/mml/v4/mfraction.rb +31 -0
- data/lib/mml/v4/mglyph.rb +46 -0
- data/lib/mml/v4/mi.rb +41 -0
- data/lib/mml/v4/mlabeledtr.rb +34 -0
- data/lib/mml/v4/mlongdiv.rb +29 -0
- data/lib/mml/v4/mmultiscripts.rb +35 -0
- data/lib/mml/v4/mn.rb +40 -0
- data/lib/mml/v4/mo.rb +86 -0
- data/lib/mml/v4/mover.rb +31 -0
- data/lib/mml/v4/mpadded.rb +37 -0
- data/lib/mml/v4/mphantom.rb +27 -0
- data/lib/mml/v4/mprescripts.rb +22 -0
- data/lib/mml/v4/mroot.rb +27 -0
- data/lib/mml/v4/mrow.rb +31 -0
- data/lib/mml/v4/ms.rb +45 -0
- data/lib/mml/v4/mscarries.rb +31 -0
- data/lib/mml/v4/mscarry.rb +27 -0
- data/lib/mml/v4/msgroup.rb +29 -0
- data/lib/mml/v4/msline.rb +32 -0
- data/lib/mml/v4/mspace.rb +60 -0
- data/lib/mml/v4/msqrt.rb +27 -0
- data/lib/mml/v4/msrow.rb +29 -0
- data/lib/mml/v4/mstack.rb +35 -0
- data/lib/mml/v4/mstyle.rb +197 -0
- data/lib/mml/v4/msub.rb +29 -0
- data/lib/mml/v4/msubsup.rb +31 -0
- data/lib/mml/v4/msup.rb +29 -0
- data/lib/mml/v4/mtable.rb +66 -0
- data/lib/mml/v4/mtd.rb +31 -0
- data/lib/mml/v4/mtext.rb +40 -0
- data/lib/mml/v4/mtr.rb +36 -0
- data/lib/mml/v4/munder.rb +33 -0
- data/lib/mml/v4/munderover.rb +33 -0
- data/lib/mml/v4/namespace.rb +10 -0
- data/lib/mml/v4/none.rb +22 -0
- data/lib/mml/v4/opal_setup.rb.erb +6 -0
- data/lib/mml/v4/semantics.rb +23 -0
- data/lib/mml/v4/version.rb +7 -0
- data/lib/mml/v4.rb +81 -0
- data/lib/mml/version.rb +1 -1
- data/lib/mml.rb +24 -90
- metadata +101 -49
- data/lib/mml/common_attributes.rb +0 -21
- data/lib/mml/configuration.rb +0 -103
- data/lib/mml/maction.rb +0 -20
- data/lib/mml/maligngroup.rb +0 -18
- data/lib/mml/malignmark.rb +0 -18
- data/lib/mml/math.rb +0 -18
- data/lib/mml/menclose.rb +0 -19
- data/lib/mml/merror.rb +0 -17
- data/lib/mml/mfenced.rb +0 -26
- data/lib/mml/mfrac.rb +0 -25
- data/lib/mml/mfraction.rb +0 -25
- data/lib/mml/mglyph.rb +0 -44
- data/lib/mml/mi.rb +0 -36
- data/lib/mml/mlabeledtr.rb +0 -29
- data/lib/mml/mlongdiv.rb +0 -23
- data/lib/mml/mmultiscripts.rb +0 -25
- data/lib/mml/mn.rb +0 -36
- data/lib/mml/mo.rb +0 -84
- data/lib/mml/mover.rb +0 -21
- data/lib/mml/mpadded.rb +0 -27
- data/lib/mml/mphantom.rb +0 -17
- data/lib/mml/mprescripts.rb +0 -16
- data/lib/mml/mroot.rb +0 -17
- data/lib/mml/mrow.rb +0 -23
- data/lib/mml/ms.rb +0 -41
- data/lib/mml/mscarries.rb +0 -25
- data/lib/mml/mscarry.rb +0 -21
- data/lib/mml/msgroup.rb +0 -23
- data/lib/mml/msline.rb +0 -26
- data/lib/mml/mspace.rb +0 -56
- data/lib/mml/msqrt.rb +0 -17
- data/lib/mml/msrow.rb +0 -19
- data/lib/mml/mstack.rb +0 -25
- data/lib/mml/mstyle.rb +0 -209
- data/lib/mml/msub.rb +0 -19
- data/lib/mml/msubsup.rb +0 -21
- data/lib/mml/msup.rb +0 -19
- data/lib/mml/mtable.rb +0 -59
- data/lib/mml/mtd.rb +0 -21
- data/lib/mml/mtext.rb +0 -36
- data/lib/mml/mtr.rb +0 -27
- data/lib/mml/munder.rb +0 -23
- data/lib/mml/munderover.rb +0 -23
- data/lib/mml/namespace.rb +0 -9
- data/lib/mml/none.rb +0 -16
- data/lib/mml/semantics.rb +0 -17
- /data/lib/mml/{opal_setup.rb.erb → v3/opal_setup.rb.erb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: efbc2e4b8156916d34e524d2f7b6456168f8ef4a0c0c2ade8fbfb2b02bdc2efb
|
|
4
|
+
data.tar.gz: 8f826d13adfc7f0b556aa5ab6f32f8e8390bf06002a76570845605af7282058a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 694df3fcc6b3611d6bac5b5c380b420b91823e697b219ba93a5d9ec22c70d910f8ecef6fef6c419b1acf80660d726259056717380faf8e77d235879b056e3c85
|
|
7
|
+
data.tar.gz: 72b8f2d1960adec6a3777e43c792cf3d1d3aa4658be47e5bdbf9f7e5cd428ac1dbd3990d7c1685ae4f6ed1a90566b80932046c15424bf4b6a94efa4e39360a29
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-03-
|
|
3
|
+
# on 2026-03-31 03:44:08 UTC using RuboCop version 1.86.0.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
-
# Offense count:
|
|
10
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
-
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
12
|
-
# SupportedStyles: with_first_argument, with_fixed_indentation
|
|
13
|
-
Layout/ArgumentAlignment:
|
|
14
|
-
Exclude:
|
|
15
|
-
- 'spec/mml_spec.rb'
|
|
16
|
-
|
|
17
|
-
# Offense count: 5
|
|
9
|
+
# Offense count: 3
|
|
18
10
|
# This cop supports safe autocorrection (--autocorrect).
|
|
19
11
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
20
12
|
# URISchemes: http, https
|
|
@@ -25,28 +17,28 @@ Layout/LineLength:
|
|
|
25
17
|
- 'spec/spec_helper.rb'
|
|
26
18
|
|
|
27
19
|
# Offense count: 1
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- 'spec/mml_spec.rb'
|
|
20
|
+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
|
21
|
+
# AllowedMethods: refine
|
|
22
|
+
Metrics/BlockLength:
|
|
23
|
+
Max: 27
|
|
33
24
|
|
|
34
|
-
# Offense count:
|
|
25
|
+
# Offense count: 3
|
|
35
26
|
# Configuration parameters: Prefixes, AllowedPatterns.
|
|
36
27
|
# Prefixes: when, with, without
|
|
37
28
|
RSpec/ContextWording:
|
|
38
29
|
Exclude:
|
|
30
|
+
- 'spec/mml4_spec.rb'
|
|
39
31
|
- 'spec/mml_spec.rb'
|
|
40
32
|
|
|
41
33
|
# Offense count: 1
|
|
42
|
-
RSpec/
|
|
34
|
+
RSpec/MultipleDescribes:
|
|
43
35
|
Exclude:
|
|
44
36
|
- 'spec/mml_spec.rb'
|
|
45
37
|
|
|
46
38
|
# Offense count: 1
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
Style/StringLiterals:
|
|
39
|
+
# Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
|
|
40
|
+
# SupportedInflectors: default, active_support
|
|
41
|
+
RSpec/SpecFilePathFormat:
|
|
51
42
|
Exclude:
|
|
52
|
-
- 'spec/
|
|
43
|
+
- '**/spec/routing/**/*'
|
|
44
|
+
- 'spec/mml4_spec.rb'
|
data/README.adoc
CHANGED
|
@@ -5,181 +5,269 @@
|
|
|
5
5
|
|
|
6
6
|
== Purpose
|
|
7
7
|
|
|
8
|
-
Mml provides MathML 3 XML parsing and serialization for Ruby. It maps
|
|
9
|
-
MathML element set into Ruby model classes using the
|
|
8
|
+
Mml provides MathML 3 and MathML 4 XML parsing and serialization for Ruby. It maps
|
|
9
|
+
the full MathML element set into Ruby model classes using the
|
|
10
10
|
https://github.com/lutaml/lutaml-model[lutaml-model] framework and is used by
|
|
11
11
|
https://github.com/plurimath/plurimath[Plurimath] for mathematical formula
|
|
12
12
|
representation.
|
|
13
13
|
|
|
14
14
|
Key features:
|
|
15
15
|
|
|
16
|
-
* **MathML
|
|
17
|
-
|
|
18
|
-
* **
|
|
19
|
-
|
|
20
|
-
* **Round-trip fidelity**: Parse XML to an object graph, modify, and serialize
|
|
21
|
-
back
|
|
16
|
+
* **Dual MathML version support**: Separate class hierarchies for MathML 3 and
|
|
17
|
+
MathML 4 with explicit version selection
|
|
18
|
+
* **Round-trip fidelity**: Parse XML to an object graph, modify, and serialize back
|
|
19
|
+
* **Namespace handling**: Default `xmlns`, prefixed `mml:`, and namespace-less input
|
|
22
20
|
* **Opal support**: Runs in the browser via Ruby-to-JavaScript compilation
|
|
23
21
|
|
|
24
22
|
== Installation
|
|
25
23
|
|
|
26
|
-
Add to your application's Gemfile:
|
|
27
|
-
|
|
28
24
|
[source,ruby]
|
|
29
25
|
----
|
|
30
26
|
gem 'mml'
|
|
31
27
|
----
|
|
32
28
|
|
|
33
|
-
Then execute:
|
|
34
|
-
|
|
35
29
|
[source,bash]
|
|
36
30
|
----
|
|
37
31
|
$ bundle install
|
|
32
|
+
# or
|
|
33
|
+
$ gem install mml
|
|
38
34
|
----
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
== Quick start
|
|
41
37
|
|
|
42
|
-
[source,
|
|
38
|
+
[source,ruby]
|
|
43
39
|
----
|
|
44
|
-
|
|
40
|
+
require "mml"
|
|
41
|
+
|
|
42
|
+
# Parse MathML (defaults to MathML 3)
|
|
43
|
+
math = Mml.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>')
|
|
44
|
+
|
|
45
|
+
# Serialize back to XML
|
|
46
|
+
math.to_xml
|
|
47
|
+
# => "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mi>x</mi></math>"
|
|
48
|
+
|
|
49
|
+
# Parse with explicit version
|
|
50
|
+
math4 = Mml.parse(input, version: 4)
|
|
45
51
|
----
|
|
46
52
|
|
|
47
|
-
==
|
|
53
|
+
== MathML version architecture
|
|
54
|
+
|
|
55
|
+
Mml maintains two parallel class hierarchies under `Mml::V3` and `Mml::V4`.
|
|
56
|
+
Both versions share the same namespace URI (`http://www.w3.org/1998/Math/MathML`)
|
|
57
|
+
for backward compatibility.
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
[source]
|
|
60
|
+
----
|
|
61
|
+
┌───────────────────────────────────────────┐
|
|
62
|
+
│ Mml │
|
|
63
|
+
│ (aliases Mml::V3 for backward compat) │
|
|
64
|
+
└────────────────────┬──────────────────────┘
|
|
65
|
+
│
|
|
66
|
+
┌───────────────────┴────────────────────┐
|
|
67
|
+
│ │
|
|
68
|
+
┌────┴────┐ ┌────┴────┐
|
|
69
|
+
│ Mml::V3 │ │ Mml::V4 │
|
|
70
|
+
└────┬────┘ └────┬────┘
|
|
71
|
+
│ │
|
|
72
|
+
┌───────────────┼─────────────────────┐ ┌───────────────┼───────────────┐
|
|
73
|
+
│ ┌────────────┴───────────────┐ │ │ ┌────────────┴────────────┐ │
|
|
74
|
+
│ │ Element classes │ │ │ │ Element classes │ │
|
|
75
|
+
│ │ (Mi, Mn, Mo, Mrow, ...) │ │ │ │ (Mi, Mn, Mo, Mrow, ...) │ │
|
|
76
|
+
│ │ │ │ │ │ + intent, arg, │ │
|
|
77
|
+
│ │ Inherits from │ │ │ │ displaystyle, │ │
|
|
78
|
+
│ │ Lutaml::Model::Serializable│ │ │ │ scriptlevel │ │
|
|
79
|
+
│ └────────────┬───────────────┘ │ │ │ + <a> element │ │
|
|
80
|
+
│ │ │ │ └────────────┬────────────┘ │
|
|
81
|
+
│ ┌────────────┴────────────┐ │ │ ┌────────────┴────────────┐ │
|
|
82
|
+
│ │ CommonAttributes │ │ │ │ CommonAttributes │ │
|
|
83
|
+
│ │ (child element mixin) │ │ │ │ (v4 version) │ │
|
|
84
|
+
│ └─────────────────────────┘ │ | └─────────────────────────┘ |
|
|
85
|
+
└─────────────────────────────────────┘ └───────────────────────────────┘
|
|
86
|
+
│
|
|
87
|
+
┌──────────────────┴──────────────────────┐
|
|
88
|
+
│ Lutaml::Model::Serializable │
|
|
89
|
+
│ (XML mapping framework) │
|
|
90
|
+
└─────────────────────────────────────────┘
|
|
91
|
+
----
|
|
50
92
|
|
|
51
|
-
|
|
52
|
-
both default and prefixed forms:
|
|
93
|
+
=== Version selection
|
|
53
94
|
|
|
54
95
|
[source,ruby]
|
|
55
96
|
----
|
|
56
|
-
|
|
97
|
+
Mml.parse(input) # Default: MathML 3 (Mml::V3)
|
|
98
|
+
Mml.parse(input, version: 3) # Explicit MathML 3
|
|
99
|
+
Mml.parse(input, version: 4) # MathML 4 with intent/arg attributes
|
|
100
|
+
Mml::V4.parse(input) # Direct v4 parsing (no default fallback)
|
|
101
|
+
----
|
|
57
102
|
|
|
58
|
-
|
|
59
|
-
math = Mml.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>')
|
|
103
|
+
=== Key differences between MathML 3 and MathML 4
|
|
60
104
|
|
|
61
|
-
|
|
62
|
-
|
|
105
|
+
[cols="1,2",options="header"]
|
|
106
|
+
|===
|
|
107
|
+
|Feature |MathML 4 additions
|
|
108
|
+
|Universal attributes |`intent`, `arg`, `displaystyle`, `scriptlevel` available on all presentation elements
|
|
109
|
+
|New element |`<a>` hyperlink element with `href`, `hreflang`
|
|
110
|
+
|Deprecated (not serialized) a|
|
|
111
|
+
* `fontfamily`, `fontweight`, `fontstyle`, `fontsize`, `color`, `background` on `mstyle`, `mglyph`, `mspace`
|
|
112
|
+
* `groupalign` on `mtable`, `mtr`, `mlabeledtr`
|
|
113
|
+
* `fence`, `separator` on `mo`
|
|
114
|
+
|Deprecated (recognized but hidden) |`<mlabeledtr>`, `<none>` removed from `CommonAttributes` but classes still exist
|
|
115
|
+
|===
|
|
116
|
+
|
|
117
|
+
=== Migration from MathML 3 to MathML 4
|
|
118
|
+
|
|
119
|
+
==== For gem users (upgrading parsing)
|
|
120
|
+
|
|
121
|
+
If you currently parse MathML and want to use MathML 4 features:
|
|
122
|
+
|
|
123
|
+
[source,ruby]
|
|
124
|
+
----
|
|
125
|
+
# Change this:
|
|
126
|
+
math = Mml.parse(input)
|
|
127
|
+
|
|
128
|
+
# To this:
|
|
129
|
+
math = Mml.parse(input, version: 4)
|
|
130
|
+
----
|
|
131
|
+
|
|
132
|
+
==== For gem users (upgrading serialized output)
|
|
133
|
+
|
|
134
|
+
If you serialize MathML 4 documents and want to ensure compatibility:
|
|
135
|
+
|
|
136
|
+
[source,ruby]
|
|
137
|
+
----
|
|
138
|
+
# MathML 4 serialization removes deprecated attributes from XML output
|
|
139
|
+
math = Mml.parse(input, version: 4)
|
|
140
|
+
math.to_xml # No fontfamily, fontweight, color, groupalign, etc. in output
|
|
141
|
+
----
|
|
142
|
+
|
|
143
|
+
==== For gem extenders (adding custom elements)
|
|
144
|
+
|
|
145
|
+
Custom elements registered via `Configuration.custom_models` are version-specific:
|
|
146
|
+
|
|
147
|
+
[source,ruby]
|
|
148
|
+
----
|
|
149
|
+
# Register a custom element for MathML 4 only
|
|
150
|
+
Mml::V4::Configuration.custom_models = { Mi => MyCustomMiV4 }
|
|
151
|
+
----
|
|
152
|
+
|
|
153
|
+
CommonAttributes is version-specific. Elements that exist only in v4 (like `<a>`)
|
|
154
|
+
are automatically handled:
|
|
155
|
+
|
|
156
|
+
[source,ruby]
|
|
157
|
+
----
|
|
158
|
+
# The <a> element is only in v4 CommonAttributes
|
|
159
|
+
Mml::V4::Mrow.new(a_value: [Mml::V4::A.new(href: "https://...")])
|
|
63
160
|
----
|
|
64
161
|
|
|
65
|
-
|
|
162
|
+
== Parsing and serialization
|
|
66
163
|
|
|
67
|
-
|
|
68
|
-
non-compliant but common in practice. Pass `namespace_exist: false` to handle
|
|
69
|
-
this — the namespace is injected internally before parsing:
|
|
164
|
+
=== Parsing
|
|
70
165
|
|
|
71
166
|
[source,ruby]
|
|
72
167
|
----
|
|
73
|
-
|
|
168
|
+
# Default namespace
|
|
169
|
+
Mml.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>')
|
|
170
|
+
|
|
171
|
+
# Prefixed namespace
|
|
172
|
+
Mml.parse('<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>x</mml:mi></mml:math>')
|
|
173
|
+
|
|
174
|
+
# No namespace (namespace injected internally)
|
|
175
|
+
Mml.parse("<math><mi>x</mi></math>", namespace_exist: false)
|
|
74
176
|
----
|
|
75
177
|
|
|
76
|
-
===
|
|
178
|
+
=== Serialization
|
|
77
179
|
|
|
78
180
|
[source,ruby]
|
|
79
181
|
----
|
|
80
|
-
# Default namespace (default)
|
|
81
182
|
math.to_xml
|
|
82
183
|
# => "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mi>x</mi></math>"
|
|
83
184
|
|
|
84
|
-
# Prefixed namespace
|
|
85
185
|
math.to_xml(prefix: true)
|
|
86
186
|
# => "<mml:math xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mi>x</mml:mi></mml:math>"
|
|
87
187
|
|
|
88
|
-
# Omit XML declaration
|
|
89
188
|
math.to_xml(declaration: false)
|
|
189
|
+
# => "<math xmlns=\"...\"><mi>x</mi></math>"
|
|
190
|
+
----
|
|
191
|
+
|
|
192
|
+
=== Round-trip (parse, modify, serialize)
|
|
193
|
+
|
|
194
|
+
[source,ruby]
|
|
90
195
|
----
|
|
196
|
+
math = Mml.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>')
|
|
197
|
+
math.display = "block"
|
|
198
|
+
math.to_xml
|
|
199
|
+
# => "<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><mi>x</mi></math>"
|
|
200
|
+
----
|
|
201
|
+
|
|
202
|
+
== Element reference
|
|
203
|
+
|
|
204
|
+
=== Element types
|
|
91
205
|
|
|
92
|
-
|
|
206
|
+
*Token elements*: `mi`, `mn`, `mo`, `ms`, `mtext`, `mspace`, `mglyph`
|
|
93
207
|
|
|
94
|
-
|
|
208
|
+
*General layout*: `mrow`, `mfrac`, `msqrt`, `mroot`, `mstyle`, `merror`, `mpadded`, `mphantom`, `mfenced`, `menclose`, `maction`
|
|
95
209
|
|
|
96
|
-
|
|
97
|
-
|
|
210
|
+
*Script elements*: `msub`, `msup`, `msubsup`, `munder`, `mover`, `munderover`, `mmultiscripts`, `mprescripts`
|
|
211
|
+
|
|
212
|
+
*Table elements*: `mtable`, `mtr`, `mtd`
|
|
213
|
+
|
|
214
|
+
*Row and stack elements*: `mstack`, `msrow`, `mscarries`, `mscarry`, `msline`, `msgroup`, `mlongdiv`
|
|
215
|
+
|
|
216
|
+
*Semantic elements*: `mfraction`, `semantics`
|
|
217
|
+
|
|
218
|
+
*v4 only*: `a` (hyperlink)
|
|
219
|
+
|
|
220
|
+
*Deprecated*: `mlabeledtr`, `none` (classes exist but hidden from CommonAttributes in v4)
|
|
221
|
+
|
|
222
|
+
=== Token elements (leaf nodes)
|
|
223
|
+
|
|
224
|
+
Token elements hold text content in the `value` attribute:
|
|
98
225
|
|
|
99
226
|
[source,ruby]
|
|
100
227
|
----
|
|
101
|
-
# An identifier: <mi>x</mi>
|
|
102
228
|
Mml::Mi.new(value: "x")
|
|
103
|
-
|
|
104
|
-
# A number: <mn>42</mn>
|
|
105
229
|
Mml::Mn.new(value: "42")
|
|
106
|
-
|
|
107
|
-
# An operator: <mo>+</mo>
|
|
108
230
|
Mml::Mo.new(value: "+")
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
Mml::
|
|
231
|
+
Mml::Ms.new(value: "text")
|
|
232
|
+
Mml::Mtext.new(value: "label")
|
|
233
|
+
Mml::Mspace.new(width: "1em")
|
|
234
|
+
Mml::Mglyph.new(alt: "symbol")
|
|
112
235
|
----
|
|
113
236
|
|
|
114
237
|
=== Container elements
|
|
115
238
|
|
|
116
|
-
Container elements hold child elements via collection attributes
|
|
117
|
-
`#{tag}_value`. The supported child types come from the `CommonAttributes` model
|
|
118
|
-
mixed into container classes.
|
|
239
|
+
Container elements hold child elements via `#{tag}_value` collection attributes:
|
|
119
240
|
|
|
120
241
|
[source,ruby]
|
|
121
242
|
----
|
|
122
|
-
# <mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow>
|
|
123
243
|
Mml::Mrow.new(
|
|
124
244
|
mi_value: [Mml::Mi.new(value: "x")],
|
|
125
245
|
mo_value: [Mml::Mo.new(value: "+")],
|
|
126
246
|
mn_value: [Mml::Mn.new(value: "1")],
|
|
127
247
|
)
|
|
248
|
+
# => <mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow>
|
|
128
249
|
----
|
|
129
250
|
|
|
130
|
-
=== Composing
|
|
251
|
+
=== Composing expressions
|
|
131
252
|
|
|
132
|
-
Build an expression tree by nesting elements
|
|
253
|
+
Build an expression tree by nesting elements:
|
|
133
254
|
|
|
134
255
|
[source,ruby]
|
|
135
256
|
----
|
|
136
|
-
|
|
137
|
-
# <mfrac><mi>a</mi><mi>b</mi></mfrac>
|
|
138
|
-
# </math>
|
|
139
|
-
math = Mml::Math.new(
|
|
257
|
+
Mml::Math.new(
|
|
140
258
|
mfrac_value: [
|
|
141
259
|
Mml::Mfrac.new(
|
|
142
260
|
mi_value: [Mml::Mi.new(value: "a"), Mml::Mi.new(value: "b")],
|
|
143
261
|
),
|
|
144
262
|
],
|
|
145
263
|
)
|
|
146
|
-
|
|
147
|
-
math.to_xml
|
|
148
|
-
----
|
|
149
|
-
|
|
150
|
-
=== Fractions, subscripts, and superscripts
|
|
151
|
-
|
|
152
|
-
[source,ruby]
|
|
153
|
-
----
|
|
154
|
-
# <msup><mi>x</mi><mn>2</mn></msup> — x²
|
|
155
|
-
Mml::Msup.new(mi_value: [Mml::Mi.new(value: "x")],
|
|
156
|
-
mn_value: [Mml::Mn.new(value: "2")])
|
|
157
|
-
|
|
158
|
-
# <msub><mi>a</mi><mn>1</mn></msup> — a₁
|
|
159
|
-
Mml::Msub.new(mi_value: [Mml::Mi.new(value: "a")],
|
|
160
|
-
mn_value: [Mml::Mn.new(value: "1")])
|
|
161
|
-
|
|
162
|
-
# <msubsup><mi>b</mi><mn>1</mn><mn>2</mn></msubsup> — b₁²
|
|
163
|
-
Mml::Msubsup.new(mi_value: [Mml::Mi.new(value: "b")],
|
|
164
|
-
mn_value: [Mml::Mn.new(value: "1"),
|
|
165
|
-
Mml::Mn.new(value: "2")])
|
|
166
|
-
|
|
167
|
-
# <mfrac linethickness="0"><mi>a</mi><mi>b</mi></mfrac> — a/b
|
|
168
|
-
Mml::Mfrac.new(
|
|
169
|
-
linethickness: "0",
|
|
170
|
-
mi_value: [Mml::Mi.new(value: "a"), Mml::Mi.new(value: "b")],
|
|
171
|
-
)
|
|
264
|
+
# => <math><mfrac><mi>a</mi><mi>b</mi></mfrac></math>
|
|
172
265
|
----
|
|
173
266
|
|
|
174
267
|
=== Tables
|
|
175
268
|
|
|
176
|
-
`Mtable` uses typed `mtr_value` and `mlabeledtr_value` attributes for its rows:
|
|
177
|
-
|
|
178
269
|
[source,ruby]
|
|
179
270
|
----
|
|
180
|
-
# <mtable>
|
|
181
|
-
# <mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd></mtr>
|
|
182
|
-
# </mtable>
|
|
183
271
|
Mml::Mtable.new(
|
|
184
272
|
mtr_value: [
|
|
185
273
|
Mml::Mtr.new(
|
|
@@ -192,112 +280,76 @@ Mml::Mtable.new(
|
|
|
192
280
|
)
|
|
193
281
|
----
|
|
194
282
|
|
|
195
|
-
===
|
|
196
|
-
|
|
197
|
-
The object graph is fully mutable — parse, modify attributes or children, then
|
|
198
|
-
serialize back:
|
|
283
|
+
=== Hyperlinks (MathML 4 only)
|
|
199
284
|
|
|
200
285
|
[source,ruby]
|
|
201
286
|
----
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
#
|
|
208
|
-
math.to_xml
|
|
209
|
-
# => "<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\">...</math>"
|
|
287
|
+
Mml::V4::A.new(
|
|
288
|
+
href: "https://example.com",
|
|
289
|
+
hreflang: "en",
|
|
290
|
+
mi_value: [Mml::V4::Mi.new(value: "click")]
|
|
291
|
+
)
|
|
292
|
+
# => <a href="https://example.com" hreflang="en"><mi>click</mi></a>
|
|
210
293
|
----
|
|
211
294
|
|
|
212
|
-
==
|
|
213
|
-
|
|
214
|
-
Mml follows a data mapper pattern where each MathML element is a Ruby class
|
|
215
|
-
under the `Mml::` namespace, inheriting from `Lutaml::Model::Serializable`.
|
|
295
|
+
== Internal architecture
|
|
216
296
|
|
|
217
|
-
=== Element
|
|
297
|
+
=== Element class patterns
|
|
218
298
|
|
|
219
|
-
|
|
299
|
+
All element classes inherit from `Lutaml::Model::Serializable`:
|
|
220
300
|
|
|
221
|
-
* *Leaf elements
|
|
222
|
-
|
|
223
|
-
* *Container elements* (`Math`, `Mrow`, `Mfrac`, `Mtable`, `Msubsup`): hold
|
|
224
|
-
child elements via `mixed_content`
|
|
301
|
+
* *Leaf elements*: use `map_content to: :value` for text content
|
|
302
|
+
* *Container elements*: use `mixed_content` for child elements
|
|
225
303
|
|
|
226
304
|
[source,ruby]
|
|
227
305
|
----
|
|
228
|
-
# Leaf
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
namespace Namespace
|
|
235
|
-
element "mi"
|
|
236
|
-
map_content to: :value
|
|
237
|
-
end
|
|
306
|
+
# Leaf — text content
|
|
307
|
+
class Mi < Lutaml::Model::Serializable
|
|
308
|
+
attribute :value, :string
|
|
309
|
+
xml do
|
|
310
|
+
element "mi"
|
|
311
|
+
map_content to: :value
|
|
238
312
|
end
|
|
239
313
|
end
|
|
240
314
|
|
|
241
|
-
# Container
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
element "mrow"
|
|
247
|
-
mixed_content
|
|
248
|
-
end
|
|
315
|
+
# Container — child elements
|
|
316
|
+
class Mrow < Lutaml::Model::Serializable
|
|
317
|
+
xml do
|
|
318
|
+
element "mrow"
|
|
319
|
+
mixed_content
|
|
249
320
|
end
|
|
250
321
|
end
|
|
251
322
|
----
|
|
252
323
|
|
|
253
324
|
=== CommonAttributes
|
|
254
325
|
|
|
255
|
-
Container elements that
|
|
256
|
-
`
|
|
257
|
-
|
|
258
|
-
The classes that receive it are listed in
|
|
326
|
+
Container elements that accept arbitrary MathML children import `CommonAttributes`,
|
|
327
|
+
which defines `#{tag}_value` collection attributes for all supported child elements.
|
|
328
|
+
The list of classes that receive this mixin is in
|
|
259
329
|
`Configuration::COMMON_ATTRIBUTES_CLASSES`.
|
|
260
330
|
|
|
261
331
|
=== Namespace
|
|
262
332
|
|
|
263
|
-
All elements
|
|
264
|
-
|
|
265
|
-
method handles three input forms:
|
|
333
|
+
All elements use the MathML namespace URI (`http://www.w3.org/1998/Math/MathML`).
|
|
334
|
+
Three input forms are supported:
|
|
266
335
|
|
|
267
336
|
* Default namespace: `<math xmlns="http://www.w3.org/1998/Math/MathML">`
|
|
268
337
|
* Prefixed: `<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML">`
|
|
269
|
-
* No namespace:
|
|
338
|
+
* No namespace: namespace is injected before parsing when `namespace_exist: false`
|
|
270
339
|
|
|
271
|
-
|
|
340
|
+
== Configuration
|
|
272
341
|
|
|
273
342
|
[source,ruby]
|
|
274
343
|
----
|
|
275
|
-
# Switch XML adapter
|
|
344
|
+
# Switch XML adapter (default: :ox, also supports :nokogiri)
|
|
276
345
|
Mml::Configuration.adapter = :nokogiri
|
|
277
346
|
|
|
278
347
|
# Register custom model replacements
|
|
279
348
|
Mml::Configuration.custom_models = { Mi => MyCustomMi }
|
|
280
349
|
----
|
|
281
350
|
|
|
282
|
-
== Supported elements
|
|
283
|
-
|
|
284
|
-
Mml supports the following MathML 3 presentation elements:
|
|
285
|
-
|
|
286
|
-
`math`, `mi`, `mn`, `mo`, `ms`, `mtext`, `mspace`, `mglyph`
|
|
287
|
-
`mrow`, `mfrac`, `msqrt`, `mroot`, `mstyle`, `merror`, `mpadded`,
|
|
288
|
-
`mphantom`, `mfenced`, `menclose`, `maction`
|
|
289
|
-
`msub`, `msup`, `msubsup`, `munder`, `mover`, `munderover`,
|
|
290
|
-
`mmultiscripts`, `mprescripts`
|
|
291
|
-
`mtable`, `mtr`, `mtd`, `mlabeledtr`
|
|
292
|
-
`mstack`, `msrow`, `mscarries`, `mscarry`, `msline`, `msgroup`, `mlongdiv`
|
|
293
|
-
`mfraction`, `semantics`, `none`
|
|
294
|
-
|
|
295
351
|
== Development
|
|
296
352
|
|
|
297
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then run
|
|
298
|
-
`rake` to run the tests and linter. You can also run `bin/console` for an
|
|
299
|
-
interactive prompt.
|
|
300
|
-
|
|
301
353
|
[source,bash]
|
|
302
354
|
----
|
|
303
355
|
rake # Run specs + rubocop
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mml
|
|
4
|
+
module V3
|
|
5
|
+
Mml::V3::Configuration::SUPPORTED_TAGS.each do |tag|
|
|
6
|
+
autoload(tag.to_s.capitalize.to_sym, "mml/v3/#{tag}.rb")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class CommonAttributes < Lutaml::Model::Serializable
|
|
10
|
+
Mml::V3::Configuration::SUPPORTED_TAGS.each do |tag|
|
|
11
|
+
attribute :"#{tag}_value", Mml::V3.const_get(tag.to_s.capitalize),
|
|
12
|
+
collection: true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
xml do
|
|
16
|
+
Mml::V3::Configuration::SUPPORTED_TAGS.each do |tag|
|
|
17
|
+
map_element tag, to: :"#{tag}_value"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|