plurimath 0.11.14 → 0.11.15
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/.github/workflows/dependent-tests.yml +1 -1
- data/.rspec-opal +1 -0
- data/Gemfile +2 -3
- data/lib/plurimath/cli/helpers.rb +4 -1
- data/lib/plurimath/cli.rb +2 -2
- data/lib/plurimath/html/parse.rb +1 -1
- data/lib/plurimath/html/parser.rb +14 -1
- data/lib/plurimath/html/transform.rb +1 -1
- data/lib/plurimath/latex/parse.rb +20 -1
- data/lib/plurimath/latex/transform.rb +9 -7
- data/lib/plurimath/math/function/unary_function.rb +1 -1
- data/lib/plurimath/math/number.rb +1 -1
- data/lib/plurimath/setup/leptris_engine.rb +14 -0
- data/lib/plurimath/unicode_math/parse.rb +7 -2
- data/lib/plurimath/unicode_math/parsing_rules/helper.rb +1 -7
- data/lib/plurimath/unicode_math/transform.rb +1 -1
- data/lib/plurimath/utility.rb +5 -1
- data/lib/plurimath/version.rb +1 -1
- data/lib/plurimath/xml_engine/leptris_engine/element.rb +181 -0
- data/lib/plurimath/xml_engine/leptris_engine.rb +41 -0
- data/lib/plurimath.rb +4 -0
- data/plurimath.gemspec +1 -0
- metadata +24 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4b65c30f11725ec42f14fe121fda3a4d3398baedf7b5442a3f87bd9cffe95573
|
|
4
|
+
data.tar.gz: 60908df104d07d036963dc5c105e0f02fb4b65a0f0336f4e21941ff5f080cef5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c4e43105945034eb0079c6d72ef9cd8593c318b12544781328547647445589808c6faef7a3e813f3c532a59d54d59a13827fa034e1496932b67c4dd95508b6f
|
|
7
|
+
data.tar.gz: 58ee38130ab763b8733f9602b07d07648605918ae1c7e7a4bb49f9d7e0fb867f45f3e062cb6837b385331e95e782ab272cfd6804b19900d4205f8f4ef4827b58
|
|
@@ -20,5 +20,5 @@ jobs:
|
|
|
20
20
|
git init ../amath
|
|
21
21
|
git -C ../amath fetch --depth 1 https://github.com/plurimath/amath.git b67f924477ce129e85926eda5973d771c007dfec
|
|
22
22
|
git -C ../amath checkout --detach FETCH_HEAD
|
|
23
|
-
printf '\ngem "amath", path: "../amath"\
|
|
23
|
+
printf '\ngem "amath", path: "../amath"\n' >> Gemfile
|
|
24
24
|
repos-json-file: .github/workflows/dependent-repos-ruby.json
|
data/.rspec-opal
CHANGED
data/Gemfile
CHANGED
|
@@ -4,6 +4,7 @@ source "https://rubygems.org"
|
|
|
4
4
|
gemspec
|
|
5
5
|
|
|
6
6
|
gem "canon"
|
|
7
|
+
gem "leptris" # third XML engine under test (spec_helper runs each example per engine)
|
|
7
8
|
# Optional native image-rendering backend for `Formula#render` / `plurimath
|
|
8
9
|
# render`. Git-pinned until `lasem` ships to RubyGems; intentionally NOT a
|
|
9
10
|
# gemspec runtime dependency so Opal/plurimath-js and lasem-less installs keep
|
|
@@ -17,9 +18,7 @@ gem "nokogiri"
|
|
|
17
18
|
# gem "omml", github: "plurimath/omml", branch: "main"
|
|
18
19
|
gem "opal-rspec", "~> 1.1.0a"
|
|
19
20
|
gem "ox"
|
|
20
|
-
|
|
21
|
-
# 1.3.112 restores the v1 edition default (1.3.110 and 1.3.111 are yanked).
|
|
22
|
-
gem "parsanol", "~> 1.3", ">= 1.3.112"
|
|
21
|
+
gem "parsanol"
|
|
23
22
|
gem "rake", "~> 12.0"
|
|
24
23
|
gem "rspec", "~> 3.0"
|
|
25
24
|
gem "rubocop-performance"
|
|
@@ -32,8 +32,11 @@ module Plurimath
|
|
|
32
32
|
when "oga"
|
|
33
33
|
require_relative "../setup/oga"
|
|
34
34
|
Plurimath::XmlEngine::Oga
|
|
35
|
+
when "leptris"
|
|
36
|
+
require_relative "../setup/leptris_engine"
|
|
37
|
+
Plurimath::XmlEngine::LeptrisEngine
|
|
35
38
|
else
|
|
36
|
-
warn_and_exit("Invalid XML engine: #{engine}. Use 'ox' or '
|
|
39
|
+
warn_and_exit("Invalid XML engine: #{engine}. Use 'ox', 'oga' or 'leptris'.")
|
|
37
40
|
end
|
|
38
41
|
Plurimath.xml_engine = engine_class
|
|
39
42
|
end
|
data/lib/plurimath/cli.rb
CHANGED
|
@@ -51,7 +51,7 @@ module Plurimath
|
|
|
51
51
|
option :xml_engine,
|
|
52
52
|
aliases: "-e",
|
|
53
53
|
default: "ox",
|
|
54
|
-
desc: "XML engine to use for parsing and rendering (ox or
|
|
54
|
+
desc: "XML engine to use for parsing and rendering (ox, oga or leptris)"
|
|
55
55
|
|
|
56
56
|
def convert
|
|
57
57
|
Convert.new(options).call
|
|
@@ -101,7 +101,7 @@ module Plurimath
|
|
|
101
101
|
option :xml_engine,
|
|
102
102
|
aliases: "-e",
|
|
103
103
|
default: "ox",
|
|
104
|
-
desc: "XML engine to use for parsing and rendering (ox or
|
|
104
|
+
desc: "XML engine to use for parsing and rendering (ox, oga or leptris)"
|
|
105
105
|
|
|
106
106
|
def render
|
|
107
107
|
Render.new(options).call
|
data/lib/plurimath/html/parse.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Plurimath
|
|
|
15
15
|
|
|
16
16
|
def parse
|
|
17
17
|
nodes = Parse.new.parse(normalized_text)
|
|
18
|
-
nodes = JSON.parse(nodes.to_json, symbolize_names: true)
|
|
18
|
+
nodes = JSON.parse(normalized_nodes(nodes).to_json, symbolize_names: true)
|
|
19
19
|
transformed_tree = Transform.new.apply(nodes)
|
|
20
20
|
return transformed_tree if transformed_tree.is_a?(Math::Formula)
|
|
21
21
|
|
|
@@ -24,6 +24,19 @@ module Plurimath
|
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
|
+
def normalized_nodes(node, depth = 0)
|
|
28
|
+
if depth >= 100 && (node.is_a?(Hash) || node.is_a?(Array))
|
|
29
|
+
raise JSON::NestingError, "nesting of #{depth + 1} is too deep"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
case node
|
|
33
|
+
when Parsanol::Slice then node.to_s
|
|
34
|
+
when Hash then node.transform_values { |child| normalized_nodes(child, depth + 1) }
|
|
35
|
+
when Array then node.map { |child| normalized_nodes(child, depth + 1) }
|
|
36
|
+
else node
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
27
40
|
def normalized_text
|
|
28
41
|
text.gsub(HTML_ENTITY) do |entity|
|
|
29
42
|
decoded_entity = Utility.html_entity_to_unicode(entity)
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Plurimath
|
|
4
4
|
class Latex
|
|
5
|
-
class Parse <
|
|
5
|
+
class Parse < Parsanol::Parser
|
|
6
6
|
include Plurimath::BaseNumberPrefix::Parser
|
|
7
7
|
|
|
8
|
+
def parse(input, options = {}, **kwargs)
|
|
9
|
+
restore_row_break_keys(super)
|
|
10
|
+
end
|
|
11
|
+
|
|
8
12
|
rule(:base) { str("_") }
|
|
9
13
|
rule(:power) { str("^") }
|
|
10
14
|
rule(:slash) { str("\\") }
|
|
@@ -276,6 +280,21 @@ module Plurimath
|
|
|
276
280
|
(str("{") >> slash >> str("color").as(:binary) >> color.as(:first_value) >> (sequence >> iteration.maybe).as(:second_value).maybe >> str("}")) |
|
|
277
281
|
(slash >> str("color").as(:binary) >> color.as(:first_value) >> expression.as(:second_value).maybe)
|
|
278
282
|
end
|
|
283
|
+
|
|
284
|
+
private
|
|
285
|
+
|
|
286
|
+
# Native captures use Symbol names; this grammar historically names its
|
|
287
|
+
# row-break capture with a String. Preserve that public raw-tree shape.
|
|
288
|
+
def restore_row_break_keys(tree)
|
|
289
|
+
case tree
|
|
290
|
+
when Hash
|
|
291
|
+
tree.to_h do |key, value|
|
|
292
|
+
[key == :"\\\\" ? "\\\\" : key, restore_row_break_keys(value)]
|
|
293
|
+
end
|
|
294
|
+
when Array then tree.map { |value| restore_row_break_keys(value) }
|
|
295
|
+
else tree
|
|
296
|
+
end
|
|
297
|
+
end
|
|
279
298
|
end
|
|
280
299
|
end
|
|
281
300
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Plurimath
|
|
4
4
|
class Latex
|
|
5
|
-
class Transform <
|
|
5
|
+
class Transform < Parsanol::Transform
|
|
6
6
|
include Plurimath::BaseNumberPrefix::Transform
|
|
7
7
|
|
|
8
8
|
rule(base: simple(:base)) { base }
|
|
@@ -25,6 +25,8 @@ module Plurimath
|
|
|
25
25
|
end
|
|
26
26
|
rule(limits: simple(:limits)) { limits }
|
|
27
27
|
rule("\\\\" => simple(:slash)) { Math::Function::Linebreak.new }
|
|
28
|
+
# Native named captures use symbol keys; Ruby retains the declared string.
|
|
29
|
+
rule("\\\\": simple(:slash)) { Math::Function::Linebreak.new }
|
|
28
30
|
rule(expression: simple(:expr)) { expr }
|
|
29
31
|
rule(environment: simple(:env)) { env }
|
|
30
32
|
rule(ternary: simple(:ternary)) { Utility.get_class(ternary).new }
|
|
@@ -52,7 +54,7 @@ module Plurimath
|
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
rule(binary: simple(:binary)) do
|
|
55
|
-
binary.is_a?(
|
|
57
|
+
binary.is_a?(Parsanol::Slice) ? Utility.get_class(binary).new : binary
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
rule(symbols: simple(:sym)) do
|
|
@@ -330,7 +332,7 @@ module Plurimath
|
|
|
330
332
|
|
|
331
333
|
rule(unary_functions: simple(:unary),
|
|
332
334
|
subscript: simple(:subscript)) do
|
|
333
|
-
unary_function = if unary.is_a?(
|
|
335
|
+
unary_function = if unary.is_a?(Parsanol::Slice)
|
|
334
336
|
Utility.get_class(unary).new
|
|
335
337
|
else
|
|
336
338
|
unary
|
|
@@ -356,7 +358,7 @@ module Plurimath
|
|
|
356
358
|
|
|
357
359
|
rule(unary_functions: simple(:unary),
|
|
358
360
|
supscript: simple(:supscript)) do
|
|
359
|
-
unary_function = if unary.is_a?(
|
|
361
|
+
unary_function = if unary.is_a?(Parsanol::Slice)
|
|
360
362
|
Utility.get_class(unary).new
|
|
361
363
|
else
|
|
362
364
|
unary
|
|
@@ -389,7 +391,7 @@ module Plurimath
|
|
|
389
391
|
rule(unary_functions: simple(:unary),
|
|
390
392
|
subscript: simple(:subscript),
|
|
391
393
|
supscript: simple(:supscript)) do
|
|
392
|
-
unary_function = if unary.is_a?(
|
|
394
|
+
unary_function = if unary.is_a?(Parsanol::Slice)
|
|
393
395
|
Utility.get_class(unary).new
|
|
394
396
|
else
|
|
395
397
|
unary
|
|
@@ -756,7 +758,7 @@ module Plurimath
|
|
|
756
758
|
rule(binary: simple(:binary),
|
|
757
759
|
subscript: simple(:subscript),
|
|
758
760
|
supscript: simple(:supscript)) do
|
|
759
|
-
if binary.is_a?(
|
|
761
|
+
if binary.is_a?(Parsanol::Slice)
|
|
760
762
|
Utility.get_class(binary).new(
|
|
761
763
|
subscript,
|
|
762
764
|
supscript,
|
|
@@ -772,7 +774,7 @@ module Plurimath
|
|
|
772
774
|
|
|
773
775
|
rule(binary: simple(:binary),
|
|
774
776
|
subscript: simple(:subscript)) do
|
|
775
|
-
if binary.is_a?(
|
|
777
|
+
if binary.is_a?(Parsanol::Slice)
|
|
776
778
|
Utility.get_class(binary).new(subscript)
|
|
777
779
|
else
|
|
778
780
|
Math::Function::Base.new(
|
|
@@ -11,7 +11,7 @@ module Plurimath
|
|
|
11
11
|
attr_accessor :parameter_one, :hide_function_name
|
|
12
12
|
|
|
13
13
|
def initialize(parameter_one = nil)
|
|
14
|
-
parameter_one = parameter_one.to_s if
|
|
14
|
+
parameter_one = parameter_one.to_s if Utility.parser_slice?(parameter_one)
|
|
15
15
|
@parameter_one = parameter_one
|
|
16
16
|
method(:post_initialize).call if methods.include?(:post_initialize)
|
|
17
17
|
ModelHelper.validate_left_right(variables.map { |var| get(var) })
|
|
@@ -7,7 +7,7 @@ module Plurimath
|
|
|
7
7
|
|
|
8
8
|
def initialize(value = nil, mini_sub_sized: false, mini_sup_sized: false,
|
|
9
9
|
base: nil)
|
|
10
|
-
@value =
|
|
10
|
+
@value = Utility.parser_slice?(value) ? value.to_s : value
|
|
11
11
|
@mini_sub_sized = mini_sub_sized
|
|
12
12
|
@mini_sup_sized = mini_sup_sized
|
|
13
13
|
@base = base
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "leptris"
|
|
5
|
+
rescue LoadError
|
|
6
|
+
raise LoadError,
|
|
7
|
+
"the leptris XML engine needs the leptris gem " \
|
|
8
|
+
"(gem install leptris, or add `gem \"leptris\"` to your Gemfile). " \
|
|
9
|
+
"leptris is an opt-in soft dependency, like the oga engine."
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require "plurimath/xml_engine/leptris_engine"
|
|
13
|
+
|
|
14
|
+
Plurimath.xml_engine = Plurimath::XmlEngine::LeptrisEngine
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Plurimath
|
|
4
4
|
class UnicodeMath
|
|
5
|
-
class Parse <
|
|
5
|
+
class Parse < Parsanol::Parser
|
|
6
6
|
include Plurimath::BaseNumberPrefix::Parser
|
|
7
7
|
include ParsingRules::Masked
|
|
8
8
|
include ParsingRules::SubSup
|
|
@@ -10,6 +10,11 @@ module Plurimath
|
|
|
10
10
|
include ParsingRules::ConstantsRules
|
|
11
11
|
include ParsingRules::AbsenceRules
|
|
12
12
|
|
|
13
|
+
# Preserve the historical UnicodeMath memo decisions in both engines.
|
|
14
|
+
def parse(input, options = {}, **kwargs)
|
|
15
|
+
super(input, options, **kwargs, compatibility: :parslet)
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
rule(:an) { an_math | an_other }
|
|
14
19
|
rule(:box) { str("□") >> operand }
|
|
15
20
|
|
|
@@ -288,7 +293,7 @@ module Plurimath
|
|
|
288
293
|
root :expression
|
|
289
294
|
|
|
290
295
|
def decimal_marker
|
|
291
|
-
# UnicodeMath::Parser entity-encodes input before
|
|
296
|
+
# UnicodeMath::Parser entity-encodes input before the grammar sees it, so
|
|
292
297
|
# non-ASCII locale markers must match that encoded parser input.
|
|
293
298
|
str(Utility.string_to_html_entity(Plurimath.configuration.decimal))
|
|
294
299
|
end
|
|
@@ -5,13 +5,7 @@ module Plurimath
|
|
|
5
5
|
module ParsingRules
|
|
6
6
|
module Helper
|
|
7
7
|
def self.included(base)
|
|
8
|
-
base.extend(ClassMethods)
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
module ClassMethods
|
|
13
|
-
def rule(name, &block)
|
|
14
|
-
Parslet::Parser.rule(name, &block)
|
|
8
|
+
base.extend(Parsanol::ClassMethods)
|
|
15
9
|
end
|
|
16
10
|
end
|
|
17
11
|
end
|
data/lib/plurimath/utility.rb
CHANGED
|
@@ -132,6 +132,10 @@ module Plurimath
|
|
|
132
132
|
}.freeze
|
|
133
133
|
|
|
134
134
|
class << self
|
|
135
|
+
def parser_slice?(value)
|
|
136
|
+
value.is_a?(::Parslet::Slice) || value.is_a?(::Parsanol::Slice)
|
|
137
|
+
end
|
|
138
|
+
|
|
135
139
|
def get_table_class(text)
|
|
136
140
|
Object.const_get("Plurimath::Math::Function::Table::#{capitalize(text)}")
|
|
137
141
|
end
|
|
@@ -210,7 +214,7 @@ module Plurimath
|
|
|
210
214
|
end
|
|
211
215
|
|
|
212
216
|
def symbols_class(string, lang:, table: false)
|
|
213
|
-
return string unless string.is_a?(String) ||
|
|
217
|
+
return string unless string.is_a?(String) || parser_slice?(string)
|
|
214
218
|
return latex_table_curly_paren(string) if table && lang == :latex
|
|
215
219
|
|
|
216
220
|
all_symbols_classes(lang)[string.to_s.strip]&.new ||
|
data/lib/plurimath/version.rb
CHANGED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plurimath
|
|
4
|
+
module XmlEngine
|
|
5
|
+
class LeptrisEngine
|
|
6
|
+
class Element
|
|
7
|
+
# strip_prefix mirrors ox's strip_namespace: names of a document
|
|
8
|
+
# loaded via LeptrisEngine.load report local names, while elements
|
|
9
|
+
# constructed by name keep their prefix ("w:rPr").
|
|
10
|
+
def initialize(node, strip_prefix: false)
|
|
11
|
+
@strip_prefix = strip_prefix
|
|
12
|
+
@node =
|
|
13
|
+
if node.is_a?(String)
|
|
14
|
+
# leptris parses namespace prefixes leniently, so prefixed names
|
|
15
|
+
# (w:rPr et al.) need no declaration; keep the owning document
|
|
16
|
+
# reachable so the FFI handle outlives this wrapper.
|
|
17
|
+
fragment = ::Leptris::XML.parse("<#{node}/>")
|
|
18
|
+
@document = fragment
|
|
19
|
+
fragment.root
|
|
20
|
+
else
|
|
21
|
+
@document = node.document if node.respond_to?(:document)
|
|
22
|
+
node
|
|
23
|
+
end
|
|
24
|
+
# The parser reports local names (prefix stripped) while the tree
|
|
25
|
+
# keeps the prefix in serialization; restore the constructed
|
|
26
|
+
# spelling so #name matches the ox contract ("w:rPr", not "rPr").
|
|
27
|
+
@node.name = node if node.is_a?(String) && @node.name != node
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ==(object)
|
|
31
|
+
self.class == object.class &&
|
|
32
|
+
@node.to_xml == object.xml_nodes.to_xml
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def [](object)
|
|
36
|
+
# leptris's own #[] lookup is namespace-aware and misses prefixed
|
|
37
|
+
# names; the attributes hash keeps the constructed spelling, which
|
|
38
|
+
# matches ox's flat string keys.
|
|
39
|
+
@node.attributes[object.to_s]&.value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def []=(attr, value)
|
|
43
|
+
@node[attr.to_s] = Utility.html_entity_to_unicode(value.to_s)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def name
|
|
47
|
+
local = @node.name
|
|
48
|
+
return local if @strip_prefix || local.include?(":")
|
|
49
|
+
|
|
50
|
+
# attached nodes report only the local name; re-attach the prefix
|
|
51
|
+
# the tree still carries for the constructed-name contract
|
|
52
|
+
prefix = @node.prefix
|
|
53
|
+
prefix ? "#{prefix}:#{local}" : local
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def name=(new_name)
|
|
57
|
+
@node.name = new_name
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def set_attr(attrs)
|
|
61
|
+
attrs&.each { |key, value| self[key] = value }
|
|
62
|
+
self
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def remove_attr(attribute)
|
|
66
|
+
@node.remove_attribute(attribute.to_s)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def <<(object)
|
|
70
|
+
@node.add_child(
|
|
71
|
+
object.is_a?(String) ? text_node_for(object) : attachable(object.xml_nodes),
|
|
72
|
+
)
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def attributes
|
|
77
|
+
@node.attributes.transform_values(&:value)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def attributes=(attr_hash = {})
|
|
81
|
+
set_attr(attr_hash)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def xml_nodes
|
|
85
|
+
@node
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def nodes
|
|
89
|
+
@node.children.map { |node| element_or_string(node) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def each(&block)
|
|
93
|
+
nodes.each(&block)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def map(&block)
|
|
97
|
+
nodes.map(&block)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def xml_node?
|
|
101
|
+
true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def insert_in_nodes(index, element)
|
|
105
|
+
children = @node.children
|
|
106
|
+
node = attachable(element.xml_nodes)
|
|
107
|
+
if index >= children.size
|
|
108
|
+
@node.add_child(node)
|
|
109
|
+
else
|
|
110
|
+
children[index].add_previous_sibling(node)
|
|
111
|
+
end
|
|
112
|
+
self
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Ox-style locate paths ("*/mfrac/@intent") are XPath-compatible once
|
|
116
|
+
# made relative; attribute results come back as plain strings, as
|
|
117
|
+
# Ox's locate returns them.
|
|
118
|
+
def locate(string)
|
|
119
|
+
@node.xpath("./#{string}").map do |found|
|
|
120
|
+
case found
|
|
121
|
+
when ::Leptris::XML::Attr then found.value
|
|
122
|
+
when ::Leptris::XML::Text then found.text
|
|
123
|
+
else self.class.new(found, strip_prefix: @strip_prefix)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def replace_nodes(nodes_array)
|
|
129
|
+
@node.children.each(&:unlink)
|
|
130
|
+
nodes_array.each do |node|
|
|
131
|
+
@node.add_child(
|
|
132
|
+
if node.is_a?(Element)
|
|
133
|
+
attachable(node.xml_nodes)
|
|
134
|
+
elsif node.is_a?(String)
|
|
135
|
+
text_node_for(node)
|
|
136
|
+
else
|
|
137
|
+
attachable(node)
|
|
138
|
+
end,
|
|
139
|
+
)
|
|
140
|
+
end
|
|
141
|
+
self
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def is_xml_comment?
|
|
145
|
+
@node.is_a?(::Leptris::XML::Comment)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
# Engine insertion has value semantics: ox and oga let the same
|
|
151
|
+
# element object be inserted twice and render twice (Abs relies on
|
|
152
|
+
# this for its open/close fences). leptris nodes are handles into a
|
|
153
|
+
# C tree where a second add_child MOVES the node, so an
|
|
154
|
+
# already-attached node is deep-copied first; freshly built nodes
|
|
155
|
+
# (no parent yet) attach directly.
|
|
156
|
+
def attachable(node)
|
|
157
|
+
return node unless node.parent
|
|
158
|
+
|
|
159
|
+
if node.is_a?(::Leptris::XML::Element)
|
|
160
|
+
node.dup
|
|
161
|
+
else
|
|
162
|
+
# dup is only supported for element nodes; rebuild text by value
|
|
163
|
+
text_node_for(node.text)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Ox stores string children raw (no markup decoding); leptris treats
|
|
168
|
+
# add_child(String) as markup, so go through create_text_node to keep
|
|
169
|
+
# entity text like "β" literal.
|
|
170
|
+
def text_node_for(string)
|
|
171
|
+
doc = @node.respond_to?(:document) ? @node.document : @node
|
|
172
|
+
doc.create_text_node(string)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def element_or_string(node)
|
|
176
|
+
node.is_a?(::Leptris::XML::Text) ? node.text : self.class.new(node, strip_prefix: @strip_prefix)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "leptris"
|
|
4
|
+
|
|
5
|
+
module Plurimath
|
|
6
|
+
module XmlEngine
|
|
7
|
+
class LeptrisEngine
|
|
8
|
+
class << self
|
|
9
|
+
def new_element(name)
|
|
10
|
+
Element.new(name)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def dump(data, indent: nil)
|
|
14
|
+
# ox dump parity: compact when indent is nil, 2-space pretty print
|
|
15
|
+
# otherwise; ox additionally wraps the output in newlines — the
|
|
16
|
+
# leading one is stripped by REPLACABLES downstream, the trailing
|
|
17
|
+
# one is part of the expected output, so it is appended here.
|
|
18
|
+
xml = data.xml_nodes.to_xml(indent: indent)
|
|
19
|
+
indent ? "#{xml}\n" : xml
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def load(data)
|
|
23
|
+
Element.new(::Leptris::XML.parse(data), strip_prefix: true)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def is_xml_comment?(node)
|
|
27
|
+
return node.is_xml_comment? if node.is_a?(Element)
|
|
28
|
+
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def replace_nodes(root, nodes)
|
|
33
|
+
root.replace_nodes(Array(nodes))
|
|
34
|
+
root
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
autoload :Element, "#{__dir__}/leptris_engine/element"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/plurimath.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "mml"
|
|
2
2
|
require "parslet"
|
|
3
|
+
require "parsanol"
|
|
3
4
|
require "htmlentities"
|
|
4
5
|
|
|
5
6
|
# Select an XML engine
|
|
@@ -64,6 +65,9 @@ default_adapter =
|
|
|
64
65
|
require "plurimath/setup/oga"
|
|
65
66
|
require "plurimath/setup/opal"
|
|
66
67
|
:oga
|
|
68
|
+
elsif ENV["PLURIMATH_LEPTRIS"]
|
|
69
|
+
require "plurimath/setup/leptris_engine"
|
|
70
|
+
:leptris
|
|
67
71
|
elsif ENV["PLURIMATH_OGA"]
|
|
68
72
|
require "plurimath/setup/oga"
|
|
69
73
|
:oga
|
data/plurimath.gemspec
CHANGED
|
@@ -35,6 +35,7 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
spec.add_dependency "omml", "~> 0.2.5"
|
|
36
36
|
spec.add_dependency "ostruct"
|
|
37
37
|
spec.add_dependency "ox"
|
|
38
|
+
spec.add_dependency "parsanol", "~> 1.3", ">= 1.3.116"
|
|
38
39
|
spec.add_dependency "parslet"
|
|
39
40
|
spec.add_dependency "thor"
|
|
40
41
|
spec.add_dependency "unitsml", "~> 0.6.4"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plurimath
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.11.
|
|
4
|
+
version: 0.11.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -122,6 +122,26 @@ dependencies:
|
|
|
122
122
|
- - ">="
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: parsanol
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '1.3'
|
|
132
|
+
- - ">="
|
|
133
|
+
- !ruby/object:Gem::Version
|
|
134
|
+
version: 1.3.116
|
|
135
|
+
type: :runtime
|
|
136
|
+
prerelease: false
|
|
137
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
138
|
+
requirements:
|
|
139
|
+
- - "~>"
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: '1.3'
|
|
142
|
+
- - ">="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: 1.3.116
|
|
125
145
|
- !ruby/object:Gem::Dependency
|
|
126
146
|
name: parslet
|
|
127
147
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -1918,6 +1938,7 @@ files:
|
|
|
1918
1938
|
- lib/plurimath/omml/parser.rb
|
|
1919
1939
|
- lib/plurimath/omml/translator.rb
|
|
1920
1940
|
- lib/plurimath/omml/utility.rb
|
|
1941
|
+
- lib/plurimath/setup/leptris_engine.rb
|
|
1921
1942
|
- lib/plurimath/setup/oga.rb
|
|
1922
1943
|
- lib/plurimath/setup/opal.rb.erb
|
|
1923
1944
|
- lib/plurimath/setup/ox_engine.rb
|
|
@@ -1940,6 +1961,8 @@ files:
|
|
|
1940
1961
|
- lib/plurimath/utility/intent_encoding.rb
|
|
1941
1962
|
- lib/plurimath/version.rb
|
|
1942
1963
|
- lib/plurimath/xml_engine.rb
|
|
1964
|
+
- lib/plurimath/xml_engine/leptris_engine.rb
|
|
1965
|
+
- lib/plurimath/xml_engine/leptris_engine/element.rb
|
|
1943
1966
|
- lib/plurimath/xml_engine/oga.rb
|
|
1944
1967
|
- lib/plurimath/xml_engine/oga/document.rb
|
|
1945
1968
|
- lib/plurimath/xml_engine/oga/dumper.rb
|