mml 2.1.0 → 2.2.1
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 +238 -166
- 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 +7 -93
- 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: b681a8e9ba48bcb41372e146fa0f16c95eae47303df8db3eb48a9561e959ce6d
|
|
4
|
+
data.tar.gz: d0d046fceba746e66519e9c6c44b395b22d0078d06140e1db04bb0aadb29f37d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e21cda0df4bada88b50899cb98b58d78ec46f3edca237ae54f064a33038fef2b7b0f5a6ce053709c2113adc0d01ffdea6efb436ca40debb85a6c54c21dbde26
|
|
7
|
+
data.tar.gz: 9544c69937ff05d4df59cd16943c9f393df5bd8a8f3a8a9cd24ba84d3bf9cb457bf6681e24e824faa6bb72c06a30729ef42963741c4034cffbb86a65925a689e
|
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 12:25: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,299 +5,371 @@
|
|
|
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 with explicit version
|
|
43
|
+
math = Mml.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>', version: 3)
|
|
44
|
+
math4 = Mml.parse(input, version: 4)
|
|
45
|
+
|
|
46
|
+
# Serialize back to XML
|
|
47
|
+
math.to_xml
|
|
48
|
+
|
|
49
|
+
# Or use versioned modules directly
|
|
50
|
+
Mml::V3::Math.from_xml(input)
|
|
51
|
+
Mml::V4::Math.from_xml(input)
|
|
45
52
|
----
|
|
46
53
|
|
|
47
|
-
==
|
|
54
|
+
== MathML version architecture
|
|
55
|
+
|
|
56
|
+
Mml maintains two parallel class hierarchies under `Mml::V3` and `Mml::V4`.
|
|
57
|
+
Both versions share the same namespace URI (`http://www.w3.org/1998/Math/MathML`)
|
|
58
|
+
for backward compatibility.
|
|
59
|
+
|
|
60
|
+
[source]
|
|
61
|
+
----
|
|
62
|
+
┌───────────────────────────────────────────┐
|
|
63
|
+
│ Mml │
|
|
64
|
+
│ parse() delegates to V3 or V4 │
|
|
65
|
+
└────────────────────┬──────────────────────┘
|
|
66
|
+
│
|
|
67
|
+
┌───────────────────┴────────────────────┐
|
|
68
|
+
│ │
|
|
69
|
+
┌────┴────┐ ┌────┴────┐
|
|
70
|
+
│ Mml::V3 │ │ Mml::V4 │
|
|
71
|
+
└────┬────┘ └────┬────┘
|
|
72
|
+
│ │
|
|
73
|
+
┌───────────────┼─────────────────────┐ ┌───────────────┼───────────────┐
|
|
74
|
+
│ ┌────────────┴───────────────┐ │ │ ┌────────────┴────────────┐ │
|
|
75
|
+
│ │ Element classes │ │ │ │ Element classes │ │
|
|
76
|
+
│ │ (Mi, Mn, Mo, Mrow, ...) │ │ │ │ (Mi, Mn, Mo, Mrow, ...) │ │
|
|
77
|
+
│ │ │ │ │ │ + intent, arg, │ │
|
|
78
|
+
│ │ Inherits from │ │ │ │ displaystyle, │ │
|
|
79
|
+
│ │ Lutaml::Model::Serializable│ │ │ │ scriptlevel │ │
|
|
80
|
+
│ └────────────┬───────────────┘ │ │ │ + <a> element │ │
|
|
81
|
+
│ │ │ │ └────────────┬────────────┘ │
|
|
82
|
+
│ ┌────────────┴────────────┐ │ │ ┌────────────┴────────────┐ │
|
|
83
|
+
│ │ CommonAttributes │ │ │ │ CommonAttributes │ │
|
|
84
|
+
│ │ (child element mixin) │ │ │ │ (v4 version) │ │
|
|
85
|
+
│ └─────────────────────────┘ │ | └─────────────────────────┘ |
|
|
86
|
+
└─────────────────────────────────────┘ └───────────────────────────────┘
|
|
87
|
+
│
|
|
88
|
+
┌──────────────────┴──────────────────────┐
|
|
89
|
+
│ Lutaml::Model::Serializable │
|
|
90
|
+
│ (XML mapping framework) │
|
|
91
|
+
└─────────────────────────────────────────┘
|
|
92
|
+
----
|
|
93
|
+
|
|
94
|
+
=== Version selection
|
|
95
|
+
|
|
96
|
+
[source,ruby]
|
|
97
|
+
----
|
|
98
|
+
Mml.parse(input) # Default: MathML 3 (Mml::V3)
|
|
99
|
+
Mml.parse(input, version: 3) # Explicit MathML 3
|
|
100
|
+
Mml.parse(input, version: 4) # MathML 4 with intent/arg attributes
|
|
101
|
+
Mml::V3.parse(input) # Direct v3 parsing
|
|
102
|
+
Mml::V4.parse(input) # Direct v4 parsing
|
|
103
|
+
----
|
|
104
|
+
|
|
105
|
+
=== Key differences between MathML 3 and MathML 4
|
|
106
|
+
|
|
107
|
+
[cols="1,2",options="header"]
|
|
108
|
+
|===
|
|
109
|
+
|Feature |MathML 4 additions
|
|
110
|
+
|Universal attributes |`intent`, `arg`, `displaystyle`, `scriptlevel` available on all presentation elements
|
|
111
|
+
|New element |`<a>` hyperlink element with `href`, `hreflang`
|
|
112
|
+
|Deprecated (not serialized) a|
|
|
113
|
+
* `fontfamily`, `fontweight`, `fontstyle`, `fontsize`, `color`, `background` on `mstyle`, `mglyph`, `mspace`
|
|
114
|
+
* `groupalign` on `mtable`, `mtr`, `mlabeledtr`
|
|
115
|
+
* `fence`, `separator` on `mo`
|
|
116
|
+
|Deprecated (recognized but hidden) |`<mlabeledtr>`, `<none>` removed from `CommonAttributes` but classes still exist
|
|
117
|
+
|===
|
|
118
|
+
|
|
119
|
+
=== Migration from previous versions
|
|
48
120
|
|
|
49
|
-
|
|
121
|
+
==== require and configuration
|
|
50
122
|
|
|
51
|
-
`Mml
|
|
52
|
-
|
|
123
|
+
The `Mml` module no longer aliases versioned constants. Use the explicit version
|
|
124
|
+
namespace:
|
|
53
125
|
|
|
54
126
|
[source,ruby]
|
|
55
127
|
----
|
|
128
|
+
# Before (no longer supported)
|
|
129
|
+
require "mml/configuration"
|
|
130
|
+
Mml::Configuration.adapter = :nokogiri
|
|
131
|
+
Mml::Configuration.custom_models = { Mi => MyCustomMi }
|
|
132
|
+
Mml::Math.new(...)
|
|
133
|
+
|
|
134
|
+
# After — explicit version
|
|
56
135
|
require "mml"
|
|
136
|
+
Mml::V3::Configuration.adapter = :nokogiri
|
|
137
|
+
Mml::V3::Configuration.custom_models = { Mi => MyCustomMi }
|
|
138
|
+
Mml::V3::Math.new(...)
|
|
139
|
+
|
|
140
|
+
# Or for MathML 4
|
|
141
|
+
Mml::V4::Configuration.adapter = :nokogiri
|
|
142
|
+
Mml::V4::Configuration.custom_models = { Mi => MyCustomMi }
|
|
143
|
+
Mml::V4::Math.new(...)
|
|
144
|
+
----
|
|
57
145
|
|
|
58
|
-
|
|
59
|
-
math = Mml.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>')
|
|
146
|
+
==== Element class references
|
|
60
147
|
|
|
61
|
-
|
|
62
|
-
|
|
148
|
+
All element classes live under their version namespace:
|
|
149
|
+
|
|
150
|
+
[source,ruby]
|
|
151
|
+
----
|
|
152
|
+
# Before (no longer supported)
|
|
153
|
+
Mml::Mi.new(value: "x")
|
|
154
|
+
Mml::Mrow.new(mi_value: [...])
|
|
155
|
+
|
|
156
|
+
# After
|
|
157
|
+
Mml::V3::Mi.new(value: "x")
|
|
158
|
+
Mml::V3::Mrow.new(mi_value: [...])
|
|
159
|
+
|
|
160
|
+
# Or for MathML 4
|
|
161
|
+
Mml::V4::Mi.new(value: "x", intent: "$x")
|
|
162
|
+
Mml::V4::Mrow.new(mi_value: [...])
|
|
163
|
+
----
|
|
164
|
+
|
|
165
|
+
==== Parsing
|
|
166
|
+
|
|
167
|
+
`Mml.parse` still works with a `version:` keyword, defaulting to version 3:
|
|
168
|
+
|
|
169
|
+
[source,ruby]
|
|
170
|
+
----
|
|
171
|
+
Mml.parse(input) # unchanged — defaults to MathML 3
|
|
172
|
+
Mml.parse(input, version: 4) # use MathML 4
|
|
63
173
|
----
|
|
64
174
|
|
|
65
|
-
|
|
175
|
+
== Parsing and serialization
|
|
66
176
|
|
|
67
|
-
|
|
68
|
-
non-compliant but common in practice. Pass `namespace_exist: false` to handle
|
|
69
|
-
this — the namespace is injected internally before parsing:
|
|
177
|
+
=== Parsing
|
|
70
178
|
|
|
71
179
|
[source,ruby]
|
|
72
180
|
----
|
|
73
|
-
|
|
181
|
+
# Default namespace
|
|
182
|
+
Mml::V3.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>')
|
|
183
|
+
|
|
184
|
+
# Prefixed namespace
|
|
185
|
+
Mml::V3.parse('<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML"><mml:mi>x</mml:mi></mml:math>')
|
|
186
|
+
|
|
187
|
+
# No namespace (namespace injected internally)
|
|
188
|
+
Mml::V3.parse("<math><mi>x</mi></math>", namespace_exist: false)
|
|
189
|
+
|
|
190
|
+
# MathML 4
|
|
191
|
+
Mml::V4.parse(input)
|
|
74
192
|
----
|
|
75
193
|
|
|
76
|
-
===
|
|
194
|
+
=== Serialization
|
|
77
195
|
|
|
78
196
|
[source,ruby]
|
|
79
197
|
----
|
|
80
|
-
# Default namespace (default)
|
|
81
198
|
math.to_xml
|
|
82
199
|
# => "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><mi>x</mi></math>"
|
|
83
200
|
|
|
84
|
-
# Prefixed namespace
|
|
85
201
|
math.to_xml(prefix: true)
|
|
86
202
|
# => "<mml:math xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mi>x</mml:mi></mml:math>"
|
|
87
203
|
|
|
88
|
-
# Omit XML declaration
|
|
89
204
|
math.to_xml(declaration: false)
|
|
205
|
+
# => "<math xmlns=\"...\"><mi>x</mi></math>"
|
|
90
206
|
----
|
|
91
207
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
=== Leaf elements
|
|
95
|
-
|
|
96
|
-
Leaf elements (`Mi`, `Mn`, `Mo`, `Ms`, `Mtext`) hold text content in the `value`
|
|
97
|
-
attribute:
|
|
208
|
+
=== Round-trip (parse, modify, serialize)
|
|
98
209
|
|
|
99
210
|
[source,ruby]
|
|
100
211
|
----
|
|
101
|
-
|
|
102
|
-
|
|
212
|
+
math = Mml.parse('<math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math>')
|
|
213
|
+
math.display = "block"
|
|
214
|
+
math.to_xml
|
|
215
|
+
# => "<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><mi>x</mi></math>"
|
|
216
|
+
----
|
|
103
217
|
|
|
104
|
-
|
|
105
|
-
Mml::Mn.new(value: "42")
|
|
218
|
+
== Element reference
|
|
106
219
|
|
|
107
|
-
|
|
108
|
-
Mml::Mo.new(value: "+")
|
|
220
|
+
=== Element types
|
|
109
221
|
|
|
110
|
-
|
|
111
|
-
Mml::Mi.new(value: "x", mathvariant: "bold")
|
|
112
|
-
----
|
|
222
|
+
*Token elements*: `mi`, `mn`, `mo`, `ms`, `mtext`, `mspace`, `mglyph`
|
|
113
223
|
|
|
114
|
-
|
|
224
|
+
*General layout*: `mrow`, `mfrac`, `msqrt`, `mroot`, `mstyle`, `merror`, `mpadded`, `mphantom`, `mfenced`, `menclose`, `maction`
|
|
225
|
+
|
|
226
|
+
*Script elements*: `msub`, `msup`, `msubsup`, `munder`, `mover`, `munderover`, `mmultiscripts`, `mprescripts`
|
|
227
|
+
|
|
228
|
+
*Table elements*: `mtable`, `mtr`, `mtd`
|
|
229
|
+
|
|
230
|
+
*Row and stack elements*: `mstack`, `msrow`, `mscarries`, `mscarry`, `msline`, `msgroup`, `mlongdiv`
|
|
115
231
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
232
|
+
*Semantic elements*: `mfraction`, `semantics`
|
|
233
|
+
|
|
234
|
+
*v4 only*: `a` (hyperlink)
|
|
235
|
+
|
|
236
|
+
*Deprecated*: `mlabeledtr`, `none` (classes exist but hidden from CommonAttributes in v4)
|
|
237
|
+
|
|
238
|
+
=== Token elements (leaf nodes)
|
|
239
|
+
|
|
240
|
+
Token elements hold text content in the `value` attribute:
|
|
119
241
|
|
|
120
242
|
[source,ruby]
|
|
121
243
|
----
|
|
122
|
-
|
|
123
|
-
Mml::
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
244
|
+
Mml::V3::Mi.new(value: "x")
|
|
245
|
+
Mml::V3::Mn.new(value: "42")
|
|
246
|
+
Mml::V3::Mo.new(value: "+")
|
|
247
|
+
Mml::V3::Ms.new(value: "text")
|
|
248
|
+
Mml::V3::Mtext.new(value: "label")
|
|
249
|
+
Mml::V3::Mspace.new(width: "1em")
|
|
250
|
+
Mml::V3::Mglyph.new(alt: "symbol")
|
|
128
251
|
----
|
|
129
252
|
|
|
130
|
-
===
|
|
253
|
+
=== Container elements
|
|
131
254
|
|
|
132
|
-
|
|
255
|
+
Container elements hold child elements via `#{tag}_value` collection attributes:
|
|
133
256
|
|
|
134
257
|
[source,ruby]
|
|
135
258
|
----
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
mfrac_value: [
|
|
141
|
-
Mml::Mfrac.new(
|
|
142
|
-
mi_value: [Mml::Mi.new(value: "a"), Mml::Mi.new(value: "b")],
|
|
143
|
-
),
|
|
144
|
-
],
|
|
259
|
+
Mml::V3::Mrow.new(
|
|
260
|
+
mi_value: [Mml::V3::Mi.new(value: "x")],
|
|
261
|
+
mo_value: [Mml::V3::Mo.new(value: "+")],
|
|
262
|
+
mn_value: [Mml::V3::Mn.new(value: "1")],
|
|
145
263
|
)
|
|
146
|
-
|
|
147
|
-
math.to_xml
|
|
264
|
+
# => <mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow>
|
|
148
265
|
----
|
|
149
266
|
|
|
150
|
-
===
|
|
267
|
+
=== Composing expressions
|
|
268
|
+
|
|
269
|
+
Build an expression tree by nesting elements:
|
|
151
270
|
|
|
152
271
|
[source,ruby]
|
|
153
272
|
----
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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")],
|
|
273
|
+
Mml::V3::Math.new(
|
|
274
|
+
mfrac_value: [
|
|
275
|
+
Mml::V3::Mfrac.new(
|
|
276
|
+
mi_value: [Mml::V3::Mi.new(value: "a"), Mml::V3::Mi.new(value: "b")],
|
|
277
|
+
),
|
|
278
|
+
],
|
|
171
279
|
)
|
|
280
|
+
# => <math><mfrac><mi>a</mi><mi>b</mi></mfrac></math>
|
|
172
281
|
----
|
|
173
282
|
|
|
174
283
|
=== Tables
|
|
175
284
|
|
|
176
|
-
`Mtable` uses typed `mtr_value` and `mlabeledtr_value` attributes for its rows:
|
|
177
|
-
|
|
178
285
|
[source,ruby]
|
|
179
286
|
----
|
|
180
|
-
|
|
181
|
-
# <mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd></mtr>
|
|
182
|
-
# </mtable>
|
|
183
|
-
Mml::Mtable.new(
|
|
287
|
+
Mml::V3::Mtable.new(
|
|
184
288
|
mtr_value: [
|
|
185
|
-
Mml::Mtr.new(
|
|
289
|
+
Mml::V3::Mtr.new(
|
|
186
290
|
mtd_value: [
|
|
187
|
-
Mml::Mtd.new(mi_value: [Mml::Mi.new(value: "a")]),
|
|
188
|
-
Mml::Mtd.new(mi_value: [Mml::Mi.new(value: "b")]),
|
|
291
|
+
Mml::V3::Mtd.new(mi_value: [Mml::V3::Mi.new(value: "a")]),
|
|
292
|
+
Mml::V3::Mtd.new(mi_value: [Mml::V3::Mi.new(value: "b")]),
|
|
189
293
|
],
|
|
190
294
|
),
|
|
191
295
|
],
|
|
192
296
|
)
|
|
193
297
|
----
|
|
194
298
|
|
|
195
|
-
===
|
|
196
|
-
|
|
197
|
-
The object graph is fully mutable — parse, modify attributes or children, then
|
|
198
|
-
serialize back:
|
|
299
|
+
=== Hyperlinks (MathML 4 only)
|
|
199
300
|
|
|
200
301
|
[source,ruby]
|
|
201
302
|
----
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
#
|
|
208
|
-
math.to_xml
|
|
209
|
-
# => "<math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\">...</math>"
|
|
303
|
+
Mml::V4::A.new(
|
|
304
|
+
href: "https://example.com",
|
|
305
|
+
hreflang: "en",
|
|
306
|
+
mi_value: [Mml::V4::Mi.new(value: "click")]
|
|
307
|
+
)
|
|
308
|
+
# => <a href="https://example.com" hreflang="en"><mi>click</mi></a>
|
|
210
309
|
----
|
|
211
310
|
|
|
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`.
|
|
311
|
+
== Internal architecture
|
|
216
312
|
|
|
217
|
-
=== Element
|
|
313
|
+
=== Element class patterns
|
|
218
314
|
|
|
219
|
-
|
|
315
|
+
All element classes inherit from `Lutaml::Model::Serializable`:
|
|
220
316
|
|
|
221
|
-
* *Leaf elements
|
|
222
|
-
|
|
223
|
-
* *Container elements* (`Math`, `Mrow`, `Mfrac`, `Mtable`, `Msubsup`): hold
|
|
224
|
-
child elements via `mixed_content`
|
|
317
|
+
* *Leaf elements*: use `map_content to: :value` for text content
|
|
318
|
+
* *Container elements*: use `mixed_content` for child elements
|
|
225
319
|
|
|
226
320
|
[source,ruby]
|
|
227
321
|
----
|
|
228
|
-
# Leaf
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
namespace Namespace
|
|
235
|
-
element "mi"
|
|
236
|
-
map_content to: :value
|
|
237
|
-
end
|
|
322
|
+
# Leaf — text content
|
|
323
|
+
class Mi < Lutaml::Model::Serializable
|
|
324
|
+
attribute :value, :string
|
|
325
|
+
xml do
|
|
326
|
+
element "mi"
|
|
327
|
+
map_content to: :value
|
|
238
328
|
end
|
|
239
329
|
end
|
|
240
330
|
|
|
241
|
-
# Container
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
element "mrow"
|
|
247
|
-
mixed_content
|
|
248
|
-
end
|
|
331
|
+
# Container — child elements
|
|
332
|
+
class Mrow < Lutaml::Model::Serializable
|
|
333
|
+
xml do
|
|
334
|
+
element "mrow"
|
|
335
|
+
mixed_content
|
|
249
336
|
end
|
|
250
337
|
end
|
|
251
338
|
----
|
|
252
339
|
|
|
253
340
|
=== CommonAttributes
|
|
254
341
|
|
|
255
|
-
Container elements that
|
|
256
|
-
`
|
|
257
|
-
|
|
258
|
-
The classes that receive it are listed in
|
|
342
|
+
Container elements that accept arbitrary MathML children import `CommonAttributes`,
|
|
343
|
+
which defines `#{tag}_value` collection attributes for all supported child elements.
|
|
344
|
+
The list of classes that receive this mixin is in
|
|
259
345
|
`Configuration::COMMON_ATTRIBUTES_CLASSES`.
|
|
260
346
|
|
|
261
347
|
=== Namespace
|
|
262
348
|
|
|
263
|
-
All elements
|
|
264
|
-
|
|
265
|
-
method handles three input forms:
|
|
349
|
+
All elements use the MathML namespace URI (`http://www.w3.org/1998/Math/MathML`).
|
|
350
|
+
Three input forms are supported:
|
|
266
351
|
|
|
267
352
|
* Default namespace: `<math xmlns="http://www.w3.org/1998/Math/MathML">`
|
|
268
353
|
* Prefixed: `<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML">`
|
|
269
|
-
* No namespace:
|
|
354
|
+
* No namespace: namespace is injected before parsing when `namespace_exist: false`
|
|
355
|
+
|
|
356
|
+
== Configuration
|
|
270
357
|
|
|
271
|
-
|
|
358
|
+
Configuration is version-specific. Use the namespace matching your target version:
|
|
272
359
|
|
|
273
360
|
[source,ruby]
|
|
274
361
|
----
|
|
275
|
-
# Switch XML adapter
|
|
276
|
-
Mml::Configuration.adapter = :nokogiri
|
|
362
|
+
# Switch XML adapter (default: :ox, also supports :nokogiri)
|
|
363
|
+
Mml::V3::Configuration.adapter = :nokogiri
|
|
364
|
+
Mml::V4::Configuration.adapter = :nokogiri
|
|
277
365
|
|
|
278
366
|
# Register custom model replacements
|
|
279
|
-
Mml::Configuration.custom_models = { Mi => MyCustomMi }
|
|
367
|
+
Mml::V3::Configuration.custom_models = { Mi => MyCustomMi }
|
|
368
|
+
Mml::V4::Configuration.custom_models = { Mi => MyCustomMi }
|
|
280
369
|
----
|
|
281
370
|
|
|
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
371
|
== Development
|
|
296
372
|
|
|
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
373
|
[source,bash]
|
|
302
374
|
----
|
|
303
375
|
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
|