moxml 0.5.123 → 0.5.124
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/Gemfile +1 -1
- data/lib/moxml/adapter/base.rb +41 -0
- data/lib/moxml/adapter/leptris.rb +60 -0
- data/lib/moxml/adapter/nokogiri.rb +34 -0
- data/lib/moxml/context.rb +23 -0
- data/lib/moxml/document.rb +16 -0
- data/lib/moxml/html_fragment.rb +43 -0
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml.rb +1 -0
- data/spec/moxml/html_fragment_spec.rb +87 -0
- data/spec/moxml/to_html_spec.rb +90 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 23e5ad1aa792190fa5588d08c6869fabfb6c7984ec4959d05d21add53ebf3ab3
|
|
4
|
+
data.tar.gz: a7bbc8695859d2b84b4e65e8abfe5a4922d52056be0d81a483cdd82be00f6c91
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b970f9b7d6ecc4d64d19ce08d9d84ffa438bcafa93c48935ed35b91113513488fa4b7f64b263832e6b6e33317ae1b775c12706b50961f153f0cb909144f4c02
|
|
7
|
+
data.tar.gz: 57d5ac6080f8e5ad8a85511dfb22e4598c7d5c546c66f71c5f5493339f83f182add0f5da51164fb0ec6f25af94b0e1397de2711a234229c74c68afc23741de2b
|
data/Gemfile
CHANGED
data/lib/moxml/adapter/base.rb
CHANGED
|
@@ -84,6 +84,18 @@ module Moxml
|
|
|
84
84
|
)
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
# HTML serialization through the engine's HTML method
|
|
88
|
+
# (issue #354): void elements slash-less, raw text verbatim,
|
|
89
|
+
# no declaration. indent:/indent_text: thread the
|
|
90
|
+
# pretty-print knobs where the adapter's engine carries
|
|
91
|
+
# them. Adapters without an HTML serializer raise.
|
|
92
|
+
def serialize_html(_node, _options = {})
|
|
93
|
+
raise Moxml::AdapterError.new(
|
|
94
|
+
"HTML serialization is not supported by the #{name.split('::').last} adapter",
|
|
95
|
+
adapter: name, operation: "serialize_html",
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
87
99
|
# Tolerant HTML4/5 parsing into the standard DOM (engine
|
|
88
100
|
# issue leptris/leptris#659): implied end tags, void elements,
|
|
89
101
|
# case-insensitive lowercased names, the HTML named-entity
|
|
@@ -103,6 +115,35 @@ module Moxml
|
|
|
103
115
|
)
|
|
104
116
|
end
|
|
105
117
|
|
|
118
|
+
# WHATWG fragment parsing with a context element (issue
|
|
119
|
+
# #353, the parse_html_fragment contract): body context by
|
|
120
|
+
# default; table contexts (td/th/tr/tbody/thead/tfoot/
|
|
121
|
+
# caption/colgroup/table) where the adapter's engine
|
|
122
|
+
# carries them. Returns the adapter's native fragment for
|
|
123
|
+
# HtmlFragment to wrap.
|
|
124
|
+
def parse_html_fragment(_html, _context_tag = :body, _context = nil)
|
|
125
|
+
raise Moxml::AdapterError.new(
|
|
126
|
+
"HTML fragment parsing is not supported by the #{name.split('::').last} adapter",
|
|
127
|
+
adapter: name, operation: "parse_html_fragment",
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# The native fragment's top-level children (native nodes).
|
|
132
|
+
def fragment_children(_native_fragment)
|
|
133
|
+
raise Moxml::NotImplementedError.new(
|
|
134
|
+
"fragment_children not implemented",
|
|
135
|
+
feature: "fragment_children", adapter: name,
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# The native fragment serialized as its children joined.
|
|
140
|
+
def serialize_fragment(_native_fragment)
|
|
141
|
+
raise Moxml::NotImplementedError.new(
|
|
142
|
+
"serialize_fragment not implemented",
|
|
143
|
+
feature: "serialize_fragment", adapter: name,
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
|
|
106
147
|
# Parse XML using SAX (event-driven) parsing
|
|
107
148
|
#
|
|
108
149
|
# SAX parsing provides a memory-efficient way to process XML
|
|
@@ -161,6 +161,27 @@ module Moxml
|
|
|
161
161
|
::Leptris::XML::Document.method_defined?(:absorb) &&
|
|
162
162
|
Gem::Version.new(::Leptris::VERSION) >= Gem::Version.new("1.9.311.3")
|
|
163
163
|
|
|
164
|
+
# Document#to_html indent kwargs (issue #354, engine
|
|
165
|
+
# leptris#1637 via leptris-ruby#421): the nested HTML layout
|
|
166
|
+
# (indent_html ext option — libxml2 format-mode shape). The
|
|
167
|
+
# parameter probe pairs the version gate: a pre-#421 binding's
|
|
168
|
+
# to_html takes no kwargs and would raise ArgumentError from
|
|
169
|
+
# the pass-through.
|
|
170
|
+
HTML_SERIALIZE_INDENT =
|
|
171
|
+
Gem::Version.new(::Leptris::VERSION) >= Gem::Version.new("1.9.338.0") &&
|
|
172
|
+
defined?(::Leptris::XML::Document) &&
|
|
173
|
+
::Leptris::XML::Document.method_defined?(:to_html) &&
|
|
174
|
+
::Leptris::XML::Document.instance_method(:to_html)
|
|
175
|
+
.parameters.any? { |_, key| key == :indent }
|
|
176
|
+
|
|
177
|
+
# Leptris::HTML.parse_fragment (leptris-ruby#422, engine
|
|
178
|
+
# in-body drops leptris#1638): the WHATWG fragment semantics
|
|
179
|
+
# composed over the binding's WHATWG lane. The face probe
|
|
180
|
+
# gates the ride — older bindings raise a named error.
|
|
181
|
+
HTML_FRAGMENT =
|
|
182
|
+
defined?(::Leptris::HTML) &&
|
|
183
|
+
::Leptris::HTML.respond_to?(:parse_fragment)
|
|
184
|
+
|
|
164
185
|
# Markup-accumulating builder face (leptris-ruby#374 lever 2,
|
|
165
186
|
# binding 1.9.313): the DSL accumulates markup in a plain
|
|
166
187
|
# String and ONE native crossing (parse + attach) flushes the
|
|
@@ -1077,6 +1098,45 @@ module Moxml
|
|
|
1077
1098
|
end
|
|
1078
1099
|
end
|
|
1079
1100
|
|
|
1101
|
+
def serialize_html(node, options = {})
|
|
1102
|
+
kwargs = options.slice(:indent, :indent_text).compact
|
|
1103
|
+
if kwargs.empty?
|
|
1104
|
+
return node.to_html
|
|
1105
|
+
end
|
|
1106
|
+
unless HTML_SERIALIZE_INDENT
|
|
1107
|
+
raise Moxml::AdapterError.new(
|
|
1108
|
+
"HTML serialization with indent options requires leptris >= 1.9.338.0 " \
|
|
1109
|
+
"(got #{::Leptris::VERSION})",
|
|
1110
|
+
adapter: name, operation: "serialize_html",
|
|
1111
|
+
)
|
|
1112
|
+
end
|
|
1113
|
+
node.to_html(**kwargs)
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1116
|
+
def parse_html_fragment(html, context_tag = :body, _context = nil)
|
|
1117
|
+
unless HTML_FRAGMENT
|
|
1118
|
+
raise Moxml::AdapterError.new(
|
|
1119
|
+
"HTML fragment parsing requires leptris >= 1.9.338.0 " \
|
|
1120
|
+
"(got #{::Leptris::VERSION})",
|
|
1121
|
+
adapter: name, operation: "parse_html_fragment",
|
|
1122
|
+
)
|
|
1123
|
+
end
|
|
1124
|
+
begin
|
|
1125
|
+
::Leptris::HTML.parse_fragment(html, context: context_tag)
|
|
1126
|
+
rescue ::ArgumentError => e
|
|
1127
|
+
raise Moxml::AdapterError.new(e.message,
|
|
1128
|
+
adapter: name, operation: "parse_html_fragment")
|
|
1129
|
+
end
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
def fragment_children(native_fragment)
|
|
1133
|
+
native_fragment.children
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
def serialize_fragment(native_fragment)
|
|
1137
|
+
native_fragment.to_html
|
|
1138
|
+
end
|
|
1139
|
+
|
|
1080
1140
|
def parse_html(html, _options = {}, _context = nil)
|
|
1081
1141
|
html_string = html.is_a?(IO) || html.is_a?(StringIO) ? html.read : html.to_s
|
|
1082
1142
|
native_doc = begin
|
|
@@ -159,6 +159,40 @@ module Moxml
|
|
|
159
159
|
Wrappers::Document.new(native_doc, _context || Context.new(:nokogiri))
|
|
160
160
|
end
|
|
161
161
|
|
|
162
|
+
# HTML method pass-through: the engine's own bytes (libxml2
|
|
163
|
+
# HTML serializer; the HTML5/gumbo serializer ignores indent
|
|
164
|
+
# kwargs — pass-through parity with direct Nokogiri calls,
|
|
165
|
+
# which is the byte contract of this adapter's to_html).
|
|
166
|
+
def serialize_html(node, options = {})
|
|
167
|
+
kwargs = {}
|
|
168
|
+
kwargs[:indent] = options[:indent] if options[:indent]
|
|
169
|
+
kwargs[:indent_text] = options[:indent_text] if options[:indent_text]
|
|
170
|
+
kwargs[:encoding] = options[:encoding] if options[:encoding]
|
|
171
|
+
node.to_html(**kwargs)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# WHATWG fragment parse through Nokogiri::HTML5.fragment
|
|
175
|
+
# (issue #353) — the same tree construction the leptris
|
|
176
|
+
# lane composes over its WHATWG engine.
|
|
177
|
+
def parse_html_fragment(html, context_tag = :body, _context = nil)
|
|
178
|
+
unless context_tag == :body
|
|
179
|
+
raise Moxml::AdapterError.new(
|
|
180
|
+
"nokogiri fragment contexts beyond :body are not supported " \
|
|
181
|
+
"(got #{context_tag.inspect})",
|
|
182
|
+
adapter: name, operation: "parse_html_fragment",
|
|
183
|
+
)
|
|
184
|
+
end
|
|
185
|
+
::Nokogiri::HTML5.fragment(html)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def fragment_children(native_fragment)
|
|
189
|
+
native_fragment.children.to_a
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def serialize_fragment(native_fragment)
|
|
193
|
+
native_fragment.children.map(&:to_html).join
|
|
194
|
+
end
|
|
195
|
+
|
|
162
196
|
# Nokogiri parses with `config.recover` unless strict, so
|
|
163
197
|
# recoverable syntax errors land on `doc.errors` instead of
|
|
164
198
|
# raising (issue #147).
|
data/lib/moxml/context.rb
CHANGED
|
@@ -133,6 +133,29 @@ module Moxml
|
|
|
133
133
|
config.adapter.parse_html(html, options, self)
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
+
# WHATWG fragment parse (issue #353): the parsed top-level
|
|
137
|
+
# nodes with fragment semantics — the context element's
|
|
138
|
+
# insertion mode governs tree construction (:body default keeps
|
|
139
|
+
# head-swept elements at fragment top level; the table
|
|
140
|
+
# contexts take the in-table rules). Returns an
|
|
141
|
+
# Moxml::HtmlFragment whose #children are the moxml-wrapped
|
|
142
|
+
# top-level nodes.
|
|
143
|
+
#
|
|
144
|
+
# @param html [String, IO] the fragment source
|
|
145
|
+
# @param context_tag [Symbol] :body (default) or a table
|
|
146
|
+
# context (:td, :th, :tr, :tbody, :thead, :tfoot, :caption,
|
|
147
|
+
# :colgroup, :table)
|
|
148
|
+
# @return [Moxml::HtmlFragment]
|
|
149
|
+
# @raise [Moxml::AdapterError] on adapters without fragment
|
|
150
|
+
# support or an unknown context tag
|
|
151
|
+
def parse_html_fragment(html, context_tag: :body)
|
|
152
|
+
html_string = html.is_a?(IO) || html.is_a?(StringIO) ? html.read : html.to_s
|
|
153
|
+
HtmlFragment.new(
|
|
154
|
+
config.adapter.parse_html_fragment(html_string, context_tag, self),
|
|
155
|
+
self,
|
|
156
|
+
)
|
|
157
|
+
end
|
|
158
|
+
|
|
136
159
|
# Compile an XSLT stylesheet with this context's adapter
|
|
137
160
|
# (implementation-agnostic; nokogiri/libxslt and leptris ship
|
|
138
161
|
# engines, leptris covering XSLT 2.0/3.0 per its engine). Apply
|
data/lib/moxml/document.rb
CHANGED
|
@@ -119,6 +119,22 @@ module Moxml
|
|
|
119
119
|
adapter.parse_errors(@native)
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
+
# HTML serialization (issue #354): documents parsed through
|
|
123
|
+
# parse_html — and XML documents alike — serialize through the
|
|
124
|
+
# adapter's HTML method: void elements slash-less, raw text
|
|
125
|
+
# (script/style) verbatim, no XML declaration.
|
|
126
|
+
#
|
|
127
|
+
# indent: N (spaces per level) and indent_text: unit (e.g. "\t")
|
|
128
|
+
# thread the pretty-print knobs on adapters that carry them
|
|
129
|
+
# (leptris >= the #354 ride; nokogiri passes them to the
|
|
130
|
+
# engine). Adapters without the knob raise Moxml::AdapterError.
|
|
131
|
+
def to_html(options = {})
|
|
132
|
+
result = adapter.serialize_html(@native, options)
|
|
133
|
+
apply_line_ending(result,
|
|
134
|
+
options.fetch(:line_ending, Config::LINE_ENDING_LF))
|
|
135
|
+
result
|
|
136
|
+
end
|
|
137
|
+
|
|
122
138
|
def create_element(name)
|
|
123
139
|
Wrappers::Element.new(adapter.create_element(name, owner_doc: @native), context)
|
|
124
140
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
# An HTML fragment (issue #353): the parsed top-level nodes of a
|
|
5
|
+
# WHATWG fragment parse with a context element (body by default).
|
|
6
|
+
# Not a Node — no parent, no document of its own; the adapter's
|
|
7
|
+
# native fragment owns the parsed tree's lifetime.
|
|
8
|
+
class HtmlFragment
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
def initialize(native_fragment, context)
|
|
12
|
+
@native_fragment = native_fragment
|
|
13
|
+
@context = context
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The top-level nodes, moxml-wrapped, in tree order.
|
|
17
|
+
def children
|
|
18
|
+
children_natives.map { |n| Node.wrap(n, @context) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def each(&block)
|
|
22
|
+
children.each(&block)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def size
|
|
26
|
+
children_natives.size
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def empty?
|
|
30
|
+
children_natives.empty?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_html(_options = {})
|
|
34
|
+
@context.config.adapter.serialize_fragment(@native_fragment)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def children_natives
|
|
40
|
+
@context.config.adapter.fragment_children(@native_fragment)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/moxml/version.rb
CHANGED
data/lib/moxml.rb
CHANGED
|
@@ -83,6 +83,7 @@ module Moxml
|
|
|
83
83
|
autoload :Doctype, "moxml/doctype"
|
|
84
84
|
autoload :EntityReference, "moxml/entity_reference"
|
|
85
85
|
autoload :DocumentBuilder, "moxml/document_builder"
|
|
86
|
+
autoload :HtmlFragment, "moxml/html_fragment"
|
|
86
87
|
autoload :Builder, "moxml/builder"
|
|
87
88
|
autoload :Entity, "moxml/entity"
|
|
88
89
|
autoload :EntityRegistry, "moxml/entity_registry"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# Context#parse_html_fragment (#353): WHATWG fragment semantics on
|
|
6
|
+
# the moxml surface — head-swept elements stay at fragment top
|
|
7
|
+
# level, table-structure tags follow the in-body rules, whitespace
|
|
8
|
+
# is preserved. The leptris lane composes over the binding's
|
|
9
|
+
# fragment face (leptris-ruby#422); nokogiri maps to
|
|
10
|
+
# Nokogiri::HTML5.fragment.
|
|
11
|
+
RSpec.describe "Context#parse_html_fragment" do
|
|
12
|
+
describe "nokogiri" do
|
|
13
|
+
let(:ctx) { Moxml.new(:nokogiri) }
|
|
14
|
+
|
|
15
|
+
it "keeps head-swept elements at fragment top level" do
|
|
16
|
+
frag = ctx.parse_html_fragment("<title>T</title><p>x</p>")
|
|
17
|
+
expect(frag.children.map(&:name)).to eq(%w[title p])
|
|
18
|
+
expect(frag.children.first).to be_element
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "drops table-structure elements, keeping their text" do
|
|
22
|
+
frag = ctx.parse_html_fragment("<td>cell</td>")
|
|
23
|
+
expect(frag.children.map(&:name)).to eq(["text"])
|
|
24
|
+
expect(frag.children.first.text).to eq("cell")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "preserves whitespace-only text" do
|
|
28
|
+
frag = ctx.parse_html_fragment(" <p>lead ws</p> ")
|
|
29
|
+
expect(frag.children.map(&:name).first).to eq("text")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "is enumerable and serializes as children joined" do
|
|
33
|
+
frag = ctx.parse_html_fragment("<p>a</p>tail")
|
|
34
|
+
expect(frag.size).to eq(2)
|
|
35
|
+
expect(frag.to_html).to eq("<p>a</p>tail")
|
|
36
|
+
expect(frag).not_to be_empty
|
|
37
|
+
expect(ctx.parse_html_fragment("")).to be_empty
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "wraps children with the context" do
|
|
41
|
+
frag = ctx.parse_html_fragment("<p>x</p>")
|
|
42
|
+
expect(frag.children.first.context).to eq(ctx)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "leptris" do
|
|
47
|
+
let(:ctx) { Moxml.new(:leptris) }
|
|
48
|
+
|
|
49
|
+
before do
|
|
50
|
+
unless Moxml::Adapter::Leptris::HTML_FRAGMENT
|
|
51
|
+
skip "binding #{Leptris::VERSION} predates the #353 fragment face"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "keeps head-swept elements at fragment top level" do
|
|
56
|
+
frag = ctx.parse_html_fragment("<title>T</title><p>x</p>")
|
|
57
|
+
expect(frag.children.map(&:name)).to eq(%w[title p])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "parses inside a table context" do
|
|
61
|
+
frag = ctx.parse_html_fragment("<b>x</b>", context_tag: :td)
|
|
62
|
+
expect(frag.children.map(&:name)).to eq(%w[b])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "raises a named error for unknown context tags" do
|
|
66
|
+
expect { ctx.parse_html_fragment("<p/>", context_tag: :nope) }
|
|
67
|
+
.to raise_error(Moxml::AdapterError, /table context/)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "drops table-structure elements, keeping their text" do
|
|
71
|
+
frag = ctx.parse_html_fragment("<td>cell</td>")
|
|
72
|
+
expect(frag.children.map(&:name)).to eq(["text"])
|
|
73
|
+
expect(frag.children.first.text).to eq("cell")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "serializes as children joined" do
|
|
77
|
+
expect(ctx.parse_html_fragment("<p>a</p>tail").to_html).to eq("<p>a</p>tail")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "adapters without fragment support" do
|
|
82
|
+
it "raise a named AdapterError" do
|
|
83
|
+
expect { Moxml.new(:rexml).parse_html_fragment("<p>x</p>") }
|
|
84
|
+
.to raise_error(Moxml::AdapterError, /HTML fragment parsing/)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# Document#to_html (issue #354): HTML-method serialization with the
|
|
6
|
+
# pretty-print knobs. The byte contract is per-engine pass-through —
|
|
7
|
+
# the leptris nested layout (engine leptris#1637) and Nokogiri's own
|
|
8
|
+
# serializer bytes — not cross-adapter byte equality.
|
|
9
|
+
RSpec.describe "Moxml::Document#to_html" do
|
|
10
|
+
let(:src) do
|
|
11
|
+
"<html><head><title>T</title></head><body><div id=\"a\"><p>x</p>" \
|
|
12
|
+
"<span>y</span></div><script>if (a < b) { c(); }</script></body></html>"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "nokogiri" do
|
|
16
|
+
let(:doc) { Moxml.new(:nokogiri).parse_html(src) }
|
|
17
|
+
|
|
18
|
+
it "serializes the engine's HTML bytes by default" do
|
|
19
|
+
expect(doc.to_html).to eq(Nokogiri::HTML(src).to_html)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "threads indent through to the engine" do
|
|
23
|
+
expect(doc.to_html(indent: 2))
|
|
24
|
+
.to eq(Nokogiri::HTML(src).to_html(indent: 2))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "threads the indent unit through to the engine" do
|
|
28
|
+
expect(doc.to_html(indent: 1, indent_text: "\t"))
|
|
29
|
+
.to eq(Nokogiri::HTML(src).to_html(indent: 1, indent_text: "\t"))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe "leptris" do
|
|
34
|
+
let(:doc) { Moxml.new(:leptris).parse_html(src) }
|
|
35
|
+
|
|
36
|
+
it "serializes single-line without kwargs" do
|
|
37
|
+
expect(doc.to_html).to eq(doc.native.to_html)
|
|
38
|
+
expect(doc.to_html).to start_with("<html>")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "with the indent ride armed (binding >= 1.9.338.0)" do
|
|
42
|
+
before do
|
|
43
|
+
unless Moxml::Adapter::Leptris::HTML_SERIALIZE_INDENT
|
|
44
|
+
skip "binding #{Leptris::VERSION} predates the #354 ride"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "nests block children with space leads" do
|
|
49
|
+
expect(doc.to_html(indent: 2)).to eq(
|
|
50
|
+
"<html>\n " \
|
|
51
|
+
"<head><title>T</title></head>\n " \
|
|
52
|
+
"<body>\n " \
|
|
53
|
+
"<div id=\"a\">\n " \
|
|
54
|
+
"<p>x</p>\n " \
|
|
55
|
+
"<span>y</span>\n " \
|
|
56
|
+
"</div>\n " \
|
|
57
|
+
"<script>if (a < b) { c(); }</script>\n " \
|
|
58
|
+
"</body>\n" \
|
|
59
|
+
"</html>",
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "nests with the indent_text unit" do
|
|
64
|
+
expect(doc.to_html(indent: 1, indent_text: "\t")).to include(
|
|
65
|
+
"<body>\n\t\t<div id=\"a\">\n\t\t\t<p>x</p>",
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context "when the binding predates the ride" do
|
|
71
|
+
before do
|
|
72
|
+
if Moxml::Adapter::Leptris::HTML_SERIALIZE_INDENT
|
|
73
|
+
skip "binding #{Leptris::VERSION} carries the ride"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "raises a named AdapterError instead of silently degrading" do
|
|
78
|
+
expect { doc.to_html(indent: 2) }.to raise_error(Moxml::AdapterError, /indent/)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe "adapters without an HTML serializer" do
|
|
84
|
+
it "raise a named AdapterError" do
|
|
85
|
+
doc = Moxml.new(:rexml).parse("<r><a>x</a></r>")
|
|
86
|
+
expect { doc.to_html }
|
|
87
|
+
.to raise_error(Moxml::AdapterError, /HTML serialization/)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: moxml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.124
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -214,6 +214,7 @@ files:
|
|
|
214
214
|
- lib/moxml/entity_registry.rb
|
|
215
215
|
- lib/moxml/entity_registry_opal_data.rb
|
|
216
216
|
- lib/moxml/error.rb
|
|
217
|
+
- lib/moxml/html_fragment.rb
|
|
217
218
|
- lib/moxml/lazy_node_set.rb
|
|
218
219
|
- lib/moxml/materializer.rb
|
|
219
220
|
- lib/moxml/namespace.rb
|
|
@@ -500,6 +501,7 @@ files:
|
|
|
500
501
|
- spec/moxml/entity_registry_spec.rb
|
|
501
502
|
- spec/moxml/entity_spec.rb
|
|
502
503
|
- spec/moxml/error_spec.rb
|
|
504
|
+
- spec/moxml/html_fragment_spec.rb
|
|
503
505
|
- spec/moxml/lazy_parse_spec.rb
|
|
504
506
|
- spec/moxml/materializer_spec.rb
|
|
505
507
|
- spec/moxml/moxml_spec.rb
|
|
@@ -543,6 +545,7 @@ files:
|
|
|
543
545
|
- spec/moxml/struct_plan_spec.rb
|
|
544
546
|
- spec/moxml/struct_plan_typed_spec.rb
|
|
545
547
|
- spec/moxml/text_spec.rb
|
|
548
|
+
- spec/moxml/to_html_spec.rb
|
|
546
549
|
- spec/moxml/version_spec.rb
|
|
547
550
|
- spec/moxml/xml_emitter_spec.rb
|
|
548
551
|
- spec/moxml/xml_utils/.gitkeep
|