leptris 1.9.57 → 1.9.58

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: 9fe43887876480fe4a97b6133facd465257fd25dc8e0304e97057c1a59bf909d
4
- data.tar.gz: a3aa3e2010b04f08ae53c2fc3efeade0b8a07640610cc549dfeaa0e329f03746
3
+ metadata.gz: 159f07010d3dd22a62761daef970c4090a47ee9d7ba6471099380410119dadf2
4
+ data.tar.gz: b80e233d06f4d3af6bb14cc1cbf157ce88dfd7c745ffe7c936bc333d77b7e92d
5
5
  SHA512:
6
- metadata.gz: 96c857442e1b239c4740f061b0a656dec46f6f09ec1501609d2c095e088f214c8b7d1b495a72f3848548621a40764bb1b16ed3ece3e0986d7a31dcd3583d409f
7
- data.tar.gz: 89a40a7423ce40ded296919d5bb8532bf5e7bfc252bf301a71bee12f7f5e275134494853ae5d08d1728627c2b2d0b32b68ffcc4dd6304cbdc79dcd2b8869cbbc
6
+ metadata.gz: c2a1504b697e82a0eddeb8966597f2e39ba27362fa6ebdff2edf9dae2258f5a6cf5757b7088c144f69309ca5016297cba39513fe3a1a901b709029d82a45e88f
7
+ data.tar.gz: 4314c5cf903efe548acaec50494a40578e543f31268ffa9fcdee9e0bd9a069efa152bb8889ad86f6c43b638bd48ad7d554428e9ea9c48b1970301913aa905d66
data/CHANGELOG.md CHANGED
@@ -5,6 +5,63 @@ 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.58] - 2026-09-03
9
+
10
+ ### Added
11
+
12
+ - **Lockstep with libleptris 1.9.75** (1.9.68 → 1.9.75, eight
13
+ releases). One new C symbol attached (audit 260/260):
14
+ - **`Leptris::XML.parse_html`** (1.9.75, leptris/leptris#659 —
15
+ the last Nokogiri capability gap): tolerant HTML4/5 into the
16
+ STANDARD DOM — implied end tags, void elements, raw-text
17
+ script/style, lowercased names, minimized/unquoted attributes,
18
+ HTML named entities; html/head/body synthesized (Nokogiri::HTML
19
+ parity), tbody never implied; malformed markup degrades to
20
+ text. Eight specs; README HTML section; the migration list
21
+ drops "No Nokogiri::HTML".
22
+ - **XPath 2.0 ledger** (1.9.69/1.9.73, closes most of the #683
23
+ grammar list): value comparators (`eq`/`gt`/…), quantifiers
24
+ (`some`/`every`), set algebra (`intersect`/`except`), node
25
+ identity (`is`) — all standalone from `#xpath`, specced.
26
+ - **XQuery windows and typeswitch** (1.9.69/1.9.70): tumbling
27
+ and sliding `window` clauses, `typeswitch` dispatch, the error
28
+ code model (`try/catch` reaches its catch arm — the #790
29
+ cast-error piece landed). Specced.
30
+ - **Sequence items are readable**: `for … return`, sequence
31
+ literals, and XQuery constructor results arrive as
32
+ `Leptris::XML::ResultText` (new) — `#content` serves the value
33
+ directly, captured at result materialization through
34
+ `leptris_xpath_result_node_value` (the only accessor that can
35
+ read the engine's synthetic sequence carriers). The
36
+ "consume through an aggregate" caveat is retired.
37
+ - Upstream perf work adopted: AVT compile cache, keyed mutation
38
+ tail caches, fragment-output tail caches (1.9.71/1.9.72).
39
+
40
+ ### Fixed
41
+
42
+ - **#130 closed** (dup degradation): the monotonic per-cycle rise
43
+ lived in the C-copy path — `dup` reverts to the serialization
44
+ round-trip (see #812 below) and the repro runs flat (~95 µs
45
+ per copy across 20 rounds × 15 copies).
46
+ - **#790 mostly fixed upstream** (1.9.68): constructor-as-return
47
+ parses (items arrive as readable serialized strings),
48
+ where/at-in-function-argument parses, cast errors reach
49
+ try/catch. Follow-up found and reported: the `where` clause is
50
+ silently IGNORED in the function-argument position (bare FLWOR
51
+ filters, wrapped does not) — one pending spec holds the correct
52
+ expectation.
53
+ - **leptris/leptris#812 filed** (1.9.74 copy rewrite regresses
54
+ #721): `leptris_element_copy` drops declarations used only by
55
+ descendants and resolution returns NULL on the copied subtree —
56
+ `dup` and the indent-unit path revert to the serialization
57
+ round-trip (byte-exact) until it lands.
58
+ - **leptris/leptris#815 filed** (from #131): the indenting
59
+ DOCUMENT serializer intermittently emits unescaped `<` in text
60
+ (invalid XML out) for ~5-7% of parses under allocation churn —
61
+ localized to the engine (all three C serialization paths corrupt;
62
+ `indent: 0` and the element face are clean). #131 stays open as
63
+ the tracker.
64
+
8
65
  ## [1.9.57] - 2026-09-03
9
66
 
10
67
  ### Changed
data/README.adoc CHANGED
@@ -106,6 +106,26 @@ doc.root # => nil
106
106
  Leptris::XML::FFI.leptris_last_error # => "..."
107
107
  ----
108
108
 
109
+ == HTML parsing
110
+
111
+ `Leptris::XML.parse_html(html)` parses tolerant HTML4/5 into a
112
+ standard Document — the same nodes, pool, serializer, and
113
+ XPath/XSLT/XQuery machinery as XML (libleptris 1.9.75, the last
114
+ Nokogiri capability gap):
115
+
116
+ [source,ruby]
117
+ ----
118
+ doc = Leptris::XML.parse_html(%(<ul><li>a<li>b</ul>))
119
+ doc.at_css("body").inner_html # => "<ul><li>a</li><li>b</li></ul>"
120
+ ----
121
+
122
+ Implied end tags (`p`/`li`/`td`/`tr`/...), void elements, raw-text
123
+ `<script>`/`<style>`, case-insensitive lowercased names,
124
+ minimized/unquoted attributes, and the HTML named entities all
125
+ parse; `html`/`head`/`body` are synthesized (Nokogiri::HTML parity)
126
+ but `tbody` is never implied. Malformed markup degrades to text
127
+ rather than raising.
128
+
109
129
  == Reading nodes
110
130
 
111
131
  [horizontal]
@@ -247,17 +267,21 @@ doc.xpath("[10, 20, 30]?2") # 3.1 arrays
247
267
  doc.xpath(%q{serialize(parse-json('{"b":"beta"}'), map { 'method': 'json' })})
248
268
  doc.xpath("function($x) { $x + 1 }(41)") # 3.1 function items
249
269
  doc.xpath("fold-left(1 to 4, 0, function($a, $b) { $a + $b })")
270
+ doc.xpath("count(//a) eq 2") # 2.0 value comparators
271
+ doc.xpath("some $a in //a satisfies $a/@v > 1") # 2.0 quantifiers
272
+ doc.xpath("count(//a except //a[@v = 1])") # 2.0 set algebra
273
+ ----
274
+
275
+ Sequence and constructor items arrive as `Leptris::XML::ResultText`
276
+ objects — `#content` serves the value directly:
277
+
278
+ [source,ruby]
279
+ ----
280
+ doc.xpath("for $w in //a return string($w/@v)").map(&:content) # => ["1", "2"]
250
281
  ----
251
282
 
252
- Two caveats: `for … return` sequences come back as opaque result
253
- nodes — consume them through an aggregate (`count(...)`,
254
- `string-join(...)`) until the engine materializes readable sequence
255
- items; and XQuery-only syntax (`order by`, `try/catch`, map
256
- constructors) raises `XPathError` rather than evaluating silently
257
- wrong. The remaining grammar gaps — value comparators (`eq`),
258
- quantifiers, `intersect`/`except`, string templates — and XQuery
259
- itself are
260
- https://github.com/leptris/leptris/issues/683[tracked upstream].
283
+ Remaining grammar gaps (https://github.com/leptris/leptris/issues/683[tracked
284
+ upstream]): 3.1 string templates, XQuery beyond the 1.0 core.
261
285
 
262
286
  === Supported CSS selectors
263
287
 
@@ -585,7 +609,9 @@ Notable differences:
585
609
  Nokogiri is silent on this — migrating code that holds Node references
586
610
  past Document disposal will see the error; silence-replace-UAF patterns
587
611
  from Nokogiri do not apply.
588
- * No `Nokogiri::HTML` or `Nokogiri::CSS` parser. Leptris is XML-only.
612
+ * No `Nokogiri::CSS` parser. HTML parsing is supported
613
+ (`Leptris::XML.parse_html`, libleptris 1.9.75); Nokogiri's
614
+ HTML-specific node subclasses have no equivalent.
589
615
  * No RelaxNG / DTD validation, no schema caching (XSLT 1.0–3.0
590
616
  and an XQuery 1.0 core are supported — see above).
591
617
  * No built-in JRuby / TruffleRuby support — only CRuby via `ffi`.
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.67"
11
+ LIBLEPTRIS_VERSION = "1.9.75"
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.57"
4
+ VERSION = "1.9.58"
5
5
  end
@@ -251,16 +251,12 @@ class Leptris::XML::Element < Leptris::XML::Node
251
251
  self
252
252
  end
253
253
 
254
- # Deep copy in a NEW document via the C copy (both engine gaps
255
- # closed: comment/PI children in 1.9.39, namespaces in 1.9.47 —
256
- # leptris/leptris#696, #721), attached as the fresh document's
257
- # root so the tree is fully navigable.
254
+ # Deep copy in a NEW document via serialization round-trip
255
+ # (leptris/leptris#812: the 1.9.74 copy rewrite drops
256
+ # descendant-used declarations; the serializer is byte-exact).
258
257
  def dup
259
258
  ensure_alive!
260
- new_doc = Leptris::XML::Document.create
261
- copy = Leptris::XML::FFI.leptris_element_copy(@c_ptr, new_doc.c_ptr)
262
- raise Leptris::XML::Error, "leptris_element_copy failed" if copy.null?
263
- new_doc.root = Leptris::XML::Node.wrap(copy, new_doc)
259
+ Leptris::XML::Document.parse(to_xml).root
264
260
  end
265
261
  alias_method :clone, :dup
266
262
 
@@ -133,7 +133,16 @@ module Leptris
133
133
  attach_function :leptris_version, [], :string
134
134
  attach_function :leptris_version_components, [:pointer, :pointer, :pointer], :void
135
135
 
136
- attach_function :leptris_parse_string,
136
+ # Tolerant HTML4/5 parse into the STANDARD DOM (libleptris
137
+ # 1.9.75, #659): implied end tags, void elements, raw-text
138
+ # script/style, case-insensitive (lowercased) names, the HTML
139
+ # named-entity table. Document shape — html/head/body
140
+ # synthesized; no implied tbody. Malformed input never fails
141
+ # the parse; only an entirely empty result is an error.
142
+ attach_function :leptris_parse_html_string,
143
+ [:string, :size_t, :pointer], :leptris_document
144
+
145
+ attach_function :leptris_parse_string,
137
146
  [:string, :size_t, :pointer], :leptris_document
138
147
  attach_function :leptris_parse_string_flags,
139
148
  [:string, :size_t, :uint, :pointer], :leptris_document
@@ -780,6 +789,11 @@ module Leptris
780
789
  NODE_COMMENT = 2
781
790
  NODE_CDATA = 3
782
791
  NODE_PI = 4
792
+ # Internal XPath-synthetic text node (leptris/types.h): the
793
+ # carrier for sequence/map/array items in result nodesets —
794
+ # readable only through the result handle, so the binding
795
+ # captures the value at materialization (ResultText).
796
+ NODE_SYNTHETIC_TEXT = 8
783
797
  NODE_DOCTYPE = 5
784
798
  NODE_ATTRIBUTE = 6
785
799
 
@@ -1070,15 +1084,19 @@ module Leptris
1070
1084
  # get_type in the wrapper. Returns [pointers, element_hints].
1071
1085
  XPATH_KIND_HINT = { XPATH_NODE_ELEMENT => NODE_ELEMENT }.freeze
1072
1086
 
1087
+ # Returns [pointers, element_hints, raw_kinds] — the raw
1088
+ # XPATH_NODE-space kinds ride along so the materializer can
1089
+ # spot TEXT items (synthetic sequence carriers) and capture
1090
+ # their values while the result handle is alive.
1073
1091
  def self.fetch_result_nodes(result_ptr, count)
1074
- return [[], nil] if count.zero?
1092
+ return [[], nil, nil] if count.zero?
1075
1093
  buffer = scratch_pointers(count)
1076
1094
  kinds = scratch_ints(count)
1077
1095
  copied = leptris_xpath_result_get_nodes_ex(
1078
1096
  result_ptr, buffer, kinds, count)
1079
- hints = kinds.get_array_of_int(0, copied)
1080
- .map { |k| XPATH_KIND_HINT[k] }
1081
- [buffer.get_array_of_pointer(0, copied), hints]
1097
+ raw = kinds.get_array_of_int(0, copied)
1098
+ hints = raw.map { |k| XPATH_KIND_HINT[k] }
1099
+ [buffer.get_array_of_pointer(0, copied), hints, raw]
1082
1100
  end
1083
1101
 
1084
1102
  # Fragment parse with the status out-param read: returns
@@ -15,7 +15,7 @@ class Leptris::XML::Node
15
15
  # node_type: callers holding a batch-fetched kind (the XPath
16
16
  # result-set batch fills out_kinds) pass it so the wrap skips the
17
17
  # get_type dispatch; nil (the default) dispatches as before.
18
- def self.wrap(c_ptr, document, parent: nil, node_type: nil)
18
+ def self.wrap(c_ptr, document, parent: nil, node_type: nil, result_value: nil)
19
19
  # Per-document weak-ref cache. Returns the existing wrapper when the
20
20
  # same c_ptr is wrapped twice (common in children/sibling walks,
21
21
  # repeated xpath queries, traverse-then-access patterns). The cache
@@ -37,6 +37,11 @@ class Leptris::XML::Node
37
37
  Leptris::XML::Element.new(c_ptr, document, parent: parent, node_type: node_type)
38
38
  when Leptris::XML::FFI::NODE_TEXT
39
39
  Leptris::XML::Text.new(c_ptr, document, parent: parent, node_type: node_type)
40
+ when Leptris::XML::FFI::NODE_SYNTHETIC_TEXT
41
+ # Sequence/map/array items: value captured by the NodeSet at
42
+ # materialization (only the result handle can read them).
43
+ Leptris::XML::ResultText.new(
44
+ c_ptr, document, result_value, parent: parent, node_type: node_type)
40
45
  when Leptris::XML::FFI::NODE_COMMENT
41
46
  Leptris::XML::Comment.new(c_ptr, document, parent: parent, node_type: node_type)
42
47
  when Leptris::XML::FFI::NODE_CDATA
@@ -369,18 +374,17 @@ class Leptris::XML::Node
369
374
  result
370
375
  end
371
376
 
372
- # Deep copy in a NEW document via the C copy (both engine gaps
373
- # closed: comment/PI children in 1.9.39, namespaces in 1.9.47 —
374
- # leptris/leptris#696, #721). The copy is attached as the fresh
375
- # document's root so the tree is fully navigable.
377
+ # Deep copy in a NEW document. Rounds through serialization: the
378
+ # 1.9.74 copy rewrite (#653 perf lane) drops declarations used
379
+ # only by descendants — resolution on the copied subtree resolves
380
+ # NULL (leptris/leptris#812, an #721 regression) — while the
381
+ # serializer preserves every child kind, prefixed name, and
382
+ # declaration byte-for-byte.
376
383
  def dup
377
384
  ensure_alive!
378
385
  elem_ptr = Leptris::XML::FFI.leptris_node_as_element(@c_ptr)
379
386
  raise Leptris::XML::Error, "dup is only supported for element nodes" if elem_ptr.null?
380
- new_doc = Leptris::XML::Document.create
381
- copy = Leptris::XML::FFI.leptris_element_copy(elem_ptr, new_doc.c_ptr)
382
- raise Leptris::XML::Error, "leptris_element_copy failed" if copy.null?
383
- new_doc.root = Leptris::XML::Node.wrap(copy, new_doc)
387
+ Leptris::XML::Document.parse(to_xml).root
384
388
  end
385
389
  alias_method :clone, :dup
386
390
 
@@ -62,10 +62,21 @@ class Leptris::XML::NodeSet
62
62
  if @result_ptr
63
63
  ptr = Leptris::XML::FFI.leptris_xpath_result_get_node(@result_ptr, idx)
64
64
  return nil if ptr.null?
65
- Leptris::XML::Node.wrap(ptr, @document)
65
+ Leptris::XML::Node.wrap(
66
+ ptr, @document,
67
+ result_value: text_item_value(
68
+ Leptris::XML::FFI.leptris_xpath_result_node_kind(@result_ptr, idx), idx))
66
69
  end
67
70
  end
68
71
 
72
+ # Sequence/map/array items ride synthetic text nodes whose value
73
+ # only the live result handle can serve — capture it now.
74
+ def text_item_value(kind, index)
75
+ return nil unless kind == Leptris::XML::FFI::XPATH_NODE_TEXT
76
+ Leptris::XML::FFI.leptris_xpath_result_node_value(@result_ptr, index)
77
+ end
78
+ private :text_item_value
79
+
69
80
  # Iteration materializes: the first pass batch-fetches into @array
70
81
  # (yielding as it wraps), and every subsequent reader — each, [],
71
82
  # length — serves from the array. Repeated iteration without an
@@ -81,16 +92,21 @@ class Leptris::XML::NodeSet
81
92
  # not just elements); the batch accessor under-copies
82
93
  # mixed-kind results (upstream leptris#477), so per-index
83
94
  # fetch covers the remainder.
84
- pointers, kinds = Leptris::XML::FFI.fetch_result_nodes(@result_ptr, n)
95
+ pointers, kinds, raw = Leptris::XML::FFI.fetch_result_nodes(@result_ptr, n)
85
96
  nodes = []
86
97
  pointers.each_with_index do |ptr, i|
87
98
  next if ptr.null?
88
- nodes << Leptris::XML::Node.wrap(ptr, @document, node_type: kinds[i])
99
+ nodes << Leptris::XML::Node.wrap(
100
+ ptr, @document, node_type: kinds[i],
101
+ result_value: text_item_value(raw[i], i))
89
102
  end
90
103
  (pointers.length...n).each do |i|
91
104
  ptr = Leptris::XML::FFI.leptris_xpath_result_get_node(@result_ptr, i)
92
105
  next if ptr.null?
93
- nodes << Leptris::XML::Node.wrap(ptr, @document)
106
+ nodes << Leptris::XML::Node.wrap(
107
+ ptr, @document,
108
+ result_value: text_item_value(
109
+ Leptris::XML::FFI.leptris_xpath_result_node_kind(@result_ptr, i), i))
94
110
  end
95
111
  @array = nodes
96
112
  else
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Text-kind item from an XPath/XQuery sequence result: the engine
4
+ # materializes sequence, map, and array items as synthetic text
5
+ # nodes (leptris/types.h's internal kind 8) whose value is readable
6
+ # only through the live result handle — the node-pointer accessors
7
+ # return nothing for them. The NodeSet therefore captures the string
8
+ # value at materialization time and hands it to this wrapper.
9
+ #
10
+ # doc.xpath("for $w in //a return string($w/@v)").map(&:content)
11
+ # # => ["1", "2"]
12
+ #
13
+ class Leptris::XML::ResultText < Leptris::XML::Node
14
+ def initialize(c_ptr, document, value, parent: nil, node_type: nil)
15
+ super(c_ptr, document, parent: parent, node_type: node_type)
16
+ @value = value
17
+ end
18
+
19
+ def name
20
+ "text"
21
+ end
22
+
23
+ # The captured string: safe to read even after the owning result
24
+ # set has been collected (unlike pointer-backed reads).
25
+ def content
26
+ @value
27
+ end
28
+
29
+ def to_s
30
+ @value
31
+ end
32
+
33
+ def text?
34
+ true
35
+ end
36
+ end
@@ -115,17 +115,14 @@ module Leptris::XML::Serialization
115
115
 
116
116
  # Element-face indent unit (leptris-ruby#109 residual 2): no
117
117
  # element-level ext-serialize entry exists yet, so the unit path
118
- # C-copies the subtree into a fresh document (the copy keeps
119
- # every child kind and namespace since leptris 1.9.47 — #696,
120
- # #721) and serializes that document without a declaration —
121
- # identical output to the element serializer for the standard
122
- # layout, with the unit and every child kind intact.
118
+ # rounds the subtree through serialization into a fresh document
119
+ # (the 1.9.74 C copy drops descendant-used declarations —
120
+ # leptris/leptris#812) and serializes that document without a
121
+ # declaration — identical output to the element serializer for
122
+ # the standard layout, with the unit and every child kind intact.
123
123
  def self.to_xml_element_unit(element, unit, indent: 0)
124
- document = Leptris::XML::Document.create
124
+ document = Leptris::XML::Document.parse(element.to_xml)
125
125
  begin
126
- copy = Leptris::XML::FFI.leptris_element_copy(element.c_ptr, document.c_ptr)
127
- raise Leptris::XML::Error, "leptris_element_copy failed" if copy.null?
128
- document.root = Leptris::XML::Node.wrap(copy, document)
129
126
  to_xml_indent_unit(document.c_ptr, unit,
130
127
  indent: indent, no_decl: true)
131
128
  ensure
data/lib/leptris/xml.rb CHANGED
@@ -22,6 +22,7 @@ module Leptris
22
22
  autoload :Serialization, "leptris/xml/serialization"
23
23
  autoload :SAX, "leptris/xml/sax"
24
24
  autoload :XPath, "leptris/xml/xpath"
25
+ autoload :ResultText, "leptris/xml/result_text"
25
26
  autoload :XSLT, "leptris/xml/xslt"
26
27
  autoload :XQuery, "leptris/xml/xquery"
27
28
  autoload :Pull, "leptris/xml/pull"
@@ -44,6 +45,24 @@ module Leptris
44
45
  string, string.bytesize) != 0
45
46
  end
46
47
 
48
+ # Tolerant HTML4/5 parse into a standard Document (libleptris
49
+ # 1.9.75): implied end tags, void elements, raw-text script and
50
+ # style, lowercased names, minimized/unquoted attributes, and
51
+ # the HTML named entities. Document shape — html/head/body are
52
+ # synthesized (Nokogiri::HTML parity), but NO implied tbody.
53
+ # Malformed input degrades to text rather than raising; only an
54
+ # entirely empty result is an error.
55
+ def self.parse_html(html)
56
+ html = html.to_s
57
+ raw = Leptris::XML::FFI.leptris_parse_html_string(
58
+ html, html.bytesize, nil)
59
+ if raw.null?
60
+ raise Leptris::XML::ParseError,
61
+ "HTML parse failed: #{Leptris::XML::FFI.leptris_last_error}"
62
+ end
63
+ Leptris::XML::Document.wrap(raw)
64
+ end
65
+
47
66
  def self.parse_file(path)
48
67
  Document.parse_file(path)
49
68
  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.57
4
+ version: 1.9.58
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -96,6 +96,7 @@ files:
96
96
  - lib/leptris/xml/parse_options.rb
97
97
  - lib/leptris/xml/processing_instruction.rb
98
98
  - lib/leptris/xml/pull.rb
99
+ - lib/leptris/xml/result_text.rb
99
100
  - lib/leptris/xml/sax.rb
100
101
  - lib/leptris/xml/sax/document.rb
101
102
  - lib/leptris/xml/sax/dom_dispatch.rb