leptris 1.4.0 → 1.6.0

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: b2d88ed5cdbe9a27cb5ab05f1b1fd6c96b290e22291eea46f8b5d331b65acb4c
4
- data.tar.gz: 2ef52039eca7c8c3dd85f0d933982a550dc3a3f4e63c151c0fd91c96a957c725
3
+ metadata.gz: 28f24417196438a9a1aef17c3e1f648b7d85048659268a332341c36663a4a16a
4
+ data.tar.gz: 542fa2497b09a734f2cd65ca3eb398c90d24841bc4ed70577e7ed177e323f521
5
5
  SHA512:
6
- metadata.gz: fda307a95ea72f82d137681698bb67d2d03482a285f52a31fd7d4e30293fdd5680c2fbd435ef503251f8ccb479f7f0affa19d5e60bb2686c0bf9c747572b50ea
7
- data.tar.gz: e1794499e7134b8fad62cb782f6cab99e13fe4197c48bbb4ab67d395ec607aea878312d033e3a006cc29c2f3b9c12cc0b6dd5a6fedc572352ddd2b7a8d8a06ba
6
+ metadata.gz: d46d2a265f3c07326fda5e152f338373772b9f804f5c5c7d8174dcb78dff3f10e5a875972b5635ab94e2309001552e85f0a45c26e14687c713d8647cdd32815c
7
+ data.tar.gz: a7ae147afbd49cf1afe4eebfd6f9e2ba4dea2e682a2da7cbd3e7b892aaf5bc3150eeffca6bdecd840a166499d17eefd6debf4f4df3e0fe59d34cdfe0613da84f
data/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ All notable changes to Leptris will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.6.0] - 2026-08-24
9
+
10
+ Lockstep with libleptris 1.6.0 — the moxml-adapter blockers fixed:
11
+ same-parent node moves no longer corrupt the sibling chain (#518),
12
+ detached PI/comment/CDATA mutation works on rootless documents
13
+ (#519); union nodesets keep attribute identity (#514); document-level
14
+ processing instructions gained a public API (#526).
15
+
16
+ ## [1.5.0] - 2026-08-24
17
+
18
+ Lockstep with libleptris 1.5.0 — the engine pins the TODO.engine
19
+ release: file-backed pull/iterparse streaming (bounded memory off
20
+ disk), compiled XPath ns/vars contexts, Rust crate publish workflow.
21
+
8
22
  ## [1.4.0] - 2026-08-23
9
23
 
10
24
  Lockstep with libleptris 1.4.0 — engine pins the TODO.bindings
@@ -12,6 +26,34 @@ release: pull (StAX) API, bounded iterparse, compiled XPath
12
26
  expressions, per-parse options, truthful serialization encoding
13
27
  declarations. Binding-side adoption of the new APIs follows.
14
28
 
29
+ ## [1.6.0] - 2026-08-24
30
+
31
+ Lockstep with libleptris 1.6.0 (v1.4/v1.5 were fix releases with no
32
+ public API changes).
33
+
34
+ ### Added
35
+
36
+ - **`Leptris::XML::XPath` — compiled expressions** (parse once,
37
+ evaluate many): `XPath.compile("//item[@qty > 3]")` returns a
38
+ reusable handle (GC-managed) whose `#eval(doc_or_element[, ns])`
39
+ shares result-wrapping semantics with `Searchable#xpath`,
40
+ including namespace bindings.
41
+ - **`Leptris::XML::Pull` — StAX-style pull parsing**:
42
+ `Pull.parse(xml) { |event| }` streams start_element (with captured
43
+ attributes), end_element, text, comment, cdata, pi, end_document,
44
+ and error events; `Pull.parse_file` streams from disk.
45
+ - **`Leptris::XML::Iterparse` — incremental tree iteration**: yields
46
+ each completed top-level child element; the previous subtree is
47
+ released as the next is produced (memory bounded by the largest
48
+ subtree, not the document). Yielded elements have no parent
49
+ Document; upstream v1 limitation: namespace prefixes are not
50
+ re-resolved.
51
+ - **Document-level processing instructions**: `Document#processing_instructions`
52
+ (array of [target, data]) and `Document#add_pi(target, data)` —
53
+ document PIs are not tree nodes, per the C contract.
54
+ - `leptris_parse_string_ex` bound (options-struct parse; the flags
55
+ path remains the default).
56
+
15
57
  ## [1.3.0] - 2026-08-23
16
58
 
17
59
  Lockstep with libleptris 1.3.0 — takes full advantage of the
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.4.0"
11
+ LIBLEPTRIS_VERSION = "1.6.0"
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.4.0"
4
+ VERSION = "1.6.0"
5
5
  end
@@ -234,6 +234,24 @@ class Leptris::XML::Document
234
234
  self
235
235
  end
236
236
 
237
+ # Document-level processing instructions (not tree nodes):
238
+ # an array of [target, data] pairs in document order.
239
+ def processing_instructions
240
+ count = Leptris::XML::FFI.leptris_document_pi_count(@c_ptr)
241
+ count.times.map do |i|
242
+ [Leptris::XML::FFI.leptris_document_pi_target(@c_ptr, i),
243
+ Leptris::XML::FFI.leptris_document_pi_data(@c_ptr, i)]
244
+ end
245
+ end
246
+
247
+ # Append a document-level processing instruction. Returns self.
248
+ def add_pi(target, data = "")
249
+ witness = Leptris::XML::FFI.leptris_document_add_pi(
250
+ @c_ptr, target.to_s, data.to_s)
251
+ raise Leptris::XML::Error, "leptris_document_add_pi failed" if witness.null?
252
+ self
253
+ end
254
+
237
255
  # The most recent error recorded against this document, or nil.
238
256
  def last_error
239
257
  msg = Leptris::XML::FFI.leptris_document_last_error(@c_ptr)
@@ -24,6 +24,9 @@ module Leptris
24
24
  typedef :pointer, :leptris_doctype
25
25
  typedef :pointer, :leptris_xpath_result
26
26
  typedef :pointer, :leptris_xpath_ns_set
27
+ typedef :pointer, :leptris_xpath_compiled
28
+ typedef :pointer, :leptris_pull_parser
29
+ typedef :pointer, :leptris_iterparse
27
30
  typedef :pointer, :leptris_xpath_var_set
28
31
  typedef :pointer, :leptris_sax_parser
29
32
  typedef :int, :leptris_status
@@ -73,6 +76,20 @@ module Leptris
73
76
  [:leptris_document, :leptris_element], :leptris_status
74
77
  attach_function :leptris_document_root,
75
78
  [:leptris_document], :leptris_element
79
+ # Document-level PIs (v1.6.0): not tree nodes — enumerate via
80
+ # these accessors only.
81
+ attach_function :leptris_document_pi_count,
82
+ [:leptris_document], :size_t
83
+ attach_function :leptris_document_pi_target,
84
+ [:leptris_document, :size_t], :string
85
+ attach_function :leptris_document_pi_data,
86
+ [:leptris_document, :size_t], :string
87
+ attach_function :leptris_document_add_pi,
88
+ [:leptris_document, :string, :string], :pointer
89
+ # Options-struct parse (v1.6.0): supersedes the flags variants;
90
+ # the flags path remains bound for compatibility.
91
+ attach_function :leptris_parse_string_ex,
92
+ [:string, :size_t, :pointer, :pointer], :leptris_document
76
93
  attach_function :leptris_document_encoding,
77
94
  [:leptris_document], :string
78
95
  attach_function :leptris_document_finalize_strings,
@@ -385,6 +402,20 @@ module Leptris
385
402
  attach_function :leptris_xpath_eval_ns,
386
403
  [:leptris_document, :leptris_element, :string, :leptris_xpath_ns_set],
387
404
  :leptris_xpath_result
405
+ # Compiled expressions (v1.6.0): parse once, evaluate many.
406
+ attach_function :leptris_xpath_compile,
407
+ [:string], :leptris_xpath_compiled
408
+ attach_function :leptris_xpath_compiled_eval,
409
+ [:leptris_xpath_compiled, :leptris_document, :leptris_element],
410
+ :leptris_xpath_result
411
+ attach_function :leptris_xpath_compiled_eval_ns,
412
+ [:leptris_xpath_compiled, :leptris_document, :leptris_element,
413
+ :leptris_xpath_ns_set], :leptris_xpath_result
414
+ attach_function :leptris_xpath_compiled_eval_vars,
415
+ [:leptris_xpath_compiled, :leptris_document, :leptris_element,
416
+ :leptris_xpath_var_set], :leptris_xpath_result
417
+ attach_function :leptris_xpath_compiled_free,
418
+ [:leptris_xpath_compiled], :void
388
419
 
389
420
  attach_function :leptris_sax_parse,
390
421
  [:string, :size_t, :pointer, :pointer], :int
@@ -397,6 +428,33 @@ module Leptris
397
428
  attach_function :leptris_sax_parser_set_streaming,
398
429
  [:leptris_sax_parser, :int], :int
399
430
 
431
+ # Pull parsing (v1.6.0): StAX-style cursor over a document.
432
+ attach_function :leptris_pull_new,
433
+ [:string, :size_t], :leptris_pull_parser
434
+ attach_function :leptris_pull_new_file,
435
+ [:string], :leptris_pull_parser
436
+ attach_function :leptris_pull_next,
437
+ [:leptris_pull_parser], :pointer
438
+ attach_function :leptris_pull_attr_count,
439
+ [:leptris_pull_parser], :size_t
440
+ attach_function :leptris_pull_attr_name,
441
+ [:leptris_pull_parser, :size_t], :string
442
+ attach_function :leptris_pull_attr_value,
443
+ [:leptris_pull_parser, :size_t], :string
444
+ attach_function :leptris_pull_free,
445
+ [:leptris_pull_parser], :void
446
+
447
+ # Iterparse (v1.6.0): yields each completed top-level child
448
+ # element; the previous subtree is released on each next call.
449
+ attach_function :leptris_iterparse_new,
450
+ [:string, :size_t], :leptris_iterparse
451
+ attach_function :leptris_iterparse_new_file,
452
+ [:string], :leptris_iterparse
453
+ attach_function :leptris_iterparse_next,
454
+ [:leptris_iterparse], :leptris_element
455
+ attach_function :leptris_iterparse_free,
456
+ [:leptris_iterparse], :void
457
+
400
458
  attach_function :leptris_document_serialize,
401
459
  [:leptris_document, :pointer], :pointer
402
460
  # Legacy simple serializer, declared retroactively in v1.1.0.
@@ -491,6 +549,15 @@ module Leptris
491
549
  TRAVERSE_PRE_ORDER = 0
492
550
  TRAVERSE_POST_ORDER = 1
493
551
 
552
+ PULL_START_ELEMENT = 0
553
+ PULL_END_ELEMENT = 1
554
+ PULL_TEXT = 2
555
+ PULL_COMMENT = 3
556
+ PULL_CDATA = 4
557
+ PULL_PI = 5
558
+ PULL_END_DOCUMENT = 6
559
+ PULL_ERROR = 7
560
+
494
561
  LEPTRIS_PARSE_DEFAULT = 0
495
562
  LEPTRIS_PARSE_DROP_WS_TEXT = 1
496
563
 
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ # Incremental tree iteration (libleptris v1.6.0): yields each
6
+ # completed TOP-LEVEL child element of the document root as it
7
+ # parses. The previous element's whole subtree is released when the
8
+ # next is produced — memory stays bounded by the largest subtree,
9
+ # not the document.
10
+ #
11
+ # Leptris::XML::Iterparse.parse(huge_xml) do |element|
12
+ # process(element) # subtree valid until the next iteration
13
+ # end
14
+ #
15
+ # v1 limitation (upstream): element names are the QName as written;
16
+ # namespace prefixes are not re-resolved — use the DOM path when
17
+ # namespace URIs matter. The yielded elements have no parent
18
+ # Document; #document returns nil and they must not outlive the
19
+ # iteration.
20
+ class Leptris::XML::Iterparse
21
+ def self.parse(xml_or_io, &block)
22
+ xml = xml_or_io.respond_to?(:read) ? xml_or_io.read : xml_or_io.to_s
23
+ iterator = new(Leptris::XML::FFI.leptris_iterparse_new(xml, xml.bytesize))
24
+ iterator.run(&block)
25
+ end
26
+
27
+ def self.parse_file(path, &block)
28
+ iterator = new(Leptris::XML::FFI.leptris_iterparse_new_file(path))
29
+ iterator.run(&block)
30
+ end
31
+
32
+ def initialize(handle)
33
+ raise Leptris::XML::ParseError, "leptris_iterparse_new failed" if handle.null?
34
+ @handle = handle
35
+ end
36
+
37
+ def run
38
+ return enum_for(:run) unless block_given?
39
+ loop do
40
+ ptr = Leptris::XML::FFI.leptris_iterparse_next(@handle)
41
+ break if ptr.null?
42
+ # document: nil — the subtree belongs to the iterator's pool,
43
+ # not a long-lived Document, so wrapper caching is skipped and
44
+ # #document is nil on the yielded elements.
45
+ yield Leptris::XML::Node.wrap(ptr, nil)
46
+ end
47
+ self
48
+ ensure
49
+ free
50
+ end
51
+
52
+ def free
53
+ return if @handle.nil?
54
+ Leptris::XML::FFI.leptris_iterparse_free(@handle)
55
+ @handle = nil
56
+ end
57
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ # Pull parsing (libleptris v1.6.0): a StAX-style cursor over a
6
+ # document. Each #next advances one event; attributes are readable
7
+ # only during the start_element event just returned.
8
+ #
9
+ # Leptris::XML::Pull.parse(xml).each do |event|
10
+ # case event.type
11
+ # when :start_element then handle(event.name, event.attrs)
12
+ # when :text then handle(event.text)
13
+ # end
14
+ # end
15
+ #
16
+ module Leptris::XML::Pull
17
+ Event = Struct.new(:type, :name, :text, :attrs, keyword_init: true)
18
+
19
+ TYPES = {
20
+ Leptris::XML::FFI::PULL_START_ELEMENT => :start_element,
21
+ Leptris::XML::FFI::PULL_END_ELEMENT => :end_element,
22
+ Leptris::XML::FFI::PULL_TEXT => :text,
23
+ Leptris::XML::FFI::PULL_COMMENT => :comment,
24
+ Leptris::XML::FFI::PULL_CDATA => :cdata,
25
+ Leptris::XML::FFI::PULL_PI => :pi,
26
+ Leptris::XML::FFI::PULL_END_DOCUMENT => :end_document,
27
+ Leptris::XML::FFI::PULL_ERROR => :error,
28
+ }.freeze
29
+
30
+ class Parser
31
+ def self.parse(xml_or_io)
32
+ xml = xml_or_io.respond_to?(:read) ? xml_or_io.read : xml_or_io.to_s
33
+ new(Leptris::XML::FFI.leptris_pull_new(xml, xml.bytesize))
34
+ end
35
+
36
+ def self.parse_file(path)
37
+ new(Leptris::XML::FFI.leptris_pull_new_file(path))
38
+ end
39
+
40
+ def initialize(handle)
41
+ raise Leptris::XML::ParseError, "leptris_pull_new failed" if handle.null?
42
+ @handle = handle
43
+ end
44
+
45
+ # Releases the C parser. Safe to call twice.
46
+ def free
47
+ return if @handle.nil?
48
+ Leptris::XML::FFI.leptris_pull_free(@handle)
49
+ @handle = nil
50
+ end
51
+
52
+ def each
53
+ return enum_for(:each) unless block_given?
54
+ loop do
55
+ event = next_event
56
+ break if event.nil?
57
+ yield event
58
+ break if event.type == :end_document || event.type == :error
59
+ end
60
+ self
61
+ end
62
+
63
+ # Advances the cursor and returns the next Event, or nil after the
64
+ # end of the document. Attribute values are captured during
65
+ # start_element because the C accessors are valid only for the
66
+ # most recently returned event.
67
+ def next_event
68
+ raw = Leptris::XML::FFI.leptris_pull_next(@handle)
69
+ return nil if raw.null?
70
+ type_code = raw.get_int(0)
71
+ type = TYPES[type_code]
72
+ name = read_string_at(raw, 8)
73
+ text_ptr = raw.get_pointer(16)
74
+ text = text_ptr.null? ? nil : text_ptr.read_string
75
+ attrs = type == :start_element ? capture_attrs : nil
76
+ Event.new(type: type, name: name, text: text, attrs: attrs)
77
+ end
78
+
79
+ private
80
+
81
+ # struct LeptrisPullEvent { int type; const char* name; const
82
+ # char* text; size_t text_len; } — pointer-sized fields follow the
83
+ # 4-byte enum on 64-bit ABIs (name at 8, text at 16).
84
+ def read_string_at(raw, offset)
85
+ ptr = raw.get_pointer(offset)
86
+ ptr.null? ? nil : ptr.read_string
87
+ end
88
+
89
+ def capture_attrs
90
+ count = Leptris::XML::FFI.leptris_pull_attr_count(@handle)
91
+ count.times.each_with_object({}) do |i, hash|
92
+ hash[Leptris::XML::FFI.leptris_pull_attr_name(@handle, i)] =
93
+ Leptris::XML::FFI.leptris_pull_attr_value(@handle, i)
94
+ end
95
+ end
96
+ end
97
+
98
+ def self.parse(xml_or_io, &block)
99
+ parser = Parser.parse(xml_or_io)
100
+ if block
101
+ begin
102
+ parser.each(&block)
103
+ ensure
104
+ parser.free
105
+ end
106
+ else
107
+ parser
108
+ end
109
+ end
110
+
111
+ def self.parse_file(path, &block)
112
+ parser = Parser.parse_file(path)
113
+ if block
114
+ begin
115
+ parser.each(&block)
116
+ ensure
117
+ parser.free
118
+ end
119
+ else
120
+ parser
121
+ end
122
+ end
123
+ end
@@ -20,7 +20,7 @@ module Leptris::XML::Searchable
20
20
  Leptris::XML::FFI.leptris_status_string(Leptris::XML::FFI::LEPTRIS_ERROR_XPATH)
21
21
  end
22
22
 
23
- wrap_xpath_result(result_ptr)
23
+ Leptris::XML::Searchable.wrap_xpath_result(document, result_ptr)
24
24
  end
25
25
 
26
26
  def at_xpath(*paths)
@@ -88,7 +88,10 @@ module Leptris::XML::Searchable
88
88
  %r{\A(\./|/|\.\.|\.)}.match?(str)
89
89
  end
90
90
 
91
- def wrap_xpath_result(result_ptr)
91
+ # Shared by Searchable#xpath and Leptris::XML::XPath (compiled
92
+ # expressions): wraps a raw TaurusXPathResult pointer into the
93
+ # Ruby-typed result and frees the C handle.
94
+ def self.wrap_xpath_result(document, result_ptr)
92
95
  type = Leptris::XML::FFI.leptris_xpath_result_type(result_ptr)
93
96
  case type
94
97
  when Leptris::XML::FFI::XPATH_NODESET
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ # Compiled XPath expression: parse once, evaluate many times against
6
+ # any document (libleptris v1.6.0). The C handle is released by GC.
7
+ #
8
+ # expr = Leptris::XML::XPath.compile("//item[@qty > 3]")
9
+ # expr.eval(doc_a).length
10
+ # expr.eval(doc_b, "p" => "urn:p").length
11
+ #
12
+ class Leptris::XML::XPath
13
+ class CompiledHandle < ::FFI::AutoPointer
14
+ def self.release(ptr)
15
+ Leptris::XML::FFI.leptris_xpath_compiled_free(ptr)
16
+ end
17
+ end
18
+
19
+ attr_reader :expression
20
+
21
+ def self.compile(expression)
22
+ raw = Leptris::XML::FFI.leptris_xpath_compile(expression.to_s)
23
+ if raw.null?
24
+ raise Leptris::XML::XPathError,
25
+ "invalid expression: #{Leptris::XML::FFI.leptris_last_error}"
26
+ end
27
+ new(expression.to_s, CompiledHandle.new(raw))
28
+ end
29
+
30
+ def initialize(expression, handle)
31
+ @expression = expression
32
+ @handle = handle
33
+ end
34
+
35
+ # Evaluates against +doc_or_element+. An optional trailing hash of
36
+ # namespace bindings ("prefix" => uri) routes the evaluation through
37
+ # the namespace-bound path, matching Searchable#xpath semantics.
38
+ def eval(doc_or_element, ns = nil)
39
+ context = resolve_context(doc_or_element)
40
+ document = context.document
41
+ result_ptr =
42
+ if ns && !ns.empty?
43
+ flat = ns.flat_map { |prefix, uri| [prefix.to_s, uri.to_s] }
44
+ buffer, _anchors = Leptris::XML::CStringArray.to_c(flat)
45
+ set = Leptris::XML::FFI.leptris_xpath_ns_set_new_from_pairs(
46
+ buffer, flat.length / 2)
47
+ raise Leptris::XML::Error, "leptris_xpath_ns_set_new_from_pairs failed" if set.null?
48
+ begin
49
+ Leptris::XML::FFI.leptris_xpath_compiled_eval_ns(
50
+ @handle, document.c_ptr, context_ptr(context), set)
51
+ ensure
52
+ Leptris::XML::FFI.leptris_xpath_ns_set_free(set)
53
+ end
54
+ else
55
+ Leptris::XML::FFI.leptris_xpath_compiled_eval(
56
+ @handle, document.c_ptr, context_ptr(context))
57
+ end
58
+ if result_ptr.null?
59
+ raise Leptris::XML::XPathError,
60
+ Leptris::XML::FFI.leptris_last_error.to_s
61
+ end
62
+ Leptris::XML::Searchable.wrap_xpath_result(document, result_ptr)
63
+ end
64
+
65
+ private
66
+
67
+ def resolve_context(doc_or_element)
68
+ case doc_or_element
69
+ when Leptris::XML::Document then doc_or_element
70
+ when Leptris::XML::Element then doc_or_element
71
+ else
72
+ raise ArgumentError,
73
+ "expected a Leptris::XML::Document or Element, got #{doc_or_element.class}"
74
+ end
75
+ end
76
+
77
+ def context_ptr(context)
78
+ context.is_a?(Leptris::XML::Document) ? nil : context.c_ptr
79
+ end
80
+ end
data/lib/leptris/xml.rb CHANGED
@@ -21,6 +21,9 @@ module Leptris
21
21
  autoload :CStringArray, "leptris/xml/c_string_array"
22
22
  autoload :Serialization, "leptris/xml/serialization"
23
23
  autoload :SAX, "leptris/xml/sax"
24
+ autoload :XPath, "leptris/xml/xpath"
25
+ autoload :Pull, "leptris/xml/pull"
26
+ autoload :Iterparse, "leptris/xml/iterparse"
24
27
 
25
28
  # Nokogiri-style top-level entry points (Nokogiri::XML(...) /
26
29
  # Nokogiri::XML.parse). Delegates to Document.parse.
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.4.0
4
+ version: 1.6.0
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-23 00:00:00.000000000 Z
11
+ date: 2026-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -121,17 +121,20 @@ files:
121
121
  - lib/leptris/xml/document_fragment.rb
122
122
  - lib/leptris/xml/element.rb
123
123
  - lib/leptris/xml/ffi.rb
124
+ - lib/leptris/xml/iterparse.rb
124
125
  - lib/leptris/xml/namespace.rb
125
126
  - lib/leptris/xml/node.rb
126
127
  - lib/leptris/xml/node_set.rb
127
128
  - lib/leptris/xml/parse_options.rb
128
129
  - lib/leptris/xml/processing_instruction.rb
130
+ - lib/leptris/xml/pull.rb
129
131
  - lib/leptris/xml/sax.rb
130
132
  - lib/leptris/xml/sax/document.rb
131
133
  - lib/leptris/xml/sax/parser.rb
132
134
  - lib/leptris/xml/searchable.rb
133
135
  - lib/leptris/xml/serialization.rb
134
136
  - lib/leptris/xml/text.rb
137
+ - lib/leptris/xml/xpath.rb
135
138
  homepage: https://github.com/leptris/leptris-ruby
136
139
  licenses:
137
140
  - MIT