leptris 1.9.39 → 1.9.40
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/CHANGELOG.md +32 -0
- data/Rakefile +12 -2
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/document_fragment.rb +3 -2
- data/lib/leptris/xml/ffi.rb +60 -4
- data/lib/leptris/xml/node.rb +6 -3
- data/lib/leptris/xml/sax/dom_dispatch.rb +8 -14
- data/lib/leptris/xml/sax/parser.rb +8 -8
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 63ca61bcacf68aee02e3fb94c53f84d64af4474cf5b250482135a632b5ac2009
|
|
4
|
+
data.tar.gz: 269dd93a547a099a5eb0685f9d58ecfa2d281d373f969cc8e69a7cd6aece5614
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d908e6a85d409bae57e50703a87be059e984a67af44139769475f6baa82631894d9cbd26390442f32af54d2987242fee8bc528f70f52e0284692fd522cb2ea23
|
|
7
|
+
data.tar.gz: 9826c4922df24a0703eca6e39b8b6f62fe5c6deccdf5212b7e8bcc76897b74ce4cc587add6a95aa60324dcff538087cdc5bb5ba35e421a37ce0bc26a18237bad
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ All notable changes to Leptris will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.40] - 2026-08-30
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **SAX delivers through the engine transports again** — the #95
|
|
13
|
+
attribute corruption is fixed upstream (libleptris 1.9.18,
|
|
14
|
+
verified on the issue fixture through both engine transports:
|
|
15
|
+
all 7 image attributes intact). `SAX::Parser` defaults to
|
|
16
|
+
`streaming: true`; `streaming: false` keeps the DOM-backed
|
|
17
|
+
dispatcher as a fallback for older engines. The correctness tax
|
|
18
|
+
is gone: all-events 119 ms and text-only 21.6 ms per big.xml
|
|
19
|
+
parse vs Nokogiri's 131/130 ms — SAX wins every shape outright
|
|
20
|
+
again, with correct data.
|
|
21
|
+
- **libleptris 1.9.14–1.9.18 lockstep** (audit 253/253, three new
|
|
22
|
+
symbols): fixes for everything we were tracking upstream —
|
|
23
|
+
#625 (SAX attrs), #626 (MSVC non-ASCII names; the Windows spec
|
|
24
|
+
gate is removed), #627/#628/#630 (XSLT unknown fns and last();
|
|
25
|
+
relative namespaced descendant paths — spec added), #613
|
|
26
|
+
(latin-1), #608 (combined ns+vars eval; attached), #617
|
|
27
|
+
(node_children out_kinds; wired), #633 (pretty-print parity),
|
|
28
|
+
#635 (xmlns interleave; wired).
|
|
29
|
+
- **Children batches carry kinds** (`leptris_node_children_ex`):
|
|
30
|
+
`#children` and the fragment/dispatch walks wrap with the kind
|
|
31
|
+
hint — no per-child get_type dispatch. Measured: the cold
|
|
32
|
+
full-tree walk's remaining gap vs Nokogiri (1.5x) is the Ruby
|
|
33
|
+
wrapper allocation floor, not type dispatch; noted for the
|
|
34
|
+
record.
|
|
35
|
+
- **Exact xmlns interleave** (`leptris_element_attributes_raw`):
|
|
36
|
+
the DOM-backed fallback now reproduces the streaming contract's
|
|
37
|
+
byte-positioned declarations; the #99 spec is upgraded from
|
|
38
|
+
set-equality to exact order equality.
|
|
39
|
+
|
|
8
40
|
## [1.9.39] - 2026-08-29
|
|
9
41
|
|
|
10
42
|
### Fixed
|
data/Rakefile
CHANGED
|
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
8
8
|
# Pin for `rake compile` and the platform-gem builds. Keep in lockstep
|
|
9
9
|
# with .github/workflows/build.yml (which calls `rake compile`) and the
|
|
10
10
|
# CHANGELOG when libleptris releases.
|
|
11
|
-
LIBLEPTRIS_VERSION = "1.9.
|
|
11
|
+
LIBLEPTRIS_VERSION = "1.9.18"
|
|
12
12
|
|
|
13
13
|
CMAKE_FLAGS = %w[
|
|
14
14
|
-DCMAKE_BUILD_TYPE=Release
|
|
@@ -30,7 +30,17 @@ task :compile do
|
|
|
30
30
|
mkdir_p(build)
|
|
31
31
|
url = "https://api.github.com/repos/leptris/leptris/tarball/v#{version}"
|
|
32
32
|
sh "curl -sL #{url} | tar xz -C #{build} --strip-components=1"
|
|
33
|
-
|
|
33
|
+
# libleptris 1.9.18's xslt_functions.c:270 assigns LeptrisElement
|
|
34
|
+
# to LeptrisNodeRef — GCC 14 (Alpine/musl) makes incompatible
|
|
35
|
+
# pointer types an error by default and the musl platform gems
|
|
36
|
+
# fail to build; clang toolchains only warn. Downgrade to warning
|
|
37
|
+
# until the upstream fix (leptris/leptris#640).
|
|
38
|
+
# No quoting: the flag carries no spaces, and single quotes are
|
|
39
|
+
# literal on Windows shells (they broke the MSVC build).
|
|
40
|
+
# GCC-family only — MSVC's cl rejects the flag outright (D8021).
|
|
41
|
+
cflags = Gem.win_platform? ? "" : "-Wno-error=incompatible-pointer-types"
|
|
42
|
+
sh "cmake -B #{build}/build -S #{build} " \
|
|
43
|
+
"#{CMAKE_FLAGS.join(' ')} #{cflags.empty? ? '' : "-DCMAKE_C_FLAGS=#{cflags}"}"
|
|
34
44
|
sh "cmake --build #{build}/build --config Release -j 4"
|
|
35
45
|
# Windows names the shared library leptris.dll (no "lib" prefix);
|
|
36
46
|
# vendoring under the uniform libleptris.* name keeps the FFI
|
data/lib/leptris/version.rb
CHANGED
|
@@ -25,8 +25,9 @@ class Leptris::XML::DocumentFragment
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def children
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
pointers, kinds = Leptris::XML::FFI.fetch_children(@c_ptr)
|
|
29
|
+
nodes = Array.new(pointers.size) do |i|
|
|
30
|
+
Leptris::XML::Node.wrap(pointers[i], @document, node_type: kinds[i])
|
|
30
31
|
end
|
|
31
32
|
Leptris::XML::NodeSet.new(@document, nodes)
|
|
32
33
|
end
|
data/lib/leptris/xml/ffi.rb
CHANGED
|
@@ -225,8 +225,17 @@ module Leptris
|
|
|
225
225
|
# count-only query returning the TOTAL across every child kind.
|
|
226
226
|
attach_function :leptris_node_children,
|
|
227
227
|
[:leptris_node_ref, :pointer, :size_t], :size_t
|
|
228
|
+
# Children with out_kinds (1.9.18, upstream #617): the kind
|
|
229
|
+
# rides the batch, so wrappers skip the per-child get_type.
|
|
230
|
+
attach_function :leptris_node_children_ex,
|
|
231
|
+
[:leptris_node_ref, :pointer, :pointer, :size_t], :size_t
|
|
228
232
|
# Element-only batch; mirror-only — fetch_children rides the
|
|
229
233
|
# all-kind node_children above.
|
|
234
|
+
# Raw qname-ordered attribute list INCLUDING xmlns
|
|
235
|
+
# declarations at their byte positions (1.9.18, upstream
|
|
236
|
+
# #635) — the streaming SAX contract's mixed view.
|
|
237
|
+
attach_function :leptris_element_attributes_raw,
|
|
238
|
+
[:leptris_element, :pointer, :pointer, :size_t], :size_t
|
|
230
239
|
attach_function :leptris_element_children,
|
|
231
240
|
[:leptris_element, :pointer, :size_t], :size_t
|
|
232
241
|
attach_function :leptris_node_as_element,
|
|
@@ -538,6 +547,11 @@ module Leptris
|
|
|
538
547
|
attach_function :leptris_xpath_compiled_eval_vars,
|
|
539
548
|
[:leptris_xpath_compiled, :leptris_document, :leptris_element,
|
|
540
549
|
:leptris_xpath_var_set], :leptris_xpath_result
|
|
550
|
+
# Combined namespaces + variables (1.9.18, upstream #608).
|
|
551
|
+
attach_function :leptris_xpath_compiled_eval_ns_vars,
|
|
552
|
+
[:leptris_xpath_compiled, :leptris_document, :leptris_element,
|
|
553
|
+
:leptris_xpath_ns_set, :leptris_xpath_var_set],
|
|
554
|
+
:leptris_xpath_result
|
|
541
555
|
# Source text of a compiled expression (owned by the handle).
|
|
542
556
|
attach_function :leptris_xpath_compiled_text,
|
|
543
557
|
[:leptris_xpath_compiled], :string
|
|
@@ -893,6 +907,9 @@ module Leptris
|
|
|
893
907
|
FETCH_INITIAL = 32
|
|
894
908
|
private_constant :FETCH_INITIAL
|
|
895
909
|
|
|
910
|
+
# Returns [pointers, kinds] — the kinds ride the batch
|
|
911
|
+
# (leptris_node_children_ex, 1.9.18 #617) so wrappers skip
|
|
912
|
+
# the per-child get_type dispatch.
|
|
896
913
|
def self.fetch_children(c_ptr)
|
|
897
914
|
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
898
915
|
buffer = scratch[:pointers]
|
|
@@ -900,18 +917,57 @@ module Leptris
|
|
|
900
917
|
buffer = scratch[:pointers] =
|
|
901
918
|
::FFI::MemoryPointer.new(:pointer, FETCH_INITIAL)
|
|
902
919
|
end
|
|
920
|
+
# size the kinds buffer from the POINTERS buffer's capacity —
|
|
921
|
+
# it may have grown past FETCH_INITIAL on earlier use, and C
|
|
922
|
+
# writes one kind per copied child
|
|
903
923
|
cap = buffer.size / PTR_BYTES
|
|
904
|
-
|
|
924
|
+
kinds = scratch_ints(cap)
|
|
925
|
+
copied = leptris_node_children_ex(c_ptr, buffer, kinds, cap)
|
|
905
926
|
if copied == cap
|
|
906
|
-
total =
|
|
927
|
+
total = leptris_node_children_ex(c_ptr, nil, nil, 0)
|
|
907
928
|
if total > cap
|
|
908
929
|
buffer.free
|
|
909
930
|
buffer = scratch[:pointers] =
|
|
910
931
|
::FFI::MemoryPointer.new(:pointer, total)
|
|
911
|
-
|
|
932
|
+
kinds = scratch_ints(total)
|
|
933
|
+
copied = leptris_node_children_ex(c_ptr, buffer, kinds, total)
|
|
912
934
|
end
|
|
913
935
|
end
|
|
914
|
-
buffer.get_array_of_pointer(0, copied)
|
|
936
|
+
[buffer.get_array_of_pointer(0, copied),
|
|
937
|
+
kinds.get_array_of_int(0, copied)]
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
# Raw qname-ordered attribute pairs INCLUDING xmlns at their
|
|
941
|
+
# byte positions (leptris_element_attributes_raw, 1.9.18
|
|
942
|
+
# #635) — the streaming SAX contract's mixed view.
|
|
943
|
+
def self.fetch_attributes_raw(el_ptr)
|
|
944
|
+
total = leptris_element_attributes_raw(el_ptr, nil, nil, 0)
|
|
945
|
+
return [] if total.zero?
|
|
946
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
947
|
+
names = scratch[:attr_names]
|
|
948
|
+
if names.nil? || names.size / PTR_BYTES < total
|
|
949
|
+
names&.free
|
|
950
|
+
names = scratch[:attr_names] =
|
|
951
|
+
::FFI::MemoryPointer.new(:pointer, total)
|
|
952
|
+
end
|
|
953
|
+
values = scratch[:attr_values]
|
|
954
|
+
if values.nil? || values.size / PTR_BYTES < total
|
|
955
|
+
values&.free
|
|
956
|
+
values = scratch[:attr_values] =
|
|
957
|
+
::FFI::MemoryPointer.new(:pointer, total)
|
|
958
|
+
end
|
|
959
|
+
copied = leptris_element_attributes_raw(
|
|
960
|
+
el_ptr, names, values, total)
|
|
961
|
+
Array.new(copied) do |i|
|
|
962
|
+
[utf8(names.get_pointer(i * PTR_BYTES).read_string),
|
|
963
|
+
utf8(values.get_pointer(i * PTR_BYTES).read_string)]
|
|
964
|
+
end
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
# Attribute strings cross the seam UTF-8 on both faces
|
|
968
|
+
# (ADR-0002).
|
|
969
|
+
def self.utf8(str)
|
|
970
|
+
str.nil? ? nil : str.force_encoding(Encoding::UTF_8)
|
|
915
971
|
end
|
|
916
972
|
|
|
917
973
|
# Element-only child batch (the mirror of fetch_children over
|
data/lib/leptris/xml/node.rb
CHANGED
|
@@ -156,12 +156,15 @@ class Leptris::XML::Node
|
|
|
156
156
|
|
|
157
157
|
def children
|
|
158
158
|
# Immutable in readonly mode: the batch fetch plus wrapper
|
|
159
|
-
# construction is paid once.
|
|
159
|
+
# construction is paid once. The kinds ride the batch
|
|
160
|
+
# (leptris_node_children_ex), so no per-child get_type.
|
|
160
161
|
return @children if memo_hit?(@children_version)
|
|
161
162
|
ensure_alive!
|
|
162
163
|
parent = as_element_or_self
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
pointers, kinds = Leptris::XML::FFI.fetch_children(@c_ptr)
|
|
165
|
+
nodes = Array.new(pointers.size) do |i|
|
|
166
|
+
Leptris::XML::Node.wrap(pointers[i], @document,
|
|
167
|
+
parent: parent, node_type: kinds[i])
|
|
165
168
|
end
|
|
166
169
|
result = Leptris::XML::NodeSet.new(@document, nodes)
|
|
167
170
|
if @document
|
|
@@ -61,8 +61,9 @@ module Leptris::XML::SAX::DomDispatch
|
|
|
61
61
|
end
|
|
62
62
|
return
|
|
63
63
|
end
|
|
64
|
-
Leptris::XML::FFI.fetch_children(c_ptr)
|
|
65
|
-
|
|
64
|
+
pointers, kinds = Leptris::XML::FFI.fetch_children(c_ptr)
|
|
65
|
+
pointers.each_with_index do |child_ptr, i|
|
|
66
|
+
case kinds[i]
|
|
66
67
|
when ELEMENT
|
|
67
68
|
visit_element(
|
|
68
69
|
Leptris::XML::Node.wrap(child_ptr, doc, node_type: ELEMENT),
|
|
@@ -115,19 +116,12 @@ module Leptris::XML::SAX::DomDispatch
|
|
|
115
116
|
|
|
116
117
|
# start_element's pairs with xmlns declarations carried — the
|
|
117
118
|
# engine's streaming contract reports declarations among the
|
|
118
|
-
# attribute pairs
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
# "xmlns", prefixed as "xmlns:prefix"), then the attributes in
|
|
123
|
-
# source order (leptris-ruby#99).
|
|
119
|
+
# attribute pairs at their byte positions. Since libleptris
|
|
120
|
+
# 1.9.18 (upstream #635, closing leptris-ruby#99's documented
|
|
121
|
+
# difference), the raw qname-ordered list reproduces the exact
|
|
122
|
+
# interleave.
|
|
124
123
|
def declared_pairs(element)
|
|
125
|
-
|
|
126
|
-
return attr_pairs(element.c_ptr) if defs.empty?
|
|
127
|
-
pairs = defs.map do |ns|
|
|
128
|
-
[ns.prefix ? "xmlns:#{ns.prefix}" : "xmlns", ns.href]
|
|
129
|
-
end
|
|
130
|
-
pairs.concat(attr_pairs(element.c_ptr))
|
|
124
|
+
Leptris::XML::FFI.fetch_attributes_raw(element.c_ptr)
|
|
131
125
|
end
|
|
132
126
|
|
|
133
127
|
# [name, value] pairs in source order, read straight from the
|
|
@@ -8,15 +8,15 @@ class Leptris::XML::SAX::Parser
|
|
|
8
8
|
|
|
9
9
|
attr_reader :document, :encoding
|
|
10
10
|
|
|
11
|
-
# streaming:
|
|
12
|
-
#
|
|
13
|
-
# attribute
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
11
|
+
# streaming: true (default, since 1.9.40) delivers through the
|
|
12
|
+
# engine transports — bulk/callback picked by override weight
|
|
13
|
+
# (leptris-ruby#95's attribute corruption is fixed upstream in
|
|
14
|
+
# libleptris 1.9.18, verified on the issue fixture). streaming:
|
|
15
|
+
# false delivers from a DOM parse (SAX::DomDispatch) — the
|
|
16
|
+
# correctness-first fallback kept for engines older than 1.9.18
|
|
17
|
+
# and for consumers wanting the DOM view's shapes.
|
|
18
18
|
def initialize(handler = Leptris::XML::SAX::Document.new,
|
|
19
|
-
encoding = nil, streaming:
|
|
19
|
+
encoding = nil, streaming: true)
|
|
20
20
|
@document = handler
|
|
21
21
|
@encoding = encoding
|
|
22
22
|
@streaming = streaming
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.
|
|
4
|
+
version: 1.9.40
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|