leptris 1.9.222.0-arm-linux → 1.9.222.2-arm-linux
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/ext/leptris/native/native.c +30 -0
- data/lib/leptris/html.rb +47 -0
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/document.rb +10 -0
- data/lib/leptris/xml/element.rb +32 -1
- data/lib/leptris/xml/html_serialize.rb +97 -0
- data/lib/leptris/xml/native.so +0 -0
- data/lib/leptris/xml.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2da4a19cbca71331b31eb5eacc93924035fc1f4051bde8361b127c318354cb63
|
|
4
|
+
data.tar.gz: c794ac2ce4219f5b97ea0264b766c6e2caa9fb7acf35a3254eaa4bc62744ae35
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a7acc7d9a8828a9d4bf441240bfb0312f464e5e3556c554af119a91626373babd03fa9ab7087433936f6fdd2a0c0c648c9dd1f4d8507ef5a8b72abc36c9530a
|
|
7
|
+
data.tar.gz: 24a2ba0806bd7fcc23dfac774b6c90c6ff9ef93082140421070fc4210abde3835c4133615726a37efda58753ae678c8760b74932cdb0bbd068479727de6c1b85
|
data/ext/leptris/native/native.c
CHANGED
|
@@ -2150,6 +2150,34 @@ static VALUE nf_plan_structs_typed_p(VALUE self)
|
|
|
2150
2150
|
return Qtrue;
|
|
2151
2151
|
}
|
|
2152
2152
|
|
|
2153
|
+
/* ---- Bulk attribute rows (leptris-ruby#278) ----------------------
|
|
2154
|
+
* One C crossing per element: walks the attribute chain and
|
|
2155
|
+
* returns a flat [name, value, address, ...] array. Names
|
|
2156
|
+
* interned (they repeat), values fresh UTF-8 strings, addresses
|
|
2157
|
+
* as Integers for Attr c_handle reconstruction. Identical data
|
|
2158
|
+
* to the per-attribute FFI chain (first/next/get_name/get_value,
|
|
2159
|
+
* 4 crossings each) — the win amplifies with attribute density
|
|
2160
|
+
* (40-attr elements: ~7x on the listing). */
|
|
2161
|
+
static VALUE nf_attribute_rows(VALUE self, VALUE document, VALUE addr)
|
|
2162
|
+
{
|
|
2163
|
+
(void)self;
|
|
2164
|
+
(void)document;
|
|
2165
|
+
void *node = (void *)(uintptr_t)NUM2ULL(addr);
|
|
2166
|
+
VALUE out = rb_ary_new();
|
|
2167
|
+
if (f_node_type(node) != WS_NODE_ELEMENT) return out;
|
|
2168
|
+
|
|
2169
|
+
for (void *a = f_attr_first(node); a; a = f_attr_next(a)) {
|
|
2170
|
+
const char *an = f_attr_name(a);
|
|
2171
|
+
const char *av = f_attr_value(node, a);
|
|
2172
|
+
rb_ary_push(out, an ? rb_enc_interned_str(an, strlen(an),
|
|
2173
|
+
rb_utf8_encoding())
|
|
2174
|
+
: Qnil);
|
|
2175
|
+
rb_ary_push(out, av ? rb_utf8_str_new_cstr(av) : Qnil);
|
|
2176
|
+
rb_ary_push(out, ULL2NUM((uintptr_t)a));
|
|
2177
|
+
}
|
|
2178
|
+
return out;
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2153
2181
|
static VALUE nf_plan_structs(VALUE self, VALUE document, VALUE addr,
|
|
2154
2182
|
VALUE spec)
|
|
2155
2183
|
{
|
|
@@ -2732,6 +2760,8 @@ LEPTRIS_INIT_EXPORT void Init_native(void)
|
|
|
2732
2760
|
nf_attribute_pairs, 2);
|
|
2733
2761
|
rb_define_module_function(m_native, "plan_structs",
|
|
2734
2762
|
nf_plan_structs, 3);
|
|
2763
|
+
rb_define_module_function(m_native, "attribute_rows",
|
|
2764
|
+
nf_attribute_rows, 2);
|
|
2735
2765
|
rb_define_module_function(m_native, "plan_structs_typed?",
|
|
2736
2766
|
nf_plan_structs_typed_p, 0);
|
|
2737
2767
|
rb_define_module_function(m_native, "doc_handle_attach",
|
data/lib/leptris/html.rb
CHANGED
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
# Leptris::HTML(html) # the html4 lane (Nokogiri::HTML parity)
|
|
11
11
|
# Leptris::HTML5.parse(html) # the WHATWG engine (html5lib zero reds)
|
|
12
12
|
# Leptris::HTML4.parse(html) # explicit html4 lane
|
|
13
|
+
# Leptris::HTML5.create # fresh document, <!DOCTYPE html> preset
|
|
13
14
|
#
|
|
14
15
|
# These are pure delegates — no parallel class hierarchy, no second
|
|
15
16
|
# wrapper cache; identity and the whole XML surface carry over.
|
|
17
|
+
# Construction flows through the same face as XML (create_element,
|
|
18
|
+
# add_child, root=, set_doctype) — `create` presets the doctype so a
|
|
19
|
+
# programmatically built document serializes with it; pair with
|
|
20
|
+
# `to_xml(no_decl: true)` for declaration-free HTML output (void
|
|
21
|
+
# elements serialize with the HTML5-legal trailing slash).
|
|
16
22
|
module Leptris
|
|
17
23
|
module HTML
|
|
18
24
|
module_function
|
|
@@ -22,6 +28,37 @@ module Leptris
|
|
|
22
28
|
def parse(html)
|
|
23
29
|
Leptris::XML.parse_html(html, mode: :html4)
|
|
24
30
|
end
|
|
31
|
+
|
|
32
|
+
# Fresh document with the HTML 4.01 Transitional doctype preset
|
|
33
|
+
# (Nokogiri::HTML::Builder's .doc carries the same). Pass
|
|
34
|
+
# +doctype: nil+ for a bare document.
|
|
35
|
+
def create(doctype: :transitional, skeleton: true)
|
|
36
|
+
create_document(doctype, skeleton: skeleton)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_document(doctype, skeleton: true)
|
|
40
|
+
doc = Leptris::XML::Document.create
|
|
41
|
+
case doctype
|
|
42
|
+
when :html5, true
|
|
43
|
+
doc.set_doctype("html")
|
|
44
|
+
when :transitional
|
|
45
|
+
doc.set_doctype(
|
|
46
|
+
"HTML",
|
|
47
|
+
public_id: "-//W3C//DTD HTML 4.01 Transitional//EN",
|
|
48
|
+
system_id: "http://www.w3.org/TR/html4/loose.dtd")
|
|
49
|
+
when nil, false then nil
|
|
50
|
+
else raise ArgumentError,
|
|
51
|
+
"doctype must be :html5, :transitional, nil, or false, got #{doctype.inspect}"
|
|
52
|
+
end
|
|
53
|
+
return doc unless skeleton
|
|
54
|
+
html = doc.create_element("html")
|
|
55
|
+
head = doc.create_element("head")
|
|
56
|
+
body = doc.create_element("body")
|
|
57
|
+
html.add_child(head)
|
|
58
|
+
html.add_child(body)
|
|
59
|
+
doc.root = html
|
|
60
|
+
doc
|
|
61
|
+
end
|
|
25
62
|
end
|
|
26
63
|
|
|
27
64
|
module HTML4
|
|
@@ -30,6 +67,10 @@ module Leptris
|
|
|
30
67
|
def parse(html)
|
|
31
68
|
Leptris::XML.parse_html(html, mode: :html4)
|
|
32
69
|
end
|
|
70
|
+
|
|
71
|
+
def create(doctype: :transitional, skeleton: true)
|
|
72
|
+
Leptris::HTML.create_document(doctype, skeleton: skeleton)
|
|
73
|
+
end
|
|
33
74
|
end
|
|
34
75
|
|
|
35
76
|
module HTML5
|
|
@@ -41,5 +82,11 @@ module Leptris
|
|
|
41
82
|
def parse(html)
|
|
42
83
|
Leptris::XML.parse_html(html, mode: :whatwg)
|
|
43
84
|
end
|
|
85
|
+
|
|
86
|
+
# Fresh document with the HTML5 doctype (`<!DOCTYPE html>`)
|
|
87
|
+
# preset; pass +doctype: nil+ for a bare document.
|
|
88
|
+
def create(doctype: :html5, skeleton: true)
|
|
89
|
+
Leptris::HTML.create_document(doctype, skeleton: skeleton)
|
|
90
|
+
end
|
|
44
91
|
end
|
|
45
92
|
end
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/document.rb
CHANGED
|
@@ -474,6 +474,16 @@ class Leptris::XML::Document
|
|
|
474
474
|
alias_method :to_s, :to_xml
|
|
475
475
|
alias_method :serialize, :to_xml
|
|
476
476
|
|
|
477
|
+
# HTML5 serialization (#309): void elements without a trailing
|
|
478
|
+
# slash (`<br>`), script/style content as raw text, text/attr
|
|
479
|
+
# entity escaping per HTML rules, the DOCTYPE emitted first.
|
|
480
|
+
# Walks the tree in Ruby — the engine-side serialization mode is
|
|
481
|
+
# the perf headroom this face gates on.
|
|
482
|
+
def to_html
|
|
483
|
+
raise Leptris::XML::UseAfterFreeError if @freed.state == :freed
|
|
484
|
+
Leptris::XML::HTMLSerialize.document(self)
|
|
485
|
+
end
|
|
486
|
+
|
|
477
487
|
def save(path, **opts)
|
|
478
488
|
opts_struct, _encoding_anchor = Leptris::XML::Serialization.build_options(
|
|
479
489
|
indent: opts.fetch(:indent, 0),
|
data/lib/leptris/xml/element.rb
CHANGED
|
@@ -311,7 +311,11 @@ class Leptris::XML::Element < Leptris::XML::Node
|
|
|
311
311
|
|
|
312
312
|
def attribute_nodes
|
|
313
313
|
return @attribute_nodes if memo_hit?(@attribute_nodes_version)
|
|
314
|
-
result =
|
|
314
|
+
result = if NATIVE_ATTR_ROWS && @c_address && @document
|
|
315
|
+
attribute_rows_native
|
|
316
|
+
else
|
|
317
|
+
each_attribute.to_a
|
|
318
|
+
end
|
|
315
319
|
if @document
|
|
316
320
|
@attribute_nodes = result
|
|
317
321
|
@attribute_nodes_version = @document.version
|
|
@@ -319,6 +323,26 @@ class Leptris::XML::Element < Leptris::XML::Node
|
|
|
319
323
|
result
|
|
320
324
|
end
|
|
321
325
|
|
|
326
|
+
# One C crossing per element (leptris-ruby#278): the native face
|
|
327
|
+
# walks the attribute chain and returns flat [name, value,
|
|
328
|
+
# address] triples; the Attr value objects are minted from them
|
|
329
|
+
# with zero further engine crossings — identical objects to
|
|
330
|
+
# each_attribute. The win amplifies with attribute density
|
|
331
|
+
# (40-attr elements list ~7x faster than the chain).
|
|
332
|
+
def attribute_rows_native
|
|
333
|
+
::Leptris::XML::Native.attribute_rows(@document, @c_address)
|
|
334
|
+
.each_slice(3)
|
|
335
|
+
.map do |name, value, handle|
|
|
336
|
+
::Leptris::XML::Attr.new(name, value, self,
|
|
337
|
+
c_handle: ::FFI::Pointer.new(handle))
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
NATIVE_ATTR_ROWS =
|
|
342
|
+
defined?(::Leptris::XML::Native) &&
|
|
343
|
+
::Leptris::XML::Native.respond_to?(:attribute_rows)
|
|
344
|
+
private_constant :NATIVE_ATTR_ROWS
|
|
345
|
+
|
|
322
346
|
# The element's own namespace prefix (e.g. "foo" for <foo:child/>),
|
|
323
347
|
# or nil when the element has none.
|
|
324
348
|
def prefix
|
|
@@ -756,6 +780,13 @@ class Leptris::XML::Element < Leptris::XML::Node
|
|
|
756
780
|
indent: indent, no_decl: no_decl, encoding: encoding)
|
|
757
781
|
end
|
|
758
782
|
|
|
783
|
+
# HTML5 serialization of this element subtree (#309 — see
|
|
784
|
+
# Document#to_html for the semantics).
|
|
785
|
+
def to_html
|
|
786
|
+
ensure_alive!
|
|
787
|
+
Leptris::XML::HTMLSerialize.element(self)
|
|
788
|
+
end
|
|
789
|
+
|
|
759
790
|
def canonicalize(version = Leptris::XML::FFI::C14N_1_0,
|
|
760
791
|
inclusive_namespaces = nil,
|
|
761
792
|
with_comments: false,
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The HTML5 tree serializer (#309): Ruby-level walk emitting
|
|
4
|
+
# HTML serialization semantics the XML face can't express —
|
|
5
|
+
#
|
|
6
|
+
# - VOID elements (br, meta, img, …) emit without the trailing
|
|
7
|
+
# slash and without a closing tag (`<br>`, `<meta charset="utf-8">`)
|
|
8
|
+
# - script/style content is RAW TEXT — emitted verbatim, never
|
|
9
|
+
# entity-escaped (`a > b` stays `a > b` inside `<style>`)
|
|
10
|
+
# - childless non-void elements get explicit closing tags
|
|
11
|
+
# (`<div></div>`, never `<div/>`)
|
|
12
|
+
# - text escapes &, <, > (and U+00A0 as ); attributes escape
|
|
13
|
+
# &, ", <, >
|
|
14
|
+
#
|
|
15
|
+
# `Document#to_html` / `Element#to_html` are one-line delegates.
|
|
16
|
+
# The walk is Ruby-level by design for now — the engine-side
|
|
17
|
+
# serialization mode (raw-text + void handling in C) is the
|
|
18
|
+
# perf headroom this face gates on.
|
|
19
|
+
module Leptris::XML::HTMLSerialize
|
|
20
|
+
VOID = %w[
|
|
21
|
+
area base br col embed hr img input link meta param source
|
|
22
|
+
track wbr
|
|
23
|
+
].freeze
|
|
24
|
+
RAW_TEXT = %w[script style].freeze
|
|
25
|
+
|
|
26
|
+
def self.document(doc)
|
|
27
|
+
out = +""
|
|
28
|
+
if (dt = doc.doctype)
|
|
29
|
+
out << "<!DOCTYPE" << " #{dt.name}"
|
|
30
|
+
out << " PUBLIC \"#{dt.public_id}\"" if dt.public_id
|
|
31
|
+
out << " \"#{dt.system_id}\"" if dt.system_id
|
|
32
|
+
out << ">"
|
|
33
|
+
end
|
|
34
|
+
doc.children.each { |child| node(child, out) }
|
|
35
|
+
out
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.element(element)
|
|
39
|
+
out = +""
|
|
40
|
+
node(element, out)
|
|
41
|
+
out
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.node(node, out)
|
|
45
|
+
case node
|
|
46
|
+
when Leptris::XML::Element then element_node(node, out)
|
|
47
|
+
when Leptris::XML::Comment then out << "<!--" << node.content.to_s << "-->"
|
|
48
|
+
when Leptris::XML::CDATA
|
|
49
|
+
# HTML5: CDATA sections in HTML serialize as bogus comments.
|
|
50
|
+
out << "<!--[CDATA[" << node.content.to_s << "]]-->"
|
|
51
|
+
when Leptris::XML::ProcessingInstruction
|
|
52
|
+
# HTML5: PIs serialize as bogus comments (?> is not a thing).
|
|
53
|
+
out << "<?" << node.target.to_s
|
|
54
|
+
out << " " << node.data.to_s unless node.data.to_s.empty?
|
|
55
|
+
out << ">"
|
|
56
|
+
when Leptris::XML::Text then text(node, out)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.element_node(el, out)
|
|
61
|
+
name = el.name
|
|
62
|
+
out << "<" << name
|
|
63
|
+
el.attributes.each do |attr_name, attr|
|
|
64
|
+
out << " " << attr_name << "=\"" << escape_attr(attr.value) << "\""
|
|
65
|
+
end
|
|
66
|
+
out << ">"
|
|
67
|
+
return if VOID.include?(name)
|
|
68
|
+
|
|
69
|
+
if RAW_TEXT.include?(name)
|
|
70
|
+
# Raw text: the element's text content verbatim — no entity
|
|
71
|
+
# escaping (CSS child selectors, JS comparisons survive).
|
|
72
|
+
el.children.each do |child|
|
|
73
|
+
out << child.content.to_s if child.is_a?(Leptris::XML::Text)
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
el.children.each { |child| node(child, out) }
|
|
77
|
+
end
|
|
78
|
+
out << "</" << name << ">"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.text(node, out)
|
|
82
|
+
parent_raw = node.parent && RAW_TEXT.include?(node.parent.name)
|
|
83
|
+
s = node.content.to_s
|
|
84
|
+
out << (parent_raw ? s : escape_text(s))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.escape_text(s)
|
|
88
|
+
s.gsub("&", "&").gsub("<", "<").gsub(">", ">")
|
|
89
|
+
.gsub("\u00A0", " ")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.escape_attr(s)
|
|
93
|
+
s.to_s.gsub("&", "&").gsub("\"", """)
|
|
94
|
+
.gsub("<", "<").gsub(">", ">")
|
|
95
|
+
.gsub("\u00A0", " ")
|
|
96
|
+
end
|
|
97
|
+
end
|
data/lib/leptris/xml/native.so
CHANGED
|
Binary file
|
data/lib/leptris/xml.rb
CHANGED
|
@@ -21,6 +21,7 @@ module Leptris
|
|
|
21
21
|
autoload :CssToXPath, "leptris/xml/css_to_xpath"
|
|
22
22
|
autoload :CStringArray, "leptris/xml/c_string_array"
|
|
23
23
|
autoload :Serialization, "leptris/xml/serialization"
|
|
24
|
+
autoload :HTMLSerialize, "leptris/xml/html_serialize"
|
|
24
25
|
autoload :SAX, "leptris/xml/sax"
|
|
25
26
|
autoload :XPath, "leptris/xml/xpath"
|
|
26
27
|
autoload :EvaluationContext, "leptris/xml/evaluation_context"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.222.
|
|
4
|
+
version: 1.9.222.2
|
|
5
5
|
platform: arm-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -158,6 +158,7 @@ files:
|
|
|
158
158
|
- lib/leptris/xml/entity_reference.rb
|
|
159
159
|
- lib/leptris/xml/evaluation_context.rb
|
|
160
160
|
- lib/leptris/xml/ffi.rb
|
|
161
|
+
- lib/leptris/xml/html_serialize.rb
|
|
161
162
|
- lib/leptris/xml/iteration_scope.rb
|
|
162
163
|
- lib/leptris/xml/iterparse.rb
|
|
163
164
|
- lib/leptris/xml/namespace.rb
|