asciichem 0.27.0 → 0.28.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4602bf349585d9d81483e3561d970efd6bb06f3196d30a0a3017df316699664f
4
- data.tar.gz: ea4c38d2af66b75ce2024c5cb1cc866af19584af2edba92b09cc264a7e48037e
3
+ metadata.gz: 8fb92ff1cd35eeb546372b2ac9c3cf97b908971409e9a1d473b575479464e356
4
+ data.tar.gz: 2cc3be9f85b7ca2d7e3fe773e981073b6a755344cc6b593b1940666653fb52e7
5
5
  SHA512:
6
- metadata.gz: 4dad38021607a88a0f37b90a2320b228d47b6e6197b7102eb48616ea94486ccfc16f953c2c233446ca216eefa1d76aebd0c88b1d40edcb2f582abb56c062e79f
7
- data.tar.gz: 4fc1f074a3b182e2d22c263f09044d873a9d96ba1e627e89780e42977a00aedd0e7142590df6aa645e405e7dcbca89076e505abccc3e1e37be99dddfca527372
6
+ metadata.gz: 6d2f065122017d83a4e0fdb5a9da9db50a9dbd321e335a9f49bce5c3d253e78ae11f7ae33899ad4ce60fa28b9053a085f4cac7acefbd22999c88287fc0d38d2d
7
+ data.tar.gz: 369b73e26be9c6234fd36c6a2e5d14b53a8746a5fa44c7bc5949297cc17978e6a135e4f003a90641ad7e63a2ce4dd400e05107bb79157628028f14bc68104ac2
data/CHANGELOG.md CHANGED
@@ -3,6 +3,19 @@
3
3
  All notable changes to AsciiChem are documented here.
4
4
  This project follows [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [0.28.0] - 2026-09-14
7
+
8
+ ### Changed
9
+ - Embedded-math MathML now crosses through the mml gem
10
+ (plurimath/mml) in both directions: Plurimath output is parsed
11
+ into a typed Mml::V3 graph and re-serialized by the framework
12
+ before grafting - replacing xpath surgery on the raw string.
13
+ mml (~> 2.3) is now a direct dependency (previously transitive
14
+ via plurimath).
15
+ - New spec contract: every emitted MathML (and every shared-corpus
16
+ golden) parses back through Mml.parse - output is valid per the
17
+ typed MathML contract model, not just well-formed XML.
18
+
6
19
  ## [0.27.0] - 2026-09-14
7
20
 
8
21
  ### Added
@@ -505,3 +518,13 @@ This project follows [Semantic Versioning](https://semver.org/).
505
518
  [0.3.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.2.0...v0.3.0
506
519
  [0.2.0]: https://github.com/asciichem/asciichem-ruby/compare/v0.1.0...v0.2.0
507
520
  [0.1.0]: https://github.com/asciichem/asciichem-ruby/releases/tag/v0.1.0
521
+ ### Changed
522
+ - Embedded-math MathML now crosses through the mml gem (plurimath/mml)
523
+ in both directions: Plurimath output is parsed into a typed
524
+ Mml::V3 graph and re-serialized by the framework before grafting —
525
+ replacing xpath surgery on the raw string. mml (~> 2.3) is now a
526
+ direct dependency (previously transitive via plurimath).
527
+ - New spec contract: every emitted MathML (and every shared-corpus
528
+ golden) parses back through Mml.parse — output is valid per the
529
+ typed MathML contract model, not just well-formed XML.
530
+
data/asciichem.gemspec CHANGED
@@ -36,6 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_dependency "chemicalml", "~> 0.3.0"
37
37
  spec.add_dependency "elkrb", "~> 1.0"
38
38
  spec.add_dependency "lutaml-model", ">= 0.8", "< 2"
39
+ spec.add_dependency "mml", "~> 2.3"
39
40
  spec.add_dependency "nokogiri", "~> 1.16"
40
41
  spec.add_dependency "parslet", "~> 2.0"
41
42
  spec.add_dependency "relaton-bib", ">= 0.1", "< 2"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "nokogiri"
4
+ require "mml"
4
5
 
5
6
  module AsciiChem
6
7
  module Formatter
@@ -196,17 +197,27 @@ module AsciiChem
196
197
  end
197
198
 
198
199
  def visit_embedded_math(em)
199
- # Strip the outer <math> wrapper so the embedded fragment slots
200
- # into our surrounding <mrow>.
201
- fragment = em.formula.to_mathml
202
- parsed = Nokogiri::XML(fragment)
203
- math = parsed.at_xpath("//m:math", m: MATHML_NS)
204
- return el("mrow") unless math
205
-
206
- # Detach children into a fresh <mrow>.
200
+ # Embedded math crosses through the mml gem in both directions:
201
+ # Plurimath's MathML string is parsed into a typed Mml::V3
202
+ # graph (the MathML contract model), and each top-level child
203
+ # is re-serialized by the framework before grafting — never
204
+ # ad-hoc xpath surgery on the string.
205
+ math = Mml.parse(em.formula.to_mathml, version: 3)
207
206
  mrow = el("mrow")
208
- math.children.each { |c| mrow.add_child(c.dup) }
207
+ math.element_order.each do |entry|
208
+ next unless entry.respond_to?(:name)
209
+
210
+ attr_name = xml_element_attribute(math.class, entry.name)
211
+ next unless attr_name
212
+
213
+ Array(math.public_send(attr_name)).each do |child|
214
+ fragment = Nokogiri::XML::DocumentFragment.parse(child.to_xml)
215
+ fragment.children.each { |node| mrow.add_child(node) }
216
+ end
217
+ end
209
218
  mrow
219
+ rescue Mml::Error, Lutaml::Model::Error, Nokogiri::XML::SyntaxError
220
+ el("mrow")
210
221
  end
211
222
 
212
223
  def visit_text(text)
@@ -309,6 +320,14 @@ module AsciiChem
309
320
 
310
321
  private
311
322
 
323
+ # Symbol of the model attribute an XML child element name maps
324
+ # to on a Mml class (e.g. "mstyle" => :mstyle_value), via the
325
+ # lutaml-model XML mapping — no name-munging.
326
+ def xml_element_attribute(klass, element_name)
327
+ rule = klass.mappings_for(:xml).elements.find { |r| r.name == element_name }
328
+ rule&.to
329
+ end
330
+
312
331
  def render_node(node)
313
332
  node.accept(self)
314
333
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AsciiChem
4
- VERSION = "0.27.0"
4
+ VERSION = "0.28.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciichem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.27.0
4
+ version: 0.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -57,6 +57,20 @@ dependencies:
57
57
  - - "<"
58
58
  - !ruby/object:Gem::Version
59
59
  version: '2'
60
+ - !ruby/object:Gem::Dependency
61
+ name: mml
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.3'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '2.3'
60
74
  - !ruby/object:Gem::Dependency
61
75
  name: nokogiri
62
76
  requirement: !ruby/object:Gem::Requirement