leptris 1.9.30 → 1.9.31

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: b0b15f4a5205c3ad2ed40cddbddf2c6d517b02fba4d80001d1a803ee4d1c5c47
4
- data.tar.gz: 52cbfce90c464a45894568060b38d906e0ab9e2d613f0d005051ff51768ef180
3
+ metadata.gz: 61af1b12021e7a1cf22f04004ea36d27df6f740ff135d039854c51497abf87f3
4
+ data.tar.gz: 0a842331a02a988b8bfce2920f8878b87c5ff5fdbd4c471f2f04694f4a1b3465
5
5
  SHA512:
6
- metadata.gz: 6eec31bcfa4b5fdadcaa14902374fe177541e8db51a1b13488899984c8ec425d94e7d047f1a4726173869a9b306e15519bb097018109ec9177dc4b11b72cb103
7
- data.tar.gz: 21a07b86e6fb0237eca6aed383badc2f30c41caafb690dbb45ba152bdabd6a9f25446cb8ebd9c7c52a99446da5fe1bae88b76abb95078a0d18c70a80e7b00098
6
+ metadata.gz: e832da72a4e2fe0ddede057023c1e981705a41f196d85e7d7e5d61051d524bddfc2305065fef940ef60af48b87e978bc46be7e61030d598de83fb916db8bba3e
7
+ data.tar.gz: 7a266c15d5983229591bf414ad0dde95cc93018ba01388bf721f98977c026c164797e1dc805fc9a46625a6b2037c7709a65cb0e0640ca5ed6c46f40614dd37c0
data/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ 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.31] - 2026-08-28
9
+
10
+ ### Fixed
11
+
12
+ - **PI data consumes the leading whitespace run (leptris-ruby#85,
13
+ libxml2 parity)**: the engine retains the full whitespace run
14
+ after the PI target as data where libxml2 consumes it at parse
15
+ time — every Ruby-facing PI-data read now normalizes through one
16
+ seam helper (`FFI.read_pi_data`): `PI#content`,
17
+ `Document#processing_instructions` pairs, the SAX
18
+ `processing_instruction` callback, pull `:pi` events, and
19
+ recorder `:pi` events. Whitespace-only data reads as `""`, so
20
+ "pi-without-data" PIs report empty consistently; trailing
21
+ whitespace is kept (libxml2 trims only the leading run).
22
+ Read-time only — `PI#data=` still stores verbatim.
23
+
8
24
  ## [1.9.30] - 2026-08-28
9
25
 
10
26
  ### Fixed
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.30"
4
+ VERSION = "1.9.31"
5
5
  end
@@ -295,7 +295,8 @@ class Leptris::XML::Document
295
295
  count = Leptris::XML::FFI.leptris_document_pi_count(@c_ptr)
296
296
  result = count.times.map do |i|
297
297
  [Leptris::XML::FFI.leptris_document_pi_target(@c_ptr, i),
298
- Leptris::XML::FFI.leptris_document_pi_data(@c_ptr, i)]
298
+ Leptris::XML::FFI.read_pi_data(
299
+ Leptris::XML::FFI.leptris_document_pi_data(@c_ptr, i)).to_s]
299
300
  end
300
301
  @processing_instructions = result
301
302
  @pi_version = @version
@@ -924,6 +924,16 @@ module Leptris
924
924
  [raw, status.read_int]
925
925
  end
926
926
 
927
+ # libxml2 consumes the whole whitespace run following the PI
928
+ # target when parsing; the engine retains it as data
929
+ # (leptris-ruby#85). Every Ruby-facing PI-data read normalizes
930
+ # here — whitespace-only data becomes "" so
931
+ # "pi-without-data" PIs report empty consistently. Read-time
932
+ # only: PI#data= stores verbatim.
933
+ def self.read_pi_data(data)
934
+ data&.sub(/\A[ \t\r\n]+/, "")
935
+ end
936
+
927
937
  # Thread-local scratch buffers for batch handle fetches (round
928
938
  # XX): the per-call MemoryPointer new/free was pure cold-path
929
939
  # overhead — two allocations and a GC visit per children() /
@@ -16,7 +16,8 @@ class Leptris::XML::ProcessingInstruction < Leptris::XML::Node
16
16
  def content
17
17
  return @content if memo_hit?(@content_version)
18
18
  ensure_alive!
19
- result = Leptris::XML::FFI.leptris_pi_node_get_data(@c_ptr).to_s
19
+ result = Leptris::XML::FFI.read_pi_data(
20
+ Leptris::XML::FFI.leptris_pi_node_get_data(@c_ptr)).to_s
20
21
  if @document
21
22
  @content = result
22
23
  @content_version = @document.version
@@ -84,13 +84,14 @@ module Leptris::XML::Pull
84
84
  base = i * stride
85
85
  name_ptr = buffer.get_pointer(base + name_off)
86
86
  text_ptr = buffer.get_pointer(base + text_off)
87
- Event.new(
88
- TYPES[buffer.get_int(base + type_off)],
87
+ type = TYPES[buffer.get_int(base + type_off)]
88
+ text = text_ptr.null? ? nil :
89
+ text_ptr.read_string.force_encoding(Encoding::UTF_8)
90
+ text = Leptris::XML::FFI.read_pi_data(text) if type == :pi
91
+ Event.new(type,
89
92
  name_ptr.null? ? nil :
90
93
  name_ptr.read_string.force_encoding(Encoding::UTF_8),
91
- text_ptr.null? ? nil :
92
- text_ptr.read_string.force_encoding(Encoding::UTF_8),
93
- nil
94
+ text, nil
94
95
  )
95
96
  end
96
97
  # The attr mirror holds the batch's most recent start.
@@ -125,11 +126,13 @@ module Leptris::XML::Pull
125
126
  name_ptr = raw.get_pointer(NAME_OFFSET)
126
127
  text_ptr = raw.get_pointer(TEXT_OFFSET)
127
128
  attrs = type == :start_element ? capture_attrs : nil
129
+ text = text_ptr.null? ? nil :
130
+ text_ptr.read_string.force_encoding(Encoding::UTF_8)
131
+ text = Leptris::XML::FFI.read_pi_data(text) if type == :pi
128
132
  Event.new(
129
133
  type,
130
134
  name_ptr.null? ? nil : name_ptr.read_string.force_encoding(Encoding::UTF_8),
131
- text_ptr.null? ? nil : text_ptr.read_string.force_encoding(Encoding::UTF_8),
132
- attrs
135
+ text, attrs
133
136
  )
134
137
  end
135
138
 
@@ -149,7 +149,8 @@ class Leptris::XML::SAX::Parser
149
149
 
150
150
  if overridden?(:processing_instruction)
151
151
  s[:processing_instruction] = callback(:void, [:pointer, :string, :string]) do |_, target, data|
152
- handler.processing_instruction(utf8(target), utf8(data))
152
+ handler.processing_instruction(
153
+ utf8(target), Leptris::XML::FFI.read_pi_data(utf8(data)))
153
154
  end
154
155
  end
155
156
 
@@ -122,9 +122,11 @@ class Leptris::XML::SAX::Recorder
122
122
  kind = KIND_BY_CODE[fields[i * 9]]
123
123
  if kind && (wanted.nil? || wanted[kind])
124
124
  base = i * 9 + 1
125
+ text = slice(arena, fields[base + 2], fields[base + 3])
126
+ text = Leptris::XML::FFI.read_pi_data(text) if kind == :pi
125
127
  yield kind,
126
128
  slice(arena, fields[base], fields[base + 1]),
127
- slice(arena, fields[base + 2], fields[base + 3]),
129
+ text,
128
130
  attrs_from(arena, fields[base + 4], fields[base + 5]),
129
131
  fields[base + 6], fields[base + 7]
130
132
  end
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.30
4
+ version: 1.9.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.