leptris 1.9.36-x86_64-linux → 1.9.37-x86_64-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4be54118ce35832b98391483d01500bd26bb78627f6f22b8c7f2aafd9fd5828
4
- data.tar.gz: 35b928a020f94c23c8fb53b7c44836fc91fc0edca78e842ff5d128b0d5668d79
3
+ metadata.gz: 87d2effb07e2fb9f93d586b12433c01ce390c04303d1ef061bd8c7c1f7b70c3f
4
+ data.tar.gz: ebc3a9b7a9acb3f477088e8922f87e1387857f0cd80970f93c3e5b462503d7ae
5
5
  SHA512:
6
- metadata.gz: ec5af59d3374938a0646ddafd3849b0387cc59d4b2c1c4f85efd159cfd3b120027b0f28f3287110901046919c83b70b08705f0620c358a37ec16971a182b5815
7
- data.tar.gz: 25e80c6c256cc6f57ba49be772728bb72d335d57e2c04d85d7ecc03b6fd1cfd6dcfea8abe47ae3ca552039011732a314e9bc931077fc0c20ab8594c88c46dc67
6
+ metadata.gz: f8f517db0f999dfade73cdaedee26f0b0ba52fc963010232d72a02b0bb73202c0337b1c9213f9edb4dd7652492542066ecfe90fb85d5eb9c535a90a7445ed9e2
7
+ data.tar.gz: cd2083d13f71dbd42ebf8c3c6326e8ab98f51439ee3b4b89415eda00cf3e2b09cbff6f1e67ca6f446ca71abb9f37e5c918d32d93ab21d09ad40f85047e0383a9
data/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@ 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.37] - 2026-08-29
9
+
10
+ ### Added
11
+
12
+ - **`Element#inner_html`** (Nokogiri parity): the serialized
13
+ children — elements through the engine serializer, text
14
+ XML-escaped at the seam (`& < >` and CR → `&#xD;`, libxml2's
15
+ rules), comments/CDATA/PIs in literal forms. Well-formed by
16
+ construction: a spec re-parses the output to the same children.
17
+ (Nokogiri's inner_html HTML-serializes XML documents — SGML-style
18
+ PI closes, bare CDATA content — and its output does not
19
+ re-parse.) Measured 21 µs/element vs Nokogiri 15 — a first cut
20
+ on a new API with correct forms as the contract.
21
+ - **libleptris 1.9.12 lockstep** (with 1.9.11): pure XSLT
22
+ conformance upstream (libxslt suite 152 -> 180/205 — template
23
+ priority, xsl:number, attribute sets, namespace-declaration
24
+ ordering, strip/preserve-space, copy semantics); audit 250/250,
25
+ no new C surface.
26
+
27
+ ### Changed
28
+
29
+ - **Serialize byte-scratch**: the size+fill serialization pair
30
+ allocated and freed a MemoryPointer per call — inner_html
31
+ serializes each child, and the allocation dominated per-child
32
+ cost. A grow-only thread-local byte scratch (the pointer-scratch
33
+ discipline) now serves every serialize call. Serialized output
34
+ is also forced UTF-8 at the seam (previously true only by
35
+ accident of ASCII-only content comparisons).
36
+
8
37
  ## [1.9.36] - 2026-08-29
9
38
 
10
39
  ### 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.10"
11
+ LIBLEPTRIS_VERSION = "1.9.12"
12
12
 
13
13
  CMAKE_FLAGS = %w[
14
14
  -DCMAKE_BUILD_TYPE=Release
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.36"
4
+ VERSION = "1.9.37"
5
5
  end
@@ -336,6 +336,28 @@ class Leptris::XML::Element < Leptris::XML::Node
336
336
  scopes
337
337
  end
338
338
 
339
+ # The serialized children (Nokogiri parity): elements serialize
340
+ # through the engine (correct escaping), text is XML-escaped,
341
+ # comments/CDATA/PIs render their literal forms. The complement
342
+ # of #inner_text, which returns the unescaped text content.
343
+ def inner_html
344
+ children.map do |child|
345
+ case child
346
+ when Leptris::XML::Element then child.to_xml
347
+ when Leptris::XML::CDATA # before Text: CDATA subclasses it
348
+ "<![CDATA[#{child.content}]]>"
349
+ when Leptris::XML::Text
350
+ Leptris::XML::Serialization.escape_text(child.content)
351
+ when Leptris::XML::Comment then "<!--#{child.content}-->"
352
+ when Leptris::XML::ProcessingInstruction
353
+ data = child.content
354
+ data.empty? ? "<?#{child.name}?>" : "<?#{child.name} #{data}?>"
355
+ else
356
+ Leptris::XML::Serialization.escape_text(child.content.to_s)
357
+ end
358
+ end.join
359
+ end
360
+
339
361
  def to_xml(indent: 0, no_decl: false, encoding: nil)
340
362
  Leptris::XML::Serialization.to_xml(
341
363
  Leptris::XML::FFI.method(:leptris_element_serialize_into), @c_ptr,
@@ -865,13 +865,24 @@ module Leptris
865
865
  def self.serialize_into_string(ffi_function, c_ptr, options)
866
866
  need = ffi_function.call(c_ptr, nil, 0, nil, options)
867
867
  return "" if need.zero?
868
- buffer = ::FFI::MemoryPointer.new(:char, need)
869
- begin
870
- ffi_function.call(c_ptr, buffer, need, nil, options)
871
- buffer.read_string
872
- ensure
873
- buffer.free
868
+ buffer = scratch_bytes(need)
869
+ ffi_function.call(c_ptr, buffer, need, nil, options)
870
+ buffer.read_string.force_encoding(Encoding::UTF_8)
871
+ end
872
+
873
+ # Byte scratch for serialize-into cycles: the size+fill pair
874
+ # allocated and freed a buffer per call — inner_html
875
+ # serializes each child, and the allocation was most of the
876
+ # per-child cost. Grows to the largest serialization seen;
877
+ # no Ruby reentrancy during a serialize call.
878
+ def self.scratch_bytes(need)
879
+ scratch = (Thread.current[:leptris_scratch] ||= {})
880
+ ptr = scratch[:bytes]
881
+ if ptr.nil? || ptr.size < need
882
+ ptr&.free
883
+ ptr = scratch[:bytes] = ::FFI::MemoryPointer.new(:char, need)
874
884
  end
885
+ ptr
875
886
  end
876
887
 
877
888
  # All-kind child handle batch (libleptris 1.7.0). Opportunistic
@@ -62,6 +62,19 @@ module Leptris::XML::Serialization
62
62
  Leptris::XML::FFI.read_owned_string(str_ptr)
63
63
  end
64
64
 
65
+ # XML-escapes text content for inner_html: & first, then < >
66
+ # and CR (libxml2 emits &#xD; for a bare carriage return).
67
+ ESCAPE_TEXT = {
68
+ "&" => "&amp;", "<" => "&lt;", ">" => "&gt;", "\r" => "&#xD;",
69
+ }.freeze
70
+ private_constant :ESCAPE_TEXT
71
+ ESCAPE_TEXT_RE = /[&<>\r]/.freeze
72
+ private_constant :ESCAPE_TEXT_RE
73
+
74
+ def self.escape_text(string)
75
+ string.gsub(ESCAPE_TEXT_RE, ESCAPE_TEXT)
76
+ end
77
+
65
78
  # Builds a SerializeOptions struct. Returns [opts, encoding_anchor];
66
79
  # the anchor must stay referenced while opts is in an FFI call.
67
80
  def self.build_options(indent: 0, no_decl: false, encoding: nil)
data/lib/libleptris.so CHANGED
Binary file
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.36
4
+ version: 1.9.37
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-28 00:00:00.000000000 Z
11
+ date: 2026-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi